@jsenv/dom 0.17.71 → 0.17.73
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 +213 -144
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -8891,6 +8891,7 @@ const captureHolderByPointerId = new Map();
|
|
|
8891
8891
|
* `[data-droppable]` places) goes inert, a backdrop unifies the cursor and takes
|
|
8892
8892
|
* the pointer events, the focus moves to what is held and comes back at the
|
|
8893
8893
|
* release, and the selection is refused for the length of the gesture.
|
|
8894
|
+
* `documentInteractions` and `selection` each hand their part back to the caller.
|
|
8894
8895
|
*
|
|
8895
8896
|
* Whether the element may be grabbed AT ALL is decided before the finger lands
|
|
8896
8897
|
* and elsewhere: see `markDragSource` in drag_after_intent.js for the
|
|
@@ -8914,15 +8915,25 @@ const captureHolderByPointerId = new Map();
|
|
|
8914
8915
|
* @param {"auto"|"manual"} [options.documentInteractions="auto"]
|
|
8915
8916
|
* `"manual"` leaves the document alone — no inertness, no backdrop, no focus taken. For a
|
|
8916
8917
|
* gesture that only measures and hands over (see `dragAfterIntent`).
|
|
8918
|
+
* @param {"auto"|"manual"} [options.selection="auto"]
|
|
8919
|
+
* `"auto"` refuses the selection from the grab to the release, a press that may
|
|
8920
|
+
* become a drag not being a press that starts a selection. `"manual"` leaves it
|
|
8921
|
+
* alone — nothing refused, nothing collapsed, double and triple clicks the
|
|
8922
|
+
* browser's — for a gesture where a press on text is still a selection until it
|
|
8923
|
+
* has become something else, and says so itself once it has (a travel, see
|
|
8924
|
+
* drag_to_travel.js).
|
|
8917
8925
|
* @param {boolean} [options.backdrop=true]
|
|
8918
8926
|
* @param {number} [options.backdropZIndex=999999]
|
|
8919
8927
|
* @returns {{grab: function, grabViaPointer: function}}
|
|
8920
|
-
* `grabViaPointer(pointerdownEvent, { element, direction, cursor, scrollContainer
|
|
8921
|
-
* gesture a hand starts
|
|
8922
|
-
*
|
|
8923
|
-
*
|
|
8924
|
-
*
|
|
8925
|
-
*
|
|
8928
|
+
* `grabViaPointer(pointerdownEvent, { element, direction, cursor, scrollContainer,
|
|
8929
|
+
* pointerCaptureElement })` for a gesture a hand starts — `pointerCaptureElement` (the
|
|
8930
|
+
* pressed target by default) must outlive whatever the gesture re-renders, or the capture
|
|
8931
|
+
* is lost and the gesture ends cancelled; `grab({ element, grabX, grabY })` for one nothing
|
|
8932
|
+
* pressed. Both give back the gesture — `gestureInfo` (its `layout` with `xDelta`/`yDelta`,
|
|
8933
|
+
* its velocity, the way it is going), `drag`, `release`, and
|
|
8934
|
+
* `addDragCallback`/`addReleaseCallback` for whoever joins after it started.
|
|
8935
|
+
* `grabViaPointer` gives back `null` when the press is not one it can read: a secondary
|
|
8936
|
+
* button, a text node, an element that has left the document since the press.
|
|
8926
8937
|
*/
|
|
8927
8938
|
const createDragGestureController = (options = {}) => {
|
|
8928
8939
|
const {
|
|
@@ -8934,6 +8945,7 @@ const createDragGestureController = (options = {}) => {
|
|
|
8934
8945
|
threshold = 5,
|
|
8935
8946
|
direction: defaultDirection = { x: true, y: true },
|
|
8936
8947
|
documentInteractions = "auto",
|
|
8948
|
+
selection = "auto",
|
|
8937
8949
|
backdrop = true,
|
|
8938
8950
|
backdropZIndex = 999999,
|
|
8939
8951
|
} = options;
|
|
@@ -9456,96 +9468,101 @@ const createDragGestureController = (options = {}) => {
|
|
|
9456
9468
|
};
|
|
9457
9469
|
dragGesture.dragViaPointer = dragViaPointer;
|
|
9458
9470
|
dragGesture.releaseViaPointer = releaseViaPointer;
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
* own gesture — the words under the finger turn blue while the element
|
|
9463
|
-
* travels, and the selection outlives the release.
|
|
9464
|
-
*
|
|
9465
|
-
* Refused from the grab, before any threshold: whether the press becomes a
|
|
9466
|
-
* drag is decided a few pixels later, but the selection is decided at the
|
|
9467
|
-
* FIRST move, and by then it is too late to say no.
|
|
9468
|
-
*
|
|
9469
|
-
* `user-select: none` would say it in CSS, but it would say it to
|
|
9470
|
-
* everybody: the element would stop being selectable even when nobody is
|
|
9471
|
-
* dragging it. Here it is refused for the length of one gesture.
|
|
9472
|
-
*/
|
|
9473
|
-
const preventSelectStart = (selectStartEvent) => {
|
|
9474
|
-
selectStartEvent.preventDefault();
|
|
9475
|
-
};
|
|
9476
|
-
document.addEventListener("selectstart", preventSelectStart);
|
|
9477
|
-
// A press also puts an end to the selection the page was already holding,
|
|
9478
|
-
// the way the browser's own press does: refusing selectstart keeps a new
|
|
9479
|
-
// selection from being made, it says nothing about the one painted before
|
|
9480
|
-
// — which would otherwise sit there through a gesture that has nothing to
|
|
9481
|
-
// do with it.
|
|
9482
|
-
collapseSelection();
|
|
9483
|
-
dragGesture.addReleaseCallback(() => {
|
|
9484
|
-
document.removeEventListener("selectstart", preventSelectStart);
|
|
9485
|
-
});
|
|
9486
|
-
/*
|
|
9487
|
-
* Refusing every selection also refuses the ones a press is entitled to
|
|
9488
|
-
* make: a double click selects the word under it, a triple click the
|
|
9489
|
-
* paragraph around it, and both are over before the pointer has gone
|
|
9490
|
-
* anywhere. They are made here instead, spelled out (see
|
|
9491
|
-
* selectWordAtPoint, selectParagraphAtPoint) rather than left to a browser
|
|
9492
|
-
* heuristic that cannot tell a drag from a click.
|
|
9493
|
-
*
|
|
9494
|
-
* Read from `click` rather than `dblclick`, because a triple click has no
|
|
9495
|
-
* event of its own: what tells the clicks apart is `detail`, the count the
|
|
9496
|
-
* browser keeps of how many presses landed in the same place in a row — 2
|
|
9497
|
-
* for a word, 3 and beyond for a paragraph (a fourth click keeps the
|
|
9498
|
-
* paragraph, the way the browser does).
|
|
9499
|
-
*
|
|
9500
|
-
* On the document and outliving the gesture, because the gesture is
|
|
9501
|
-
* already over when the second click completes: click comes after mouseup,
|
|
9502
|
-
* the gesture ends at pointerup. Kept installed after it fires, since the
|
|
9503
|
-
* click that selects a word is also the one the next click turns into a
|
|
9504
|
-
* paragraph; it goes when the next press installs its own — a listener
|
|
9505
|
-
* waiting for a click that never comes costs nothing until then.
|
|
9506
|
-
*/
|
|
9507
|
-
removePendingMultiClickListener();
|
|
9508
|
-
const onClick = (clickEvent) => {
|
|
9509
|
-
const clickCount = clickEvent.detail;
|
|
9510
|
-
if (clickCount < 2) {
|
|
9511
|
-
return;
|
|
9512
|
-
}
|
|
9513
|
-
// A drag that happened is a gesture, not a click: the second press of a
|
|
9514
|
-
// double click can be the one that drags, and what it drags must not end
|
|
9515
|
-
// up selected too.
|
|
9516
|
-
if (dragGesture.gestureInfo.started) {
|
|
9517
|
-
return;
|
|
9518
|
-
}
|
|
9519
|
-
// Only the clicks that continue THIS press: the listener outlives the
|
|
9520
|
-
// gesture and the page keeps being clicked elsewhere, where the browser
|
|
9521
|
-
// is doing its own selecting — a second opinion there would only fight
|
|
9522
|
-
// it.
|
|
9523
|
-
const clickTarget = clickEvent.target;
|
|
9524
|
-
if (
|
|
9525
|
-
clickTarget !== grabEvent.target &&
|
|
9526
|
-
!clickTarget.contains(grabEvent.target)
|
|
9527
|
-
) {
|
|
9528
|
-
return;
|
|
9471
|
+
refuse_selection: {
|
|
9472
|
+
if (selection === "manual") {
|
|
9473
|
+
break refuse_selection;
|
|
9529
9474
|
}
|
|
9530
|
-
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
|
|
9544
|
-
|
|
9545
|
-
|
|
9546
|
-
|
|
9547
|
-
document.
|
|
9548
|
-
|
|
9475
|
+
/*
|
|
9476
|
+
* A press that starts a drag is not a press that starts a selection: the
|
|
9477
|
+
* browser sees a pointer going down on text and moving, and that is its
|
|
9478
|
+
* own gesture — the words under the finger turn blue while the element
|
|
9479
|
+
* travels, and the selection outlives the release.
|
|
9480
|
+
*
|
|
9481
|
+
* Refused from the grab, before any threshold: whether the press becomes a
|
|
9482
|
+
* drag is decided a few pixels later, but the selection is decided at the
|
|
9483
|
+
* FIRST move, and by then it is too late to say no.
|
|
9484
|
+
*
|
|
9485
|
+
* `user-select: none` would say it in CSS, but it would say it to
|
|
9486
|
+
* everybody: the element would stop being selectable even when nobody is
|
|
9487
|
+
* dragging it. Here it is refused for the length of one gesture.
|
|
9488
|
+
*/
|
|
9489
|
+
const preventSelectStart = (selectStartEvent) => {
|
|
9490
|
+
selectStartEvent.preventDefault();
|
|
9491
|
+
};
|
|
9492
|
+
document.addEventListener("selectstart", preventSelectStart);
|
|
9493
|
+
// A press also puts an end to the selection the page was already holding,
|
|
9494
|
+
// the way the browser's own press does: refusing selectstart keeps a new
|
|
9495
|
+
// selection from being made, it says nothing about the one painted before
|
|
9496
|
+
// — which would otherwise sit there through a gesture that has nothing to
|
|
9497
|
+
// do with it.
|
|
9498
|
+
collapseSelection();
|
|
9499
|
+
dragGesture.addReleaseCallback(() => {
|
|
9500
|
+
document.removeEventListener("selectstart", preventSelectStart);
|
|
9501
|
+
});
|
|
9502
|
+
/*
|
|
9503
|
+
* Refusing every selection also refuses the ones a press is entitled to
|
|
9504
|
+
* make: a double click selects the word under it, a triple click the
|
|
9505
|
+
* paragraph around it, and both are over before the pointer has gone
|
|
9506
|
+
* anywhere. They are made here instead, spelled out (see
|
|
9507
|
+
* selectWordAtPoint, selectParagraphAtPoint) rather than left to a browser
|
|
9508
|
+
* heuristic that cannot tell a drag from a click.
|
|
9509
|
+
*
|
|
9510
|
+
* Read from `click` rather than `dblclick`, because a triple click has no
|
|
9511
|
+
* event of its own: what tells the clicks apart is `detail`, the count the
|
|
9512
|
+
* browser keeps of how many presses landed in the same place in a row — 2
|
|
9513
|
+
* for a word, 3 and beyond for a paragraph (a fourth click keeps the
|
|
9514
|
+
* paragraph, the way the browser does).
|
|
9515
|
+
*
|
|
9516
|
+
* On the document and outliving the gesture, because the gesture is
|
|
9517
|
+
* already over when the second click completes: click comes after mouseup,
|
|
9518
|
+
* the gesture ends at pointerup. Kept installed after it fires, since the
|
|
9519
|
+
* click that selects a word is also the one the next click turns into a
|
|
9520
|
+
* paragraph; it goes when the next press installs its own — a listener
|
|
9521
|
+
* waiting for a click that never comes costs nothing until then.
|
|
9522
|
+
*/
|
|
9523
|
+
removePendingMultiClickListener();
|
|
9524
|
+
const onClick = (clickEvent) => {
|
|
9525
|
+
const clickCount = clickEvent.detail;
|
|
9526
|
+
if (clickCount < 2) {
|
|
9527
|
+
return;
|
|
9528
|
+
}
|
|
9529
|
+
// A drag that happened is a gesture, not a click: the second press of a
|
|
9530
|
+
// double click can be the one that drags, and what it drags must not end
|
|
9531
|
+
// up selected too.
|
|
9532
|
+
if (dragGesture.gestureInfo.started) {
|
|
9533
|
+
return;
|
|
9534
|
+
}
|
|
9535
|
+
// Only the clicks that continue THIS press: the listener outlives the
|
|
9536
|
+
// gesture and the page keeps being clicked elsewhere, where the browser
|
|
9537
|
+
// is doing its own selecting — a second opinion there would only fight
|
|
9538
|
+
// it.
|
|
9539
|
+
const clickTarget = clickEvent.target;
|
|
9540
|
+
if (
|
|
9541
|
+
clickTarget !== grabEvent.target &&
|
|
9542
|
+
!clickTarget.contains(grabEvent.target)
|
|
9543
|
+
) {
|
|
9544
|
+
return;
|
|
9545
|
+
}
|
|
9546
|
+
// Text the page says is not selectable stays not selectable: a
|
|
9547
|
+
// programmatic selection goes through `user-select: none` in every
|
|
9548
|
+
// engine — it is a rule about what the USER may start, and the browser
|
|
9549
|
+
// does not read it back when asked directly. Read here so that doing the
|
|
9550
|
+
// browser's work does not also undo what the page asked of it.
|
|
9551
|
+
if (!isSelectable(clickEvent.target)) {
|
|
9552
|
+
return;
|
|
9553
|
+
}
|
|
9554
|
+
if (clickCount === 2) {
|
|
9555
|
+
selectWordAtPoint(clickEvent.clientX, clickEvent.clientY);
|
|
9556
|
+
return;
|
|
9557
|
+
}
|
|
9558
|
+
selectParagraphAtPoint(clickEvent.clientX, clickEvent.clientY);
|
|
9559
|
+
};
|
|
9560
|
+
document.addEventListener("click", onClick);
|
|
9561
|
+
removePendingMultiClickListener = () => {
|
|
9562
|
+
removePendingMultiClickListener = NOOP;
|
|
9563
|
+
document.removeEventListener("click", onClick);
|
|
9564
|
+
};
|
|
9565
|
+
}
|
|
9549
9566
|
const cleanup = initializer({
|
|
9550
9567
|
onMove: dragViaPointer,
|
|
9551
9568
|
onRelease: releaseViaPointer,
|
|
@@ -10107,6 +10124,13 @@ const dragSourceThatStoodDown = (pressEvent) => {
|
|
|
10107
10124
|
* The pointer moved or lifted before the wait was over.
|
|
10108
10125
|
* @param {function} [options.onPress]
|
|
10109
10126
|
* The wait completed and the object is now held (haptics, scale…).
|
|
10127
|
+
* @param {"auto"|"manual"} [options.selection="auto"]
|
|
10128
|
+
* Whether the selection is refused while the press travels towards the
|
|
10129
|
+
* distance: a press on a source belongs to the drag, so what its first pixels
|
|
10130
|
+
* would select is refused before the drag is sure (see `selection` in
|
|
10131
|
+
* drag_gesture.js). `"manual"` leaves the press to the browser until the
|
|
10132
|
+
* caller's own gesture says otherwise. A long press waits without refusing
|
|
10133
|
+
* anything either way (see the stylesheet above).
|
|
10110
10134
|
*/
|
|
10111
10135
|
const dragAfterIntent = (
|
|
10112
10136
|
grabEvent,
|
|
@@ -10119,6 +10143,7 @@ const dragAfterIntent = (
|
|
|
10119
10143
|
onPressStart,
|
|
10120
10144
|
onPressCancel,
|
|
10121
10145
|
onPress,
|
|
10146
|
+
selection = "auto",
|
|
10122
10147
|
} = {},
|
|
10123
10148
|
) => {
|
|
10124
10149
|
if (!isPrimaryButtonEvent(grabEvent)) {
|
|
@@ -10148,7 +10173,7 @@ const dragAfterIntent = (
|
|
|
10148
10173
|
});
|
|
10149
10174
|
return;
|
|
10150
10175
|
}
|
|
10151
|
-
dragAfterDistance(grabEvent, dragGestureInitializer, threshold);
|
|
10176
|
+
dragAfterDistance(grabEvent, dragGestureInitializer, threshold, selection);
|
|
10152
10177
|
};
|
|
10153
10178
|
|
|
10154
10179
|
const startDragGesture = (dragGestureInitializer, catchUpEvent) => {
|
|
@@ -10165,13 +10190,19 @@ const startDragGesture = (dragGestureInitializer, catchUpEvent) => {
|
|
|
10165
10190
|
return dragGesture;
|
|
10166
10191
|
};
|
|
10167
10192
|
|
|
10168
|
-
const dragAfterDistance = (
|
|
10193
|
+
const dragAfterDistance = (
|
|
10194
|
+
grabEvent,
|
|
10195
|
+
dragGestureInitializer,
|
|
10196
|
+
threshold,
|
|
10197
|
+
selection,
|
|
10198
|
+
) => {
|
|
10169
10199
|
const significantDragGestureController = createDragGestureController({
|
|
10170
10200
|
threshold,
|
|
10171
10201
|
// allow interaction for this intermediate gesture:
|
|
10172
10202
|
// user should still be able to scroll or interact with the document
|
|
10173
10203
|
// only once the gesture is significant we take control
|
|
10174
10204
|
documentInteractions: "manual",
|
|
10205
|
+
selection,
|
|
10175
10206
|
onDragStart: (gestureInfo) => {
|
|
10176
10207
|
significantDragGesture.release(); // kill that gesture
|
|
10177
10208
|
startDragGesture(dragGestureInitializer, gestureInfo.dragEvent);
|
|
@@ -11966,8 +11997,6 @@ const roundForConstraints = (value) => {
|
|
|
11966
11997
|
* @param {Object} gestureInfo - Gesture information
|
|
11967
11998
|
* @param {Element[]} targetElements - Array of potential drop target elements
|
|
11968
11999
|
* @param {object} [options]
|
|
11969
|
-
* @param {Element} [options.dragElement] - The element being dragged. When provided and
|
|
11970
|
-
* `fallbackToEdge` is true, used to compute the fallback rect.
|
|
11971
12000
|
* @param {boolean} [options.fallbackToEdge=false] - When true and the drag element does
|
|
11972
12001
|
* not intersect any target, falls back to the first item (if above all items) or the
|
|
11973
12002
|
* last item (if below all items) so there is always a valid drop target at list edges.
|
|
@@ -12248,6 +12277,10 @@ import.meta.css = /* css */ [`:root[data-drag-travel-gesture] {
|
|
|
12248
12277
|
overscroll-behavior: none;
|
|
12249
12278
|
}
|
|
12250
12279
|
|
|
12280
|
+
:root[data-drag-travel-walking] {
|
|
12281
|
+
user-select: none;
|
|
12282
|
+
}
|
|
12283
|
+
|
|
12251
12284
|
[data-drag-travel*="x"] {
|
|
12252
12285
|
overscroll-behavior-x: contain !important;
|
|
12253
12286
|
}
|
|
@@ -12782,8 +12815,11 @@ const startDragToTravel = (
|
|
|
12782
12815
|
// never come.
|
|
12783
12816
|
// Nothing is being carried: the page keeps its focus, its scrolling and its
|
|
12784
12817
|
// cursor while a screen slides under the finger. That is the whole
|
|
12785
|
-
// difference with a drag that moves an object
|
|
12818
|
+
// difference with a drag that moves an object.
|
|
12786
12819
|
documentInteractions: "manual",
|
|
12820
|
+
// And a press on text is a selection until it has become a travel, which
|
|
12821
|
+
// is where the selection is refused (see where WALKING_ATTRIBUTE is set).
|
|
12822
|
+
selection: "manual",
|
|
12787
12823
|
onDragStart: () => {
|
|
12788
12824
|
document.documentElement.setAttribute(GESTURE_ATTRIBUTE, "");
|
|
12789
12825
|
},
|
|
@@ -12884,6 +12920,9 @@ const startDragToTravel = (
|
|
|
12884
12920
|
pulled: started.slack || 0,
|
|
12885
12921
|
};
|
|
12886
12922
|
document.documentElement.setAttribute(WALKING_ATTRIBUTE, axis);
|
|
12923
|
+
// What the first pixels may have started selecting is not a selection:
|
|
12924
|
+
// it is the beginning of this travel.
|
|
12925
|
+
collapseSelection();
|
|
12887
12926
|
// The travel exists: from here the pointer is this box's, and it is
|
|
12888
12927
|
// followed wherever it goes.
|
|
12889
12928
|
dragGesture.capturePointer();
|
|
@@ -13007,6 +13046,7 @@ const startDragToTravel = (
|
|
|
13007
13046
|
dragAfterIntent(pointerDownEvent, grab, {
|
|
13008
13047
|
longPress: false,
|
|
13009
13048
|
threshold: DRAG_START_THRESHOLD,
|
|
13049
|
+
selection: "manual",
|
|
13010
13050
|
});
|
|
13011
13051
|
}
|
|
13012
13052
|
window.addEventListener("pointerup", onPressOver);
|
|
@@ -13430,7 +13470,11 @@ const findPanZoomSurface = (element) => {
|
|
|
13430
13470
|
* @param {Element} element
|
|
13431
13471
|
* @param {object} options
|
|
13432
13472
|
* @param {(detail: {event: PointerEvent, x: number, y: number}) => void} [options.onPan]
|
|
13433
|
-
* The hand moved: `x`/`y` are how far since the last report, in px.
|
|
13473
|
+
* The hand moved: `x`/`y` are how far since the last report, in px. Left out,
|
|
13474
|
+
* one pointer is not the surface's: it is heard only for the pinch a second
|
|
13475
|
+
* one would make with it, and otherwise left to whatever else reads it — no
|
|
13476
|
+
* capture, no hold waited for, no click swallowed, no grab. `afterHold` then
|
|
13477
|
+
* leaves its scroll to the page, and `"kept"` has no pan to keep.
|
|
13434
13478
|
* @param {(detail: {event: PointerEvent|WheelEvent, factor: number, x: number, y: number}) => void} [options.onZoom]
|
|
13435
13479
|
* The zoom changed by `factor` (above 1 is in) around the point `x`/`y` of the
|
|
13436
13480
|
* surface, measured inside its border. Left out, a wheel over the surface is
|
|
@@ -13553,9 +13597,10 @@ const installPanZoom = (
|
|
|
13553
13597
|
|
|
13554
13598
|
const activate = (anchorWhere, event) => {
|
|
13555
13599
|
active = true;
|
|
13556
|
-
if (afterHold === "kept" && holdIsOwed) {
|
|
13600
|
+
if (afterHold === "kept" && holdIsOwed && onPan) {
|
|
13557
13601
|
// Asked for and given: whatever proved it — the hold, a second finger, a
|
|
13558
|
-
// mouse travelling — the surface is the hand's from here.
|
|
13602
|
+
// mouse travelling — the surface is the hand's from here. What it keeps
|
|
13603
|
+
// is the pan on contact, which a surface that does not pan has none of.
|
|
13559
13604
|
keepTheHand();
|
|
13560
13605
|
}
|
|
13561
13606
|
for (const pointerId of pointers.keys()) {
|
|
@@ -13649,6 +13694,12 @@ const installPanZoom = (
|
|
|
13649
13694
|
activate("now", event);
|
|
13650
13695
|
return;
|
|
13651
13696
|
}
|
|
13697
|
+
if (!onPan) {
|
|
13698
|
+
// One pointer is the pan's to read. Without one it is only heard for the
|
|
13699
|
+
// pinch a second pointer would make with it: a tap, a hold or a double
|
|
13700
|
+
// click on it belongs to whatever else reads it.
|
|
13701
|
+
return;
|
|
13702
|
+
}
|
|
13652
13703
|
if (holdIsOwed && event.pointerType === "touch") {
|
|
13653
13704
|
pointer.waitsForHold = true;
|
|
13654
13705
|
pointer.holdWait = waitForPressHeld(event, {
|
|
@@ -13669,7 +13720,9 @@ const installPanZoom = (
|
|
|
13669
13720
|
pointer.x = event.clientX;
|
|
13670
13721
|
pointer.y = event.clientY;
|
|
13671
13722
|
if (!active) {
|
|
13672
|
-
|
|
13723
|
+
// No pan for the travel to start (see onPointerDown), or a finger whose
|
|
13724
|
+
// travel is the page scrolling.
|
|
13725
|
+
if (!onPan || pointer.waitsForHold) {
|
|
13673
13726
|
return;
|
|
13674
13727
|
}
|
|
13675
13728
|
const travelled = Math.hypot(
|
|
@@ -14529,10 +14582,12 @@ const createDragToMoveGestureController = ({
|
|
|
14529
14582
|
*
|
|
14530
14583
|
* @param {PointerEvent} event The `pointerdown` that may become a drag.
|
|
14531
14584
|
* @param {("move"|"reorder"|"toss"|"land"|"leave")[]} effects
|
|
14532
|
-
* What letting go of this element can mean
|
|
14533
|
-
*
|
|
14534
|
-
*
|
|
14535
|
-
*
|
|
14585
|
+
* What letting go of this element can mean, and only what is listed is ever
|
|
14586
|
+
* answered. `reorder`, `toss` and `land` carry a copy; `move` carries the
|
|
14587
|
+
* element itself, and `leave` goes with either. Asking for `move` beside any of
|
|
14588
|
+
* the three that carry a copy is asking one release to mean two things, and so
|
|
14589
|
+
* is asking for `reorder` and `land`. A gesture taken away mid-air
|
|
14590
|
+
* (`gestureInfo.cancelled`) means none of them, and what it carried goes back.
|
|
14536
14591
|
* @param {object} [options]
|
|
14537
14592
|
* @param {Element} [options.draggedElement=event.currentTarget]
|
|
14538
14593
|
* @param {(detail: {gestureInfo: object, x: number, y: number}) => void} [options.onMoving]
|
|
@@ -14552,8 +14607,8 @@ const createDragToMoveGestureController = ({
|
|
|
14552
14607
|
* a node rebuilt), and the element's own translate otherwise, baked in — see
|
|
14553
14608
|
* settleMovedElement.
|
|
14554
14609
|
* @param {(detail: {gestureInfo: object, x: number, y: number}) => Promise|void} [options.onLeave]
|
|
14555
|
-
* It was let go of away from every place:
|
|
14556
|
-
* from all of
|
|
14610
|
+
* It was let go of away from every place: beside `reorder` or `land`, away
|
|
14611
|
+
* from all of their places; otherwise, out of `outsideOf`. Beside `move` the element
|
|
14557
14612
|
* itself is left where the hand put it while this runs, and the answer says
|
|
14558
14613
|
* what becomes of that position — let go of on a resolve (the caller has
|
|
14559
14614
|
* removed the thing, or drawn it where it goes back to), travelled home on a
|
|
@@ -14588,7 +14643,7 @@ const createDragToMoveGestureController = ({
|
|
|
14588
14643
|
* if the promise rejects, because the thing still exists and the screen has to
|
|
14589
14644
|
* say so.
|
|
14590
14645
|
* @param {(detail: {fromId: string, toId: string, x: number, y: number, width: number, height: number, syncCloneWithDropTarget: Function}) => Promise|void} [options.onLand]
|
|
14591
|
-
* It came down on `toId
|
|
14646
|
+
* It came down on the element `toId` names, never null: nothing under the
|
|
14592
14647
|
* copy is a cancelled release. `x`/`y`/`width`/`height` say WHERE on it, which
|
|
14593
14648
|
* is the whole answer when the place is a surface — a plan, a map — with no
|
|
14594
14649
|
* element under the copy to name. The copy is held until what comes back
|
|
@@ -14651,6 +14706,7 @@ const startDragTo = (
|
|
|
14651
14706
|
}
|
|
14652
14707
|
return startDragToMoveElement(event, {
|
|
14653
14708
|
draggedElement,
|
|
14709
|
+
canMove,
|
|
14654
14710
|
canLeave,
|
|
14655
14711
|
...options,
|
|
14656
14712
|
});
|
|
@@ -14762,12 +14818,14 @@ const refuseDragTo = (
|
|
|
14762
14818
|
* go of away from it, when it can `leave`.
|
|
14763
14819
|
*
|
|
14764
14820
|
* No copy, unlike the others: what is being moved is the thing and not a
|
|
14765
|
-
* stand-in for it, so there is nothing to put back and nothing to reveal.
|
|
14821
|
+
* stand-in for it, so there is nothing to put back and nothing to reveal. What a
|
|
14822
|
+
* release means is read by resolveDropMeaning, as it is for a copy.
|
|
14766
14823
|
*/
|
|
14767
14824
|
const startDragToMoveElement = (
|
|
14768
14825
|
event,
|
|
14769
14826
|
{
|
|
14770
14827
|
draggedElement,
|
|
14828
|
+
canMove,
|
|
14771
14829
|
canLeave,
|
|
14772
14830
|
onMoving,
|
|
14773
14831
|
onMove,
|
|
@@ -14817,26 +14875,26 @@ const startDragToMoveElement = (
|
|
|
14817
14875
|
});
|
|
14818
14876
|
}
|
|
14819
14877
|
dragGesture.addReleaseCallback(async (gestureInfo) => {
|
|
14878
|
+
const dropMeans = resolveDropMeaning({
|
|
14879
|
+
gestureInfo,
|
|
14880
|
+
releasedOutside: canLeave && isOutsideOf(gestureInfo, outsideOf),
|
|
14881
|
+
canMove,
|
|
14882
|
+
canLeave,
|
|
14883
|
+
});
|
|
14820
14884
|
const { xDelta, yDelta } = gestureInfo.layout;
|
|
14821
|
-
if (!xDelta && !yDelta) {
|
|
14822
|
-
// Picked up and put back down: nothing moved, so no outcome is told.
|
|
14823
|
-
onRelease?.({ gestureInfo, x: xDelta, y: yDelta, outcome: null });
|
|
14824
|
-
gestureInfo.cancelPosition();
|
|
14825
|
-
return;
|
|
14826
|
-
}
|
|
14827
|
-
const leaving =
|
|
14828
|
-
canLeave &&
|
|
14829
|
-
!gestureInfo.cancelled &&
|
|
14830
|
-
isOutsideOf(gestureInfo, outsideOf);
|
|
14831
14885
|
onRelease?.({
|
|
14832
14886
|
gestureInfo,
|
|
14833
14887
|
x: xDelta,
|
|
14834
14888
|
y: yDelta,
|
|
14835
|
-
|
|
14836
|
-
// going: `onMoving` alone has already told all of it.
|
|
14837
|
-
outcome: leaving ? "leave" : onMove ? "move" : null,
|
|
14889
|
+
outcome: dropMeans === "cancel" ? null : dropMeans,
|
|
14838
14890
|
});
|
|
14839
|
-
if (
|
|
14891
|
+
if (dropMeans === "cancel") {
|
|
14892
|
+
// Nothing answers it: whatever the gesture translated goes home — and
|
|
14893
|
+
// there is nothing to take back when `onMoving` had the caller draw.
|
|
14894
|
+
gestureInfo.cancelPositionAnimated();
|
|
14895
|
+
return;
|
|
14896
|
+
}
|
|
14897
|
+
if (dropMeans === "leave") {
|
|
14840
14898
|
// Left where the hand let go of it while the answer is asked — a thing
|
|
14841
14899
|
// that snaps home with the request in flight says the gesture was not
|
|
14842
14900
|
// understood. The answer then says what becomes of that position: let
|
|
@@ -14930,10 +14988,14 @@ const readOwnLayout = (element) => ({
|
|
|
14930
14988
|
const TOSS_DISTANCE_TO_COMMIT = 110;
|
|
14931
14989
|
const TOSS_SPEED_TO_COMMIT = 0.45;
|
|
14932
14990
|
|
|
14991
|
+
// What a release means, whether it carried the element itself or a copy: one
|
|
14992
|
+
// reading, so a gesture taken away mid-air is nothing on both paths, and an
|
|
14993
|
+
// outcome is answered only when the caller listed it.
|
|
14933
14994
|
const resolveDropMeaning = ({
|
|
14934
14995
|
gestureInfo,
|
|
14935
14996
|
hasDropTarget,
|
|
14936
14997
|
releasedOutside,
|
|
14998
|
+
canMove,
|
|
14937
14999
|
canReorder,
|
|
14938
15000
|
canToss,
|
|
14939
15001
|
canLand,
|
|
@@ -14962,15 +15024,19 @@ const resolveDropMeaning = ({
|
|
|
14962
15024
|
return "reorder";
|
|
14963
15025
|
}
|
|
14964
15026
|
}
|
|
15027
|
+
// It has to have gone somewhere to be put anywhere, or away from anything:
|
|
15028
|
+
// picked up and put straight back down is a hand that changed its mind.
|
|
15029
|
+
const { xDelta, yDelta } = gestureInfo.layout;
|
|
15030
|
+
if (!xDelta && !yDelta) {
|
|
15031
|
+
return "cancel";
|
|
15032
|
+
}
|
|
14965
15033
|
if (canLeave && releasedOutside) {
|
|
14966
15034
|
// Let go of away from every place — off the plan and down, deliberate and
|
|
14967
|
-
// never a flick.
|
|
14968
|
-
|
|
14969
|
-
|
|
14970
|
-
|
|
14971
|
-
|
|
14972
|
-
return "leave";
|
|
14973
|
-
}
|
|
15035
|
+
// never a flick.
|
|
15036
|
+
return "leave";
|
|
15037
|
+
}
|
|
15038
|
+
if (canMove) {
|
|
15039
|
+
return "move";
|
|
14974
15040
|
}
|
|
14975
15041
|
return "cancel";
|
|
14976
15042
|
};
|
|
@@ -15428,20 +15494,24 @@ const getRectInside = (element, containerElement) => {
|
|
|
15428
15494
|
};
|
|
15429
15495
|
};
|
|
15430
15496
|
|
|
15431
|
-
// Creates the two-layer clone structure
|
|
15497
|
+
// Creates the two-layer clone structure carried by reorder, land, toss and leave.
|
|
15432
15498
|
//
|
|
15433
15499
|
// Layer 1 — wrapper (navi-drag-clone-wrapper):
|
|
15434
|
-
// Positioned
|
|
15435
|
-
//
|
|
15436
|
-
//
|
|
15500
|
+
// Positioned fixed via the --clone-* CSS vars, which also give it its size.
|
|
15501
|
+
// Moved every drag frame via dragStyleController.
|
|
15502
|
+
// It paints nothing, so it takes no view-transition-name: a name on it would
|
|
15503
|
+
// be a group with an empty image, and one more name to keep unique.
|
|
15437
15504
|
//
|
|
15438
15505
|
// Layer 2 — inner clone (navi-drag-clone):
|
|
15439
|
-
// A deep clone of the grabbed element
|
|
15440
|
-
//
|
|
15441
|
-
//
|
|
15442
|
-
//
|
|
15506
|
+
// A deep clone of the grabbed element, and what the eye follows — so it is
|
|
15507
|
+
// the one named (view-transition-name: navi-drag-clone).
|
|
15508
|
+
// Casts the shadow and applies transform: scale(var(--drag-clone-scale, 1.03))
|
|
15509
|
+
// via the CSS rule for [navi-drag-clone], giving the "lifted" feel. The
|
|
15510
|
+
// transform-origin is set to the grab point so the element expands naturally
|
|
15511
|
+
// from where the user clicked.
|
|
15443
15512
|
// On release, the `navi-drag-clone` attribute is removed inside
|
|
15444
|
-
// startViewTransition to drop the scale back to 1 as the "new" state
|
|
15513
|
+
// startViewTransition to drop the scale back to 1 as the "new" state; the
|
|
15514
|
+
// name stays, so the scale is morphed with the box rather than cross-faded.
|
|
15445
15515
|
|
|
15446
15516
|
// The chevron is the one the table's column drop preview uses, rotated by the
|
|
15447
15517
|
// CSS above so each cap points into the line.
|
|
@@ -15699,10 +15769,9 @@ const createDragClone = (element, pointerEvent) => {
|
|
|
15699
15769
|
// Manual: it is opened and closed with the drag, and must survive an Escape
|
|
15700
15770
|
// or a click elsewhere (light dismiss would take it away mid-gesture).
|
|
15701
15771
|
wrapper.setAttribute("popover", "manual");
|
|
15702
|
-
wrapper.viewTransitionName = "navi-drag-clone-wrapper";
|
|
15703
15772
|
setCloneViewportRect(wrapper, element);
|
|
15704
15773
|
// Grab point within the element — used as transform-origin so the
|
|
15705
|
-
// scale
|
|
15774
|
+
// scale expands from where the user clicked, not the element center.
|
|
15706
15775
|
// These offsets are element-relative so viewport coords are correct here.
|
|
15707
15776
|
wrapper.style.setProperty(
|
|
15708
15777
|
"--drag-origin",
|