@jsenv/dom 0.10.3 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jsenv_dom.js +100 -53
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -5419,6 +5419,31 @@ const getScrollContainerSet = (element) => {
|
|
|
5419
5419
|
return scrollContainerSet;
|
|
5420
5420
|
};
|
|
5421
5421
|
|
|
5422
|
+
/**
|
|
5423
|
+
* Rounds a CSS pixel value to the nearest physical pixel boundary for the current display.
|
|
5424
|
+
*
|
|
5425
|
+
* At zoom levels other than 100%, `devicePixelRatio` is not an integer (e.g. 1.25, 1.5),
|
|
5426
|
+
* so fractional CSS pixel values from `getBoundingClientRect()` may not align to the physical
|
|
5427
|
+
* pixel grid. Setting `top`/`left` to such values causes the browser to interpolate across
|
|
5428
|
+
* pixels, resulting in blurry rendering or misalignment with adjacent elements.
|
|
5429
|
+
*
|
|
5430
|
+
* Snapping to the physical grid ensures the value falls exactly on a pixel boundary.
|
|
5431
|
+
*
|
|
5432
|
+
* @param {number} value - A CSS pixel value (e.g. from getBoundingClientRect or scroll offset).
|
|
5433
|
+
* @returns {number} The nearest physical-pixel-aligned CSS pixel value.
|
|
5434
|
+
* @example
|
|
5435
|
+
* // At devicePixelRatio 1.25, snapToPixel(154.4) → 154.4 (already on grid)
|
|
5436
|
+
* // At devicePixelRatio 1.25, snapToPixel(154.3) → 154.4
|
|
5437
|
+
*/
|
|
5438
|
+
const snapToPixel = (value) => {
|
|
5439
|
+
return Math.round(value * devicePixelRatio) / devicePixelRatio;
|
|
5440
|
+
};
|
|
5441
|
+
|
|
5442
|
+
// Round a CSS-pixel value to the nearest physical pixel boundary.
|
|
5443
|
+
// At zoom levels other than 100%, devicePixelRatio is not an integer (e.g. 1.25, 1.5),
|
|
5444
|
+
// so CSS pixels don't align 1:1 with physical pixels. Rounding to the physical grid
|
|
5445
|
+
// ensures the browser can render the element without sub-pixel blurring.
|
|
5446
|
+
|
|
5422
5447
|
const getBorderSizes = (element) => {
|
|
5423
5448
|
const {
|
|
5424
5449
|
borderLeftWidth,
|
|
@@ -5426,11 +5451,12 @@ const getBorderSizes = (element) => {
|
|
|
5426
5451
|
borderTopWidth,
|
|
5427
5452
|
borderBottomWidth,
|
|
5428
5453
|
} = window.getComputedStyle(element, null);
|
|
5454
|
+
|
|
5429
5455
|
return {
|
|
5430
|
-
left: parseFloat(borderLeftWidth),
|
|
5431
|
-
right: parseFloat(borderRightWidth),
|
|
5432
|
-
top: parseFloat(borderTopWidth),
|
|
5433
|
-
bottom: parseFloat(borderBottomWidth),
|
|
5456
|
+
left: snapToPixel(parseFloat(borderLeftWidth)),
|
|
5457
|
+
right: snapToPixel(parseFloat(borderRightWidth)),
|
|
5458
|
+
top: snapToPixel(parseFloat(borderTopWidth)),
|
|
5459
|
+
bottom: snapToPixel(parseFloat(borderBottomWidth)),
|
|
5434
5460
|
};
|
|
5435
5461
|
};
|
|
5436
5462
|
|
|
@@ -5782,8 +5808,8 @@ const measureScrollbar = (scrollableElement) => {
|
|
|
5782
5808
|
const scrollbarHeight = scrollDiv.offsetHeight - scrollDiv.clientHeight;
|
|
5783
5809
|
scrollableElement.removeChild(scrollDiv);
|
|
5784
5810
|
return [
|
|
5785
|
-
hasXScrollbar ? scrollbarWidth : 0,
|
|
5786
|
-
hasYScrollbar ? scrollbarHeight : 0,
|
|
5811
|
+
hasXScrollbar ? snapToPixel(scrollbarWidth) : 0,
|
|
5812
|
+
hasYScrollbar ? snapToPixel(scrollbarHeight) : 0,
|
|
5787
5813
|
];
|
|
5788
5814
|
};
|
|
5789
5815
|
|
|
@@ -6096,6 +6122,18 @@ const scrollIntoViewWithStickyAwareness = (
|
|
|
6096
6122
|
}
|
|
6097
6123
|
};
|
|
6098
6124
|
|
|
6125
|
+
const getPaddingSizes = (element) => {
|
|
6126
|
+
const { paddingLeft, paddingRight, paddingTop, paddingBottom } =
|
|
6127
|
+
window.getComputedStyle(element, null);
|
|
6128
|
+
|
|
6129
|
+
return {
|
|
6130
|
+
left: snapToPixel(parseFloat(paddingLeft)),
|
|
6131
|
+
right: snapToPixel(parseFloat(paddingRight)),
|
|
6132
|
+
top: snapToPixel(parseFloat(paddingTop)),
|
|
6133
|
+
bottom: snapToPixel(parseFloat(paddingBottom)),
|
|
6134
|
+
};
|
|
6135
|
+
};
|
|
6136
|
+
|
|
6099
6137
|
/**
|
|
6100
6138
|
* Prevents scrolling on all scrollable containers that are ancestors of (or
|
|
6101
6139
|
* siblings preceding) `element`. Used when an overlay (popover, dialog) is
|
|
@@ -6132,11 +6170,10 @@ const trapScrollInside = (element) => {
|
|
|
6132
6170
|
return;
|
|
6133
6171
|
}
|
|
6134
6172
|
const [scrollbarWidth, scrollbarHeight] = measureScrollbar(el);
|
|
6135
|
-
const
|
|
6136
|
-
const paddingBottom = parseInt(getStyle(el, "padding-bottom"), 0);
|
|
6173
|
+
const { right, bottom } = getPaddingSizes(el);
|
|
6137
6174
|
const removeScrollLockStyles = setStyles(el, {
|
|
6138
|
-
"padding-right": `${
|
|
6139
|
-
"padding-bottom": `${
|
|
6175
|
+
"padding-right": `${right + scrollbarWidth}px`,
|
|
6176
|
+
"padding-bottom": `${bottom + scrollbarHeight}px`,
|
|
6140
6177
|
"overflow": "hidden",
|
|
6141
6178
|
});
|
|
6142
6179
|
cleanupCallbackSet.add(removeScrollLockStyles);
|
|
@@ -9930,6 +9967,8 @@ const pickPositionRelativeTo = (
|
|
|
9930
9967
|
positionYFixed,
|
|
9931
9968
|
alignToViewportEdgeWhenAnchorNearEdge = 0,
|
|
9932
9969
|
minLeft = 0,
|
|
9970
|
+
spacing = 0,
|
|
9971
|
+
viewportSpacing = 0,
|
|
9933
9972
|
} = {},
|
|
9934
9973
|
) => {
|
|
9935
9974
|
|
|
@@ -9944,12 +9983,10 @@ const pickPositionRelativeTo = (
|
|
|
9944
9983
|
top: elementTop,
|
|
9945
9984
|
bottom: elementBottom,
|
|
9946
9985
|
} = elementRect;
|
|
9947
|
-
const
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
bottom: anchorBottom,
|
|
9952
|
-
} = anchorRect;
|
|
9986
|
+
const anchorLeft = snapToPixel(anchorRect.left);
|
|
9987
|
+
const anchorTop = snapToPixel(anchorRect.top);
|
|
9988
|
+
const anchorRight = snapToPixel(anchorRect.right);
|
|
9989
|
+
const anchorBottom = snapToPixel(anchorRect.bottom);
|
|
9953
9990
|
const elementWidth = elementRight - elementLeft;
|
|
9954
9991
|
const elementHeight = elementBottom - elementTop;
|
|
9955
9992
|
const anchorWidth = anchorRight - anchorLeft;
|
|
@@ -9992,16 +10029,16 @@ const pickPositionRelativeTo = (
|
|
|
9992
10029
|
// Compute effective space for a given Y value
|
|
9993
10030
|
const spaceFor = (y) => {
|
|
9994
10031
|
if (y === "above") {
|
|
9995
|
-
return spaceAbove;
|
|
10032
|
+
return spaceAbove - spacing - viewportSpacing;
|
|
9996
10033
|
}
|
|
9997
10034
|
if (y === "above-overlap") {
|
|
9998
|
-
return spaceAbove + anchorHeight;
|
|
10035
|
+
return spaceAbove + anchorHeight - viewportSpacing;
|
|
9999
10036
|
}
|
|
10000
10037
|
if (y === "below") {
|
|
10001
|
-
return spaceBelow;
|
|
10038
|
+
return spaceBelow - spacing - viewportSpacing;
|
|
10002
10039
|
}
|
|
10003
10040
|
if (y === "below-overlap") {
|
|
10004
|
-
return spaceBelow + anchorHeight;
|
|
10041
|
+
return spaceBelow + anchorHeight - viewportSpacing;
|
|
10005
10042
|
}
|
|
10006
10043
|
return Infinity; // center
|
|
10007
10044
|
};
|
|
@@ -10049,16 +10086,16 @@ const pickPositionRelativeTo = (
|
|
|
10049
10086
|
// Compute effective space for a given X value
|
|
10050
10087
|
const spaceFor = (x) => {
|
|
10051
10088
|
if (x === "to-the-left") {
|
|
10052
|
-
return spaceLeft;
|
|
10089
|
+
return spaceLeft - spacing - viewportSpacing;
|
|
10053
10090
|
}
|
|
10054
10091
|
if (x === "left-aligned") {
|
|
10055
|
-
return viewportWidth - anchorLeft;
|
|
10092
|
+
return viewportWidth - anchorLeft - viewportSpacing;
|
|
10056
10093
|
}
|
|
10057
10094
|
if (x === "right-aligned") {
|
|
10058
|
-
return anchorRight;
|
|
10095
|
+
return anchorRight - viewportSpacing;
|
|
10059
10096
|
}
|
|
10060
10097
|
if (x === "to-the-right") {
|
|
10061
|
-
return spaceRight;
|
|
10098
|
+
return spaceRight - spacing - viewportSpacing;
|
|
10062
10099
|
}
|
|
10063
10100
|
return Infinity; // center
|
|
10064
10101
|
};
|
|
@@ -10095,7 +10132,7 @@ const pickPositionRelativeTo = (
|
|
|
10095
10132
|
let elementPositionLeft;
|
|
10096
10133
|
{
|
|
10097
10134
|
if (finalX === "to-the-left") {
|
|
10098
|
-
elementPositionLeft = anchorLeft - elementWidth;
|
|
10135
|
+
elementPositionLeft = anchorLeft - elementWidth - spacing;
|
|
10099
10136
|
} else if (finalX === "left-aligned") {
|
|
10100
10137
|
elementPositionLeft = anchorLeft;
|
|
10101
10138
|
} else if (finalX === "center") {
|
|
@@ -10132,13 +10169,16 @@ const pickPositionRelativeTo = (
|
|
|
10132
10169
|
elementPositionLeft = anchorRight - elementWidth;
|
|
10133
10170
|
} else {
|
|
10134
10171
|
// "to-the-right"
|
|
10135
|
-
elementPositionLeft = anchorRight;
|
|
10172
|
+
elementPositionLeft = anchorRight + spacing;
|
|
10136
10173
|
}
|
|
10137
|
-
// Constrain horizontal position to viewport boundaries
|
|
10138
|
-
if (elementPositionLeft <
|
|
10139
|
-
elementPositionLeft =
|
|
10140
|
-
} else if (
|
|
10141
|
-
elementPositionLeft
|
|
10174
|
+
// Constrain horizontal position to viewport boundaries (with viewportSpacing margin)
|
|
10175
|
+
if (elementPositionLeft < viewportSpacing) {
|
|
10176
|
+
elementPositionLeft = viewportSpacing;
|
|
10177
|
+
} else if (
|
|
10178
|
+
elementPositionLeft + elementWidth >
|
|
10179
|
+
viewportWidth - viewportSpacing
|
|
10180
|
+
) {
|
|
10181
|
+
elementPositionLeft = viewportWidth - viewportSpacing - elementWidth;
|
|
10142
10182
|
}
|
|
10143
10183
|
}
|
|
10144
10184
|
|
|
@@ -10146,11 +10186,14 @@ const pickPositionRelativeTo = (
|
|
|
10146
10186
|
let elementPositionTop;
|
|
10147
10187
|
{
|
|
10148
10188
|
if (finalY === "above") {
|
|
10149
|
-
|
|
10150
|
-
|
|
10189
|
+
// top is always anchorTop - elementHeight - spacing — max-height truncates if needed.
|
|
10190
|
+
const idealTop = anchorTop - elementHeight - spacing;
|
|
10191
|
+
elementPositionTop =
|
|
10192
|
+
idealTop < viewportSpacing ? viewportSpacing : idealTop;
|
|
10151
10193
|
} else if (finalY === "above-overlap") {
|
|
10152
10194
|
const idealTop = anchorBottom - elementHeight;
|
|
10153
|
-
elementPositionTop =
|
|
10195
|
+
elementPositionTop =
|
|
10196
|
+
idealTop < viewportSpacing ? viewportSpacing : idealTop;
|
|
10154
10197
|
} else if (finalY === "center") {
|
|
10155
10198
|
elementPositionTop = anchorTop + anchorHeight / 2 - elementHeight / 2;
|
|
10156
10199
|
} else if (finalY === "below-overlap") {
|
|
@@ -10159,7 +10202,9 @@ const pickPositionRelativeTo = (
|
|
|
10159
10202
|
idealTop % 1 === 0 ? idealTop : Math.floor(idealTop) + 1;
|
|
10160
10203
|
} else {
|
|
10161
10204
|
// "below"
|
|
10162
|
-
|
|
10205
|
+
// top is always anchorBottom + spacing — max-height (via --space-available) truncates
|
|
10206
|
+
// the element height so it doesn't overflow the viewport bottom.
|
|
10207
|
+
const idealTop = anchorBottom + spacing;
|
|
10163
10208
|
elementPositionTop =
|
|
10164
10209
|
idealTop % 1 === 0 ? idealTop : Math.floor(idealTop) + 1;
|
|
10165
10210
|
}
|
|
@@ -10176,13 +10221,26 @@ const pickPositionRelativeTo = (
|
|
|
10176
10221
|
|
|
10177
10222
|
// Get document scroll for final coordinate conversion
|
|
10178
10223
|
const { scrollLeft, scrollTop } = document.documentElement;
|
|
10179
|
-
const elementDocumentLeft = elementPositionLeft + scrollLeft;
|
|
10180
|
-
const elementDocumentTop = elementPositionTop + scrollTop;
|
|
10224
|
+
const elementDocumentLeft = snapToPixel(elementPositionLeft + scrollLeft);
|
|
10225
|
+
const elementDocumentTop = snapToPixel(elementPositionTop + scrollTop);
|
|
10181
10226
|
const anchorDocumentLeft = anchorLeft + scrollLeft;
|
|
10182
10227
|
const anchorDocumentTop = anchorTop + scrollTop;
|
|
10183
10228
|
const anchorDocumentRight = anchorRight + scrollLeft;
|
|
10184
10229
|
const anchorDocumentBottom = anchorBottom + scrollTop;
|
|
10185
10230
|
|
|
10231
|
+
// For overlap variants the element starts at the anchor edge (not past it),
|
|
10232
|
+
// so the usable space includes the anchor dimension.
|
|
10233
|
+
// spacing (gap between anchor and element) and viewportSpacing are subtracted
|
|
10234
|
+
// so callers get the net usable space directly.
|
|
10235
|
+
const effectiveSpaceAbove =
|
|
10236
|
+
(finalY === "above-overlap" ? spaceAbove + anchorHeight : spaceAbove) -
|
|
10237
|
+
(finalY === "above" ? spacing : 0) -
|
|
10238
|
+
viewportSpacing;
|
|
10239
|
+
const effectiveSpaceBelow =
|
|
10240
|
+
(finalY === "below-overlap" ? spaceBelow + anchorHeight : spaceBelow) -
|
|
10241
|
+
(finalY === "below" ? spacing : 0) -
|
|
10242
|
+
viewportSpacing;
|
|
10243
|
+
|
|
10186
10244
|
return {
|
|
10187
10245
|
positionX: finalX,
|
|
10188
10246
|
positionY: finalY,
|
|
@@ -10194,10 +10252,10 @@ const pickPositionRelativeTo = (
|
|
|
10194
10252
|
anchorTop: anchorDocumentTop,
|
|
10195
10253
|
anchorRight: anchorDocumentRight,
|
|
10196
10254
|
anchorBottom: anchorDocumentBottom,
|
|
10197
|
-
spaceLeft,
|
|
10198
|
-
spaceRight,
|
|
10199
|
-
spaceAbove,
|
|
10200
|
-
spaceBelow,
|
|
10255
|
+
spaceLeft: spaceLeft - viewportSpacing,
|
|
10256
|
+
spaceRight: spaceRight - viewportSpacing,
|
|
10257
|
+
spaceAbove: effectiveSpaceAbove,
|
|
10258
|
+
spaceBelow: effectiveSpaceBelow,
|
|
10201
10259
|
};
|
|
10202
10260
|
};
|
|
10203
10261
|
|
|
@@ -11973,17 +12031,6 @@ const getWidthWithoutTransition = (element) =>
|
|
|
11973
12031
|
const getHeightWithoutTransition = (element) =>
|
|
11974
12032
|
getHeight$1(element, transitionStyleController);
|
|
11975
12033
|
|
|
11976
|
-
const getPaddingSizes = (element) => {
|
|
11977
|
-
const { paddingLeft, paddingRight, paddingTop, paddingBottom } =
|
|
11978
|
-
window.getComputedStyle(element, null);
|
|
11979
|
-
return {
|
|
11980
|
-
left: parseFloat(paddingLeft),
|
|
11981
|
-
right: parseFloat(paddingRight),
|
|
11982
|
-
top: parseFloat(paddingTop),
|
|
11983
|
-
bottom: parseFloat(paddingBottom),
|
|
11984
|
-
};
|
|
11985
|
-
};
|
|
11986
|
-
|
|
11987
12034
|
const getInnerHeight = (element) => {
|
|
11988
12035
|
// Always subtract paddings and borders to get the content height
|
|
11989
12036
|
const paddingSizes = getPaddingSizes(element);
|
|
@@ -13324,4 +13371,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
13324
13371
|
};
|
|
13325
13372
|
};
|
|
13326
13373
|
|
|
13327
|
-
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isSameColor, isScrollable, measureScrollbar, mergeOneStyle, mergeTwoStyles, normalizeStyles, parseStyle, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, setAttribute, setAttributes, setStyles, startDragToResizeGesture, stickyAsRelativeCoords, stringifyStyle, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|
|
13374
|
+
export { EASING, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, canInterceptKeys, captureScrollState, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dragAfterThreshold, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findFocusable, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isSameColor, isScrollable, measureScrollbar, mergeOneStyle, mergeTwoStyles, normalizeStyle, normalizeStyles, parseStyle, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, setAttribute, setAttributes, setStyles, snapToPixel, startDragToResizeGesture, stickyAsRelativeCoords, stringifyStyle, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect };
|