add viewport is target mode

This commit is contained in:
Rene
2022-07-07 13:27:31 +02:00
parent 66c55f98e9
commit b581c91738
17 changed files with 643 additions and 336 deletions
+189 -111
View File
@@ -195,6 +195,17 @@ function attr(elm, attrName, value) {
elm && elm.setAttribute(attrName, value);
}
const attrClass = (elm, attrName, value, add) => {
const currValues = attr(elm, attrName) || '';
const currValuesSet = new Set(currValues.split(' '));
currValuesSet[add ? 'add' : 'delete'](value);
attr(elm, attrName, from(currValuesSet).join(' ').trim());
};
const hasAttrClass = (elm, attrName, value) => {
const currValues = attr(elm, attrName) || '';
const currValuesSet = new Set(currValues.split(' '));
return currValuesSet.has(value);
};
const removeAttr = (elm, attrName) => {
elm && elm.removeAttribute(attrName);
};
@@ -213,6 +224,11 @@ const find = (selector, elm) => {
return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;
};
const findFirst = (selector, elm) => {
const rootElm = elm ? isElement(elm) ? elm : null : document;
return rootElm ? rootElm.querySelector(selector) : null;
};
const is = (elm, selector) => {
if (isElement(elm)) {
const fn = elmPrototype.matches || elmPrototype.msMatchesSelector;
@@ -226,6 +242,32 @@ const contents = elm => elm ? from(elm.childNodes) : [];
const parent = elm => elm ? elm.parentElement : null;
const closest = (elm, selector) => {
if (isElement(elm)) {
const closestFn = elmPrototype.closest;
if (closestFn) {
return closestFn.call(elm, selector);
}
do {
if (is(elm, selector)) {
return elm;
}
elm = parent(elm);
} while (elm);
}
return null;
};
const liesBetween = (elm, highBoundarySelector, deepBoundarySelector) => {
const closestHighBoundaryElm = elm && closest(elm, highBoundarySelector);
const closestDeepBoundaryElm = elm && findFirst(deepBoundarySelector, closestHighBoundaryElm);
return closestHighBoundaryElm && closestDeepBoundaryElm ? closestHighBoundaryElm === elm || closestDeepBoundaryElm === elm || closest(closest(elm, deepBoundarySelector), highBoundarySelector) !== closestHighBoundaryElm : false;
};
const before = (parentElm, preferredAnchor, insertedElms) => {
if (insertedElms) {
let anchor = preferredAnchor;
@@ -349,7 +391,7 @@ const classListAction = (elm, className, action) => {
let i = 0;
let result = false;
if (elm && isString(className)) {
if (elm && className && isString(className)) {
const classes = className.match(rnothtmlwhite) || [];
result = classes.length > 0;
@@ -360,6 +402,8 @@ const classListAction = (elm, className, action) => {
return result;
};
const hasClass = (elm, className) => classListAction(elm, className, (classList, clazz) => classList.contains(clazz));
const removeClass = (elm, className) => {
classListAction(elm, className, (classList, clazz) => classList.remove(clazz));
};
@@ -367,22 +411,6 @@ const addClass = (elm, className) => {
classListAction(elm, className, (classList, clazz) => classList.add(clazz));
return removeClass.bind(0, elm, className);
};
const diffClass = (classNameA, classNameB) => {
const classNameASplit = classNameA && classNameA.split(' ');
const classNameBSplit = classNameB && classNameB.split(' ');
const tempObj = {};
each(classNameASplit, className => {
tempObj[className] = 1;
});
each(classNameBSplit, className => {
if (tempObj[className]) {
delete tempObj[className];
} else {
tempObj[className] = 1;
}
});
return keys(tempObj);
};
const equal = (a, b, props, propMutation) => {
if (a && b) {
@@ -688,6 +716,10 @@ const classNameEnvironment = 'os-environment';
const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-glue`;
const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;
const dataAttributeHost = 'data-overlayscrollbars';
const dataAttributeHostOverflowX = `${dataAttributeHost}-overflow-x`;
const dataAttributeHostOverflowY = `${dataAttributeHost}-overflow-y`;
const dataValueHostOverflowVisible = 'overflowVisible';
const dataValueHostViewportScrollbarStyling = 'viewportStyled';
const classNamePadding = 'os-padding';
const classNameViewport = 'os-viewport';
const classNameViewportArrange = `${classNameViewport}-arrange`;
@@ -716,17 +748,21 @@ const stringify = value => JSON.stringify(value, (_, val) => {
});
const defaultOptions = {
resize: 'none',
paddingAbsolute: false,
updating: {
elementEvents: [['img', 'load']],
debounce: [0, 33],
attributes: null,
debounce: [0, 33]
ignoreMutation: null
},
overflow: {
x: 'scroll',
y: 'scroll'
},
nativeScrollbarsOverlaid: {
show: false,
initialize: false
},
scrollbars: {
visibility: 'auto',
autoHide: 'never',
@@ -734,18 +770,6 @@ const defaultOptions = {
dragScroll: true,
clickScroll: false,
touch: true
},
textarea: {
dynWidth: false,
dynHeight: false,
inheritedAttrs: ['style', 'class']
},
nativeScrollbarsOverlaid: {
show: false,
initialize: false
},
callbacks: {
onUpdated: null
}
};
const getOptionsDiff = (currOptions, newOptions) => {
@@ -988,8 +1012,8 @@ const dynamicCreationFromStrategy = (target, initializationValue, strategy) => {
return result === true ? createDiv() : result;
};
const addDataAttrHost = elm => {
attr(elm, dataAttributeHost, '');
const addDataAttrHost = (elm, value) => {
attr(elm, dataAttributeHost, value || '');
return removeAttr.bind(0, elm, dataAttributeHost);
};
@@ -1014,20 +1038,28 @@ const createStructureSetupElements = target => {
const ownerDocument = targetElement.ownerDocument;
const bodyElm = ownerDocument.body;
const wnd = ownerDocument.defaultView;
const singleElmSupport = !!ResizeObserverConstructor && _nativeScrollbarStyling;
const potentialViewportElement = staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy);
const potentiallySingleElm = potentialViewportElement === targetElement;
const viewportIsTarget = singleElmSupport && potentiallySingleElm;
const viewportElement = potentiallySingleElm && !viewportIsTarget ? staticCreationFromStrategy(targetElement) : potentialViewportElement;
const evaluatedTargetObj = {
_target: targetElement,
_host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy) : targetElement,
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy),
_viewport: viewportElement,
_padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy),
_content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy),
_viewportArrange: createUniqueViewportArrangeElement(),
_viewportArrange: !viewportIsTarget && createUniqueViewportArrangeElement(),
_windowElm: wnd,
_documentElm: ownerDocument,
_htmlElm: parent(bodyElm),
_bodyElm: bodyElm,
_isTextarea: isTextarea,
_isBody: isBody,
_targetIsElm: targetIsElm
_targetIsElm: targetIsElm,
_viewportIsTarget: viewportIsTarget,
_viewportHasClass: (className, attributeClassName) => viewportIsTarget ? hasAttrClass(viewportElement, dataAttributeHost, attributeClassName) : hasClass(viewportElement, className),
_viewportAddRemoveClass: (className, attributeClassName, add) => viewportIsTarget ? attrClass(viewportElement, dataAttributeHost, attributeClassName, add) : (add ? addClass : removeClass)(viewportElement, className)
};
const generatedElements = keys(evaluatedTargetObj).reduce((arr, key) => {
const value = evaluatedTargetObj[key];
@@ -1048,9 +1080,9 @@ const createStructureSetupElements = target => {
const isTextareaHostGenerated = isTextarea && elementIsGenerated(_host);
const targetContents = isTextarea ? _target : contents([_content, _viewport, _padding, _host, _target].find(elm => elementIsGenerated(elm) === false));
const contentSlot = _content || _viewport;
const removeHostDataAttr = addDataAttrHost(_host);
const removeHostDataAttr = addDataAttrHost(_host, viewportIsTarget ? 'viewport' : 'host');
const removePaddingClass = addClass(_padding, classNamePadding);
const removeViewportClass = addClass(_viewport, classNameViewport);
const removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport);
const removeContentClass = addClass(_content, classNameContent);
if (isTextareaHostGenerated) {
@@ -1063,34 +1095,31 @@ const createStructureSetupElements = target => {
appendChildren(contentSlot, targetContents);
appendChildren(_host, _padding);
appendChildren(_padding || _host, _viewport);
appendChildren(_padding || _host, !viewportIsTarget && _viewport);
appendChildren(_viewport, _content);
push(destroyFns, () => {
if (targetIsElm) {
appendChildren(_host, contents(contentSlot));
removeElements(_padding || _viewport);
removeHostDataAttr();
} else {
if (elementIsGenerated(_content)) {
unwrap(_content);
}
removeHostDataAttr();
removeAttr(_viewport, dataAttributeHostOverflowX);
removeAttr(_viewport, dataAttributeHostOverflowY);
if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
removeHostDataAttr();
removePaddingClass();
removeViewportClass();
removeContentClass();
if (elementIsGenerated(_content)) {
unwrap(_content);
}
if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
removePaddingClass();
removeViewportClass();
removeContentClass();
});
if (_nativeScrollbarStyling) {
if (_nativeScrollbarStyling && !viewportIsTarget) {
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
}
@@ -1121,8 +1150,7 @@ const createTrinsicUpdate = (structureSetupElements, state) => {
if (heightIntrinsicChanged) {
style(_content, {
height: _heightIntrinsic ? '' : '100%',
display: _heightIntrinsic ? '' : 'inline'
height: _heightIntrinsic ? '' : '100%'
});
}
@@ -1138,7 +1166,8 @@ const createPaddingUpdate = (structureSetupElements, state) => {
const {
_host,
_padding,
_viewport
_viewport,
_viewportIsTarget: _isSingleElm
} = structureSetupElements;
const [updatePaddingCache, currentPaddingCache] = createCache({
_equal: equalTRBL,
@@ -1165,7 +1194,7 @@ const createPaddingUpdate = (structureSetupElements, state) => {
[padding, paddingChanged] = updatePaddingCache(force);
}
const paddingStyleChanged = paddingAbsoluteChanged || _directionChanged || paddingChanged;
const paddingStyleChanged = !_isSingleElm && (paddingAbsoluteChanged || _directionChanged || paddingChanged);
if (paddingStyleChanged) {
const paddingRelative = !paddingAbsolute || !_padding && !_nativeScrollbarStyling;
@@ -1234,7 +1263,7 @@ const getOverflowAmount = (viewportScrollSize, viewportClientSize, sizeFraction)
};
};
const conditionalClass = (elm, classNames, condition) => condition ? addClass(elm, classNames) : removeClass(elm, classNames);
const conditionalClass = (elm, classNames, add) => add ? addClass(elm, classNames) : removeClass(elm, classNames);
const overflowIsVisible = overflowBehavior => overflowBehavior.indexOf(strVisible) === 0;
@@ -1244,7 +1273,9 @@ const createOverflowUpdate = (structureSetupElements, state) => {
_host,
_padding,
_viewport,
_viewportArrange
_viewportArrange,
_viewportIsTarget,
_viewportAddRemoveClass
} = structureSetupElements;
const {
_nativeScrollbarSize,
@@ -1252,7 +1283,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
_nativeScrollbarStyling,
_nativeScrollbarIsOverlaid
} = getEnvironment();
const doViewportArrange = !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
const doViewportArrange = !_viewportIsTarget && !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
const [updateSizeFraction, getCurrentSizeFraction] = createCache(whCacheOptions, fractionalSize.bind(0, _host));
const [updateViewportScrollSizeCache, getCurrentViewportScrollSizeCache] = createCache(whCacheOptions, scrollSize.bind(0, _viewport));
const [updateOverflowAmountCache, getCurrentOverflowAmountCache] = createCache(whCacheOptions);
@@ -1483,7 +1514,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
const [showNativeOverlaidScrollbarsOption, showNativeOverlaidScrollbarsChanged] = checkOption('nativeScrollbarsOverlaid.show');
const [overflow, overflowChanged] = checkOption('overflow');
const showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
const adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || _heightIntrinsicChanged);
const adjustFlexboxGlue = !_viewportIsTarget && !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || _heightIntrinsicChanged);
const overflowXVisible = overflowIsVisible(overflow.x);
const overflowYVisible = overflowIsVisible(overflow.y);
const overflowVisible = overflowXVisible || overflowYVisible;
@@ -1493,7 +1524,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
let preMeasureViewportOverflowState;
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);
_viewportAddRemoveClass(classNameViewportScrollbarStyling, dataValueHostViewportScrollbarStyling, !showNativeOverlaidScrollbars);
}
if (adjustFlexboxGlue) {
@@ -1503,7 +1534,7 @@ const createOverflowUpdate = (structureSetupElements, state) => {
if (_sizeChanged || _paddingStyleChanged || _contentMutation || _directionChanged || showNativeOverlaidScrollbarsChanged) {
if (overflowVisible) {
removeClass(_viewport, classNameOverflowVisible);
_viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, false);
}
const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(showNativeOverlaidScrollbars, _directionIsRTL, preMeasureViewportOverflowState);
@@ -1548,18 +1579,26 @@ const createOverflowUpdate = (structureSetupElements, state) => {
};
const viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, hasOverflow, overflow, viewportStyle);
const viewportArranged = arrangeViewport(viewportOverflowState, viewportScrollSize, sizeFraction, _directionIsRTL);
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
if (!_viewportIsTarget) {
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
}
if (adjustFlexboxGlue) {
fixFlexboxGlue(viewportOverflowState, _heightIntrinsic);
}
style(_viewport, viewportStyle);
if (_viewportIsTarget) {
attr(_host, dataAttributeHostOverflowX, viewportStyle.overflowX);
attr(_host, dataAttributeHostOverflowY, viewportStyle.overflowY);
} else {
style(_viewport, viewportStyle);
}
}
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
attrClass(_host, dataAttributeHost, dataValueHostOverflowVisible, removeClipping);
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
!_viewportIsTarget && conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
const [overflowStyle, overflowStyleChanged] = updateOverflowStyleCache(getViewportOverflowState(showNativeOverlaidScrollbars)._overflowStyle);
setState({
_overflowStyle: overflowStyle,
@@ -1910,7 +1949,6 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
_eventContentChange,
_nestedTargetSelector,
_ignoreTargetChange,
_ignoreNestedTargetChange,
_ignoreContentChange
} = options || {};
const [destroyEventContentChange, updateEventContentChangeElements] = createEventContentChange(target, debounce(() => {
@@ -1926,7 +1964,7 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
const observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
const observerCallback = mutations => {
const ignoreTargetChange = (isContentObserver ? _ignoreNestedTargetChange : _ignoreTargetChange) || noop;
const ignoreTargetChange = _ignoreTargetChange || noop;
const ignoreContentChange = _ignoreContentChange || noop;
const targetChangedAttrs = [];
const totalAddedNodes = [];
@@ -2002,20 +2040,11 @@ const createDOMObserver = (target, isContentObserver, callback, options) => {
}];
};
const ignorePrefix = 'os-';
const hostSelector = `[${dataAttributeHost}]`;
const viewportSelector = `.${classNameViewport}`;
const viewportAttrsFromTarget = ['tabindex'];
const baseStyleChangingAttrsTextarea = ['wrap', 'cols', 'rows'];
const baseStyleChangingAttrs = ['id', 'class', 'style', 'open'];
const ignoreTargetChange = (target, attrName, oldValue, newValue) => {
if (attrName === 'class' && oldValue && newValue) {
const diff = diffClass(oldValue, newValue);
return !!diff.find(addedOrRemovedClass => addedOrRemovedClass.indexOf(ignorePrefix) !== 0);
}
return false;
};
const createStructureSetupObservers = (structureSetupElements, state, structureSetupUpdate) => {
let debounceTimeout;
let debounceMaxDelay;
@@ -2025,12 +2054,34 @@ const createStructureSetupObservers = (structureSetupElements, state, structureS
_host,
_viewport,
_content,
_isTextarea
_isTextarea,
_viewportIsTarget,
_viewportHasClass,
_viewportAddRemoveClass
} = structureSetupElements;
const {
_nativeScrollbarStyling,
_flexboxGlue
} = getEnvironment();
const [updateContentSizeCache] = createCache({
_equal: equalWH,
_initialValue: {
w: 0,
h: 0
}
}, () => {
const has = _viewportHasClass(classNameOverflowVisible, dataValueHostOverflowVisible);
has && _viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible);
const contentScroll = scrollSize(_content);
const viewportScroll = scrollSize(_viewport);
const fractional = fractionalSize(_viewport);
has && _viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, true);
return {
w: viewportScroll.w + contentScroll.w + fractional.w,
h: viewportScroll.h + contentScroll.h + fractional.h
};
});
const contentMutationObserverAttr = _isTextarea ? baseStyleChangingAttrsTextarea : baseStyleChangingAttrs.concat(baseStyleChangingAttrsTextarea);
const structureSetupUpdateWithDebouncedAdaptiveUpdateHints = debounce(structureSetupUpdate, {
_timeout: () => debounceTimeout,
@@ -2094,10 +2145,14 @@ const createStructureSetupObservers = (structureSetupElements, state, structureS
};
const onContentMutation = contentChangedTroughEvent => {
const [, contentSizeChanged] = updateContentSizeCache();
const updateFn = contentChangedTroughEvent ? structureSetupUpdate : structureSetupUpdateWithDebouncedAdaptiveUpdateHints;
updateFn({
_contentMutation: true
});
if (contentSizeChanged) {
updateFn({
_contentMutation: true
});
}
};
const onHostMutation = (targetChangedAttrs, targetStyleChanged) => {
@@ -2105,28 +2160,34 @@ const createStructureSetupObservers = (structureSetupElements, state, structureS
structureSetupUpdateWithDebouncedAdaptiveUpdateHints({
_hostMutation: true
});
} else {
} else if (!_viewportIsTarget) {
updateViewportAttrsFromHost(targetChangedAttrs);
}
};
const destroyTrinsicObserver = (_content || !_flexboxGlue) && createTrinsicObserver(_host, onTrinsicChanged);
const destroySizeObserver = createSizeObserver(_host, onSizeChanged, {
const destroySizeObserver = !_viewportIsTarget && createSizeObserver(_host, onSizeChanged, {
_appear: true,
_direction: !_nativeScrollbarStyling
});
const [destroyHostMutationObserver] = createDOMObserver(_host, false, onHostMutation, {
_styleChangingAttributes: baseStyleChangingAttrs,
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget),
_ignoreTargetChange: ignoreTargetChange
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget)
});
const viewportIsTargetResizeObserver = _viewportIsTarget && new ResizeObserverConstructor(onSizeChanged.bind(0, {
_sizeChanged: true
}));
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.observe(_host);
updateViewportAttrsFromHost();
return [checkOption => {
const [elementEvents, elementEventsChanged] = checkOption('updating.elementEvents');
const [ignoreMutation] = checkOption('updating.ignoreMutation');
const [attributes, attributesChanged] = checkOption('updating.attributes');
const [elementEvents, elementEventsChanged] = checkOption('updating.elementEvents');
const [debounceValue, debounceChanged] = checkOption('updating.debounce');
const updateContentMutationObserver = elementEventsChanged || attributesChanged;
const ignoreMutationFromOptions = mutation => isFunction(ignoreMutation) && ignoreMutation(mutation);
if (updateContentMutationObserver) {
if (contentMutationObserver) {
contentMutationObserver[1]();
@@ -2137,7 +2198,15 @@ const createStructureSetupObservers = (structureSetupElements, state, structureS
_styleChangingAttributes: contentMutationObserverAttr.concat(attributes || []),
_attributes: contentMutationObserverAttr.concat(attributes || []),
_eventContentChange: elementEvents,
_ignoreNestedTargetChange: ignoreTargetChange
_nestedTargetSelector: hostSelector,
_ignoreContentChange: (mutation, isNestedTarget) => {
const {
target,
attributeName
} = mutation;
const ignore = !isNestedTarget && attributeName ? liesBetween(target, hostSelector, viewportSelector) : false;
return ignore || !!ignoreMutationFromOptions(mutation);
}
});
}
@@ -2160,7 +2229,8 @@ const createStructureSetupObservers = (structureSetupElements, state, structureS
}, () => {
contentMutationObserver && contentMutationObserver[0]();
destroyTrinsicObserver && destroyTrinsicObserver();
destroySizeObserver();
destroySizeObserver && destroySizeObserver();
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.disconnect();
destroyHostMutationObserver();
}];
};
@@ -2335,18 +2405,16 @@ const optionsTemplateTypes = ['boolean', 'number', 'string', 'array', 'object',
const numberAllowedValues = optionsTemplateTypes.number;
const booleanAllowedValues = optionsTemplateTypes.boolean;
const arrayNullValues = [optionsTemplateTypes.array, optionsTemplateTypes.null];
const stringArrayNullAllowedValues = [optionsTemplateTypes.string, optionsTemplateTypes.array, optionsTemplateTypes.null];
const resizeAllowedValues = 'none both horizontal vertical';
const overflowAllowedValues = 'hidden scroll visible visible-hidden';
const scrollbarsVisibilityAllowedValues = 'visible hidden auto';
const scrollbarsAutoHideAllowedValues = 'never scroll leavemove';
({
resize: resizeAllowedValues,
paddingAbsolute: booleanAllowedValues,
updating: {
elementEvents: arrayNullValues,
attributes: arrayNullValues,
debounce: [optionsTemplateTypes.number, optionsTemplateTypes.array, optionsTemplateTypes.null]
debounce: [optionsTemplateTypes.number, optionsTemplateTypes.array, optionsTemplateTypes.null],
ignoreMutation: [optionsTemplateTypes.function, optionsTemplateTypes.null]
},
overflow: {
x: overflowAllowedValues,
@@ -2360,17 +2428,9 @@ const scrollbarsAutoHideAllowedValues = 'never scroll leavemove';
clickScroll: booleanAllowedValues,
touch: booleanAllowedValues
},
textarea: {
dynWidth: booleanAllowedValues,
dynHeight: booleanAllowedValues,
inheritedAttrs: stringArrayNullAllowedValues
},
nativeScrollbarsOverlaid: {
show: booleanAllowedValues,
initialize: booleanAllowedValues
},
callbacks: {
onUpdated: [optionsTemplateTypes.function, optionsTemplateTypes.null]
}
});
const optionsValidationPluginName = '__osOptionsValidationPlugin';
@@ -2469,7 +2529,8 @@ const OverlayScrollbars = (target, options, eventListeners) => {
on: addEvent,
off: removeEvent,
state: () => {
state() {
const {
_overflowAmount,
_overflowStyle,
@@ -2486,6 +2547,23 @@ const OverlayScrollbars = (target, options, eventListeners) => {
});
},
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) {
update({}, force);
},
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+205 -118
View File
@@ -218,6 +218,17 @@
elm && elm.setAttribute(attrName, value);
}
var attrClass = function attrClass(elm, attrName, value, add) {
var currValues = attr(elm, attrName) || '';
var currValuesSet = new Set(currValues.split(' '));
currValuesSet[add ? 'add' : 'delete'](value);
attr(elm, attrName, from(currValuesSet).join(' ').trim());
};
var hasAttrClass = function hasAttrClass(elm, attrName, value) {
var currValues = attr(elm, attrName) || '';
var currValuesSet = new Set(currValues.split(' '));
return currValuesSet.has(value);
};
var removeAttr = function removeAttr(elm, attrName) {
elm && elm.removeAttribute(attrName);
};
@@ -236,6 +247,11 @@
return rootElm ? push(arr, rootElm.querySelectorAll(selector)) : arr;
};
var findFirst = function findFirst(selector, elm) {
var rootElm = elm ? isElement(elm) ? elm : null : document;
return rootElm ? rootElm.querySelector(selector) : null;
};
var is = function is(elm, selector) {
if (isElement(elm)) {
var fn = elmPrototype.matches || elmPrototype.msMatchesSelector;
@@ -253,6 +269,32 @@
return elm ? elm.parentElement : null;
};
var closest = function closest(elm, selector) {
if (isElement(elm)) {
var closestFn = elmPrototype.closest;
if (closestFn) {
return closestFn.call(elm, selector);
}
do {
if (is(elm, selector)) {
return elm;
}
elm = parent(elm);
} while (elm);
}
return null;
};
var liesBetween = function liesBetween(elm, highBoundarySelector, deepBoundarySelector) {
var closestHighBoundaryElm = elm && closest(elm, highBoundarySelector);
var closestDeepBoundaryElm = elm && findFirst(deepBoundarySelector, closestHighBoundaryElm);
return closestHighBoundaryElm && closestDeepBoundaryElm ? closestHighBoundaryElm === elm || closestDeepBoundaryElm === elm || closest(closest(elm, deepBoundarySelector), highBoundarySelector) !== closestHighBoundaryElm : false;
};
var before = function before(parentElm, preferredAnchor, insertedElms) {
if (insertedElms) {
var anchor = preferredAnchor;
@@ -386,7 +428,7 @@
var i = 0;
var result = false;
if (elm && isString(className)) {
if (elm && className && isString(className)) {
var classes = className.match(rnothtmlwhite) || [];
result = classes.length > 0;
@@ -397,6 +439,12 @@
return result;
};
var hasClass = function hasClass(elm, className) {
return classListAction(elm, className, function (classList, clazz) {
return classList.contains(clazz);
});
};
var removeClass = function removeClass(elm, className) {
classListAction(elm, className, function (classList, clazz) {
return classList.remove(clazz);
@@ -408,22 +456,6 @@
});
return removeClass.bind(0, elm, className);
};
var diffClass = function diffClass(classNameA, classNameB) {
var classNameASplit = classNameA && classNameA.split(' ');
var classNameBSplit = classNameB && classNameB.split(' ');
var tempObj = {};
each(classNameASplit, function (className) {
tempObj[className] = 1;
});
each(classNameBSplit, function (className) {
if (tempObj[className]) {
delete tempObj[className];
} else {
tempObj[className] = 1;
}
});
return keys(tempObj);
};
var equal = function equal(a, b, props, propMutation) {
if (a && b) {
@@ -774,6 +806,10 @@
var classNameEnvironmentFlexboxGlue = classNameEnvironment + "-flexbox-glue";
var classNameEnvironmentFlexboxGlueMax = classNameEnvironmentFlexboxGlue + "-max";
var dataAttributeHost = 'data-overlayscrollbars';
var dataAttributeHostOverflowX = dataAttributeHost + "-overflow-x";
var dataAttributeHostOverflowY = dataAttributeHost + "-overflow-y";
var dataValueHostOverflowVisible = 'overflowVisible';
var dataValueHostViewportScrollbarStyling = 'viewportStyled';
var classNamePadding = 'os-padding';
var classNameViewport = 'os-viewport';
var classNameViewportArrange = classNameViewport + "-arrange";
@@ -804,17 +840,21 @@
};
var defaultOptions = {
resize: 'none',
paddingAbsolute: false,
updating: {
elementEvents: [['img', 'load']],
debounce: [0, 33],
attributes: null,
debounce: [0, 33]
ignoreMutation: null
},
overflow: {
x: 'scroll',
y: 'scroll'
},
nativeScrollbarsOverlaid: {
show: false,
initialize: false
},
scrollbars: {
visibility: 'auto',
autoHide: 'never',
@@ -822,18 +862,6 @@
dragScroll: true,
clickScroll: false,
touch: true
},
textarea: {
dynWidth: false,
dynHeight: false,
inheritedAttrs: ['style', 'class']
},
nativeScrollbarsOverlaid: {
show: false,
initialize: false
},
callbacks: {
onUpdated: null
}
};
var getOptionsDiff = function getOptionsDiff(currOptions, newOptions) {
@@ -1085,8 +1113,8 @@
return result === true ? createDiv() : result;
};
var addDataAttrHost = function addDataAttrHost(elm) {
attr(elm, dataAttributeHost, '');
var addDataAttrHost = function addDataAttrHost(elm, value) {
attr(elm, dataAttributeHost, value || '');
return removeAttr.bind(0, elm, dataAttributeHost);
};
@@ -1109,20 +1137,32 @@
var ownerDocument = targetElement.ownerDocument;
var bodyElm = ownerDocument.body;
var wnd = ownerDocument.defaultView;
var singleElmSupport = !!ResizeObserverConstructor && _nativeScrollbarStyling;
var potentialViewportElement = staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy);
var potentiallySingleElm = potentialViewportElement === targetElement;
var viewportIsTarget = singleElmSupport && potentiallySingleElm;
var viewportElement = potentiallySingleElm && !viewportIsTarget ? staticCreationFromStrategy(targetElement) : potentialViewportElement;
var evaluatedTargetObj = {
_target: targetElement,
_host: isTextarea ? staticCreationFromStrategy(targetElement, targetStructureInitialization.host, hostInitializationStrategy) : targetElement,
_viewport: staticCreationFromStrategy(targetElement, targetStructureInitialization.viewport, viewportInitializationStrategy),
_viewport: viewportElement,
_padding: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.padding, paddingInitializationStrategy),
_content: dynamicCreationFromStrategy(targetElement, targetStructureInitialization.content, contentInitializationStrategy),
_viewportArrange: createUniqueViewportArrangeElement(),
_viewportArrange: !viewportIsTarget && createUniqueViewportArrangeElement(),
_windowElm: wnd,
_documentElm: ownerDocument,
_htmlElm: parent(bodyElm),
_bodyElm: bodyElm,
_isTextarea: isTextarea,
_isBody: isBody,
_targetIsElm: targetIsElm
_targetIsElm: targetIsElm,
_viewportIsTarget: viewportIsTarget,
_viewportHasClass: function _viewportHasClass(className, attributeClassName) {
return viewportIsTarget ? hasAttrClass(viewportElement, dataAttributeHost, attributeClassName) : hasClass(viewportElement, className);
},
_viewportAddRemoveClass: function _viewportAddRemoveClass(className, attributeClassName, add) {
return viewportIsTarget ? attrClass(viewportElement, dataAttributeHost, attributeClassName, add) : (add ? addClass : removeClass)(viewportElement, className);
}
};
var generatedElements = keys(evaluatedTargetObj).reduce(function (arr, key) {
var value = evaluatedTargetObj[key];
@@ -1145,9 +1185,9 @@
return elementIsGenerated(elm) === false;
}));
var contentSlot = _content || _viewport;
var removeHostDataAttr = addDataAttrHost(_host);
var removeHostDataAttr = addDataAttrHost(_host, viewportIsTarget ? 'viewport' : 'host');
var removePaddingClass = addClass(_padding, classNamePadding);
var removeViewportClass = addClass(_viewport, classNameViewport);
var removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport);
var removeContentClass = addClass(_content, classNameContent);
if (isTextareaHostGenerated) {
@@ -1160,34 +1200,31 @@
appendChildren(contentSlot, targetContents);
appendChildren(_host, _padding);
appendChildren(_padding || _host, _viewport);
appendChildren(_padding || _host, !viewportIsTarget && _viewport);
appendChildren(_viewport, _content);
push(destroyFns, function () {
if (targetIsElm) {
appendChildren(_host, contents(contentSlot));
removeElements(_padding || _viewport);
removeHostDataAttr();
} else {
if (elementIsGenerated(_content)) {
unwrap(_content);
}
removeHostDataAttr();
removeAttr(_viewport, dataAttributeHostOverflowX);
removeAttr(_viewport, dataAttributeHostOverflowY);
if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
removeHostDataAttr();
removePaddingClass();
removeViewportClass();
removeContentClass();
if (elementIsGenerated(_content)) {
unwrap(_content);
}
if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
removePaddingClass();
removeViewportClass();
removeContentClass();
});
if (_nativeScrollbarStyling) {
if (_nativeScrollbarStyling && !viewportIsTarget) {
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
}
@@ -1214,8 +1251,7 @@
if (heightIntrinsicChanged) {
style(_content, {
height: _heightIntrinsic ? '' : '100%',
display: _heightIntrinsic ? '' : 'inline'
height: _heightIntrinsic ? '' : '100%'
});
}
@@ -1231,7 +1267,8 @@
setState = state[1];
var _host = structureSetupElements._host,
_padding = structureSetupElements._padding,
_viewport = structureSetupElements._viewport;
_viewport = structureSetupElements._viewport,
_isSingleElm = structureSetupElements._viewportIsTarget;
var _createCache = createCache({
_equal: equalTRBL,
@@ -1269,7 +1306,7 @@
paddingChanged = _updatePaddingCache[1];
}
var paddingStyleChanged = paddingAbsoluteChanged || _directionChanged || paddingChanged;
var paddingStyleChanged = !_isSingleElm && (paddingAbsoluteChanged || _directionChanged || paddingChanged);
if (paddingStyleChanged) {
var paddingRelative = !paddingAbsolute || !_padding && !_nativeScrollbarStyling;
@@ -1336,8 +1373,8 @@
};
};
var conditionalClass = function conditionalClass(elm, classNames, condition) {
return condition ? addClass(elm, classNames) : removeClass(elm, classNames);
var conditionalClass = function conditionalClass(elm, classNames, add) {
return add ? addClass(elm, classNames) : removeClass(elm, classNames);
};
var overflowIsVisible = function overflowIsVisible(overflowBehavior) {
@@ -1350,7 +1387,9 @@
var _host = structureSetupElements._host,
_padding = structureSetupElements._padding,
_viewport = structureSetupElements._viewport,
_viewportArrange = structureSetupElements._viewportArrange;
_viewportArrange = structureSetupElements._viewportArrange,
_viewportIsTarget = structureSetupElements._viewportIsTarget,
_viewportAddRemoveClass = structureSetupElements._viewportAddRemoveClass;
var _getEnvironment = getEnvironment(),
_nativeScrollbarSize = _getEnvironment._nativeScrollbarSize,
@@ -1358,7 +1397,7 @@
_nativeScrollbarStyling = _getEnvironment._nativeScrollbarStyling,
_nativeScrollbarIsOverlaid = _getEnvironment._nativeScrollbarIsOverlaid;
var doViewportArrange = !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
var doViewportArrange = !_viewportIsTarget && !_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
var _createCache = createCache(whCacheOptions, fractionalSize.bind(0, _host)),
updateSizeFraction = _createCache[0],
@@ -1603,7 +1642,7 @@
overflowChanged = _checkOption2[1];
var showNativeOverlaidScrollbars = showNativeOverlaidScrollbarsOption && _nativeScrollbarIsOverlaid.x && _nativeScrollbarIsOverlaid.y;
var adjustFlexboxGlue = !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || _heightIntrinsicChanged);
var adjustFlexboxGlue = !_viewportIsTarget && !_flexboxGlue && (_sizeChanged || _contentMutation || _hostMutation || showNativeOverlaidScrollbarsChanged || _heightIntrinsicChanged);
var overflowXVisible = overflowIsVisible(overflow.x);
var overflowYVisible = overflowIsVisible(overflow.y);
var overflowVisible = overflowXVisible || overflowYVisible;
@@ -1613,7 +1652,7 @@
var preMeasureViewportOverflowState;
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);
_viewportAddRemoveClass(classNameViewportScrollbarStyling, dataValueHostViewportScrollbarStyling, !showNativeOverlaidScrollbars);
}
if (adjustFlexboxGlue) {
@@ -1623,7 +1662,7 @@
if (_sizeChanged || _paddingStyleChanged || _contentMutation || _directionChanged || showNativeOverlaidScrollbarsChanged) {
if (overflowVisible) {
removeClass(_viewport, classNameOverflowVisible);
_viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, false);
}
var _undoViewportArrange = undoViewportArrange(showNativeOverlaidScrollbars, _directionIsRTL, preMeasureViewportOverflowState),
@@ -1683,18 +1722,26 @@
};
var viewportOverflowState = setViewportOverflowState(showNativeOverlaidScrollbars, hasOverflow, overflow, viewportStyle);
var viewportArranged = arrangeViewport(viewportOverflowState, viewportScrollSize, sizeFraction, _directionIsRTL);
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
if (!_viewportIsTarget) {
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
}
if (adjustFlexboxGlue) {
fixFlexboxGlue(viewportOverflowState, _heightIntrinsic);
}
style(_viewport, viewportStyle);
if (_viewportIsTarget) {
attr(_host, dataAttributeHostOverflowX, viewportStyle.overflowX);
attr(_host, dataAttributeHostOverflowY, viewportStyle.overflowY);
} else {
style(_viewport, viewportStyle);
}
}
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
attrClass(_host, dataAttributeHost, dataValueHostOverflowVisible, removeClipping);
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
!_viewportIsTarget && conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
var _updateOverflowStyleC = updateOverflowStyleCache(getViewportOverflowState(showNativeOverlaidScrollbars)._overflowStyle),
overflowStyle = _updateOverflowStyleC[0],
@@ -2070,7 +2117,6 @@
_eventContentChange = _ref._eventContentChange,
_nestedTargetSelector = _ref._nestedTargetSelector,
_ignoreTargetChange = _ref._ignoreTargetChange,
_ignoreNestedTargetChange = _ref._ignoreNestedTargetChange,
_ignoreContentChange = _ref._ignoreContentChange;
var _createEventContentCh = createEventContentChange(target, debounce(function () {
@@ -2089,7 +2135,7 @@
var observedAttributes = finalAttributes.concat(finalStyleChangingAttributes);
var observerCallback = function observerCallback(mutations) {
var ignoreTargetChange = (isContentObserver ? _ignoreNestedTargetChange : _ignoreTargetChange) || noop;
var ignoreTargetChange = _ignoreTargetChange || noop;
var ignoreContentChange = _ignoreContentChange || noop;
var targetChangedAttrs = [];
var totalAddedNodes = [];
@@ -2165,22 +2211,11 @@
}];
};
var ignorePrefix = 'os-';
var hostSelector = "[" + dataAttributeHost + "]";
var viewportSelector = "." + classNameViewport;
var viewportAttrsFromTarget = ['tabindex'];
var baseStyleChangingAttrsTextarea = ['wrap', 'cols', 'rows'];
var baseStyleChangingAttrs = ['id', 'class', 'style', 'open'];
var ignoreTargetChange = function ignoreTargetChange(target, attrName, oldValue, newValue) {
if (attrName === 'class' && oldValue && newValue) {
var diff = diffClass(oldValue, newValue);
return !!diff.find(function (addedOrRemovedClass) {
return addedOrRemovedClass.indexOf(ignorePrefix) !== 0;
});
}
return false;
};
var createStructureSetupObservers = function createStructureSetupObservers(structureSetupElements, state, structureSetupUpdate) {
var debounceTimeout;
var debounceMaxDelay;
@@ -2189,12 +2224,36 @@
var _host = structureSetupElements._host,
_viewport = structureSetupElements._viewport,
_content = structureSetupElements._content,
_isTextarea = structureSetupElements._isTextarea;
_isTextarea = structureSetupElements._isTextarea,
_viewportIsTarget = structureSetupElements._viewportIsTarget,
_viewportHasClass = structureSetupElements._viewportHasClass,
_viewportAddRemoveClass = structureSetupElements._viewportAddRemoveClass;
var _getEnvironment = getEnvironment(),
_nativeScrollbarStyling = _getEnvironment._nativeScrollbarStyling,
_flexboxGlue = _getEnvironment._flexboxGlue;
var _createCache = createCache({
_equal: equalWH,
_initialValue: {
w: 0,
h: 0
}
}, function () {
var has = _viewportHasClass(classNameOverflowVisible, dataValueHostOverflowVisible);
has && _viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible);
var contentScroll = scrollSize(_content);
var viewportScroll = scrollSize(_viewport);
var fractional = fractionalSize(_viewport);
has && _viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, true);
return {
w: viewportScroll.w + contentScroll.w + fractional.w,
h: viewportScroll.h + contentScroll.h + fractional.h
};
}),
updateContentSizeCache = _createCache[0];
var contentMutationObserverAttr = _isTextarea ? baseStyleChangingAttrsTextarea : baseStyleChangingAttrs.concat(baseStyleChangingAttrsTextarea);
var structureSetupUpdateWithDebouncedAdaptiveUpdateHints = debounce(structureSetupUpdate, {
_timeout: function _timeout() {
@@ -2261,10 +2320,16 @@
};
var onContentMutation = function onContentMutation(contentChangedTroughEvent) {
var _updateContentSizeCac = updateContentSizeCache(),
contentSizeChanged = _updateContentSizeCac[1];
var updateFn = contentChangedTroughEvent ? structureSetupUpdate : structureSetupUpdateWithDebouncedAdaptiveUpdateHints;
updateFn({
_contentMutation: true
});
if (contentSizeChanged) {
updateFn({
_contentMutation: true
});
}
};
var onHostMutation = function onHostMutation(targetChangedAttrs, targetStyleChanged) {
@@ -2272,40 +2337,50 @@
structureSetupUpdateWithDebouncedAdaptiveUpdateHints({
_hostMutation: true
});
} else {
} else if (!_viewportIsTarget) {
updateViewportAttrsFromHost(targetChangedAttrs);
}
};
var destroyTrinsicObserver = (_content || !_flexboxGlue) && createTrinsicObserver(_host, onTrinsicChanged);
var destroySizeObserver = createSizeObserver(_host, onSizeChanged, {
var destroySizeObserver = !_viewportIsTarget && createSizeObserver(_host, onSizeChanged, {
_appear: true,
_direction: !_nativeScrollbarStyling
});
var _createDOMObserver = createDOMObserver(_host, false, onHostMutation, {
_styleChangingAttributes: baseStyleChangingAttrs,
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget),
_ignoreTargetChange: ignoreTargetChange
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget)
}),
destroyHostMutationObserver = _createDOMObserver[0];
var viewportIsTargetResizeObserver = _viewportIsTarget && new ResizeObserverConstructor(onSizeChanged.bind(0, {
_sizeChanged: true
}));
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.observe(_host);
updateViewportAttrsFromHost();
return [function (checkOption) {
var _checkOption = checkOption('updating.elementEvents'),
elementEvents = _checkOption[0],
elementEventsChanged = _checkOption[1];
var _checkOption = checkOption('updating.ignoreMutation'),
ignoreMutation = _checkOption[0];
var _checkOption2 = checkOption('updating.attributes'),
attributes = _checkOption2[0],
attributesChanged = _checkOption2[1];
var _checkOption3 = checkOption('updating.debounce'),
debounceValue = _checkOption3[0],
debounceChanged = _checkOption3[1];
var _checkOption3 = checkOption('updating.elementEvents'),
elementEvents = _checkOption3[0],
elementEventsChanged = _checkOption3[1];
var _checkOption4 = checkOption('updating.debounce'),
debounceValue = _checkOption4[0],
debounceChanged = _checkOption4[1];
var updateContentMutationObserver = elementEventsChanged || attributesChanged;
var ignoreMutationFromOptions = function ignoreMutationFromOptions(mutation) {
return isFunction(ignoreMutation) && ignoreMutation(mutation);
};
if (updateContentMutationObserver) {
if (contentMutationObserver) {
contentMutationObserver[1]();
@@ -2316,7 +2391,13 @@
_styleChangingAttributes: contentMutationObserverAttr.concat(attributes || []),
_attributes: contentMutationObserverAttr.concat(attributes || []),
_eventContentChange: elementEvents,
_ignoreNestedTargetChange: ignoreTargetChange
_nestedTargetSelector: hostSelector,
_ignoreContentChange: function _ignoreContentChange(mutation, isNestedTarget) {
var target = mutation.target,
attributeName = mutation.attributeName;
var ignore = !isNestedTarget && attributeName ? liesBetween(target, hostSelector, viewportSelector) : false;
return ignore || !!ignoreMutationFromOptions(mutation);
}
});
}
@@ -2339,7 +2420,8 @@
}, function () {
contentMutationObserver && contentMutationObserver[0]();
destroyTrinsicObserver && destroyTrinsicObserver();
destroySizeObserver();
destroySizeObserver && destroySizeObserver();
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.disconnect();
destroyHostMutationObserver();
}];
};
@@ -2521,18 +2603,16 @@
var numberAllowedValues = optionsTemplateTypes.number;
var booleanAllowedValues = optionsTemplateTypes.boolean;
var arrayNullValues = [optionsTemplateTypes.array, optionsTemplateTypes.null];
var stringArrayNullAllowedValues = [optionsTemplateTypes.string, optionsTemplateTypes.array, optionsTemplateTypes.null];
var resizeAllowedValues = 'none both horizontal vertical';
var overflowAllowedValues = 'hidden scroll visible visible-hidden';
var scrollbarsVisibilityAllowedValues = 'visible hidden auto';
var scrollbarsAutoHideAllowedValues = 'never scroll leavemove';
({
resize: resizeAllowedValues,
paddingAbsolute: booleanAllowedValues,
updating: {
elementEvents: arrayNullValues,
attributes: arrayNullValues,
debounce: [optionsTemplateTypes.number, optionsTemplateTypes.array, optionsTemplateTypes.null]
debounce: [optionsTemplateTypes.number, optionsTemplateTypes.array, optionsTemplateTypes.null],
ignoreMutation: [optionsTemplateTypes.function, optionsTemplateTypes.null]
},
overflow: {
x: overflowAllowedValues,
@@ -2546,17 +2626,9 @@
clickScroll: booleanAllowedValues,
touch: booleanAllowedValues
},
textarea: {
dynWidth: booleanAllowedValues,
dynHeight: booleanAllowedValues,
inheritedAttrs: stringArrayNullAllowedValues
},
nativeScrollbarsOverlaid: {
show: booleanAllowedValues,
initialize: booleanAllowedValues
},
callbacks: {
onUpdated: [optionsTemplateTypes.function, optionsTemplateTypes.null]
}
});
var optionsValidationPluginName = '__osOptionsValidationPlugin';
@@ -2683,6 +2755,21 @@
paddingAbsolute: _paddingAbsolute
});
},
elements: function elements() {
var _structureState$_elem = structureState._elements,
_target = _structureState$_elem._target,
_host = _structureState$_elem._host,
_padding = _structureState$_elem._padding,
_viewport = _structureState$_elem._viewport,
_content = _structureState$_elem._content;
return assignDeep({}, {
target: _target,
host: _host,
padding: _padding || _viewport,
viewport: _viewport,
content: _content || _viewport
});
},
update: function update(force) {
_update({}, force);
},
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -3,6 +3,10 @@ export const classNameEnvironmentFlexboxGlue = `${classNameEnvironment}-flexbox-
export const classNameEnvironmentFlexboxGlueMax = `${classNameEnvironmentFlexboxGlue}-max`;
export const dataAttributeHost = 'data-overlayscrollbars';
export const dataAttributeHostOverflowX = `${dataAttributeHost}-overflow-x`;
export const dataAttributeHostOverflowY = `${dataAttributeHost}-overflow-y`;
export const dataValueHostOverflowVisible = 'overflowVisible';
export const dataValueHostViewportScrollbarStyling = 'viewportStyled';
export const classNamePadding = 'os-padding';
export const classNameViewport = 'os-viewport';
export const classNameViewportArrange = `${classNameViewport}-arrange`;
@@ -10,6 +10,7 @@ import {
indexOf,
removeElements,
removeClass,
hasClass,
push,
runEach,
insertBefore,
@@ -18,9 +19,14 @@ import {
isFunction,
keys,
removeAttr,
attrClass,
hasAttrClass,
ResizeObserverConstructor,
} from 'support';
import {
dataAttributeHost,
dataAttributeHostOverflowX,
dataAttributeHostOverflowY,
classNamePadding,
classNameViewport,
classNameViewportArrange,
@@ -51,6 +57,9 @@ export interface StructureSetupElementsObj {
_windowElm: Window;
_documentElm: Document;
_targetIsElm: boolean;
_viewportIsTarget: boolean;
_viewportHasClass: (className: string, attributeClassName: string) => boolean;
_viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) => void;
}
let contentArrangeCounter = 0;
@@ -80,8 +89,8 @@ const createUniqueViewportArrangeElement = (): HTMLStyleElement | false => {
const staticCreationFromStrategy = (
target: OSTargetElement,
initializationValue: HTMLElement | undefined,
strategy: StructureInitializationStrategyStaticElement
initializationValue?: HTMLElement | undefined,
strategy?: StructureInitializationStrategyStaticElement
): HTMLElement => {
const result =
initializationValue ||
@@ -104,8 +113,8 @@ const dynamicCreationFromStrategy = (
return result === true ? createDiv() : result;
};
const addDataAttrHost = (elm: HTMLElement) => {
attr(elm, dataAttributeHost, '');
const addDataAttrHost = (elm: HTMLElement, value?: string | false | null | undefined) => {
attr(elm, dataAttributeHost, value || '');
return removeAttr.bind(0, elm, dataAttributeHost);
};
@@ -127,6 +136,18 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
const ownerDocument = targetElement!.ownerDocument;
const bodyElm = ownerDocument.body as HTMLBodyElement;
const wnd = ownerDocument.defaultView as Window;
const singleElmSupport = !!ResizeObserverConstructor && _nativeScrollbarStyling;
const potentialViewportElement = staticCreationFromStrategy(
targetElement,
targetStructureInitialization.viewport,
viewportInitializationStrategy
);
const potentiallySingleElm = potentialViewportElement === targetElement;
const viewportIsTarget = singleElmSupport && potentiallySingleElm;
const viewportElement =
potentiallySingleElm && !viewportIsTarget
? staticCreationFromStrategy(targetElement)
: potentialViewportElement;
const evaluatedTargetObj: StructureSetupElementsObj = {
_target: targetElement,
_host: isTextarea
@@ -136,11 +157,7 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
hostInitializationStrategy
)
: (targetElement as HTMLElement),
_viewport: staticCreationFromStrategy(
targetElement,
targetStructureInitialization.viewport,
viewportInitializationStrategy
),
_viewport: viewportElement,
_padding: dynamicCreationFromStrategy(
targetElement,
targetStructureInitialization.padding,
@@ -151,7 +168,7 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
targetStructureInitialization.content,
contentInitializationStrategy
),
_viewportArrange: createUniqueViewportArrangeElement(),
_viewportArrange: !viewportIsTarget && createUniqueViewportArrangeElement(),
_windowElm: wnd,
_documentElm: ownerDocument,
_htmlElm: parent(bodyElm) as HTMLHtmlElement,
@@ -159,6 +176,15 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
_isTextarea: isTextarea,
_isBody: isBody,
_targetIsElm: targetIsElm,
_viewportIsTarget: viewportIsTarget,
_viewportHasClass: (className: string, attributeClassName: string) =>
viewportIsTarget
? hasAttrClass(viewportElement, dataAttributeHost, attributeClassName)
: hasClass(viewportElement, className),
_viewportAddRemoveClass: (className: string, attributeClassName: string, add?: boolean) =>
viewportIsTarget
? attrClass(viewportElement, dataAttributeHost, attributeClassName, add)
: (add ? addClass : removeClass)(viewportElement, className),
};
const generatedElements = keys(evaluatedTargetObj).reduce((arr, key: string) => {
const value = evaluatedTargetObj[key];
@@ -177,9 +203,9 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
)
);
const contentSlot = _content || _viewport;
const removeHostDataAttr = addDataAttrHost(_host);
const removeHostDataAttr = addDataAttrHost(_host, viewportIsTarget ? 'viewport' : 'host');
const removePaddingClass = addClass(_padding, classNamePadding);
const removeViewportClass = addClass(_viewport, classNameViewport);
const removeViewportClass = addClass(_viewport, !viewportIsTarget && classNameViewport);
const removeContentClass = addClass(_content, classNameContent);
// only insert host for textarea after target if it was generated
@@ -194,32 +220,29 @@ export const createStructureSetupElements = (target: OSTarget): StructureSetupEl
appendChildren(contentSlot, targetContents);
appendChildren(_host, _padding);
appendChildren(_padding || _host, _viewport);
appendChildren(_padding || _host, !viewportIsTarget && _viewport);
appendChildren(_viewport, _content);
push(destroyFns, () => {
if (targetIsElm) {
appendChildren(_host, contents(contentSlot));
removeElements(_padding || _viewport);
removeHostDataAttr();
} else {
if (elementIsGenerated(_content)) {
unwrap(_content);
}
if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
removeHostDataAttr();
removePaddingClass();
removeViewportClass();
removeContentClass();
removeHostDataAttr();
removeAttr(_viewport, dataAttributeHostOverflowX);
removeAttr(_viewport, dataAttributeHostOverflowY);
if (elementIsGenerated(_content)) {
unwrap(_content);
}
if (elementIsGenerated(_viewport)) {
unwrap(_viewport);
}
if (elementIsGenerated(_padding)) {
unwrap(_padding);
}
removePaddingClass();
removeViewportClass();
removeContentClass();
});
if (_nativeScrollbarStyling) {
if (_nativeScrollbarStyling && !viewportIsTarget) {
push(destroyFns, removeClass.bind(0, _viewport, classNameViewportScrollbarStyling));
}
if (_viewportArrange) {
@@ -15,13 +15,16 @@ import {
createCache,
WH,
fractionalSize,
removeClass,
addClass,
hasClass,
isFunction,
ResizeObserverConstructor,
} from 'support';
import { getEnvironment } from 'environment';
import { dataAttributeHost, classNameViewport, classNameOverflowVisible } from 'classnames';
import {
dataAttributeHost,
dataValueHostOverflowVisible,
classNameViewport,
classNameOverflowVisible,
} from 'classnames';
import { createSizeObserver, SizeObserverCallbackParams } from 'observers/sizeObserver';
import { createTrinsicObserver } from 'observers/trinsicObserver';
import { createDOMObserver, DOMObserver } from 'observers/domObserver';
@@ -66,22 +69,31 @@ export const createStructureSetupObservers = (
let debounceMaxDelay: number | false | undefined;
let contentMutationObserver: DOMObserver | undefined;
const [, setState] = state;
const { _host, _viewport, _content, _isTextarea } = structureSetupElements;
const {
_host,
_viewport,
_content,
_isTextarea,
_viewportIsTarget,
_viewportHasClass,
_viewportAddRemoveClass,
} = structureSetupElements;
const { _nativeScrollbarStyling, _flexboxGlue } = getEnvironment();
const [updateContentSizeCache] = createCache<WH<number>>(
{
_equal: equalWH,
_initialValue: { w: 0, h: 0 },
},
() => {
const has = hasClass(_viewport, classNameOverflowVisible);
has && removeClass(_viewport, classNameOverflowVisible);
const has = _viewportHasClass(classNameOverflowVisible, dataValueHostOverflowVisible);
has && _viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible);
const contentScroll = scrollSize(_content);
const viewportScroll = scrollSize(_viewport);
const fractional = fractionalSize(_viewport);
has && addClass(_viewport, classNameOverflowVisible);
has && _viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, true);
return {
w: viewportScroll.w + contentScroll.w + fractional.w,
h: viewportScroll.h + contentScroll.h + fractional.h,
@@ -162,22 +174,29 @@ export const createStructureSetupObservers = (
structureSetupUpdateWithDebouncedAdaptiveUpdateHints({
_hostMutation: true,
});
} else {
} else if (!_viewportIsTarget) {
updateViewportAttrsFromHost(targetChangedAttrs);
}
};
const destroyTrinsicObserver =
(_content || !_flexboxGlue) && createTrinsicObserver(_host, onTrinsicChanged);
const destroySizeObserver = createSizeObserver(_host, onSizeChanged, {
_appear: true,
_direction: !_nativeScrollbarStyling,
});
const destroySizeObserver =
!_viewportIsTarget &&
createSizeObserver(_host, onSizeChanged, {
_appear: true,
_direction: !_nativeScrollbarStyling,
});
const [destroyHostMutationObserver] = createDOMObserver(_host, false, onHostMutation, {
_styleChangingAttributes: baseStyleChangingAttrs,
_attributes: baseStyleChangingAttrs.concat(viewportAttrsFromTarget),
});
const viewportIsTargetResizeObserver =
_viewportIsTarget &&
new ResizeObserverConstructor!(onSizeChanged.bind(0, { _sizeChanged: true }));
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.observe(_host);
updateViewportAttrsFromHost();
return [
@@ -239,7 +258,8 @@ export const createStructureSetupObservers = (
() => {
contentMutationObserver && contentMutationObserver[0](); // destroy
destroyTrinsicObserver && destroyTrinsicObserver();
destroySizeObserver();
destroySizeObserver && destroySizeObserver();
viewportIsTargetResizeObserver && viewportIsTargetResizeObserver.disconnect();
destroyHostMutationObserver();
},
];
@@ -14,6 +14,7 @@ import {
noop,
each,
equalXY,
attrClass,
} from 'support';
import { getEnvironment } from 'environment';
import {
@@ -21,6 +22,10 @@ import {
classNameViewportScrollbarStyling,
classNameOverflowVisible,
dataAttributeHost,
dataAttributeHostOverflowX,
dataAttributeHostOverflowY,
dataValueHostViewportScrollbarStyling,
dataValueHostOverflowVisible,
} from 'classnames';
import type { StyleObject, OverflowStyle } from 'typings';
import type { OverflowBehavior } from 'options';
@@ -71,8 +76,8 @@ const getOverflowAmount = (
const conditionalClass = (
elm: Element | false | null | undefined,
classNames: string,
condition: boolean
) => (condition ? addClass(elm, classNames) : removeClass(elm, classNames));
add: boolean
) => (add ? addClass(elm, classNames) : removeClass(elm, classNames));
const overflowIsVisible = (overflowBehavior: string) => overflowBehavior.indexOf(strVisible) === 0;
@@ -86,7 +91,14 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
state
) => {
const [getState, setState] = state;
const { _host, _padding, _viewport, _viewportArrange } = structureSetupElements;
const {
_host,
_padding,
_viewport,
_viewportArrange,
_viewportIsTarget,
_viewportAddRemoveClass,
} = structureSetupElements;
const {
_nativeScrollbarSize,
_flexboxGlue,
@@ -94,7 +106,9 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
_nativeScrollbarIsOverlaid,
} = getEnvironment();
const doViewportArrange =
!_nativeScrollbarStyling && (_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
!_viewportIsTarget &&
!_nativeScrollbarStyling &&
(_nativeScrollbarIsOverlaid.x || _nativeScrollbarIsOverlaid.y);
const [updateSizeFraction, getCurrentSizeFraction] = createCache<WH<number>>(
whCacheOptions,
@@ -426,6 +440,7 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
_nativeScrollbarIsOverlaid.x &&
_nativeScrollbarIsOverlaid.y;
const adjustFlexboxGlue =
!_viewportIsTarget &&
!_flexboxGlue &&
(_sizeChanged ||
_contentMutation ||
@@ -443,7 +458,11 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
let preMeasureViewportOverflowState: ViewportOverflowState | undefined;
if (showNativeOverlaidScrollbarsChanged && _nativeScrollbarStyling) {
conditionalClass(_viewport, classNameViewportScrollbarStyling, !showNativeOverlaidScrollbars);
_viewportAddRemoveClass(
classNameViewportScrollbarStyling,
dataValueHostViewportScrollbarStyling,
!showNativeOverlaidScrollbars
);
}
if (adjustFlexboxGlue) {
@@ -459,7 +478,7 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
showNativeOverlaidScrollbarsChanged
) {
if (overflowVisible) {
removeClass(_viewport, classNameOverflowVisible);
_viewportAddRemoveClass(classNameOverflowVisible, dataValueHostOverflowVisible, false);
}
const [redoViewportArrange, undoViewportArrangeOverflowState] = undoViewportArrange(
@@ -550,18 +569,31 @@ export const createOverflowUpdate: CreateStructureUpdateSegment = (
sizeFraction,
_directionIsRTL
);
hideNativeScrollbars(viewportOverflowState, _directionIsRTL, viewportArranged, viewportStyle);
if (!_viewportIsTarget) {
hideNativeScrollbars(
viewportOverflowState,
_directionIsRTL,
viewportArranged,
viewportStyle
);
}
if (adjustFlexboxGlue) {
fixFlexboxGlue(viewportOverflowState, _heightIntrinsic);
}
style(_viewport, viewportStyle);
if (_viewportIsTarget) {
attr(_host, dataAttributeHostOverflowX, viewportStyle.overflowX as string);
attr(_host, dataAttributeHostOverflowY, viewportStyle.overflowY as string);
} else {
style(_viewport, viewportStyle);
}
}
attr(_host, dataAttributeHost, removeClipping ? 'overflowVisible' : '');
attrClass(_host, dataAttributeHost, dataValueHostOverflowVisible, removeClipping);
conditionalClass(_padding, classNameOverflowVisible, removeClipping);
conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
!_viewportIsTarget && conditionalClass(_viewport, classNameOverflowVisible, overflowVisible);
const [overflowStyle, overflowStyleChanged] = updateOverflowStyleCache(
getViewportOverflowState(showNativeOverlaidScrollbars)._overflowStyle
@@ -13,7 +13,7 @@ export const createPaddingUpdate: CreateStructureUpdateSegment = (
state
) => {
const [getState, setState] = state;
const { _host, _padding, _viewport } = structureSetupElements;
const { _host, _padding, _viewport, _viewportIsTarget: _isSingleElm } = structureSetupElements;
const [updatePaddingCache, currentPaddingCache] = createCache(
{
_equal: equalTRBL,
@@ -34,7 +34,8 @@ export const createPaddingUpdate: CreateStructureUpdateSegment = (
[padding, paddingChanged] = updatePaddingCache(force);
}
const paddingStyleChanged = paddingAbsoluteChanged || _directionChanged || paddingChanged;
const paddingStyleChanged =
!_isSingleElm && (paddingAbsoluteChanged || _directionChanged || paddingChanged);
if (paddingStyleChanged) {
// if there is no padding element and no scrollbar styling, paddingAbsolute isn't supported
@@ -57,10 +57,13 @@
.os-viewport {
-ms-overflow-style: scrollbar !important;
}
[data-overlayscrollbars~='viewportStyled'],
.os-viewport-scrollbar-styled.os-environment,
.os-viewport-scrollbar-styled.os-viewport {
scrollbar-width: none !important;
}
[data-overlayscrollbars~='viewportStyled']::-webkit-scrollbar,
[data-overlayscrollbars~='viewportStyled']::-webkit-scrollbar-corner,
.os-viewport-scrollbar-styled.os-environment::-webkit-scrollbar,
.os-viewport-scrollbar-styled.os-viewport::-webkit-scrollbar,
.os-viewport-scrollbar-styled.os-environment::-webkit-scrollbar-corner,
@@ -72,7 +75,7 @@
background: transparent !important;
}
[data-overlayscrollbars],
[data-overlayscrollbars~='host'],
.os-padding {
position: relative;
display: flex;
@@ -115,6 +118,18 @@
[data-overlayscrollbars~='overflowVisible'] {
overflow: visible !important;
}
[data-overlayscrollbars-overflow-x='hidden'] {
overflow-x: hidden !important;
}
[data-overlayscrollbars-overflow-x='scroll'] {
overflow-x: scroll !important;
}
[data-overlayscrollbars-overflow-x='hidden'] {
overflow-y: hidden !important;
}
[data-overlayscrollbars-overflow-y='scroll'] {
overflow-y: scroll !important;
}
.os-padding,
.os-viewport {
@@ -1,3 +1,4 @@
import { from } from 'support/utils/array';
import { isUndefined } from 'support/utils/types';
type GetSetPropName = 'scrollLeft' | 'scrollTop' | 'value';
@@ -5,7 +6,7 @@ type GetSetPropName = 'scrollLeft' | 'scrollTop' | 'value';
function getSetProp(
topLeft: GetSetPropName,
fallback: number | string,
elm: HTMLElement | HTMLInputElement | null,
elm: HTMLElement | HTMLInputElement | false | null | undefined,
value?: number | string
): number | string | void {
if (isUndefined(value)) {
@@ -21,10 +22,14 @@ function getSetProp(
* @param attrName The attribute name which shall be get or set.
* @param value The value of the attribute which shall be set.
*/
export function attr(elm: HTMLElement | null, attrName: string): string | null;
export function attr(elm: HTMLElement | null, attrName: string, value: string): void;
export function attr(elm: HTMLElement | false | null | undefined, attrName: string): string | null;
export function attr(
elm: HTMLElement | null,
elm: HTMLElement | false | null | undefined,
attrName: string,
value: string
): void;
export function attr(
elm: HTMLElement | false | null | undefined,
attrName: string,
value?: string
): string | null | void {
@@ -34,12 +39,35 @@ export function attr(
elm && elm.setAttribute(attrName, value);
}
export const attrClass = (
elm: HTMLElement | false | null | undefined,
attrName: string,
value: string,
add?: boolean
) => {
const currValues = attr(elm, attrName) || '';
const currValuesSet = new Set(currValues.split(' '));
currValuesSet[add ? 'add' : 'delete'](value);
attr(elm, attrName, from(currValuesSet).join(' ').trim());
};
export const hasAttrClass = (
elm: HTMLElement | false | null | undefined,
attrName: string,
value: string
) => {
const currValues = attr(elm, attrName) || '';
const currValuesSet = new Set(currValues.split(' '));
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 | null, attrName: string): void => {
export const removeAttr = (elm: Element | false | null | undefined, attrName: string): void => {
elm && elm.removeAttribute(attrName);
};
@@ -48,9 +76,12 @@ export const removeAttr = (elm: Element | null, attrName: string): void => {
* @param elm The element of which the scrollLeft value shall be get or set.
* @param value The scrollLeft value which shall be set.
*/
export function scrollLeft(elm: HTMLElement | null): number;
export function scrollLeft(elm: HTMLElement | null, value: number): void;
export function scrollLeft(elm: HTMLElement | null, value?: number): number | void {
export function scrollLeft(elm: HTMLElement | false | null | undefined): number;
export function scrollLeft(elm: HTMLElement | false | null | undefined, value: number): void;
export function scrollLeft(
elm: HTMLElement | false | null | undefined,
value?: number
): number | void {
return getSetProp('scrollLeft', 0, elm, value) as number;
}
@@ -59,9 +90,12 @@ export function scrollLeft(elm: HTMLElement | null, value?: number): number | vo
* @param elm The element of which the scrollTop value shall be get or set.
* @param value The scrollTop value which shall be set.
*/
export function scrollTop(elm: HTMLElement | null): number;
export function scrollTop(elm: HTMLElement | null, value: number): void;
export function scrollTop(elm: HTMLElement | null, value?: number): number | void {
export function scrollTop(elm: HTMLElement | false | null | undefined): number;
export function scrollTop(elm: HTMLElement | false | null | undefined, value: number): void;
export function scrollTop(
elm: HTMLElement | false | null | undefined,
value?: number
): number | void {
return getSetProp('scrollTop', 0, elm, value) as number;
}
@@ -70,8 +104,11 @@ export function scrollTop(elm: HTMLElement | null, value?: number): number | voi
* @param elm The input element of which the value shall be get or set.
* @param value The value which shall be set.
*/
export function val(elm: HTMLInputElement | null): string;
export function val(elm: HTMLInputElement | null, value: string): void;
export function val(elm: HTMLInputElement | null, value?: string): string | void {
export function val(elm: HTMLInputElement | false | null | undefined): string;
export function val(elm: HTMLInputElement | false | null | undefined, value: string): void;
export function val(
elm: HTMLInputElement | false | null | undefined,
value?: string
): string | void {
return getSetProp('value', '', elm, value) as string;
}
@@ -5,14 +5,14 @@ import { keys } from 'support/utils/object';
const rnothtmlwhite = /[^\x20\t\r\n\f]+/g;
const classListAction = (
elm: Element | false | null | undefined,
className: string,
className: string | false | null | undefined,
action: (elmClassList: DOMTokenList, clazz: string) => boolean | void
): boolean => {
let clazz: string;
let i = 0;
let result = false;
if (elm && isString(className)) {
if (elm && className && isString(className)) {
const classes: Array<string> = className.match(rnothtmlwhite) || [];
result = classes.length > 0;
while ((clazz = classes[i++])) {
@@ -27,15 +27,20 @@ const classListAction = (
* @param elm The element.
* @param className The class name(s).
*/
export const hasClass = (elm: Element | false | null | undefined, className: string): boolean =>
classListAction(elm, className, (classList, clazz) => classList.contains(clazz));
export const hasClass = (
elm: Element | false | null | undefined,
className: string | false | null | undefined
): boolean => classListAction(elm, className, (classList, clazz) => classList.contains(clazz));
/**
* Removes the given class name(s) from the given element.
* @param elm The element.
* @param className The class name(s) which shall be removed. (separated by spaces)
*/
export const removeClass = (elm: Element | false | null | undefined, className: string): void => {
export const removeClass = (
elm: Element | false | null | undefined,
className: string | false | null | undefined
): void => {
classListAction(elm, className, (classList, clazz) => classList.remove(clazz));
};
@@ -47,7 +52,7 @@ export const removeClass = (elm: Element | false | null | undefined, className:
*/
export const addClass = (
elm: Element | false | null | undefined,
className: string
className: string | false | null | undefined
): (() => void) => {
classListAction(elm, className, (classList, clazz) => classList.add(clazz));
return removeClass.bind(0, elm, className);
@@ -110,7 +110,7 @@ let updateCount = 0;
const osInstance =
// @ts-ignore
(window.os = OverlayScrollbars(
{ target: target!, content: useContentElement },
{ target: target!, viewport: target!, content: useContentElement },
{ nativeScrollbarsOverlaid: { initialize: true } },
{
updated() {
@@ -255,18 +255,23 @@ selectCallbackEnv(containerDirectionSelect);
selectCallbackEnv(containerMinMaxSelect);
const checkMetrics = async (checkComparison: CheckComparisonObj) => {
const {
host: targetHost,
viewport: targetViewport,
padding: targetPadding,
} = osInstance.elements();
const viewportIsTarget = targetHost === targetViewport;
const { metrics: oldMetrics, updCount: oldUpdCount } = checkComparison;
const currMetrics = getMetrics(comparison!);
await waitForOrFailTest(async () => {
if (!metricsDimensionsEqual(oldMetrics, currMetrics)) {
if (!viewportIsTarget && !metricsDimensionsEqual(oldMetrics, currMetrics)) {
should.ok(updateCount > oldUpdCount, 'Update should have been triggered.');
}
});
await waitForOrFailTest(async () => {
const comparisonMetrics = getMetrics(comparison!);
const targetMetrics = getMetrics(target!);
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);
@@ -446,7 +451,7 @@ const checkMetrics = async (checkComparison: CheckComparisonObj) => {
'visible',
'Host Overflow should be visible with visible overflowing content.'
);
} else {
} else if (!viewportIsTarget) {
should.equal(
hostOverflowStyle,
'hidden',
@@ -89,13 +89,14 @@ body {
}
}
#target::after {
#target[data-overlayscrollbars~='host']::after {
display: none;
}
#target[data-overlayscrollbars~='viewport'],
#comparison {
overflow: hidden;
z-index: 0;
overflow: hidden;
}
.resize {
@@ -152,7 +153,7 @@ body {
width: auto;
display: inline-block;
}
.widthAuto > #target {
.widthAuto > #target[data-overlayscrollbars~='host'] {
display: inline-flex;
}
.widthHundred > .container,
+15 -16
View File
@@ -62,23 +62,22 @@ type RemoveEventListener<NameArgsMap extends Record<string, any>> = <Name extend
type InitialEventListeners<NameArgsMap extends Record<string, any>> = {
[K in Extract<keyof NameArgsMap, string>]?: EventListenerGroup<NameArgsMap, K>;
};
type ResizeBehavior = "none" | "both" | "horizontal" | "vertical";
type OverflowBehavior = "hidden" | "scroll" | "visible" | "visible-hidden" | "visible-scroll";
type VisibilityBehavior = "visible" | "hidden" | "auto";
type AutoHideBehavior = "never" | "scroll" | "leave" | "move";
interface OSOptions {
resize: ResizeBehavior;
paddingAbsolute: boolean;
updating: {
elementEvents: Array<[
string,
string
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;
@@ -92,18 +91,10 @@ interface OSOptions {
clickScroll: boolean;
touch: boolean;
};
textarea: {
dynWidth: boolean;
dynHeight: boolean;
inheritedAttrs: string | Array<string> | null;
};
nativeScrollbarsOverlaid: {
show: boolean;
initialize: boolean;
};
callbacks: {
onUpdated: (() => any) | null;
};
}
type StructureInitializationStrategyElementFn<T> = ((target: OSTargetElement) => HTMLElement | T) | T;
type ScrollbarsInitializationStrategyElementFn<T> = ((target: OSTargetElement, host: HTMLElement, viewport: HTMLElement) => HTMLElement | T) | T;
@@ -203,12 +194,20 @@ interface OverlayScrollbarsState {
overflowStyle: XY<OverflowStyle>;
hasOverflow: XY<boolean>;
}
interface OverlayScrollbarsElements {
target: HTMLElement;
host: HTMLElement;
padding: HTMLElement;
viewport: HTMLElement;
content: HTMLElement;
}
interface OverlayScrollbars {
options(): OSOptions;
options(newOptions?: PartialOptions<OSOptions>): OSOptions;
update(force?: boolean): void;
destroy(): void;
state(): OverlayScrollbarsState;
elements(): OverlayScrollbarsElements;
on: AddOSEventListener;
off: RemoveOSEventListener;
}