@jsenv/dom 0.17.15 → 0.17.17
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 +91 -5
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -12791,15 +12791,77 @@ import.meta.css = [/* css */`
|
|
|
12791
12791
|
|
|
12792
12792
|
!important because this is not a preference: a box that travels cannot let
|
|
12793
12793
|
the page travel with it, and the rule has to win over whatever an
|
|
12794
|
-
application says about its own scrollers.
|
|
12795
|
-
|
|
12796
|
-
|
|
12794
|
+
application says about its own scrollers.
|
|
12795
|
+
|
|
12796
|
+
Said on the box, where it is a statement about the box and not about what
|
|
12797
|
+
it happens to hold — and read only where a browser asks the box at all:
|
|
12798
|
+
one that CLIPS is asked (it is a scroll container, which is what "asked"
|
|
12799
|
+
means to a browser), one that does not is walked past. A box that travels
|
|
12800
|
+
usually clips, because moving something in and out of a box is what
|
|
12801
|
+
clipping is for. One that does not still travels — what an inner scroller
|
|
12802
|
+
has left over reaches the page there, and the rule below says why that is
|
|
12803
|
+
the lesser of the two prices. An application that knows which of ITS
|
|
12804
|
+
elements scroll can contain those itself, on the element every engine
|
|
12805
|
+
reads; nothing in here can know that from a stylesheet. */
|
|
12806
|
+
[data-drag-travel*="x"] {
|
|
12797
12807
|
overscroll-behavior-x: contain !important;
|
|
12798
12808
|
}
|
|
12799
|
-
[data-drag-travel*="y"]
|
|
12800
|
-
[data-drag-travel*="y"] * {
|
|
12809
|
+
[data-drag-travel*="y"] {
|
|
12801
12810
|
overscroll-behavior-y: contain !important;
|
|
12802
12811
|
}
|
|
12812
|
+
/* The scrollers a browser makes on its own, wherever they are inside the box:
|
|
12813
|
+
a textarea and a list of options scroll their own content by nature, and
|
|
12814
|
+
nobody had to say so for them — no stylesheet declared them, so nothing
|
|
12815
|
+
else here can find them, and they would hand what is left of a gesture to
|
|
12816
|
+
the page like any undeclared scroller does.
|
|
12817
|
+
|
|
12818
|
+
Named rather than found, because being native is exactly what makes them
|
|
12819
|
+
nameable. An input is NOT in the list: it is the one form control that has
|
|
12820
|
+
nothing to scroll on the axis anything travels on, and containing it is how
|
|
12821
|
+
a row-wide invisible checkbox becomes a hole under the wheel.
|
|
12822
|
+
|
|
12823
|
+
A textarea with nothing in it, or a list of options short enough to fit, is
|
|
12824
|
+
contained too — a browser cannot be asked "only if it scrolls". On Blink
|
|
12825
|
+
that costs a wheel over an empty textarea, which then moves nothing rather
|
|
12826
|
+
than the list around it; elsewhere the engine already only asks what
|
|
12827
|
+
scrolls. Worth the page not moving behind a travel. */
|
|
12828
|
+
[data-drag-travel*="x"] :is(textarea, select[multiple], select[size]) {
|
|
12829
|
+
overscroll-behavior-x: contain !important;
|
|
12830
|
+
}
|
|
12831
|
+
[data-drag-travel*="y"] :is(textarea, select[multiple], select[size]) {
|
|
12832
|
+
overscroll-behavior-y: contain !important;
|
|
12833
|
+
}
|
|
12834
|
+
/* The same thing said again to everything inside — and only where saying it
|
|
12835
|
+
is what works.
|
|
12836
|
+
|
|
12837
|
+
Two readings of "contain" are out there, and the rule above lands in only
|
|
12838
|
+
one of them. Blink walks EVERY scroll container between the pointer and the
|
|
12839
|
+
page and asks each one whether the gesture may go past it, whether or not
|
|
12840
|
+
it had anything to scroll: the box above is asked, and containing it is the
|
|
12841
|
+
whole answer. Gecko and WebKit ask only the ones that actually scroll: the
|
|
12842
|
+
box is skipped (it travels, it does not scroll), and what is left of a
|
|
12843
|
+
list's gesture reaches the page unless the LIST itself was told — which is
|
|
12844
|
+
what this does, to everything, because which descendant scrolls is not
|
|
12845
|
+
something a stylesheet can know.
|
|
12846
|
+
|
|
12847
|
+
Not said to Blink, where it is not needed and does harm: an element that
|
|
12848
|
+
clips is a scroll container to a browser (a line of text with an ellipsis,
|
|
12849
|
+
a rounded card, an invisible checkbox covering a row), and Blink asking one
|
|
12850
|
+
of those with nothing to scroll gets "no further" for an answer — the wheel
|
|
12851
|
+
stops there and the list right above it never moves. A dead zone under the
|
|
12852
|
+
pointer, wherever something inside the box happens to clip.
|
|
12853
|
+
|
|
12854
|
+
Blink is told apart by a property only it has, rather than by reading a user
|
|
12855
|
+
agent: the split above is between engines, and -webkit-app-region is one of
|
|
12856
|
+
the few things that names one. */
|
|
12857
|
+
@supports not (-webkit-app-region: none) {
|
|
12858
|
+
[data-drag-travel*="x"] * {
|
|
12859
|
+
overscroll-behavior-x: contain !important;
|
|
12860
|
+
}
|
|
12861
|
+
[data-drag-travel*="y"] * {
|
|
12862
|
+
overscroll-behavior-y: contain !important;
|
|
12863
|
+
}
|
|
12864
|
+
}
|
|
12803
12865
|
`, "@jsenv/dom/src/interaction/drag/drag_to_travel.js"];
|
|
12804
12866
|
|
|
12805
12867
|
// How far a pointer goes before it is a travel rather than a click: below this
|
|
@@ -12832,6 +12894,16 @@ const DRAG_EXCLUDED_SELECTOR = ["input", "textarea", "select", '[contenteditable
|
|
|
12832
12894
|
const DRAG_AXES_ATTRIBUTE = "data-travel-by-drag";
|
|
12833
12895
|
const WHEEL_AXES_ATTRIBUTE = "data-travel-by-wheel";
|
|
12834
12896
|
|
|
12897
|
+
// A surface the browser paints in the top layer: it is still a DOM descendant
|
|
12898
|
+
// of whatever it was written in, and it is nowhere near it on screen — it
|
|
12899
|
+
// covers everything. So a gesture that happened on it is not the gesture of any
|
|
12900
|
+
// box it merely sits on top of, and every walk up the tree from the pointer
|
|
12901
|
+
// ends here: the boxes above are behind, and behind is not under the finger.
|
|
12902
|
+
const TOP_LAYER_SELECTOR = [":popover-open", "dialog:modal", ":fullscreen"].join(",");
|
|
12903
|
+
const isTopLayer = element => {
|
|
12904
|
+
return element.matches(TOP_LAYER_SELECTOR);
|
|
12905
|
+
};
|
|
12906
|
+
|
|
12835
12907
|
/**
|
|
12836
12908
|
* What is left for this box of the axes it travels, once the boxes it CONTAINS
|
|
12837
12909
|
* have taken theirs: a row of slides inside a page that walks between pages, a
|
|
@@ -12846,6 +12918,10 @@ const WHEEL_AXES_ATTRIBUTE = "data-travel-by-wheel";
|
|
|
12846
12918
|
* the browser for the pointer LAST, which is the outermost box — the wrong one,
|
|
12847
12919
|
* and past that point the inner one stops being told anything. So the box that
|
|
12848
12920
|
* does not own the gesture must never ask for it.
|
|
12921
|
+
*
|
|
12922
|
+
* A box lifted into the top layer on the way up takes everything: a popover or a
|
|
12923
|
+
* modal dialog is written inside a slide and painted over the whole screen, so
|
|
12924
|
+
* the slides are nowhere near the finger and none of the axes are left.
|
|
12849
12925
|
*/
|
|
12850
12926
|
const axesLeftBy = (axes, fromElement, stopElement, attribute) => {
|
|
12851
12927
|
if (!stopElement.contains(fromElement)) {
|
|
@@ -12857,6 +12933,11 @@ const axesLeftBy = (axes, fromElement, stopElement, attribute) => {
|
|
|
12857
12933
|
let left = axes;
|
|
12858
12934
|
let element = fromElement;
|
|
12859
12935
|
while (element && element !== stopElement && element.nodeType === 1) {
|
|
12936
|
+
if (isTopLayer(element)) {
|
|
12937
|
+
// The gesture happened on a surface painted over this box, not in it:
|
|
12938
|
+
// there is nothing left of it here, whatever axes are still unclaimed.
|
|
12939
|
+
return "";
|
|
12940
|
+
}
|
|
12860
12941
|
const taken = element.getAttribute(attribute);
|
|
12861
12942
|
if (taken) {
|
|
12862
12943
|
let rest = "";
|
|
@@ -12884,6 +12965,11 @@ const axesLeftBy = (axes, fromElement, stopElement, attribute) => {
|
|
|
12884
12965
|
const scrollRoomTowards = (fromElement, stopElement, axis, sign) => {
|
|
12885
12966
|
let element = fromElement;
|
|
12886
12967
|
while (element && element !== stopElement && element.nodeType === 1) {
|
|
12968
|
+
if (isTopLayer(element)) {
|
|
12969
|
+
// A scroller above a top-layer surface is painted behind it: whatever
|
|
12970
|
+
// room it has left is not room the finger is asking for.
|
|
12971
|
+
return false;
|
|
12972
|
+
}
|
|
12887
12973
|
const size = axis === "x" ? element.clientWidth : element.clientHeight;
|
|
12888
12974
|
const scrollSize = axis === "x" ? element.scrollWidth : element.scrollHeight;
|
|
12889
12975
|
if (scrollSize > size + 1) {
|