@jsenv/dom 0.17.90 → 0.17.92
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 +389 -35
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -4987,7 +4987,9 @@ const getFocusVisibilityInfo = (node, { excludeAriaHidden } = {}) => {
|
|
|
4987
4987
|
if (
|
|
4988
4988
|
elementIsDialog(nodeOrAncestor) &&
|
|
4989
4989
|
!nodeOrAncestor.open &&
|
|
4990
|
-
!isOpenPopover
|
|
4990
|
+
!isOpenPopover &&
|
|
4991
|
+
// A closed PopupGroup is displayed in the page (see ancestor_open.js).
|
|
4992
|
+
!nodeOrAncestor.hasAttribute("navi-popup-group")
|
|
4991
4993
|
) {
|
|
4992
4994
|
return { visible: false, reason: "inside closed dialog element" };
|
|
4993
4995
|
}
|
|
@@ -5102,6 +5104,11 @@ const elementIsFocusable = (node, { excludeAriaHidden } = {}) => {
|
|
|
5102
5104
|
if (node.hasAttribute("navi-focus-delegate")) {
|
|
5103
5105
|
return false;
|
|
5104
5106
|
}
|
|
5107
|
+
// A <dialog> because it is shown modal while one of its popups is open, not
|
|
5108
|
+
// a surface of its own to focus (see ancestor_open.js).
|
|
5109
|
+
if (node.hasAttribute("navi-popup-group")) {
|
|
5110
|
+
return false;
|
|
5111
|
+
}
|
|
5105
5112
|
if (!canInteract(node)) {
|
|
5106
5113
|
return false;
|
|
5107
5114
|
}
|
|
@@ -5260,6 +5267,9 @@ const findFocusable = (element, { exclude } = {}) => {
|
|
|
5260
5267
|
// `visible` is the other non-scrolling value, and the only one on which the
|
|
5261
5268
|
// content still reaches the ancestors.
|
|
5262
5269
|
const isScrollable = (element, { includeHidden } = {}) => {
|
|
5270
|
+
if (overflowGoesToViewport(element)) {
|
|
5271
|
+
return false;
|
|
5272
|
+
}
|
|
5263
5273
|
if (canHaveVerticalScroll(element, { includeHidden })) {
|
|
5264
5274
|
return true;
|
|
5265
5275
|
}
|
|
@@ -5279,6 +5289,9 @@ const canScroll = (element, axis) => {
|
|
|
5279
5289
|
if (!element || element.nodeType !== 1) {
|
|
5280
5290
|
return false;
|
|
5281
5291
|
}
|
|
5292
|
+
if (overflowGoesToViewport(element)) {
|
|
5293
|
+
return false;
|
|
5294
|
+
}
|
|
5282
5295
|
const style = getComputedStyle(element);
|
|
5283
5296
|
const overflow = axis === "x" ? style.overflowX : style.overflowY;
|
|
5284
5297
|
if (overflow !== "auto" && overflow !== "scroll") {
|
|
@@ -5291,6 +5304,23 @@ const canScroll = (element, axis) => {
|
|
|
5291
5304
|
return scrollSize - clientSize > 1;
|
|
5292
5305
|
};
|
|
5293
5306
|
|
|
5307
|
+
/**
|
|
5308
|
+
* Whether `element` is a <body> whose overflow belongs to the viewport: when
|
|
5309
|
+
* the root leaves its own overflow visible, the body's values are the
|
|
5310
|
+
* viewport's (CSS overflow propagation), and body itself neither scrolls nor
|
|
5311
|
+
* clips, whatever its computed overflow reads — `body { overflow-x: hidden }`
|
|
5312
|
+
* computes overflow-y to auto there. The viewport scrolls, through the
|
|
5313
|
+
* scrolling element.
|
|
5314
|
+
*/
|
|
5315
|
+
const overflowGoesToViewport = (element) => {
|
|
5316
|
+
const { ownerDocument } = element;
|
|
5317
|
+
if (element !== ownerDocument.body) {
|
|
5318
|
+
return false;
|
|
5319
|
+
}
|
|
5320
|
+
const rootStyle = getComputedStyle(ownerDocument.documentElement);
|
|
5321
|
+
return rootStyle.overflowX === "visible" && rootStyle.overflowY === "visible";
|
|
5322
|
+
};
|
|
5323
|
+
|
|
5294
5324
|
const canHaveVerticalScroll = (element, { includeHidden }) => {
|
|
5295
5325
|
const verticalOverflow = getStyle(element, "overflow-y");
|
|
5296
5326
|
if (verticalOverflow === "visible") {
|
|
@@ -5516,6 +5546,20 @@ const getKeyboardEventDefaultAction = (keyboardEvent) => {
|
|
|
5516
5546
|
return "";
|
|
5517
5547
|
};
|
|
5518
5548
|
|
|
5549
|
+
// Whether the keyboard follows macOS's conventions: there Home and End scroll
|
|
5550
|
+
// the page even from a text field, and a chord with Cmd or Option scrolls it to
|
|
5551
|
+
// an end or a page away.
|
|
5552
|
+
let isMac;
|
|
5553
|
+
const isMacPlatform = () => {
|
|
5554
|
+
if (isMac === undefined) {
|
|
5555
|
+
const { userAgentData, userAgent } = window.navigator;
|
|
5556
|
+
isMac = userAgentData
|
|
5557
|
+
? userAgentData.platform === "macOS"
|
|
5558
|
+
: /Mac|iPhone|iPad|iPod/.test(userAgent);
|
|
5559
|
+
}
|
|
5560
|
+
return isMac;
|
|
5561
|
+
};
|
|
5562
|
+
|
|
5519
5563
|
const isTypingIntent = (e) => {
|
|
5520
5564
|
// Modifier keys used for shortcuts: skip
|
|
5521
5565
|
if (e.metaKey || e.ctrlKey) {
|
|
@@ -5557,10 +5601,11 @@ const DEFAULT_BEHAVIORS = [
|
|
|
5557
5601
|
return "activate";
|
|
5558
5602
|
},
|
|
5559
5603
|
enter: (e) => (e.target.form ? "form_submit" : ""),
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
5604
|
+
// Moving through a radio group; a checkbox lets them scroll.
|
|
5605
|
+
arrowleft: (e) => (e.target.type === "radio" ? "focus_nav" : undefined),
|
|
5606
|
+
arrowright: (e) => (e.target.type === "radio" ? "focus_nav" : undefined),
|
|
5607
|
+
arrowup: (e) => (e.target.type === "radio" ? "focus_nav" : undefined),
|
|
5608
|
+
arrowdown: (e) => (e.target.type === "radio" ? "focus_nav" : undefined),
|
|
5564
5609
|
},
|
|
5565
5610
|
},
|
|
5566
5611
|
{
|
|
@@ -5583,8 +5628,10 @@ const DEFAULT_BEHAVIORS = [
|
|
|
5583
5628
|
arrowright: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
5584
5629
|
arrowup: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
5585
5630
|
arrowdown: (e) => (e.target.readOnly ? "scroll" : "cursor_move"),
|
|
5586
|
-
home: (e) =>
|
|
5587
|
-
|
|
5631
|
+
home: (e) =>
|
|
5632
|
+
e.target.readOnly || isMacPlatform() ? "scroll" : "cursor_move",
|
|
5633
|
+
end: (e) =>
|
|
5634
|
+
e.target.readOnly || isMacPlatform() ? "scroll" : "cursor_move",
|
|
5588
5635
|
},
|
|
5589
5636
|
fallback: (e) => (isTypingIntent(e) ? "type" : undefined),
|
|
5590
5637
|
},
|
|
@@ -5669,13 +5716,17 @@ const DEFAULT_BEHAVIORS = [
|
|
|
5669
5716
|
fallback: (e) => (isTypingIntent(e) ? "type" : undefined),
|
|
5670
5717
|
},
|
|
5671
5718
|
{
|
|
5672
|
-
// Buttons and links:
|
|
5719
|
+
// Buttons and links: Enter triggers the element's default action, Space
|
|
5720
|
+
// only a button's — on a link it scrolls the page.
|
|
5673
5721
|
test: (el) =>
|
|
5674
5722
|
el.tagName === "BUTTON" ||
|
|
5675
5723
|
el.tagName === "A" ||
|
|
5676
5724
|
el.getAttribute("role") === "button",
|
|
5677
5725
|
keys: {
|
|
5678
|
-
space:
|
|
5726
|
+
space: (e) =>
|
|
5727
|
+
e.target.tagName === "A" && e.target.getAttribute("role") !== "button"
|
|
5728
|
+
? undefined
|
|
5729
|
+
: "activate",
|
|
5679
5730
|
enter: "activate",
|
|
5680
5731
|
},
|
|
5681
5732
|
},
|
|
@@ -7204,6 +7255,10 @@ const getScrollContainer = (arg, { includeHidden } = {}) => {
|
|
|
7204
7255
|
return null;
|
|
7205
7256
|
}
|
|
7206
7257
|
if (isScrollBoundary(element)) {
|
|
7258
|
+
const placeholder = findEngagedPopupGroupPlaceholder(element);
|
|
7259
|
+
if (placeholder) {
|
|
7260
|
+
return getScrollContainer(placeholder, { includeHidden });
|
|
7261
|
+
}
|
|
7207
7262
|
return getScrollingElement(element.ownerDocument);
|
|
7208
7263
|
}
|
|
7209
7264
|
return (
|
|
@@ -7234,12 +7289,18 @@ const findScrollContainer = (element, { includeHidden } = {}) => {
|
|
|
7234
7289
|
if (parent === document) {
|
|
7235
7290
|
return null;
|
|
7236
7291
|
}
|
|
7237
|
-
|
|
7238
|
-
|
|
7239
|
-
}
|
|
7292
|
+
// A boundary that scrolls is the scroll container of what it holds — a
|
|
7293
|
+
// popup whose own box scrolls, a PopupGroup shown modal where it stands.
|
|
7240
7294
|
if (isScrollable(parent, { includeHidden })) {
|
|
7241
7295
|
return parent;
|
|
7242
7296
|
}
|
|
7297
|
+
if (isScrollBoundary(parent)) {
|
|
7298
|
+
const placeholder = findEngagedPopupGroupPlaceholder(parent);
|
|
7299
|
+
if (placeholder) {
|
|
7300
|
+
return findScrollContainer(placeholder, { includeHidden });
|
|
7301
|
+
}
|
|
7302
|
+
return null;
|
|
7303
|
+
}
|
|
7243
7304
|
parent = parent.parentNode;
|
|
7244
7305
|
}
|
|
7245
7306
|
return null;
|
|
@@ -7263,6 +7324,29 @@ const isScrollBoundary = (node) => {
|
|
|
7263
7324
|
return getStyle(node, "position") === "fixed";
|
|
7264
7325
|
};
|
|
7265
7326
|
|
|
7327
|
+
// Except a PopupGroup shown modal (@jsenv/navi's popup_group.jsx): fixed in the
|
|
7328
|
+
// top layer at the place a placeholder holds for it in the page, it follows
|
|
7329
|
+
// that place, so what scrolls the placeholder moves the group and what it
|
|
7330
|
+
// holds. The placeholder is inserted just before it; something rendered
|
|
7331
|
+
// before the group meanwhile lands in between.
|
|
7332
|
+
const findEngagedPopupGroupPlaceholder = (node) => {
|
|
7333
|
+
if (
|
|
7334
|
+
node.tagName !== "DIALOG" ||
|
|
7335
|
+
!node.hasAttribute("navi-popup-group") ||
|
|
7336
|
+
!node.matches(":modal")
|
|
7337
|
+
) {
|
|
7338
|
+
return null;
|
|
7339
|
+
}
|
|
7340
|
+
let previous = node.previousElementSibling;
|
|
7341
|
+
while (previous) {
|
|
7342
|
+
if (previous.hasAttribute("navi-popup-group-placeholder")) {
|
|
7343
|
+
return previous;
|
|
7344
|
+
}
|
|
7345
|
+
previous = previous.previousElementSibling;
|
|
7346
|
+
}
|
|
7347
|
+
return null;
|
|
7348
|
+
};
|
|
7349
|
+
|
|
7266
7350
|
const getSelfAndAncestorScrolls = (element, startOnParent) => {
|
|
7267
7351
|
let scrollX = 0;
|
|
7268
7352
|
let scrollY = 0;
|
|
@@ -8197,18 +8281,23 @@ const TOP_LAYER_SELECTOR$1 = [
|
|
|
8197
8281
|
":fullscreen",
|
|
8198
8282
|
].join(",");
|
|
8199
8283
|
|
|
8200
|
-
// The keys that scroll the document when nothing focusable holds them
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
"
|
|
8204
|
-
"
|
|
8205
|
-
"
|
|
8206
|
-
"
|
|
8207
|
-
"
|
|
8208
|
-
"
|
|
8209
|
-
"
|
|
8210
|
-
"
|
|
8284
|
+
// The keys that scroll the document when nothing focusable holds them, and
|
|
8285
|
+
// the way each one goes, as a wheel would: [deltaX, deltaY].
|
|
8286
|
+
const SCROLL_KEY_DELTA_MAP = new Map([
|
|
8287
|
+
["ArrowUp", [0, -1]],
|
|
8288
|
+
["ArrowDown", [0, 1]],
|
|
8289
|
+
["ArrowLeft", [-1, 0]],
|
|
8290
|
+
["ArrowRight", [1, 0]],
|
|
8291
|
+
["PageUp", [0, -1]],
|
|
8292
|
+
["PageDown", [0, 1]],
|
|
8293
|
+
["Home", [0, -1]],
|
|
8294
|
+
["End", [0, 1]],
|
|
8295
|
+
[" ", [0, 1]],
|
|
8211
8296
|
]);
|
|
8297
|
+
// What a scroll key does by itself on these, whatever it would scroll: a
|
|
8298
|
+
// closed <select> changes its value with the arrows, a media element's
|
|
8299
|
+
// controls seek with them.
|
|
8300
|
+
const KEY_OWNER_SELECTOR = "select, audio, video";
|
|
8212
8301
|
|
|
8213
8302
|
/**
|
|
8214
8303
|
* Stops the background from scrolling by cancelling the scroll gestures that
|
|
@@ -8242,14 +8331,33 @@ const SCROLL_KEY_SET = new Set([
|
|
|
8242
8331
|
* background, when it is one of ours (a modal dialog covers it with its own
|
|
8243
8332
|
* `::backdrop` and there is nothing to pass). It is in the top layer like the
|
|
8244
8333
|
* overlay itself, yet a gesture on it aims at the background behind it.
|
|
8334
|
+
* @param {() => {left: number, top: number, right: number, bottom: number}} [options.getElementBox]
|
|
8335
|
+
* - Where `element` is on screen, when that is less than its border box (an
|
|
8336
|
+
* overlay clipped by a clip-path): a gesture outside that box but reported on
|
|
8337
|
+
* `element` landed on its `::backdrop`.
|
|
8338
|
+
* @param {boolean} [options.containInside] - Also cancel a gesture landing on
|
|
8339
|
+
* or inside `element` that nothing between it and `element` can scroll in
|
|
8340
|
+
* its direction, and a scroll key pressed there the same way. For an overlay
|
|
8341
|
+
* that is not a scroll container itself (a box of the page shown in the top
|
|
8342
|
+
* layer where it stood): its scroll chain goes straight to the viewport, and
|
|
8343
|
+
* no `overscroll-behavior` of its own can stop it there. Decided once what
|
|
8344
|
+
* the gesture landed on has had its say: what takes it from a listener of
|
|
8345
|
+
* its own (a control moving by transform, a drag) cancels it there, and a
|
|
8346
|
+
* gesture cancelled before it gets there is one it refuses.
|
|
8245
8347
|
* @returns {() => void} Cleanup function removing the listeners.
|
|
8246
8348
|
*/
|
|
8247
8349
|
|
|
8248
8350
|
const trapScrollGestureInside = (
|
|
8249
8351
|
element,
|
|
8250
|
-
{
|
|
8352
|
+
{
|
|
8353
|
+
boundaryElement,
|
|
8354
|
+
backdropElement,
|
|
8355
|
+
getElementBox = () => element.getBoundingClientRect(),
|
|
8356
|
+
containInside = false,
|
|
8357
|
+
} = {},
|
|
8251
8358
|
) => {
|
|
8252
8359
|
const { ownerDocument } = element;
|
|
8360
|
+
const { defaultView } = ownerDocument;
|
|
8253
8361
|
const lockedRegion = boundaryElement || ownerDocument.documentElement;
|
|
8254
8362
|
|
|
8255
8363
|
const isBackgroundGesture = (target, clientX, clientY) => {
|
|
@@ -8264,7 +8372,7 @@ const trapScrollGestureInside = (
|
|
|
8264
8372
|
if (target !== element) {
|
|
8265
8373
|
return false;
|
|
8266
8374
|
}
|
|
8267
|
-
const { left, right, top, bottom } =
|
|
8375
|
+
const { left, right, top, bottom } = getElementBox();
|
|
8268
8376
|
return (
|
|
8269
8377
|
clientX < left || clientX > right || clientY < top || clientY > bottom
|
|
8270
8378
|
);
|
|
@@ -8282,6 +8390,42 @@ const trapScrollGestureInside = (
|
|
|
8282
8390
|
return true;
|
|
8283
8391
|
};
|
|
8284
8392
|
|
|
8393
|
+
// Whether something on the event's way from what it landed on up to
|
|
8394
|
+
// `element` scrolls the way the gesture mostly goes, with room left to go
|
|
8395
|
+
// there. The composed path, not the parents: a scroller inside a shadow
|
|
8396
|
+
// root, or the shadow scroller a slotted element shows in, is on it. A box
|
|
8397
|
+
// in the top layer, or fixed, ends the walk: its scroll chain goes on to the
|
|
8398
|
+
// viewport, not to its parent in the DOM.
|
|
8399
|
+
const isTakenInside = (event, deltaX, deltaY) => {
|
|
8400
|
+
const axis = Math.abs(deltaY) >= Math.abs(deltaX) ? "y" : "x";
|
|
8401
|
+
const delta = axis === "y" ? deltaY : deltaX;
|
|
8402
|
+
for (const node of event.composedPath()) {
|
|
8403
|
+
if (node.nodeType !== 1) {
|
|
8404
|
+
continue;
|
|
8405
|
+
}
|
|
8406
|
+
if (canScroll(node, axis) && hasRoomToScroll(node, axis, delta)) {
|
|
8407
|
+
return true;
|
|
8408
|
+
}
|
|
8409
|
+
if (node === element) {
|
|
8410
|
+
return false;
|
|
8411
|
+
}
|
|
8412
|
+
if (
|
|
8413
|
+
node.matches(TOP_LAYER_SELECTOR$1) ||
|
|
8414
|
+
getComputedStyle(node).position === "fixed"
|
|
8415
|
+
) {
|
|
8416
|
+
return false;
|
|
8417
|
+
}
|
|
8418
|
+
}
|
|
8419
|
+
return false;
|
|
8420
|
+
};
|
|
8421
|
+
// On `element` itself too, inside its box: on its padding, between what it
|
|
8422
|
+
// holds. Outside that box it is the wall, decided first (isBackgroundGesture).
|
|
8423
|
+
const leaksFromInside = (event, deltaX, deltaY) =>
|
|
8424
|
+
// A move with no direction scrolls nothing.
|
|
8425
|
+
(deltaX !== 0 || deltaY !== 0) &&
|
|
8426
|
+
element.contains(event.target) &&
|
|
8427
|
+
!isTakenInside(event, deltaX, deltaY);
|
|
8428
|
+
|
|
8285
8429
|
const onWheel = (wheelEvent) => {
|
|
8286
8430
|
if (wheelEvent.ctrlKey) {
|
|
8287
8431
|
// Browser zoom, not a scroll — cancelling it would take zoom away from
|
|
@@ -8298,25 +8442,71 @@ const trapScrollGestureInside = (
|
|
|
8298
8442
|
wheelEvent.preventDefault();
|
|
8299
8443
|
}
|
|
8300
8444
|
};
|
|
8445
|
+
const onWheelInside = (wheelEvent) => {
|
|
8446
|
+
if (
|
|
8447
|
+
wheelEvent.ctrlKey ||
|
|
8448
|
+
wheelEvent.defaultPrevented ||
|
|
8449
|
+
!wheelEvent.cancelable
|
|
8450
|
+
) {
|
|
8451
|
+
return;
|
|
8452
|
+
}
|
|
8453
|
+
if (leaksFromInside(wheelEvent, wheelEvent.deltaX, wheelEvent.deltaY)) {
|
|
8454
|
+
wheelEvent.preventDefault();
|
|
8455
|
+
}
|
|
8456
|
+
};
|
|
8457
|
+
// Where the finger was at the previous touch event: a touchmove carries no
|
|
8458
|
+
// delta of its own. Read in the capture phase, which every touchmove goes
|
|
8459
|
+
// through, for the decision taken once it has been through its target.
|
|
8460
|
+
let previousTouch = null;
|
|
8461
|
+
let touchMoveDelta = null;
|
|
8462
|
+
const onTouchStart = (touchStartEvent) => {
|
|
8463
|
+
const { touches } = touchStartEvent;
|
|
8464
|
+
previousTouch =
|
|
8465
|
+
touches.length === 1
|
|
8466
|
+
? { x: touches[0].clientX, y: touches[0].clientY }
|
|
8467
|
+
: null;
|
|
8468
|
+
};
|
|
8301
8469
|
const onTouchMove = (touchMoveEvent) => {
|
|
8302
8470
|
const { touches } = touchMoveEvent;
|
|
8303
8471
|
if (touches.length !== 1) {
|
|
8304
8472
|
return; // pinch
|
|
8305
8473
|
}
|
|
8306
8474
|
const [touch] = touches;
|
|
8475
|
+
// The content moves against the finger.
|
|
8476
|
+
touchMoveDelta = {
|
|
8477
|
+
touchMoveEvent,
|
|
8478
|
+
deltaX: previousTouch ? previousTouch.x - touch.clientX : 0,
|
|
8479
|
+
deltaY: previousTouch ? previousTouch.y - touch.clientY : 0,
|
|
8480
|
+
};
|
|
8481
|
+
previousTouch = { x: touch.clientX, y: touch.clientY };
|
|
8307
8482
|
if (
|
|
8308
8483
|
isBackgroundGesture(touchMoveEvent.target, touch.clientX, touch.clientY)
|
|
8309
8484
|
) {
|
|
8310
8485
|
touchMoveEvent.preventDefault();
|
|
8311
8486
|
}
|
|
8312
8487
|
};
|
|
8488
|
+
const onTouchMoveInside = (touchMoveEvent) => {
|
|
8489
|
+
if (touchMoveDelta?.touchMoveEvent !== touchMoveEvent) {
|
|
8490
|
+
return; // pinch
|
|
8491
|
+
}
|
|
8492
|
+
const { deltaX, deltaY } = touchMoveDelta;
|
|
8493
|
+
touchMoveDelta = null;
|
|
8494
|
+
if (touchMoveEvent.defaultPrevented || !touchMoveEvent.cancelable) {
|
|
8495
|
+
return;
|
|
8496
|
+
}
|
|
8497
|
+
if (leaksFromInside(touchMoveEvent, deltaX, deltaY)) {
|
|
8498
|
+
touchMoveEvent.preventDefault();
|
|
8499
|
+
}
|
|
8500
|
+
};
|
|
8313
8501
|
const onKeyDown = (keydownEvent) => {
|
|
8314
|
-
if (!
|
|
8502
|
+
if (!SCROLL_KEY_DELTA_MAP.has(keydownEvent.key)) {
|
|
8315
8503
|
return;
|
|
8316
8504
|
}
|
|
8317
8505
|
const { target } = keydownEvent;
|
|
8318
8506
|
// Anything else focused (a field, a scrollable box, a button) owns the key
|
|
8319
|
-
// press; only a document with nothing focused scrolls on it.
|
|
8507
|
+
// press; only a document with nothing focused scrolls on it. Inside
|
|
8508
|
+
// `element`, with containInside, what really owns it is asked
|
|
8509
|
+
// (onKeyDownInside).
|
|
8320
8510
|
if (
|
|
8321
8511
|
target !== ownerDocument.body &&
|
|
8322
8512
|
target !== ownerDocument.documentElement
|
|
@@ -8327,6 +8517,37 @@ const trapScrollGestureInside = (
|
|
|
8327
8517
|
keydownEvent.preventDefault();
|
|
8328
8518
|
}
|
|
8329
8519
|
};
|
|
8520
|
+
// A key whose default would scroll, pressed where nothing between there and
|
|
8521
|
+
// `element` scrolls that way.
|
|
8522
|
+
const onKeyDownInside = (keydownEvent) => {
|
|
8523
|
+
if (keydownEvent.defaultPrevented) {
|
|
8524
|
+
return;
|
|
8525
|
+
}
|
|
8526
|
+
const scrollDelta = readKeyScrollDelta(keydownEvent);
|
|
8527
|
+
if (!scrollDelta) {
|
|
8528
|
+
return;
|
|
8529
|
+
}
|
|
8530
|
+
const { target } = keydownEvent;
|
|
8531
|
+
if (!element.contains(target)) {
|
|
8532
|
+
return;
|
|
8533
|
+
}
|
|
8534
|
+
if (keydownEvent.composedPath()[0] !== target) {
|
|
8535
|
+
// Pressed in a shadow tree, whose host the target is: what the key does
|
|
8536
|
+
// in there is not known from here.
|
|
8537
|
+
return;
|
|
8538
|
+
}
|
|
8539
|
+
if (target.matches(KEY_OWNER_SELECTOR)) {
|
|
8540
|
+
return;
|
|
8541
|
+
}
|
|
8542
|
+
const defaultAction = getKeyboardEventDefaultAction(keydownEvent);
|
|
8543
|
+
if (defaultAction !== "scroll" && defaultAction !== "scroll_self") {
|
|
8544
|
+
return;
|
|
8545
|
+
}
|
|
8546
|
+
const [deltaX, deltaY] = scrollDelta;
|
|
8547
|
+
if (!isTakenInside(keydownEvent, deltaX, deltaY)) {
|
|
8548
|
+
keydownEvent.preventDefault();
|
|
8549
|
+
}
|
|
8550
|
+
};
|
|
8330
8551
|
|
|
8331
8552
|
// Capture phase: the gesture must be cancelled before whatever it landed on
|
|
8332
8553
|
// gets a chance to act on it. passive: false is what makes preventDefault
|
|
@@ -8335,7 +8556,24 @@ const trapScrollGestureInside = (
|
|
|
8335
8556
|
ownerDocument.addEventListener("wheel", onWheel, listenerOptions);
|
|
8336
8557
|
ownerDocument.addEventListener("touchmove", onTouchMove, listenerOptions);
|
|
8337
8558
|
ownerDocument.addEventListener("keydown", onKeyDown, listenerOptions);
|
|
8559
|
+
if (containInside) {
|
|
8560
|
+
ownerDocument.addEventListener("touchstart", onTouchStart, {
|
|
8561
|
+
capture: true,
|
|
8562
|
+
passive: true,
|
|
8563
|
+
});
|
|
8564
|
+
// On the window, after every listener on the way: what is inside has had
|
|
8565
|
+
// its say. passive: false said out loud — a wheel or touch listener on the
|
|
8566
|
+
// window is passive unless told otherwise.
|
|
8567
|
+
defaultView.addEventListener("wheel", onWheelInside, { passive: false });
|
|
8568
|
+
defaultView.addEventListener("touchmove", onTouchMoveInside, {
|
|
8569
|
+
passive: false,
|
|
8570
|
+
});
|
|
8571
|
+
defaultView.addEventListener("keydown", onKeyDownInside);
|
|
8572
|
+
}
|
|
8338
8573
|
return () => {
|
|
8574
|
+
ownerDocument.removeEventListener("touchstart", onTouchStart, {
|
|
8575
|
+
capture: true,
|
|
8576
|
+
});
|
|
8339
8577
|
ownerDocument.removeEventListener("wheel", onWheel, listenerOptions);
|
|
8340
8578
|
ownerDocument.removeEventListener(
|
|
8341
8579
|
"touchmove",
|
|
@@ -8343,9 +8581,97 @@ const trapScrollGestureInside = (
|
|
|
8343
8581
|
listenerOptions,
|
|
8344
8582
|
);
|
|
8345
8583
|
ownerDocument.removeEventListener("keydown", onKeyDown, listenerOptions);
|
|
8584
|
+
defaultView.removeEventListener("wheel", onWheelInside);
|
|
8585
|
+
defaultView.removeEventListener("touchmove", onTouchMoveInside);
|
|
8586
|
+
defaultView.removeEventListener("keydown", onKeyDownInside);
|
|
8346
8587
|
};
|
|
8347
8588
|
};
|
|
8348
8589
|
|
|
8590
|
+
// Whether `scroller` has room left on `axis` the way `delta` goes, with a
|
|
8591
|
+
// pixel of slack against rounded sizes. Its scroll position counts from its
|
|
8592
|
+
// scroll origin, which is on the right of a right-to-left box and at the bottom
|
|
8593
|
+
// of some vertical writing modes: from there it reads 0, then negative.
|
|
8594
|
+
const hasRoomToScroll = (scroller, axis, delta) => {
|
|
8595
|
+
const range =
|
|
8596
|
+
axis === "y"
|
|
8597
|
+
? scroller.scrollHeight - scroller.clientHeight
|
|
8598
|
+
: scroller.scrollWidth - scroller.clientWidth;
|
|
8599
|
+
const position = axis === "y" ? scroller.scrollTop : scroller.scrollLeft;
|
|
8600
|
+
// From the top, or the left.
|
|
8601
|
+
const fromStart = isScrollOriginAtTheEnd(getComputedStyle(scroller), axis)
|
|
8602
|
+
? range + position
|
|
8603
|
+
: position;
|
|
8604
|
+
return delta < 0 ? fromStart > 1 : fromStart < range - 1;
|
|
8605
|
+
};
|
|
8606
|
+
const isScrollOriginAtTheEnd = (
|
|
8607
|
+
{ writingMode, direction, display, flexDirection, flexWrap },
|
|
8608
|
+
axis,
|
|
8609
|
+
) => {
|
|
8610
|
+
const vertical =
|
|
8611
|
+
writingMode.startsWith("vertical") || writingMode.startsWith("sideways");
|
|
8612
|
+
let atTheEnd;
|
|
8613
|
+
if (!vertical) {
|
|
8614
|
+
atTheEnd = axis === "x" && direction === "rtl";
|
|
8615
|
+
} else if (axis === "x") {
|
|
8616
|
+
// Lines stacked from the right.
|
|
8617
|
+
atTheEnd = writingMode.endsWith("-rl");
|
|
8618
|
+
} else {
|
|
8619
|
+
// sideways-lr runs its text bottom to top.
|
|
8620
|
+
atTheEnd =
|
|
8621
|
+
writingMode === "sideways-lr" ? direction !== "rtl" : direction === "rtl";
|
|
8622
|
+
}
|
|
8623
|
+
// A reversed flex container starts at the other end of that axis: its main
|
|
8624
|
+
// axis for a reversed direction (a log resting on its newest item), its
|
|
8625
|
+
// cross axis for wrap-reverse.
|
|
8626
|
+
if (display === "flex" || display === "inline-flex") {
|
|
8627
|
+
const inlineAxis = vertical ? "y" : "x";
|
|
8628
|
+
const blockAxis = vertical ? "x" : "y";
|
|
8629
|
+
const mainAxis = flexDirection.startsWith("row") ? inlineAxis : blockAxis;
|
|
8630
|
+
const reversed =
|
|
8631
|
+
axis === mainAxis
|
|
8632
|
+
? flexDirection.endsWith("-reverse")
|
|
8633
|
+
: flexWrap === "wrap-reverse";
|
|
8634
|
+
if (reversed) {
|
|
8635
|
+
atTheEnd = !atTheEnd;
|
|
8636
|
+
}
|
|
8637
|
+
}
|
|
8638
|
+
return atTheEnd;
|
|
8639
|
+
};
|
|
8640
|
+
|
|
8641
|
+
// The way a key scrolls, as a wheel would: [deltaX, deltaY], or null for a key
|
|
8642
|
+
// that scrolls nothing. With a modifier, only the platform's own chords to the
|
|
8643
|
+
// top, the bottom or a page away; never the arrows sideways, which go back and
|
|
8644
|
+
// forward in the history.
|
|
8645
|
+
const readKeyScrollDelta = (keydownEvent) => {
|
|
8646
|
+
const { key, altKey, ctrlKey, metaKey, shiftKey } = keydownEvent;
|
|
8647
|
+
if (!altKey && !ctrlKey && !metaKey) {
|
|
8648
|
+
if (key === " " && shiftKey) {
|
|
8649
|
+
return [0, -1];
|
|
8650
|
+
}
|
|
8651
|
+
return SCROLL_KEY_DELTA_MAP.get(key) || null;
|
|
8652
|
+
}
|
|
8653
|
+
if (isMacPlatform()) {
|
|
8654
|
+
if (!ctrlKey && (metaKey || altKey)) {
|
|
8655
|
+
if (key === "ArrowUp") {
|
|
8656
|
+
return [0, -1];
|
|
8657
|
+
}
|
|
8658
|
+
if (key === "ArrowDown") {
|
|
8659
|
+
return [0, 1];
|
|
8660
|
+
}
|
|
8661
|
+
}
|
|
8662
|
+
return null;
|
|
8663
|
+
}
|
|
8664
|
+
if (ctrlKey && !altKey && !metaKey) {
|
|
8665
|
+
if (key === "Home") {
|
|
8666
|
+
return [0, -1];
|
|
8667
|
+
}
|
|
8668
|
+
if (key === "End") {
|
|
8669
|
+
return [0, 1];
|
|
8670
|
+
}
|
|
8671
|
+
}
|
|
8672
|
+
return null;
|
|
8673
|
+
};
|
|
8674
|
+
|
|
8349
8675
|
// "gesture": cancel the scroll gestures aimed at the background, keeping it
|
|
8350
8676
|
// scrollable (see scroll_gesture_trap.js) — only possible when a backdrop
|
|
8351
8677
|
// covers it.
|
|
@@ -8395,16 +8721,24 @@ const SCROLL_LOCK_STRATEGY = "gesture";
|
|
|
8395
8721
|
* while the overlay is open: the backdrop element, or `true` when the browser
|
|
8396
8722
|
* paints it itself (a modal dialog's `::backdrop`). Enables the gesture
|
|
8397
8723
|
* strategy described above.
|
|
8724
|
+
* @param {Function} [options.getElementBox] - Forwarded to
|
|
8725
|
+
* trapScrollGestureInside: where `element` is on screen when that is less
|
|
8726
|
+
* than its border box.
|
|
8727
|
+
* @param {boolean} [options.containInside] - Forwarded to
|
|
8728
|
+
* trapScrollGestureInside: a gesture or a scroll key inside `element` that
|
|
8729
|
+
* nothing in it can scroll does not reach the background either.
|
|
8398
8730
|
* @returns {() => void} Cleanup function that restores all modified styles.
|
|
8399
8731
|
*/
|
|
8400
8732
|
const trapScrollInside = (
|
|
8401
8733
|
element,
|
|
8402
|
-
{ boundaryElement, backdrop } = {},
|
|
8734
|
+
{ boundaryElement, backdrop, getElementBox, containInside } = {},
|
|
8403
8735
|
) => {
|
|
8404
8736
|
if (backdrop && SCROLL_LOCK_STRATEGY === "gesture") {
|
|
8405
8737
|
return trapScrollGestureInside(element, {
|
|
8406
8738
|
boundaryElement,
|
|
8407
8739
|
backdropElement: backdrop === true ? null : backdrop,
|
|
8740
|
+
getElementBox,
|
|
8741
|
+
containInside,
|
|
8408
8742
|
});
|
|
8409
8743
|
}
|
|
8410
8744
|
|
|
@@ -10047,11 +10381,20 @@ const css$5 = /* css */ `[data-drag-handle], [data-drag-source] {
|
|
|
10047
10381
|
user-select: none;
|
|
10048
10382
|
}
|
|
10049
10383
|
|
|
10050
|
-
[data-drag-on-contact] [data-drag-ignore], [data-drag-on-contact] [popover], [data-drag-on-contact]
|
|
10384
|
+
[data-drag-on-contact] [data-drag-ignore], [data-drag-on-contact] [popover], [data-drag-on-contact] :is(input:not([data-press-only]), textarea), [data-drag-on-contact] :is([contenteditable=""], [contenteditable="true"]) {
|
|
10051
10385
|
user-select: text;
|
|
10052
10386
|
}
|
|
10053
10387
|
|
|
10054
|
-
[data-drag-
|
|
10388
|
+
[data-drag-on-contact] dialog:not([navi-popup-group]:not(:modal)) {
|
|
10389
|
+
user-select: text;
|
|
10390
|
+
}
|
|
10391
|
+
|
|
10392
|
+
[data-drag-ignore], [data-self-interactions~="drag"], [data-self-interactions~="*"], [data-drag-source] [popover] {
|
|
10393
|
+
-webkit-touch-callout: default;
|
|
10394
|
+
touch-action: auto;
|
|
10395
|
+
}
|
|
10396
|
+
|
|
10397
|
+
[data-drag-source] dialog:not([navi-popup-group]:not(:modal)) {
|
|
10055
10398
|
-webkit-touch-callout: default;
|
|
10056
10399
|
touch-action: auto;
|
|
10057
10400
|
}
|
|
@@ -12612,7 +12955,8 @@ const DRAG_EXCLUDED_SELECTOR = [
|
|
|
12612
12955
|
'[data-self-interactions~="drag"]',
|
|
12613
12956
|
'[data-self-interactions~="*"]',
|
|
12614
12957
|
"[popover]",
|
|
12615
|
-
|
|
12958
|
+
// An idle PopupGroup is part of the page (see DRAG_IGNORED_SELECTOR).
|
|
12959
|
+
"dialog:not([navi-popup-group]:not(:modal))",
|
|
12616
12960
|
].join(",");
|
|
12617
12961
|
|
|
12618
12962
|
// Which axes a box travels on, one attribute per gesture, said in the DOM by
|
|
@@ -14379,7 +14723,11 @@ const css$1 = /* css */ `.navi_drop_hint {
|
|
|
14379
14723
|
cursor: default;
|
|
14380
14724
|
}
|
|
14381
14725
|
|
|
14382
|
-
[data-drag-ignore], [data-self-interactions~="drag"], [data-self-interactions~="*"], [data-drag-source] [popover]
|
|
14726
|
+
[data-drag-ignore], [data-self-interactions~="drag"], [data-self-interactions~="*"], [data-drag-source] [popover] {
|
|
14727
|
+
cursor: auto;
|
|
14728
|
+
}
|
|
14729
|
+
|
|
14730
|
+
[data-drag-source] dialog:not([navi-popup-group]:not(:modal)) {
|
|
14383
14731
|
cursor: auto;
|
|
14384
14732
|
}
|
|
14385
14733
|
|
|
@@ -14467,8 +14815,10 @@ import.meta.css = [css$1, "@jsenv/dom/src/interaction/drag/drag_to.js"];
|
|
|
14467
14815
|
// stays a descendant of whatever it is anchored in (a callout next to a button,
|
|
14468
14816
|
// in the card that carries both), and the press bubbles through the surface as
|
|
14469
14817
|
// if it had landed on it.
|
|
14818
|
+
// An idle PopupGroup is a closed <dialog> that is part of the page, not a layer
|
|
14819
|
+
// over it (see @jsenv/navi's popup_group.jsx).
|
|
14470
14820
|
const DRAG_IGNORED_SELECTOR =
|
|
14471
|
-
'[data-drag-ignore],[data-self-interactions~="drag"],[data-self-interactions~="*"],[popover],dialog';
|
|
14821
|
+
'[data-drag-ignore],[data-self-interactions~="drag"],[data-self-interactions~="*"],[popover],dialog:not([navi-popup-group]:not(:modal))';
|
|
14472
14822
|
|
|
14473
14823
|
/**
|
|
14474
14824
|
* Creates a gesture controller that moves elements via drag.
|
|
@@ -16341,7 +16691,11 @@ const getResizeDirection = (element) => {
|
|
|
16341
16691
|
// directions: hide when a container closes, recheck when it reopens) — the
|
|
16342
16692
|
// selector/open-detection/timing primitives are identical for both, only
|
|
16343
16693
|
// what each does with a transition differs.
|
|
16344
|
-
|
|
16694
|
+
// Not a PopupGroup (@jsenv/navi's popup_group.jsx): a <dialog> that is a box
|
|
16695
|
+
// of the page, closed or shown modal where it stands. Its `open` says nothing
|
|
16696
|
+
// about whether what it holds is on screen.
|
|
16697
|
+
const OPENABLE_SELECTOR =
|
|
16698
|
+
"dialog:not([navi-popup-group]), details, [popover], [aria-expanded]";
|
|
16345
16699
|
|
|
16346
16700
|
// An element that IS openable is closed in exactly the same way an element
|
|
16347
16701
|
// inside one is — which matters for anything positioned against it, e.g. a
|
|
@@ -22405,4 +22759,4 @@ const useResizeStatus = (elementRef, { as = "number" } = {}) => {
|
|
|
22405
22759
|
};
|
|
22406
22760
|
};
|
|
22407
22761
|
|
|
22408
|
-
export { EASING, ELEMENT_SIZE_CHANGE, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, applyNewPosition, canScroll, captureScrollState, chainEvent, claimWheelGesture, clickIsSuppressed, closestOpenableAncestor, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createInternalCustomEvent, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterIntent, dragSourceThatStoodDown, 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, getScrollIntoViewScopedOffsets, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVirtualKeyboardOverlayHeight, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, installPanZoom, isAncestorOpen, isDisplayedDespiteClosedAncestor, isPressDisputedByDrag, isPressDrivenClick, isPrimaryButtonEvent, isSameColor, isScrollable, isTouchDrivenEvent, keepTouchRefusable, markDragSource, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, observeAncestorOpenState, onAncestorReopen, parsePositionArea, parseStyle, performTabNavigation, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, refuseDragTo, releaseWheelGesture, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewThroughScrollables, scrollIntoViewWithStickyAwareness, scrollRoomTowards, setAttribute, setAttributes, setPlacementViewportInsets, setStyles, setVirtualKeyboardOverlaysContent, snapToPixel, startDragTo, startDragToResizeGesture, startDragToTravel, stickyAsRelativeCoords, stringifyStyle, subscribeVirtualKeyboardGeometryChange, subscribeVisualViewportResizeSettled, subscribeWindowResizeSettled, suppressClickAfterGesture, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect, waitForPressHeld, waitForTap, watchWheelTravel, wheelGestureIsTakenFrom };
|
|
22762
|
+
export { EASING, ELEMENT_SIZE_CHANGE, activeElementSignal, addActiveElementEffect, addAttributeEffect, allowWheelThrough, appendStyles, applyNewPosition, canScroll, captureScrollState, chainEvent, claimWheelGesture, clickIsSuppressed, closestOpenableAncestor, contrastColor, createBackgroundColorTransition, createBackgroundTransition, createBorderRadiusTransition, createBorderTransition, createDragGestureController, createDragToMoveGestureController, createEventGroupLogger, createGroupTransitionController, createHeightTransition, createInternalCustomEvent, createIterableWeakSet, createOpacityTransition, createPubSub, createStyleController, createTimelineTransition, createTransition, createTranslateXTransition, createValueEffect, createWidthTransition, cubicBezier, dispatchCustomEvent, dispatchInternalCustomEvent, dispatchPublicCustomEvent, dragAfterIntent, dragSourceThatStoodDown, 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, getScrollIntoViewScopedOffsets, getScrollRelativeRect, getSelfAndAncestorScrolls, getStyle, getTranslateX, getTranslateXWithoutTransition, getTranslateY, getVirtualKeyboardOverlayHeight, getVisuallyVisibleInfo, getWidth, getWidthWithoutTransition, hasCSSSizeUnit, initFlexDetailsSet, initFocusGroup, initPositionSticky, installPanZoom, isAncestorOpen, isDisplayedDespiteClosedAncestor, isPressDisputedByDrag, isPressDrivenClick, isPrimaryButtonEvent, isSameColor, isScrollable, isTouchDrivenEvent, keepTouchRefusable, markDragSource, measureLongestVisualLineWidth, measureScrollbar, measureWidestChildRow, mergeOneStyle, mergeTwoStyles, normalizeKeyboardKey, normalizeStyle, normalizeStyles, observeAncestorOpenState, onAncestorReopen, overflowGoesToViewport, parsePositionArea, parseStyle, performTabNavigation, pickPositionRelativeTo, prefersDarkColors, prefersLightColors, preventFocusNav, preventFocusNavViaKeyboard, preventIntermediateScrollbar, refuseDragTo, releaseWheelGesture, resolveCSSColor, resolveCSSSize, resolveColorLuminance, resolveOklchLightness, scrollIntoViewScoped, scrollIntoViewThroughScrollables, scrollIntoViewWithStickyAwareness, scrollRoomTowards, setAttribute, setAttributes, setPlacementViewportInsets, setStyles, setVirtualKeyboardOverlaysContent, snapToPixel, startDragTo, startDragToResizeGesture, startDragToTravel, stickyAsRelativeCoords, stringifyStyle, subscribeVirtualKeyboardGeometryChange, subscribeVisualViewportResizeSettled, subscribeWindowResizeSettled, suppressClickAfterGesture, trapFocusInside, trapScrollInside, useActiveElement, useAvailableHeight, useAvailableWidth, useMaxHeight, useMaxWidth, useResizeStatus, visibleRectEffect, waitForPressHeld, waitForTap, watchWheelTravel, wheelGestureIsTakenFrom };
|