move viewports elements classnames to data attribute to prevent overwriting by 3rd party libs

This commit is contained in:
Rene Haas
2023-05-29 11:31:39 +02:00
parent fe026c0a43
commit 302ab3ea37
12 changed files with 144 additions and 108 deletions
+5 -3
View File
@@ -3,6 +3,7 @@ export const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-
export const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`; export const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;
export const dataAttributeHost = 'data-overlayscrollbars'; export const dataAttributeHost = 'data-overlayscrollbars';
export const dataAttributeViewport = 'data-overlayscrollbars-viewport';
export const dataAttributeInitialize = 'data-overlayscrollbars-initialize'; export const dataAttributeInitialize = 'data-overlayscrollbars-initialize';
export const dataAttributeHostOverflowX = `${dataAttributeHost}-overflow-x`; export const dataAttributeHostOverflowX = `${dataAttributeHost}-overflow-x`;
export const dataAttributeHostOverflowY = `${dataAttributeHost}-overflow-y`; export const dataAttributeHostOverflowY = `${dataAttributeHost}-overflow-y`;
@@ -11,11 +12,12 @@ export const dataValueHostScrollbarHidden = 'scrollbarHidden';
export const dataValueHostScrollbarPressed = 'scrollbarPressed'; export const dataValueHostScrollbarPressed = 'scrollbarPressed';
export const dataValueHostUpdating = 'updating'; export const dataValueHostUpdating = 'updating';
export const classNamePadding = 'os-padding'; export const classNamePadding = 'os-padding';
export const classNameViewport = 'os-viewport'; export const dataValueViewportArrange = 'arrange';
export const classNameViewportArrange = `${classNameViewport}-arrange`; export const dataValueViewportScrollbarHidden = 'scrollbarHidden';
export const dataValueViewportOverflowVisible = 'overflowVisible';
export const classNameContent = 'os-content'; export const classNameContent = 'os-content';
export const classNameViewportScrollbarHidden = `${classNameViewport}-scrollbar-hidden`;
export const classNameOverflowVisible = `os-overflow-visible`; export const classNameOverflowVisible = `os-overflow-visible`;
export const classNameScrollbarHidden = `os-scrollbar-hidden`;
export const classNameSizeObserver = 'os-size-observer'; export const classNameSizeObserver = 'os-size-observer';
export const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`; export const classNameSizeObserverAppear = `${classNameSizeObserver}-appear`;
@@ -23,7 +23,7 @@ import {
classNameEnvironment, classNameEnvironment,
classNameEnvironmentFlexboxGlue, classNameEnvironmentFlexboxGlue,
classNameEnvironmentFlexboxGlueMax, classNameEnvironmentFlexboxGlueMax,
classNameViewportScrollbarHidden, classNameScrollbarHidden,
} from '~/classnames'; } from '~/classnames';
import { defaultOptions } from '~/options'; import { defaultOptions } from '~/options';
import { getPlugins, scrollbarsHidingPluginName } from '~/plugins'; import { getPlugins, scrollbarsHidingPluginName } from '~/plugins';
@@ -120,7 +120,7 @@ const getNativeScrollbarSize = (
const getNativeScrollbarsHiding = (testElm: HTMLElement): boolean => { const getNativeScrollbarsHiding = (testElm: HTMLElement): boolean => {
let result = false; let result = false;
const revertClass = addClass(testElm, classNameViewportScrollbarHidden); const revertClass = addClass(testElm, classNameScrollbarHidden);
try { try {
result = result =
style(testElm, cssProperty('scrollbar-width')) === 'none' || style(testElm, cssProperty('scrollbar-width')) === 'none' ||
@@ -1,15 +1,5 @@
import { import { keys, attr, style, noop, each, assignDeep, windowSize, attrClass } from '~/support';
keys, import { dataValueViewportArrange, dataAttributeViewport } from '~/classnames';
attr,
style,
addClass,
removeClass,
noop,
each,
assignDeep,
windowSize,
} from '~/support';
import { classNameViewportArrange } from '~/classnames';
import type { WH, UpdateCache, XY } from '~/support'; import type { WH, UpdateCache, XY } from '~/support';
import type { StyleObject } from '~/typings'; import type { StyleObject } from '~/typings';
import type { StructureSetupState } from '~/setups/structureSetup'; import type { StructureSetupState } from '~/setups/structureSetup';
@@ -89,7 +79,11 @@ export const ScrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> =
const result = create ? document.createElement('style') : false; const result = create ? document.createElement('style') : false;
if (result) { if (result) {
attr(result, 'id', `${classNameViewportArrange}-${contentArrangeCounter}`); attr(
result,
'id',
`${dataAttributeViewport}-${dataValueViewportArrange}-${contentArrangeCounter}`
);
contentArrangeCounter++; contentArrangeCounter++;
} }
@@ -154,7 +148,10 @@ export const ScrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> =
if (cssRules) { if (cssRules) {
if (!cssRules.length) { if (!cssRules.length) {
sheet.insertRule( sheet.insertRule(
`#${attr(viewportArrange, 'id')} + .${classNameViewportArrange}::before {}`, `#${attr(
viewportArrange,
'id'
)} + [${dataAttributeViewport}~='${dataValueViewportArrange}']::before {}`,
0 0
); );
} }
@@ -211,7 +208,8 @@ export const ScrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> =
const prevStyle = style(viewport, keys(finalPaddingStyle)); const prevStyle = style(viewport, keys(finalPaddingStyle));
removeClass(viewport, classNameViewportArrange); // add class
attrClass(viewport, dataAttributeViewport, dataValueViewportArrange);
if (!flexboxGlue) { if (!flexboxGlue) {
finalPaddingStyle.height = ''; finalPaddingStyle.height = '';
@@ -228,7 +226,8 @@ export const ScrollbarsHidingPlugin: Plugin<ScrollbarsHidingPluginInstance> =
prevStyle prevStyle
); );
style(viewport, prevStyle); style(viewport, prevStyle);
addClass(viewport, classNameViewportArrange); // remove class
attrClass(viewport, dataAttributeViewport, dataValueViewportArrange, true);
}, },
finalViewportOverflowState, finalViewportOverflowState,
]; ];
@@ -9,8 +9,6 @@ import {
parent, parent,
indexOf, indexOf,
removeElements, removeElements,
removeClass,
hasClass,
push, push,
runEachAndClear, runEachAndClear,
insertBefore, insertBefore,
@@ -28,9 +26,10 @@ import {
dataAttributeHostOverflowX, dataAttributeHostOverflowX,
dataAttributeHostOverflowY, dataAttributeHostOverflowY,
classNamePadding, classNamePadding,
classNameViewport,
classNameContent, classNameContent,
classNameViewportScrollbarHidden, classNameScrollbarHidden,
dataAttributeViewport,
dataValueViewportScrollbarHidden,
} from '~/classnames'; } from '~/classnames';
import { getEnvironment } from '~/environment'; import { getEnvironment } from '~/environment';
import { getPlugins, scrollbarsHidingPluginName } from '~/plugins'; import { getPlugins, scrollbarsHidingPluginName } from '~/plugins';
@@ -69,8 +68,15 @@ export interface StructureSetupElementsObj {
_targetIsElm: boolean; _targetIsElm: boolean;
_viewportIsTarget: boolean; _viewportIsTarget: boolean;
_viewportIsContent: boolean; _viewportIsContent: boolean;
_viewportHasClass: (className: string, attributeClassName: string) => boolean; _viewportHasClass: (
_viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) => void; viewportAttributeClassName: string,
hostAttributeClassName: string
) => boolean;
_viewportAddRemoveClass: (
viewportAttributeClassName: string,
hostAttributeClassName: string,
add?: boolean
) => void;
} }
const tabIndexStr = 'tabindex'; const tabIndexStr = 'tabindex';
@@ -184,14 +190,23 @@ export const createStructureSetupElements = (
_targetIsElm: targetIsElm, _targetIsElm: targetIsElm,
_viewportIsTarget: viewportIsTarget, _viewportIsTarget: viewportIsTarget,
_viewportIsContent: viewportIsContent, _viewportIsContent: viewportIsContent,
_viewportHasClass: (className: string, attributeClassName: string) => _viewportHasClass: (viewportAttributeClassName: string, hostAttributeClassName: string) =>
viewportIsTarget hasAttrClass(
? hasAttrClass(viewportElement, dataAttributeHost, attributeClassName) viewportElement,
: hasClass(viewportElement, className), viewportIsTarget ? dataAttributeHost : dataAttributeViewport,
_viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) => viewportIsTarget ? hostAttributeClassName : viewportAttributeClassName
viewportIsTarget ),
? attrClass(viewportElement, dataAttributeHost, attributeClassName, add) _viewportAddRemoveClass: (
: (add ? addClass : removeClass)(viewportElement, className), viewportAttributeClassName: string,
hostAttributeClassName: string,
add?: boolean
) =>
attrClass(
viewportElement,
viewportIsTarget ? dataAttributeHost : dataAttributeViewport,
viewportIsTarget ? hostAttributeClassName : viewportAttributeClassName,
add
),
}; };
const generatedElements = keys(evaluatedTargetObj).reduce((arr, key: string) => { const generatedElements = keys(evaluatedTargetObj).reduce((arr, key: string) => {
const value = evaluatedTargetObj[key]; const value = evaluatedTargetObj[key];
@@ -224,12 +239,15 @@ export const createStructureSetupElements = (
const appendElements = () => { const appendElements = () => {
attr(_host, dataAttributeHost, viewportIsTarget ? 'viewport' : 'host'); attr(_host, dataAttributeHost, viewportIsTarget ? 'viewport' : 'host');
if (!viewportIsTarget) {
attr(_viewport, dataAttributeViewport, '');
}
const removePaddingClass = addClass(_padding, classNamePadding); const removePaddingClass = addClass(_padding, classNamePadding);
const removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport);
const removeContentClass = addClass(_content, classNameContent); const removeContentClass = addClass(_content, classNameContent);
const removeHtmlClass = const removeHtmlClass =
isBody && !viewportIsTarget isBody && !viewportIsTarget
? addClass(parent(targetElement), classNameViewportScrollbarHidden) ? addClass(parent(targetElement), classNameScrollbarHidden)
: noop; : noop;
// only insert host for textarea after target if it was generated // only insert host for textarea after target if it was generated
@@ -251,6 +269,7 @@ export const createStructureSetupElements = (
removeHtmlClass(); removeHtmlClass();
removeAttr(_viewport, dataAttributeHostOverflowX); removeAttr(_viewport, dataAttributeHostOverflowX);
removeAttr(_viewport, dataAttributeHostOverflowY); removeAttr(_viewport, dataAttributeHostOverflowY);
removeAttr(_viewport, dataAttributeViewport);
if (elementIsGenerated(_content)) { if (elementIsGenerated(_content)) {
unwrap(_content); unwrap(_content);
@@ -261,13 +280,14 @@ export const createStructureSetupElements = (
if (elementIsGenerated(_padding)) { if (elementIsGenerated(_padding)) {
unwrap(_padding); unwrap(_padding);
} }
removePaddingClass(); removePaddingClass();
removeViewportClass();
removeContentClass(); removeContentClass();
}); });
if (_nativeScrollbarsHiding && !viewportIsTarget) { if (_nativeScrollbarsHiding && !viewportIsTarget) {
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarHidden)); attrClass(_viewport, dataAttributeViewport, dataValueViewportScrollbarHidden, true);
push(destroyFns, removeAttr.bind(0, _viewport, dataAttributeViewport));
} }
if (_viewportArrange) { if (_viewportArrange) {
insertBefore(_viewport, _viewportArrange); insertBefore(_viewport, _viewportArrange);
@@ -27,10 +27,10 @@ import {
dataAttributeHost, dataAttributeHost,
dataValueHostOverflowVisible, dataValueHostOverflowVisible,
dataValueHostUpdating, dataValueHostUpdating,
classNameViewport,
classNameOverflowVisible,
classNameScrollbar, classNameScrollbar,
classNameViewportArrange, dataValueViewportArrange,
dataAttributeViewport,
dataValueViewportOverflowVisible,
} from '~/classnames'; } from '~/classnames';
import { createSizeObserver, createTrinsicObserver, createDOMObserver } from '~/observers'; import { createSizeObserver, createTrinsicObserver, createDOMObserver } from '~/observers';
import type { DOMObserver, SizeObserverCallbackParams } from '~/observers'; import type { DOMObserver, SizeObserverCallbackParams } from '~/observers';
@@ -62,7 +62,7 @@ const hostSelector = `[${dataAttributeHost}]`;
// TODO: observer textarea attrs if textarea // TODO: observer textarea attrs if textarea
const viewportSelector = `.${classNameViewport}`; const viewportSelector = `[${dataAttributeViewport}]`;
const viewportAttrsFromTarget = ['tabindex']; const viewportAttrsFromTarget = ['tabindex'];
const baseStyleChangingAttrsTextarea = ['wrap', 'cols', 'rows']; const baseStyleChangingAttrsTextarea = ['wrap', 'cols', 'rows'];
const baseStyleChangingAttrs = ['id', 'class', 'style', 'open']; const baseStyleChangingAttrs = ['id', 'class', 'style', 'open'];
@@ -94,20 +94,27 @@ export const createStructureSetupObservers = (
_initialValue: { w: 0, h: 0 }, _initialValue: { w: 0, h: 0 },
}, },
() => { () => {
const hasOver = _viewportHasClass(classNameOverflowVisible, dataValueHostOverflowVisible); const hasOver = _viewportHasClass(
const hasVpStyle = _viewportHasClass(classNameViewportArrange, ''); dataValueViewportOverflowVisible,
dataValueHostOverflowVisible
);
const hasVpStyle = _viewportHasClass(dataValueViewportArrange, '');
const scrollOffsetX = hasVpStyle && scrollLeft(_viewport); const scrollOffsetX = hasVpStyle && scrollLeft(_viewport);
const scrollOffsetY = hasVpStyle && scrollTop(_viewport); const scrollOffsetY = hasVpStyle && scrollTop(_viewport);
_viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible); _viewportAddRemoveClass(dataValueViewportOverflowVisible, dataValueHostOverflowVisible);
_viewportAddRemoveClass(classNameViewportArrange, ''); _viewportAddRemoveClass(dataValueViewportArrange, '');
_viewportAddRemoveClass('', dataValueHostUpdating, true); _viewportAddRemoveClass('', dataValueHostUpdating, true);
const contentScroll = scrollSize(_content); const contentScroll = scrollSize(_content);
const viewportScroll = scrollSize(_viewport); const viewportScroll = scrollSize(_viewport);
const fractional = fractionalSize(_viewport); const fractional = fractionalSize(_viewport);
_viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, hasOver); _viewportAddRemoveClass(
_viewportAddRemoveClass(classNameViewportArrange, '', hasVpStyle); dataValueViewportOverflowVisible,
dataValueHostOverflowVisible,
hasOver
);
_viewportAddRemoveClass(dataValueViewportArrange, '', hasVpStyle);
_viewportAddRemoveClass('', dataValueHostUpdating); _viewportAddRemoveClass('', dataValueHostUpdating);
scrollLeft(_viewport, scrollOffsetX); scrollLeft(_viewport, scrollOffsetX);
scrollTop(_viewport, scrollOffsetY); scrollTop(_viewport, scrollOffsetY);
@@ -14,13 +14,14 @@ import {
} from '~/support'; } from '~/support';
import { getEnvironment } from '~/environment'; import { getEnvironment } from '~/environment';
import { import {
classNameViewportScrollbarHidden,
classNameOverflowVisible, classNameOverflowVisible,
dataAttributeHost, dataAttributeHost,
dataAttributeHostOverflowX, dataAttributeHostOverflowX,
dataAttributeHostOverflowY, dataAttributeHostOverflowY,
dataValueHostScrollbarHidden, dataValueHostScrollbarHidden,
dataValueHostOverflowVisible, dataValueHostOverflowVisible,
dataValueViewportScrollbarHidden,
dataValueViewportOverflowVisible,
} from '~/classnames'; } from '~/classnames';
import { getPlugins, scrollbarsHidingPluginName } from '~/plugins'; import { getPlugins, scrollbarsHidingPluginName } from '~/plugins';
import type { WH, XY } from '~/support'; import type { WH, XY } from '~/support';
@@ -358,7 +359,7 @@ export const createOverflowUpdateSegment: CreateStructureUpdateSegment = (
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarsHiding) { if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarsHiding) {
_viewportAddRemoveClass( _viewportAddRemoveClass(
classNameViewportScrollbarHidden, dataValueViewportScrollbarHidden,
dataValueHostScrollbarHidden, dataValueHostScrollbarHidden,
!showNativeOverlaidScrollbars !showNativeOverlaidScrollbars
); );
@@ -377,7 +378,11 @@ export const createOverflowUpdateSegment: CreateStructureUpdateSegment = (
showNativeOverlaidScrollbarsChanged showNativeOverlaidScrollbarsChanged
) { ) {
if (overflowVisible) { if (overflowVisible) {
_viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, false); _viewportAddRemoveClass(
dataValueViewportOverflowVisible,
dataValueHostOverflowVisible,
false
);
} }
const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange( const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(
@@ -504,7 +509,9 @@ export const createOverflowUpdateSegment: CreateStructureUpdateSegment = (
attrClass(_host, dataAttributeHost, dataValueHostOverflowVisible, removeClipping); attrClass(_host, dataAttributeHost, dataValueHostOverflowVisible, removeClipping);
conditionalClass(_padding, classNameOverflowVisible, removeClipping); conditionalClass(_padding, classNameOverflowVisible, removeClipping);
!_viewportIsTarget && conditionalClass(_viewport, classNameOverflowVisible, overflowVisible); if (!_viewportIsTarget) {
_viewportAddRemoveClass(dataValueViewportOverflowVisible, '', overflowVisible);
}
const [overflowStyle, overflowStyleChanged] = updateOverflowStyleCache( const [overflowStyle, overflowStyleChanged] = updateOverflowStyleCache(
getViewportOverflowState(showNativeOverlaidScrollbars)._overflowStyle getViewportOverflowState(showNativeOverlaidScrollbars)._overflowStyle
@@ -58,23 +58,23 @@
*/ */
.os-environment, .os-environment,
.os-viewport { [data-overlayscrollbars-viewport] {
-ms-overflow-style: scrollbar !important; -ms-overflow-style: scrollbar !important;
} }
[data-overlayscrollbars-initialize], [data-overlayscrollbars-initialize],
[data-overlayscrollbars~='scrollbarHidden'], [data-overlayscrollbars~='scrollbarHidden'],
.os-viewport-scrollbar-hidden.os-environment, [data-overlayscrollbars-viewport~='scrollbarHidden'],
.os-viewport-scrollbar-hidden.os-viewport { .os-scrollbar-hidden.os-environment {
scrollbar-width: none !important; scrollbar-width: none !important;
} }
[data-overlayscrollbars-initialize]::-webkit-scrollbar, [data-overlayscrollbars-initialize]::-webkit-scrollbar,
[data-overlayscrollbars-initialize]::-webkit-scrollbar-corner, [data-overlayscrollbars-initialize]::-webkit-scrollbar-corner,
[data-overlayscrollbars~='scrollbarHidden']::-webkit-scrollbar, [data-overlayscrollbars~='scrollbarHidden']::-webkit-scrollbar,
[data-overlayscrollbars~='scrollbarHidden']::-webkit-scrollbar-corner, [data-overlayscrollbars~='scrollbarHidden']::-webkit-scrollbar-corner,
.os-viewport-scrollbar-hidden.os-environment::-webkit-scrollbar, [data-overlayscrollbars-viewport~='scrollbarHidden']::-webkit-scrollbar,
.os-viewport-scrollbar-hidden.os-environment::-webkit-scrollbar-corner, [data-overlayscrollbars-viewport~='scrollbarHidden']::-webkit-scrollbar-corner,
.os-viewport-scrollbar-hidden.os-viewport::-webkit-scrollbar, .os-scrollbar-hidden.os-environment::-webkit-scrollbar,
.os-viewport-scrollbar-hidden.os-viewport::-webkit-scrollbar-corner { .os-scrollbar-hidden.os-environment::-webkit-scrollbar-corner {
appearance: none !important; appearance: none !important;
display: none !important; display: none !important;
width: 0 !important; width: 0 !important;
@@ -94,8 +94,8 @@
*/ */
html[data-overlayscrollbars], html[data-overlayscrollbars],
html.os-viewport-scrollbar-hidden, html.os-scrollbar-hidden,
html.os-viewport-scrollbar-hidden > body { html.os-scrollbar-hidden > body {
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
width: 100%; width: 100%;
@@ -120,7 +120,7 @@ html[data-overlayscrollbars] > body {
} }
.os-padding, .os-padding,
.os-viewport { [data-overlayscrollbars-viewport] {
box-sizing: inherit; box-sizing: inherit;
position: relative; // needed for correct padding styles position: relative; // needed for correct padding styles
flex: auto !important; flex: auto !important;
@@ -132,11 +132,11 @@ html[data-overlayscrollbars] > body {
z-index: 0; z-index: 0;
} }
.os-viewport { [data-overlayscrollbars-viewport] {
--os-vaw: 0; --os-vaw: 0;
--os-vah: 0; --os-vah: 0;
&.os-viewport-arrange::before { &[data-overlayscrollbars-viewport~='arrange']::before {
content: ''; content: '';
position: absolute; position: absolute;
pointer-events: none; pointer-events: none;
@@ -148,11 +148,17 @@ html[data-overlayscrollbars] > body {
} }
} }
.os-padding,
[data-overlayscrollbars-viewport] {
overflow: hidden;
}
[data-overlayscrollbars~='host'], [data-overlayscrollbars~='host'],
[data-overlayscrollbars~='viewport'] { [data-overlayscrollbars~='viewport'] {
overflow: hidden; overflow: hidden;
} }
[data-overlayscrollbars~='overflowVisible'] { [data-overlayscrollbars~='overflowVisible'],
[data-overlayscrollbars-viewport~='overflowVisible'] {
overflow: visible; overflow: visible;
} }
[data-overlayscrollbars-overflow-x='hidden'] { [data-overlayscrollbars-overflow-x='hidden'] {
@@ -169,15 +175,10 @@ html[data-overlayscrollbars] > body {
} }
[data-overlayscrollbars~='scrollbarPressed'], [data-overlayscrollbars~='scrollbarPressed'],
[data-overlayscrollbars~='scrollbarPressed'] .os-viewport { [data-overlayscrollbars~='scrollbarPressed'] [data-overlayscrollbars-viewport] {
scroll-behavior: auto !important; scroll-behavior: auto !important;
} }
.os-padding,
.os-viewport {
overflow: hidden;
}
.os-overflow-visible { .os-overflow-visible {
overflow: visible; overflow: visible;
} }
@@ -196,8 +197,8 @@ html[data-overlayscrollbars] > body {
grid-template: 1fr / 1fr; grid-template: 1fr / 1fr;
} }
[data-overlayscrollbars-grid] > .os-padding, [data-overlayscrollbars-grid] > .os-padding,
[data-overlayscrollbars-grid] > .os-viewport, [data-overlayscrollbars-grid] > [data-overlayscrollbars-viewport],
[data-overlayscrollbars-grid] > .os-padding > .os-viewport { [data-overlayscrollbars-grid] > .os-padding > [data-overlayscrollbars-viewport] {
height: auto !important; height: auto !important;
width: auto !important; width: auto !important;
} }
@@ -48,6 +48,15 @@ export const attr = ((
elm && elm.setAttribute(attrName, value); elm && elm.setAttribute(attrName, value);
}) as Attr; }) as Attr;
/**
* Removes the given attribute from the given element.
* @param elm The element of which the attribute shall be removed.
* @param attrName The attribute name.
*/
export const removeAttr = (elm: Element | false | null | undefined, attrName: string): void => {
elm && elm.removeAttribute(attrName);
};
/** /**
* Treats the given attribute like the "class" attribute and adds or removes the given value from it. * Treats the given attribute like the "class" attribute and adds or removes the given value from it.
* @param elm The element. * @param elm The element.
@@ -65,8 +74,8 @@ export const attrClass = (
const currValues = attr(elm, attrName) || ''; const currValues = attr(elm, attrName) || '';
const currValuesSet = new Set(currValues.split(' ')); const currValuesSet = new Set(currValues.split(' '));
currValuesSet[add ? 'add' : 'delete'](value); currValuesSet[add ? 'add' : 'delete'](value);
const newTokens = from(currValuesSet).join(' ').trim();
attr(elm, attrName, from(currValuesSet).join(' ').trim()); attr(elm, attrName, newTokens);
} }
}; };
@@ -87,15 +96,6 @@ export const hasAttrClass = (
return currValuesSet.has(value); return currValuesSet.has(value);
}; };
/**
* Removes the given attribute from the given element.
* @param elm The element of which the attribute shall be removed.
* @param attrName The attribute name.
*/
export const removeAttr = (elm: Element | false | null | undefined, attrName: string): void => {
elm && elm.removeAttribute(attrName);
};
/** /**
* Gets or sets the scrollLeft value of the given element depending whether the value attribute is given. * Gets or sets the scrollLeft value of the given element depending whether the value attribute is given.
* @param elm The element of which the scrollLeft value shall be get or set. * @param elm The element of which the scrollLeft value shall be get or set.
@@ -1,5 +1,5 @@
import { rAF, cAF } from '~/support/compatibility'; import { rAF, cAF } from '~/support/compatibility';
import { isFunction } from '~/support/utils'; import { isFunction } from './types';
const { max } = Math; const { max } = Math;
const animationCurrentTime = () => performance.now(); const animationCurrentTime = () => performance.now();
@@ -1,11 +1,11 @@
import { hasClass, is, isHTMLElement } from '~/support'; import { is, isHTMLElement } from '~/support';
import { resolveInitialization } from '~/initialization'; import { resolveInitialization } from '~/initialization';
import { import {
dataAttributeHost, dataAttributeHost,
dataAttributeInitialize, dataAttributeInitialize,
classNamePadding, classNamePadding,
classNameViewport,
classNameContent, classNameContent,
dataAttributeViewport,
} from '~/classnames'; } from '~/classnames';
import { getEnvironment } from '~/environment'; import { getEnvironment } from '~/environment';
import { createStructureSetupElements } from '~/setups/structureSetup/structureSetup.elements'; import { createStructureSetupElements } from '~/setups/structureSetup/structureSetup.elements';
@@ -89,7 +89,7 @@ const getElements = (targetType: TargetType) => {
const target = getTarget(targetType); const target = getTarget(targetType);
const host = document.querySelector(`[${dataAttributeHost}]`)!; const host = document.querySelector(`[${dataAttributeHost}]`)!;
const padding = document.querySelector(`.${classNamePadding}`)!; const padding = document.querySelector(`.${classNamePadding}`)!;
const viewport = document.querySelector(`.${classNameViewport}`)!; const viewport = document.querySelector(`[${dataAttributeViewport}]`)!;
const content = document.querySelector(`.${classNameContent}`)!; const content = document.querySelector(`.${classNameContent}`)!;
const children = const children =
targetType === 'textarea' targetType === 'textarea'
@@ -426,16 +426,14 @@ const assertCorrectSetupElements = (
expect(_viewportHasClass('', attrName)).toBe(true); expect(_viewportHasClass('', attrName)).toBe(true);
expect(_host.getAttribute(dataAttributeHost)!.indexOf(attrName) >= 0).toBe(true); expect(_host.getAttribute(dataAttributeHost)!.indexOf(attrName) >= 0).toBe(true);
} else { } else {
expect(hasClass(_viewport, className)).toBe(true); expect(_viewportHasClass(className, attrName)).toBe(true);
expect(_viewportHasClass(className, '')).toBe(true);
} }
_viewportAddRemoveClass(className, attrName); _viewportAddRemoveClass(className, attrName);
if (_viewportIsTarget) { if (_viewportIsTarget) {
expect(_host.getAttribute(dataAttributeHost)!.indexOf(attrName) >= 0).toBe(false); expect(_host.getAttribute(dataAttributeHost)!.indexOf(attrName) >= 0).toBe(false);
expect(_viewportHasClass('', attrName)).toBe(false); expect(_viewportHasClass('', attrName)).toBe(false);
} else { } else {
expect(hasClass(_viewport, className)).toBe(false); expect(_viewportHasClass(className, attrName)).toBe(false);
expect(_viewportHasClass(className, '')).toBe(false);
} }
return [elements, destroy]; return [elements, destroy];
@@ -453,7 +451,7 @@ const assertCorrectDestroy = (snapshot: string, destroy: () => void) => {
} }
}); });
expect(snapshot).toBe(getSnapshot()); expect(getSnapshot()).toBe(snapshot);
}; };
const env: InternalEnvironment = jest.requireActual('~/environment').getEnvironment(); const env: InternalEnvironment = jest.requireActual('~/environment').getEnvironment();
@@ -2,7 +2,7 @@ import '~/index.scss';
import './index.scss'; import './index.scss';
import './handleEnvironment'; import './handleEnvironment';
import { OverlayScrollbars } from '~/overlayscrollbars'; import { OverlayScrollbars } from '~/overlayscrollbars';
import { classNameViewport } from '~/classnames'; import { dataAttributeViewport } from '~/classnames';
import should from 'should'; import should from 'should';
import { import {
generateClassChangeSelectCallback, generateClassChangeSelectCallback,
@@ -132,7 +132,7 @@ const targetUpdatesSlot: HTMLElement | null = document.querySelector('#updates')
const comparisonContentElm: HTMLElement = document.createElement('div'); const comparisonContentElm: HTMLElement = document.createElement('div');
const envElms = document.querySelectorAll<HTMLElement>('.env'); const envElms = document.querySelectorAll<HTMLElement>('.env');
const getComparisonViewport = () => const getComparisonViewport = () =>
(comparison?.querySelector(`.${classNameViewport}`) || comparison) as HTMLElement; (comparison?.querySelector(`[${dataAttributeViewport}]`) || comparison) as HTMLElement;
const initObj = hasClass(document.body, 'vpt') const initObj = hasClass(document.body, 'vpt')
? { ? {
@@ -214,7 +214,9 @@ const osInstance =
if (paddingAbsolute) { if (paddingAbsolute) {
if (comparisonViewport === comparison) { if (comparisonViewport === comparison) {
addClass(document.body, 'pa'); addClass(document.body, 'pa');
const absoluteWrapper = createDiv(classNameViewport); const absoluteWrapper = createDiv();
absoluteWrapper.setAttribute(dataAttributeViewport, '');
appendChildren(absoluteWrapper, contents(comparison)); appendChildren(absoluteWrapper, contents(comparison));
appendChildren(comparison, absoluteWrapper); appendChildren(comparison, absoluteWrapper);
@@ -72,7 +72,7 @@ body {
position: relative; position: relative;
background: rgba(0, 0, 0, 0.1); background: rgba(0, 0, 0, 0.1);
.os-viewport::after, [data-overlayscrollbars-viewport]::after,
&::after { &::after {
content: ''; content: '';
display: block; display: block;
@@ -241,7 +241,7 @@ body {
.boxSizingBorderBox > .container { .boxSizingBorderBox > .container {
box-sizing: border-box; box-sizing: border-box;
.os-viewport * { [data-overlayscrollbars-viewport] * {
box-sizing: border-box; box-sizing: border-box;
} }
} }
@@ -249,7 +249,7 @@ body {
.boxSizingContentBox > .container { .boxSizingContentBox > .container {
box-sizing: content-box; box-sizing: content-box;
.os-viewport * { [data-overlayscrollbars-viewport] * {
box-sizing: content-box; box-sizing: content-box;
} }
} }
@@ -307,11 +307,11 @@ body {
// disable native scrollbar styling detection // disable native scrollbar styling detection
body.nsh { body.nsh {
.os-viewport-scrollbar-hidden.os-environment { [data-overlayscrollbars-viewport~='scrollbarHidden'].os-environment {
scrollbar-width: auto !important; scrollbar-width: auto !important;
} }
.os-viewport-scrollbar-hidden.os-environment::-webkit-scrollbar, .os-scrollbar-hidden.os-environment::-webkit-scrollbar,
.os-viewport-scrollbar-hidden.os-environment::-webkit-scrollbar-corner { .os-scrollbar-hidden.os-environment::-webkit-scrollbar-corner {
display: block !important; display: block !important;
} }
} }
@@ -333,9 +333,9 @@ body.ccp {
// fully overlaid // fully overlaid
body.fo { body.fo {
.os-environment::-webkit-scrollbar, .os-environment::-webkit-scrollbar,
.os-viewport::-webkit-scrollbar, [data-overlayscrollbars-viewport]::-webkit-scrollbar,
.os-environment::-webkit-scrollbar-corner, .os-environment::-webkit-scrollbar-corner,
.os-viewport::-webkit-scrollbar-corner { [data-overlayscrollbars-viewport]::-webkit-scrollbar-corner {
display: none !important; display: none !important;
width: 0px !important; width: 0px !important;
height: 0px !important; height: 0px !important;
@@ -344,7 +344,7 @@ body.fo {
} }
.os-environment, .os-environment,
.os-viewport { [data-overlayscrollbars-viewport] {
scrollbar-width: none !important; scrollbar-width: none !important;
-ms-overflow-style: none !important; -ms-overflow-style: none !important;
} }
@@ -353,9 +353,9 @@ body.fo {
// partially overlaid (chrome only) // partially overlaid (chrome only)
body.po { body.po {
.os-environment::-webkit-scrollbar, .os-environment::-webkit-scrollbar,
.os-viewport::-webkit-scrollbar, [data-overlayscrollbars-viewport]::-webkit-scrollbar,
.os-environment::-webkit-scrollbar-corner, .os-environment::-webkit-scrollbar-corner,
.os-viewport::-webkit-scrollbar-corner { [data-overlayscrollbars-viewport]::-webkit-scrollbar-corner {
display: block !important; display: block !important;
width: 10px !important; width: 10px !important;
height: 0 !important; height: 0 !important;