@jsenv/dom 0.17.19 → 0.17.21
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 +271 -66
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -261,11 +261,22 @@ const chainEvent = (customEvent, parentEvent) => {
|
|
|
261
261
|
if (!parentEvent) {
|
|
262
262
|
return customEvent;
|
|
263
263
|
}
|
|
264
|
-
if (!customEvent.detail) {
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
264
|
+
if (!customEvent.detail || typeof customEvent.detail !== "object") {
|
|
265
|
+
// A native event has nowhere to hang the chain: `Event` has no detail at
|
|
266
|
+
// all and `UIEvent` (so `InputEvent` too) exposes it as a readonly number.
|
|
267
|
+
// Give it an own detail object, shadowing the prototype getter, so a
|
|
268
|
+
// synthetic event dispatched on behalf of a gesture can still say what
|
|
269
|
+
// caused it.
|
|
270
|
+
if (nativeDetailHasMeaning(customEvent)) {
|
|
271
|
+
console.warn(
|
|
272
|
+
`Chaining "${customEvent.type}" to "${parentEvent.type}" replaces its native detail (${customEvent.detail}), which carries the click count on this event type. Chain a custom event instead, or read the click count before chaining.`,
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
Object.defineProperty(customEvent, "detail", {
|
|
276
|
+
value: {},
|
|
277
|
+
configurable: true,
|
|
278
|
+
enumerable: true,
|
|
279
|
+
});
|
|
269
280
|
}
|
|
270
281
|
// Always build eventChain from the first wrapping so callers can rely on it
|
|
271
282
|
// being present whenever `parentEvent` is set.
|
|
@@ -309,6 +320,24 @@ const findEvent = (event, predicate) => {
|
|
|
309
320
|
return undefined;
|
|
310
321
|
};
|
|
311
322
|
|
|
323
|
+
// `detail` is a click count on the pointer events that define one, and 0
|
|
324
|
+
// everywhere else (`input`, `focus`, `wheel`…). Overwriting it there loses the
|
|
325
|
+
// only way to tell a real click from a keyboard/programmatic one (detail === 0),
|
|
326
|
+
// so those events must not be chained.
|
|
327
|
+
const EVENT_TYPES_WITH_MEANINGFUL_DETAIL = new Set([
|
|
328
|
+
"click",
|
|
329
|
+
"auxclick",
|
|
330
|
+
"dblclick",
|
|
331
|
+
"mousedown",
|
|
332
|
+
"mouseup",
|
|
333
|
+
]);
|
|
334
|
+
const nativeDetailHasMeaning = (event) => {
|
|
335
|
+
if (EVENT_TYPES_WITH_MEANINGFUL_DETAIL.has(event.type)) {
|
|
336
|
+
return true;
|
|
337
|
+
}
|
|
338
|
+
return typeof event.detail === "number" && event.detail !== 0;
|
|
339
|
+
};
|
|
340
|
+
|
|
312
341
|
const resolveEventPredicate = (predicate) => {
|
|
313
342
|
if (typeof predicate === "string") {
|
|
314
343
|
return (e) => e.type === predicate;
|
|
@@ -9117,12 +9146,16 @@ const css$4 = /* css */`
|
|
|
9117
9146
|
/* A source taken by long press must let the scroll through until the grab —
|
|
9118
9147
|
which is exactly what the long press is there to tell apart. Zoom has
|
|
9119
9148
|
nothing to do with the gesture and nobody should lose it by resting a
|
|
9120
|
-
finger on a word.
|
|
9149
|
+
finger on a word.
|
|
9150
|
+
|
|
9151
|
+
Vertical, because that is the way the page and the lists in it go: a
|
|
9152
|
+
source dragged along one axis is surrounded by something scrolling along
|
|
9153
|
+
that same axis (a row of a list runs the way the list scrolls), and a
|
|
9154
|
+
source dragged both ways sits on the usual vertical page. */
|
|
9121
9155
|
touch-action: pan-y pinch-zoom;
|
|
9122
9156
|
}
|
|
9123
9157
|
[data-drag-source="x"] {
|
|
9124
|
-
/*
|
|
9125
|
-
knows which way what surrounds the source scrolls. */
|
|
9158
|
+
/* …and the sideways one, for the same reason read the other way. */
|
|
9126
9159
|
touch-action: pan-x pinch-zoom;
|
|
9127
9160
|
}
|
|
9128
9161
|
[data-drag-on-contact] [data-drag-source],
|
|
@@ -9158,23 +9191,36 @@ import.meta.css = [css$4, "@jsenv/dom/src/interaction/drag/drag_after_intent.js"
|
|
|
9158
9191
|
*
|
|
9159
9192
|
* On the element and not on the window, so the rest of the page keeps its
|
|
9160
9193
|
* touches on the compositor's fast path.
|
|
9194
|
+
*
|
|
9195
|
+
* Exported because a drag does not always begin on a drag source: a copy caught
|
|
9196
|
+
* on its way home is pressed through the pictures of a view transition, and the
|
|
9197
|
+
* touch lands on the document root (see letCopyBeCaught in drag_to.js). Same
|
|
9198
|
+
* rule, other element — and it has to be the same function, or the listener put
|
|
9199
|
+
* down is not the one taken back off.
|
|
9161
9200
|
*/
|
|
9162
9201
|
const keepTouchRefusable = () => {
|
|
9163
9202
|
// Being registered IS the whole of it — see above.
|
|
9164
9203
|
};
|
|
9165
9204
|
|
|
9166
9205
|
/**
|
|
9167
|
-
* Says an element is something a drag can start from
|
|
9206
|
+
* Says an element is something a drag can start from, and which way that drag
|
|
9207
|
+
* goes.
|
|
9208
|
+
*
|
|
9209
|
+
* The axes are written in the DOM rather than kept here because they are what
|
|
9210
|
+
* someone ELSE reads: a box above this one that travels under the same finger
|
|
9211
|
+
* (a row of slides, a sheet pushed down to close it) has to know which axes are
|
|
9212
|
+
* already spoken for before it answers the press — the same thing a travel says
|
|
9213
|
+
* about itself with `data-travel-by-drag`. It is also what leaves the browser
|
|
9214
|
+
* the pan it may still do until the grab (see the stylesheet above).
|
|
9168
9215
|
*
|
|
9169
9216
|
* @param {Element} element
|
|
9170
|
-
* @param {
|
|
9171
|
-
* Which way the
|
|
9172
|
-
*
|
|
9173
|
-
* else for the usual vertical page.
|
|
9217
|
+
* @param {"x"|"y"|"xy"} [axes="xy"]
|
|
9218
|
+
* Which way the drag walks. A list reordered along its own line says `"y"`;
|
|
9219
|
+
* something carried across a board, or thrown, goes both ways.
|
|
9174
9220
|
* @returns {function} Takes the mark back off.
|
|
9175
9221
|
*/
|
|
9176
|
-
const markDragSource = (element, axes) => {
|
|
9177
|
-
element.setAttribute("data-drag-source", axes
|
|
9222
|
+
const markDragSource = (element, axes = "xy") => {
|
|
9223
|
+
element.setAttribute("data-drag-source", axes);
|
|
9178
9224
|
element.addEventListener("touchmove", keepTouchRefusable, {
|
|
9179
9225
|
passive: false
|
|
9180
9226
|
});
|
|
@@ -11569,6 +11615,18 @@ const css$1 = /* css */`
|
|
|
11569
11615
|
pointer-events: auto;
|
|
11570
11616
|
}
|
|
11571
11617
|
|
|
11618
|
+
/* …and a FINGER reaching for it does not land on it: the pictures of the
|
|
11619
|
+
transition cover the page, so as far as the browser is concerned the touch
|
|
11620
|
+
began on the document root. What a touch may do is decided there and at that
|
|
11621
|
+
moment, so the root says it for as long as the copy can be caught — the pan
|
|
11622
|
+
is ours (nothing should scroll while something is landing), zoom stays the
|
|
11623
|
+
reader's. Half of a pair: without the non-passive listener put down at the
|
|
11624
|
+
same moment (see letCopyBeCaught) every touchmove arrives already
|
|
11625
|
+
non-cancelable and refusing it does nothing. */
|
|
11626
|
+
[data-drag-catchable] {
|
|
11627
|
+
touch-action: pinch-zoom;
|
|
11628
|
+
}
|
|
11629
|
+
|
|
11572
11630
|
/* Ce qui a été lancé: il continue dans la direction du geste jusqu'à sortir de
|
|
11573
11631
|
l'écran, et revient par le même chemin si la réponse refuse. */
|
|
11574
11632
|
[navi-drag-clone-wrapper][data-tossed] {
|
|
@@ -12514,7 +12572,15 @@ const startDragToCarryCopy = (event, {
|
|
|
12514
12572
|
return dragGesture;
|
|
12515
12573
|
}, {
|
|
12516
12574
|
threshold,
|
|
12517
|
-
|
|
12575
|
+
// A copy caught on its way home is not an ambiguous press: the hand
|
|
12576
|
+
// reached for something moving, and the press was already matched
|
|
12577
|
+
// against the copy's own box before it got here. The wait a finger is
|
|
12578
|
+
// asked for elsewhere tells a scroll from a drag, and there is no scroll
|
|
12579
|
+
// to tell it from — the copy covers that spot from the top layer. Asked
|
|
12580
|
+
// for anyway it cannot even be answered: the wait is about as long as the
|
|
12581
|
+
// journey, so the thing is home before the proof is done, while a mouse
|
|
12582
|
+
// takes it in five pixels.
|
|
12583
|
+
longPress: cloneWrapperCaught ? false : longPress,
|
|
12518
12584
|
longPressDelay,
|
|
12519
12585
|
longPressSlop,
|
|
12520
12586
|
onPressStart,
|
|
@@ -12704,6 +12770,17 @@ const letCopyBeCaught = (cloneWrapper, carryAgain) => {
|
|
|
12704
12770
|
// gesture holds what it grabbed rather than whatever was behind.
|
|
12705
12771
|
cloneWrapper.setAttribute("data-catchable", "");
|
|
12706
12772
|
document.addEventListener("pointerdown", onPointerDown, true);
|
|
12773
|
+
// The touch half of the same reach, said on the root because that is where a
|
|
12774
|
+
// finger pressing through the pictures lands (see the stylesheet). Both go
|
|
12775
|
+
// down before the copy sets off, since what a touch may do is settled when it
|
|
12776
|
+
// begins: put down later, the press is still read, the carry still starts, and
|
|
12777
|
+
// the browser cancels the pointer one move afterwards — a copy that cannot be
|
|
12778
|
+
// caught with a finger and can with a mouse.
|
|
12779
|
+
const root = document.documentElement;
|
|
12780
|
+
root.setAttribute("data-drag-catchable", "");
|
|
12781
|
+
root.addEventListener("touchmove", keepTouchRefusable, {
|
|
12782
|
+
passive: false
|
|
12783
|
+
});
|
|
12707
12784
|
return {
|
|
12708
12785
|
settled: async () => {
|
|
12709
12786
|
// A hand that lets go and presses again while the copy is still there is
|
|
@@ -12715,6 +12792,8 @@ const letCopyBeCaught = (cloneWrapper, carryAgain) => {
|
|
|
12715
12792
|
}
|
|
12716
12793
|
cloneWrapper.removeAttribute("data-catchable");
|
|
12717
12794
|
document.removeEventListener("pointerdown", onPointerDown, true);
|
|
12795
|
+
root.removeAttribute("data-drag-catchable");
|
|
12796
|
+
root.removeEventListener("touchmove", keepTouchRefusable);
|
|
12718
12797
|
return caught;
|
|
12719
12798
|
}
|
|
12720
12799
|
};
|
|
@@ -13006,12 +13085,13 @@ const DRAG_FLICK_DISTANCE = 8;
|
|
|
13006
13085
|
// way. Let go and it comes back — a wall one can lean on, never walk through.
|
|
13007
13086
|
const DRAG_RESISTANCE = 0.3;
|
|
13008
13087
|
|
|
13009
|
-
// What a drag must not start on: something that reads the pointer itself
|
|
13010
|
-
// button or a link is not in the list — dragging
|
|
13011
|
-
// click it would have made is swallowed on the way
|
|
13012
|
-
//
|
|
13013
|
-
//
|
|
13014
|
-
|
|
13088
|
+
// What a drag must not start on: something that reads the pointer itself, whole,
|
|
13089
|
+
// with no axis left to share. A button or a link is not in the list — dragging
|
|
13090
|
+
// from one travels, and the click it would have made is swallowed on the way
|
|
13091
|
+
// out. A drag SOURCE is not either: it says which way it goes and only takes
|
|
13092
|
+
// that (see DRAG_SOURCE_AXES_ATTRIBUTE) — but a dedicated handle is, being a
|
|
13093
|
+
// place whose only purpose is to be taken hold of, from the first pixel.
|
|
13094
|
+
const DRAG_EXCLUDED_SELECTOR = ["input", "textarea", "select", '[contenteditable=""]', '[contenteditable="true"]', "[data-drag-handle]", "[data-no-drag-travel]"].join(",");
|
|
13015
13095
|
|
|
13016
13096
|
// Which axes a box travels on, one attribute per gesture, said in the DOM by
|
|
13017
13097
|
// whoever owns the box: it is what a box ABOVE another reads to know the
|
|
@@ -13019,6 +13099,12 @@ const DRAG_EXCLUDED_SELECTOR = ["input", "textarea", "select", '[contenteditable
|
|
|
13019
13099
|
// from the outside.
|
|
13020
13100
|
const DRAG_AXES_ATTRIBUTE = "data-travel-by-drag";
|
|
13021
13101
|
const WHEEL_AXES_ATTRIBUTE = "data-travel-by-wheel";
|
|
13102
|
+
// The same thing said by something that is PICKED UP rather than travelled: a
|
|
13103
|
+
// row taken out of a list, a card carried across a board (see markDragSource).
|
|
13104
|
+
// It holds the pointer from the press exactly as a nested travel does, so it is
|
|
13105
|
+
// read exactly as one — a list reordered along its own line takes the axis it
|
|
13106
|
+
// runs on and leaves the other to whoever is above.
|
|
13107
|
+
const DRAG_SOURCE_AXES_ATTRIBUTE = "data-drag-source";
|
|
13022
13108
|
|
|
13023
13109
|
// A surface the browser paints in the top layer: it is still a DOM descendant
|
|
13024
13110
|
// of whatever it was written in, and it is nowhere near it on screen — it
|
|
@@ -13234,10 +13320,12 @@ const startDragToTravel = (pointerDownEvent, {
|
|
|
13234
13320
|
if (!target.closest || target.closest(DRAG_EXCLUDED_SELECTOR)) {
|
|
13235
13321
|
return null;
|
|
13236
13322
|
}
|
|
13237
|
-
// A box between the finger and this one that travels the same way
|
|
13238
|
-
//
|
|
13239
|
-
//
|
|
13240
|
-
|
|
13323
|
+
// A box between the finger and this one that travels the same way, and then
|
|
13324
|
+
// anything between them that is picked up and carried the same way: the
|
|
13325
|
+
// gesture is theirs, and this one is left with the axes none of them walks —
|
|
13326
|
+
// none at all, most of the time, and then there is no gesture here to read.
|
|
13327
|
+
const axesLeftByTravels = axesLeftBy(axes, target, element, DRAG_AXES_ATTRIBUTE);
|
|
13328
|
+
const axesLeft = axesLeftByTravels && axesLeftBy(axesLeftByTravels, target, element, DRAG_SOURCE_AXES_ATTRIBUTE);
|
|
13241
13329
|
if (!axesLeft) {
|
|
13242
13330
|
return null;
|
|
13243
13331
|
}
|
|
@@ -14275,6 +14363,90 @@ const stickyAsRelativeCoords = (
|
|
|
14275
14363
|
return [leftPosition, topPosition];
|
|
14276
14364
|
};
|
|
14277
14365
|
|
|
14366
|
+
/**
|
|
14367
|
+
* The on-screen keyboard, when the app takes it over.
|
|
14368
|
+
*
|
|
14369
|
+
* By default a mobile browser answers the keyboard by shrinking the VISUAL
|
|
14370
|
+
* viewport, and everything sized against that viewport follows for free —
|
|
14371
|
+
* which is what the whole positioning layer here already relies on (see
|
|
14372
|
+
* pickPositionRelativeTo's own visualViewport reads). The VirtualKeyboard API
|
|
14373
|
+
* (Chromium only — no Firefox, no Safari) offers the other deal:
|
|
14374
|
+
* `overlaysContent = true` and the keyboard stops resizing anything, painting
|
|
14375
|
+
* over the page instead, while its geometry becomes readable — `boundingRect`
|
|
14376
|
+
* and a `geometrychange` event here, `env(keyboard-inset-*)` in CSS.
|
|
14377
|
+
*
|
|
14378
|
+
* That deal has to be taken whole: the instant the viewport stops shrinking,
|
|
14379
|
+
* whoever was sizing against it is sizing against a rectangle the keyboard now
|
|
14380
|
+
* covers. So this module answers ONE question — how many pixels at the bottom
|
|
14381
|
+
* of the visual viewport the keyboard covers — and the positioning layer
|
|
14382
|
+
* subtracts it. The answer is 0 in every other case (unsupported, never opted
|
|
14383
|
+
* in, keyboard closed), which is exactly what makes the two paths one path:
|
|
14384
|
+
* where the browser shrinks the viewport itself, there is nothing left to
|
|
14385
|
+
* subtract.
|
|
14386
|
+
*
|
|
14387
|
+
* Why take the deal at all, then, if the outcome is meant to match? Because a
|
|
14388
|
+
* resizing viewport is a resize of EVERYTHING, whether or not it had anything
|
|
14389
|
+
* to do with the field being typed into — the page reflows, fixed bars move,
|
|
14390
|
+
* and a mobile browser fires that resize transiently as focus goes from one
|
|
14391
|
+
* input to the next. Overlaying leaves the layout alone and hands over a
|
|
14392
|
+
* number instead. So navi takes it by default (see its own index.js) and only
|
|
14393
|
+
* offers a way back out, for an app whose own layout was built around the
|
|
14394
|
+
* viewport shrinking.
|
|
14395
|
+
*/
|
|
14396
|
+
|
|
14397
|
+
const virtualKeyboard = window.navigator.virtualKeyboard;
|
|
14398
|
+
|
|
14399
|
+
/**
|
|
14400
|
+
* Whether the keyboard overlays the content instead of resizing the viewport.
|
|
14401
|
+
* Returns whether it applies at all — false means the browser has no
|
|
14402
|
+
* VirtualKeyboard API and keeps shrinking the visual viewport, which is the
|
|
14403
|
+
* behavior everything here already follows, so there is nothing to report to
|
|
14404
|
+
* the caller beyond "not this way".
|
|
14405
|
+
*/
|
|
14406
|
+
const setVirtualKeyboardOverlaysContent = (value) => {
|
|
14407
|
+
if (!virtualKeyboard) {
|
|
14408
|
+
return false;
|
|
14409
|
+
}
|
|
14410
|
+
virtualKeyboard.overlaysContent = value;
|
|
14411
|
+
return true;
|
|
14412
|
+
};
|
|
14413
|
+
|
|
14414
|
+
/**
|
|
14415
|
+
* How many pixels at the bottom of the visual viewport the keyboard currently
|
|
14416
|
+
* covers — 0 unless the app opted in above AND the keyboard is up.
|
|
14417
|
+
*
|
|
14418
|
+
* `boundingRect` is all-zero when the keyboard is hidden, and also while
|
|
14419
|
+
* `overlaysContent` is false: a keyboard that resized the viewport covers
|
|
14420
|
+
* nothing that is left of it, so the zero is the right answer rather than a
|
|
14421
|
+
* missing one.
|
|
14422
|
+
*/
|
|
14423
|
+
const getVirtualKeyboardOverlayHeight = () => {
|
|
14424
|
+
if (!virtualKeyboard) {
|
|
14425
|
+
return 0;
|
|
14426
|
+
}
|
|
14427
|
+
const { height } = virtualKeyboard.boundingRect;
|
|
14428
|
+
return height > 0 ? height : 0;
|
|
14429
|
+
};
|
|
14430
|
+
|
|
14431
|
+
/**
|
|
14432
|
+
* Calls `callback` whenever the keyboard shows, hides or resizes. Returns an
|
|
14433
|
+
* unsubscribe function; a no-op (never calls back) without support.
|
|
14434
|
+
*
|
|
14435
|
+
* Undebounced on purpose, unlike window/visualViewport resize
|
|
14436
|
+
* (window_size.js): "geometrychange" is not the transient storm those are —
|
|
14437
|
+
* it fires on the keyboard itself changing, not on the layout reacting to it,
|
|
14438
|
+
* which is the whole point of overlaying.
|
|
14439
|
+
*/
|
|
14440
|
+
const subscribeVirtualKeyboardGeometryChange = (callback) => {
|
|
14441
|
+
if (!virtualKeyboard) {
|
|
14442
|
+
return () => {};
|
|
14443
|
+
}
|
|
14444
|
+
virtualKeyboard.addEventListener("geometrychange", callback);
|
|
14445
|
+
return () => {
|
|
14446
|
+
virtualKeyboard.removeEventListener("geometrychange", callback);
|
|
14447
|
+
};
|
|
14448
|
+
};
|
|
14449
|
+
|
|
14278
14450
|
// Both "resize" sources fire transiently on mobile (keyboard/UI chrome
|
|
14279
14451
|
// briefly shifting when focus moves between inputs) — debounced so
|
|
14280
14452
|
// consumers skip that in-between state. One shared timer per source (not
|
|
@@ -14289,17 +14461,29 @@ const [publishVisualViewportResize, subscribeVisualViewportResizeSettled] =
|
|
|
14289
14461
|
createPubSub();
|
|
14290
14462
|
const [publishWindowResize, subscribeWindowResizeSettled] = createPubSub();
|
|
14291
14463
|
|
|
14464
|
+
let visualViewportResizeTimeoutId;
|
|
14465
|
+
const scheduleVisualViewportResize = (event) => {
|
|
14466
|
+
visualViewportResizePending = true;
|
|
14467
|
+
clearTimeout(visualViewportResizeTimeoutId);
|
|
14468
|
+
visualViewportResizeTimeoutId = setTimeout(() => {
|
|
14469
|
+
visualViewportResizePending = false;
|
|
14470
|
+
publishVisualViewportResize(event);
|
|
14471
|
+
}, RESIZE_SETTLE_MS);
|
|
14472
|
+
};
|
|
14292
14473
|
if (window.visualViewport) {
|
|
14293
|
-
|
|
14294
|
-
|
|
14295
|
-
|
|
14296
|
-
|
|
14297
|
-
timeoutId = setTimeout(() => {
|
|
14298
|
-
visualViewportResizePending = false;
|
|
14299
|
-
publishVisualViewportResize(event);
|
|
14300
|
-
}, RESIZE_SETTLE_MS);
|
|
14301
|
-
});
|
|
14474
|
+
window.visualViewport.addEventListener(
|
|
14475
|
+
"resize",
|
|
14476
|
+
scheduleVisualViewportResize,
|
|
14477
|
+
);
|
|
14302
14478
|
}
|
|
14479
|
+
// The same event, said differently: where the keyboard overlays the content
|
|
14480
|
+
// (virtual_keyboard.js) there is no visualViewport resize at all when it
|
|
14481
|
+
// opens — the room left to place anything in changed
|
|
14482
|
+
// all the same, and every consumer here asks the same question either way
|
|
14483
|
+
// (getVisibleViewportRect in visible_rect.js already subtracts it). Through
|
|
14484
|
+
// the same debounce, and for the same reason: going straight from one input
|
|
14485
|
+
// to the next hides and re-shows the keyboard.
|
|
14486
|
+
subscribeVirtualKeyboardGeometryChange(scheduleVisualViewportResize);
|
|
14303
14487
|
|
|
14304
14488
|
let windowResizeTimeoutId;
|
|
14305
14489
|
window.addEventListener("resize", (event) => {
|
|
@@ -14318,6 +14502,39 @@ window.addEventListener("resize", (event) => {
|
|
|
14318
14502
|
}, RESIZE_SETTLE_MS);
|
|
14319
14503
|
});
|
|
14320
14504
|
|
|
14505
|
+
/**
|
|
14506
|
+
* The part of the viewport something can actually be placed in.
|
|
14507
|
+
*
|
|
14508
|
+
* visualViewport, not the layout viewport: only the visual one shrinks when
|
|
14509
|
+
* the on-screen keyboard opens (where the browser is the one shrinking it —
|
|
14510
|
+
* see below). Its offsetLeft/Top matter too, for pinch-zoom/pan.
|
|
14511
|
+
*
|
|
14512
|
+
* document.documentElement.clientWidth/Height is the fallback without
|
|
14513
|
+
* visualViewport support — the layout viewport net of any classic scrollbar,
|
|
14514
|
+
* which is what visualViewport itself reports, unlike window.innerWidth/Height
|
|
14515
|
+
* which counts the scrollbar in. Both readings existed here, one per call
|
|
14516
|
+
* site, for no reason anyone stated; they only ever differed by that scrollbar
|
|
14517
|
+
* and only on browsers with no visualViewport at all.
|
|
14518
|
+
*
|
|
14519
|
+
* The keyboard is then subtracted rather than assumed to have already shrunk
|
|
14520
|
+
* the viewport: with `overlaysContent` (virtual_keyboard.js, navi turns it on)
|
|
14521
|
+
* the viewport stays full height and the keyboard is painted over its bottom.
|
|
14522
|
+
* Zero everywhere else, the browser having done the subtraction itself.
|
|
14523
|
+
*/
|
|
14524
|
+
const getVisibleViewportRect = () => {
|
|
14525
|
+
const visualViewport = window.visualViewport;
|
|
14526
|
+
const documentElement = document.documentElement;
|
|
14527
|
+
const height = visualViewport
|
|
14528
|
+
? visualViewport.height
|
|
14529
|
+
: documentElement.clientHeight;
|
|
14530
|
+
return {
|
|
14531
|
+
left: visualViewport ? visualViewport.offsetLeft : 0,
|
|
14532
|
+
top: visualViewport ? visualViewport.offsetTop : 0,
|
|
14533
|
+
width: visualViewport ? visualViewport.width : documentElement.clientWidth,
|
|
14534
|
+
height: Math.max(0, height - getVirtualKeyboardOverlayHeight()),
|
|
14535
|
+
};
|
|
14536
|
+
};
|
|
14537
|
+
|
|
14321
14538
|
// Minimum fraction of element width/height that must be visible on the preferred side
|
|
14322
14539
|
// before flipping to the opposite side. Prevents flickering near the flip threshold.
|
|
14323
14540
|
const MIN_CONTENT_VISIBILITY_RATIO = 0.6;
|
|
@@ -14440,23 +14657,17 @@ const visibleRectEffect = (
|
|
|
14440
14657
|
const UNSET_EVENT = { type: "unset" };
|
|
14441
14658
|
const check = (event = UNSET_EVENT) => {
|
|
14442
14659
|
|
|
14443
|
-
//
|
|
14444
|
-
//
|
|
14445
|
-
// pickPositionRelativeTo's
|
|
14446
|
-
//
|
|
14447
|
-
//
|
|
14448
|
-
|
|
14449
|
-
|
|
14450
|
-
|
|
14451
|
-
|
|
14452
|
-
|
|
14453
|
-
|
|
14454
|
-
: window.innerWidth;
|
|
14455
|
-
const viewportHeight = visualViewport
|
|
14456
|
-
? visualViewport.height
|
|
14457
|
-
: window.innerHeight;
|
|
14458
|
-
const viewportOffsetLeft = visualViewport ? visualViewport.offsetLeft : 0;
|
|
14459
|
-
const viewportOffsetTop = visualViewport ? visualViewport.offsetTop : 0;
|
|
14660
|
+
// Computed here regardless of scroll container (not just where the
|
|
14661
|
+
// non-document branch below needs it) because a keyboard opening can
|
|
14662
|
+
// change pickPositionRelativeTo's available space without moving this
|
|
14663
|
+
// element's own visibleRect at all — see viewportRectChanged further
|
|
14664
|
+
// down.
|
|
14665
|
+
const {
|
|
14666
|
+
left: viewportOffsetLeft,
|
|
14667
|
+
top: viewportOffsetTop,
|
|
14668
|
+
width: viewportWidth,
|
|
14669
|
+
height: viewportHeight,
|
|
14670
|
+
} = getVisibleViewportRect();
|
|
14460
14671
|
|
|
14461
14672
|
// 1. Calculate element position relative to scrollable parent
|
|
14462
14673
|
const { scrollLeft, scrollTop } = scrollContainer;
|
|
@@ -15313,19 +15524,13 @@ const pickPositionRelativeTo = (
|
|
|
15313
15524
|
container,
|
|
15314
15525
|
} = {},
|
|
15315
15526
|
) => {
|
|
15316
|
-
// Needed before hasValidAnchor below.
|
|
15317
|
-
|
|
15318
|
-
|
|
15319
|
-
|
|
15320
|
-
|
|
15321
|
-
|
|
15322
|
-
|
|
15323
|
-
: document.documentElement.clientWidth;
|
|
15324
|
-
const viewportHeight = visualViewport
|
|
15325
|
-
? visualViewport.height
|
|
15326
|
-
: document.documentElement.clientHeight;
|
|
15327
|
-
const viewportLeft = visualViewport ? visualViewport.offsetLeft : 0;
|
|
15328
|
-
const viewportTop = visualViewport ? visualViewport.offsetTop : 0;
|
|
15527
|
+
// Needed before hasValidAnchor below.
|
|
15528
|
+
const {
|
|
15529
|
+
left: viewportLeft,
|
|
15530
|
+
top: viewportTop,
|
|
15531
|
+
width: viewportWidth,
|
|
15532
|
+
height: viewportHeight,
|
|
15533
|
+
} = getVisibleViewportRect();
|
|
15329
15534
|
|
|
15330
15535
|
// Resolved early: everything below that would otherwise reach for
|
|
15331
15536
|
// viewportLeft/Top/Width/Height instead uses these, so a "local" popover
|
|
@@ -19318,4 +19523,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
19318
19523
|
};
|
|
19319
19524
|
};
|
|
19320
19525
|
|
|
19321
|
-
export { EASING, ELEMENT_SIZE_CHANGE, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, applyNewPosition, canScroll, captureScrollState, chainEvent, claimWheelGesture, closestOpenableAncestor, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterIntent, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findEvent, findFocusDelegateTarget, findFocusable, findSelfOrAncestorFixedPosition, formatEventSideEffect, getAncestorOpenType, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getKeyboardEventDefaultAction, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPositioningScrollOffset, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isAncestorOpen, isPrimaryButtonEvent, isSameColor, isScrollable, markDragSource, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, observeAncestorOpenState, onAncestorReopen, parsePositionArea, parseStyle, performTabNavigation, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, releaseWheelGesture, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, scrollRoomTowards, setAttribute, setAttributes, setStyles, snapToPixel, startDragTo, startDragToResizeGesture, startDragToTravel, stickyAsRelativeCoords, stringifyStyle, subscribeVisualViewportResizeSettled, subscribeWindowResizeSettled, suppressClickAfterGesture, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect, waitForPressHeld, watchWheelTravel, wheelGestureIsTakenFrom };
|
|
19526
|
+
export { EASING, ELEMENT_SIZE_CHANGE, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, applyNewPosition, canScroll, captureScrollState, chainEvent, claimWheelGesture, closestOpenableAncestor, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterIntent, elementIsFocusable, elementIsVisibleForFocus, elementIsVisuallyVisible, findAfter, findAncestor, findBefore, findDescendant, findEvent, findFocusDelegateTarget, findFocusable, findSelfOrAncestorFixedPosition, formatEventSideEffect, getAncestorOpenType, getAvailableHeight, getAvailableWidth, getBackground, getBackgroundColor, getBorder, getBorderRadius, getBorderSizes, getContrastRatio, getDefaultStyles, getDragCoordinates, getDropTargetInfo, getElementSignature, getFirstVisuallyVisibleAncestor, getFocusVisibilityInfo, getHeight, getHeightWithoutTransition, getInnerHeight, getInnerWidth, getKeyboardEventDefaultAction, getLuminance, getMarginSizes, getMaxHeight, getMaxWidth, getMinHeight, getMinWidth, getOpacity, getOpacityWithoutTransition, getPaddingSizes, getPositionedParent, getPositioningScrollOffset, getPreferedColorScheme, getScrollBox, getScrollContainer, getScrollContainerSet, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVirtualKeyboardOverlayHeight, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, isAncestorOpen, isPrimaryButtonEvent, isSameColor, isScrollable, markDragSource, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, observeAncestorOpenState, onAncestorReopen, parsePositionArea, parseStyle, performTabNavigation, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, releaseWheelGesture, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewWithStickyAwareness, scrollRoomTowards, setAttribute, setAttributes, setStyles, setVirtualKeyboardOverlaysContent, snapToPixel, startDragTo, startDragToResizeGesture, startDragToTravel, stickyAsRelativeCoords, stringifyStyle, subscribeVirtualKeyboardGeometryChange, subscribeVisualViewportResizeSettled, subscribeWindowResizeSettled, suppressClickAfterGesture, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect, waitForPressHeld, watchWheelTravel, wheelGestureIsTakenFrom };
|