@jsenv/dom 0.17.81 → 0.17.82
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 +209 -19
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -10183,6 +10183,10 @@ const dragSourceThatStoodDown = (pressEvent) => {
|
|
|
10183
10183
|
* drag_gesture.js). `"manual"` leaves the press to the browser until the
|
|
10184
10184
|
* caller's own gesture says otherwise. A long press waits without refusing
|
|
10185
10185
|
* anything either way (see the stylesheet above).
|
|
10186
|
+
* @param {boolean} [options.handedOver=false]
|
|
10187
|
+
* The press was held on something else, which handed it to this drag (see
|
|
10188
|
+
* `handedOver` in drag_to.js): the hold that did so established the intent,
|
|
10189
|
+
* so the gesture starts at once, as it does from a dedicated handle.
|
|
10186
10190
|
*/
|
|
10187
10191
|
const dragAfterIntent = (
|
|
10188
10192
|
grabEvent,
|
|
@@ -10196,6 +10200,7 @@ const dragAfterIntent = (
|
|
|
10196
10200
|
onPressCancel,
|
|
10197
10201
|
onPress,
|
|
10198
10202
|
selection = "auto",
|
|
10203
|
+
handedOver = false,
|
|
10199
10204
|
} = {},
|
|
10200
10205
|
) => {
|
|
10201
10206
|
if (!isPrimaryButtonEvent(grabEvent)) {
|
|
@@ -10204,7 +10209,7 @@ const dragAfterIntent = (
|
|
|
10204
10209
|
const target = grabEvent.target;
|
|
10205
10210
|
const isDedicatedHandle =
|
|
10206
10211
|
target.closest && target.closest("[data-drag-handle]");
|
|
10207
|
-
if (isDedicatedHandle) {
|
|
10212
|
+
if (isDedicatedHandle || handedOver) {
|
|
10208
10213
|
startDragGesture(dragGestureInitializer);
|
|
10209
10214
|
return;
|
|
10210
10215
|
}
|
|
@@ -10836,6 +10841,82 @@ const getDragCoordinates = (
|
|
|
10836
10841
|
return [leftRelativeToScrollContainer, topRelativeToScrollContainer];
|
|
10837
10842
|
};
|
|
10838
10843
|
|
|
10844
|
+
/**
|
|
10845
|
+
* Which presses are still down, and where each one is now.
|
|
10846
|
+
*
|
|
10847
|
+
* A press is read by whoever it landed on, from its `pointerdown` to its
|
|
10848
|
+
* `pointerup`. Some are handed over halfway: a hold opens a popup, and
|
|
10849
|
+
* something inside it takes the press the finger is still making (see
|
|
10850
|
+
* `handedOver` in drag_to.js). Whoever receives it was not listening when it
|
|
10851
|
+
* began, so it cannot know whether the pointer has let go since, nor where it
|
|
10852
|
+
* is now — the `pointerdown` it is handed says where the finger WAS. Listened
|
|
10853
|
+
* for from the start instead, on the window in capture so that nothing lower
|
|
10854
|
+
* can hide a press from it.
|
|
10855
|
+
*
|
|
10856
|
+
* Keyed by the `pointerdown` itself and not by the pointer: the same finger
|
|
10857
|
+
* lifted and put down again is another press, and a press handed over late
|
|
10858
|
+
* must not be answered by the next one.
|
|
10859
|
+
*/
|
|
10860
|
+
|
|
10861
|
+
const pressDownByPointerId = new Map();
|
|
10862
|
+
|
|
10863
|
+
/**
|
|
10864
|
+
* Where the pointer of `pressEvent` is now, while that press is still down.
|
|
10865
|
+
*
|
|
10866
|
+
* @param {PointerEvent} pressEvent A `pointerdown`.
|
|
10867
|
+
* @returns {{ clientX: number, clientY: number } | null} `null` once that press
|
|
10868
|
+
* has ended — let go of, or cancelled by the browser.
|
|
10869
|
+
*/
|
|
10870
|
+
const readPressDown = (pressEvent) => {
|
|
10871
|
+
const pressDown = pressDownByPointerId.get(pressEvent.pointerId);
|
|
10872
|
+
if (!pressDown || pressDown.pressEvent !== pressEvent) {
|
|
10873
|
+
return null;
|
|
10874
|
+
}
|
|
10875
|
+
return { clientX: pressDown.clientX, clientY: pressDown.clientY };
|
|
10876
|
+
};
|
|
10877
|
+
|
|
10878
|
+
const onPointerMove = (pointerMoveEvent) => {
|
|
10879
|
+
const pressDown = pressDownByPointerId.get(pointerMoveEvent.pointerId);
|
|
10880
|
+
if (!pressDown) {
|
|
10881
|
+
return;
|
|
10882
|
+
}
|
|
10883
|
+
pressDown.clientX = pointerMoveEvent.clientX;
|
|
10884
|
+
pressDown.clientY = pointerMoveEvent.clientY;
|
|
10885
|
+
};
|
|
10886
|
+
const onPointerEnd = (pointerEndEvent) => {
|
|
10887
|
+
pressDownByPointerId.delete(pointerEndEvent.pointerId);
|
|
10888
|
+
if (pressDownByPointerId.size === 0) {
|
|
10889
|
+
// A mouse moves all the time without being pressed: nothing is read from
|
|
10890
|
+
// it between presses.
|
|
10891
|
+
window.removeEventListener("pointermove", onPointerMove, true);
|
|
10892
|
+
}
|
|
10893
|
+
};
|
|
10894
|
+
window.addEventListener(
|
|
10895
|
+
"pointerdown",
|
|
10896
|
+
(pointerDownEvent) => {
|
|
10897
|
+
if (pressDownByPointerId.size === 0) {
|
|
10898
|
+
window.addEventListener("pointermove", onPointerMove, {
|
|
10899
|
+
capture: true,
|
|
10900
|
+
passive: true,
|
|
10901
|
+
});
|
|
10902
|
+
}
|
|
10903
|
+
pressDownByPointerId.set(pointerDownEvent.pointerId, {
|
|
10904
|
+
pressEvent: pointerDownEvent,
|
|
10905
|
+
clientX: pointerDownEvent.clientX,
|
|
10906
|
+
clientY: pointerDownEvent.clientY,
|
|
10907
|
+
});
|
|
10908
|
+
},
|
|
10909
|
+
{ capture: true, passive: true },
|
|
10910
|
+
);
|
|
10911
|
+
window.addEventListener("pointerup", onPointerEnd, {
|
|
10912
|
+
capture: true,
|
|
10913
|
+
passive: true,
|
|
10914
|
+
});
|
|
10915
|
+
window.addEventListener("pointercancel", onPointerEnd, {
|
|
10916
|
+
capture: true,
|
|
10917
|
+
passive: true,
|
|
10918
|
+
});
|
|
10919
|
+
|
|
10839
10920
|
installImportMetaCssBuild(import.meta);
|
|
10840
10921
|
|
|
10841
10922
|
const css$4 = /* css */ `.navi_constraint_feedback_line {
|
|
@@ -14324,6 +14405,16 @@ const css$1 = /* css */ `.navi_drop_hint {
|
|
|
14324
14405
|
opacity: 0;
|
|
14325
14406
|
}
|
|
14326
14407
|
|
|
14408
|
+
[navi-drag-clone-wrapper][data-reaching] {
|
|
14409
|
+
transition: translate .2s ease-out;
|
|
14410
|
+
}
|
|
14411
|
+
|
|
14412
|
+
@starting-style {
|
|
14413
|
+
[navi-drag-clone-wrapper][data-reaching] {
|
|
14414
|
+
translate: var(--clone-reach-from);
|
|
14415
|
+
}
|
|
14416
|
+
}
|
|
14417
|
+
|
|
14327
14418
|
[navi-drag-clone] {
|
|
14328
14419
|
box-shadow: var(--drag-clone-shadow, 0 12px 28px #00000038);
|
|
14329
14420
|
transform: scale(var(--drag-clone-scale, 1.03));
|
|
@@ -14740,6 +14831,11 @@ const createDragToMoveGestureController = ({
|
|
|
14740
14831
|
element,
|
|
14741
14832
|
referenceElement,
|
|
14742
14833
|
elementToMove,
|
|
14834
|
+
// How far from `element` what moves starts, when it does not start over it
|
|
14835
|
+
// (a copy brought to a hand that pressed elsewhere, see handedOver). The
|
|
14836
|
+
// layout is then the box the hand holds, so constraints and auto-scroll
|
|
14837
|
+
// read what is seen; the translate is unaffected, it counts from the grab.
|
|
14838
|
+
grabOffset,
|
|
14743
14839
|
event,
|
|
14744
14840
|
...rest
|
|
14745
14841
|
} = {}) => {
|
|
@@ -14752,8 +14848,12 @@ const createDragToMoveGestureController = ({
|
|
|
14752
14848
|
const dragGesture = grab({
|
|
14753
14849
|
element,
|
|
14754
14850
|
scrollContainer,
|
|
14755
|
-
layoutScrollableLeft:
|
|
14756
|
-
|
|
14851
|
+
layoutScrollableLeft: grabOffset
|
|
14852
|
+
? elementScrollableLeft + grabOffset.x
|
|
14853
|
+
: elementScrollableLeft,
|
|
14854
|
+
layoutScrollableTop: grabOffset
|
|
14855
|
+
? elementScrollableTop + grabOffset.y
|
|
14856
|
+
: elementScrollableTop,
|
|
14757
14857
|
event,
|
|
14758
14858
|
...rest,
|
|
14759
14859
|
});
|
|
@@ -14847,6 +14947,23 @@ const createDragToMoveGestureController = ({
|
|
|
14847
14947
|
* for: one without the other is moving the thing while hesitating, and nothing is
|
|
14848
14948
|
* thrown away on a hesitation. A throw is judged before any landing; a release
|
|
14849
14949
|
* with no place under it is `leave`'s, not a toss — there is no speed to it.
|
|
14950
|
+
* @param {boolean} [options.handedOver=false]
|
|
14951
|
+
* `event` is a press held on something ELSE, handed to this element: a hold
|
|
14952
|
+
* opened a popup, and what the popup holds is to be carried by the finger
|
|
14953
|
+
* still down (see HANDED OVER below). Nothing happens when that press has
|
|
14954
|
+
* ended in the meantime.
|
|
14955
|
+
*
|
|
14956
|
+
* HANDED OVER. The press did not land on the element, and the element may not
|
|
14957
|
+
* have existed when it did, so the three things a press on it would have said
|
|
14958
|
+
* are said otherwise. Where it landed is none of the element's business (no
|
|
14959
|
+
* opted-out area is looked for). Whether the hand means it was proved by the
|
|
14960
|
+
* hold that handed it over, so the carry starts at once. And where the hand is
|
|
14961
|
+
* has nothing to do with where the element stands, so the copy is brought to
|
|
14962
|
+
* the hand — centred on the finger, flying there from the element's box —
|
|
14963
|
+
* rather than following it from a distance. The pointer is taken on the
|
|
14964
|
+
* element, away from what the finger first touched. Only a copy can be brought
|
|
14965
|
+
* like that: `move` carries the element itself, which would leave its place
|
|
14966
|
+
* just by being handed a press, and is not started.
|
|
14850
14967
|
*
|
|
14851
14968
|
* Everything else is forwarded to `createDragToMoveGestureController`
|
|
14852
14969
|
* (`areaConstraint`, `autoScrollAreaPadding`, `direction`…) and to `dragAfterIntent`
|
|
@@ -14868,8 +14985,9 @@ const startDragTo = (
|
|
|
14868
14985
|
{ draggedElement = event.currentTarget, ...options } = {},
|
|
14869
14986
|
) => {
|
|
14870
14987
|
// An area that opted out of dragging (a text one wants to select, a control that
|
|
14871
|
-
// owns the gesture, a callout): the press there is none of our business.
|
|
14872
|
-
|
|
14988
|
+
// owns the gesture, a callout): the press there is none of our business. A
|
|
14989
|
+
// press handed over landed outside the element by construction.
|
|
14990
|
+
if (!options.handedOver && isPressIgnored(event.target, draggedElement)) {
|
|
14873
14991
|
return undefined;
|
|
14874
14992
|
}
|
|
14875
14993
|
// A secondary button (right click and friends) is a context menu, not a grab.
|
|
@@ -14896,6 +15014,9 @@ const startDragTo = (
|
|
|
14896
15014
|
...options,
|
|
14897
15015
|
});
|
|
14898
15016
|
}
|
|
15017
|
+
if (options.handedOver) {
|
|
15018
|
+
return undefined;
|
|
15019
|
+
}
|
|
14899
15020
|
return startDragToMoveElement(event, {
|
|
14900
15021
|
draggedElement,
|
|
14901
15022
|
canMove,
|
|
@@ -15285,23 +15406,35 @@ const startDragToCarryCopy = (
|
|
|
15285
15406
|
onPressStart,
|
|
15286
15407
|
onPressCancel,
|
|
15287
15408
|
onPress,
|
|
15409
|
+
handedOver,
|
|
15288
15410
|
...options
|
|
15289
15411
|
},
|
|
15290
15412
|
) => {
|
|
15291
15413
|
// An area that opted out of dragging (a text one wants to select, a control
|
|
15292
15414
|
// that owns the gesture, a callout): the press there is none of our business.
|
|
15293
|
-
if (isPressIgnored(event.target, draggedElement)) {
|
|
15415
|
+
if (!handedOver && isPressIgnored(event.target, draggedElement)) {
|
|
15294
15416
|
return undefined;
|
|
15295
15417
|
}
|
|
15296
15418
|
// A secondary button (right click and friends) is a context menu, not a grab.
|
|
15297
15419
|
if (!isPrimaryButtonEvent(event)) {
|
|
15298
15420
|
return undefined;
|
|
15299
15421
|
}
|
|
15422
|
+
// Where the hand is, for a press handed over: its `pointerdown` says where it
|
|
15423
|
+
// WAS, before the hold and whatever the hold opened. Let go of meanwhile, it
|
|
15424
|
+
// is not picked up after the fact.
|
|
15425
|
+
const handedPointer = handedOver ? readPressDown(event) : null;
|
|
15426
|
+
if (handedOver && !handedPointer) {
|
|
15427
|
+
return undefined;
|
|
15428
|
+
}
|
|
15300
15429
|
// One press, one carry — and the same carry over again when the hand comes back
|
|
15301
15430
|
// for the copy while it is still flying home (see settleCloneBack). Nothing is
|
|
15302
15431
|
// made twice in that case: it is the same copy, taken in hand again where it
|
|
15303
|
-
// had got to.
|
|
15304
|
-
const startCarry = (
|
|
15432
|
+
// had got to — by a press ON it, so never a press handed over.
|
|
15433
|
+
const startCarry = (
|
|
15434
|
+
pointerEvent,
|
|
15435
|
+
{ cloneWrapperCaught, onCarryStart } = {},
|
|
15436
|
+
) => {
|
|
15437
|
+
const handedTo = cloneWrapperCaught ? null : handedPointer;
|
|
15305
15438
|
pointerEvent.preventDefault();
|
|
15306
15439
|
return dragAfterIntent(
|
|
15307
15440
|
pointerEvent,
|
|
@@ -15310,8 +15443,14 @@ const startDragToCarryCopy = (
|
|
|
15310
15443
|
// one moment both ways in (a finger held still, a mouse travelled)
|
|
15311
15444
|
// agree on.
|
|
15312
15445
|
onCarryStart?.();
|
|
15446
|
+
// From the element's centre to the finger: the copy is brought that far,
|
|
15447
|
+
// since the hand that pressed elsewhere has nothing to follow it from.
|
|
15448
|
+
const reach = handedTo
|
|
15449
|
+
? measureReach(draggedElement, handedTo)
|
|
15450
|
+
: undefined;
|
|
15313
15451
|
const cloneWrapper =
|
|
15314
|
-
cloneWrapperCaught ||
|
|
15452
|
+
cloneWrapperCaught ||
|
|
15453
|
+
createDragClone(draggedElement, handedTo || pointerEvent, reach);
|
|
15315
15454
|
if (cloneWrapperCaught) {
|
|
15316
15455
|
liftDragClone(cloneWrapperCaught, pointerEvent);
|
|
15317
15456
|
}
|
|
@@ -15323,10 +15462,26 @@ const startDragToCarryCopy = (
|
|
|
15323
15462
|
areaConstraint,
|
|
15324
15463
|
...options,
|
|
15325
15464
|
});
|
|
15326
|
-
const dragGesture = gestureController.grabViaPointer(
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
|
|
15465
|
+
const dragGesture = gestureController.grabViaPointer(
|
|
15466
|
+
pointerEvent,
|
|
15467
|
+
handedTo
|
|
15468
|
+
? {
|
|
15469
|
+
element: draggedElement,
|
|
15470
|
+
elementToMove: cloneWrapper,
|
|
15471
|
+
// Counted from where the finger is now, so a release that
|
|
15472
|
+
// never moved it is still a hand that changed its mind.
|
|
15473
|
+
grabX: handedTo.clientX,
|
|
15474
|
+
grabY: handedTo.clientY,
|
|
15475
|
+
grabOffset: reach,
|
|
15476
|
+
// Off what the finger first touched, which the popup now
|
|
15477
|
+
// covers: the pointer is the carry's from here.
|
|
15478
|
+
pointerCaptureElement: draggedElement,
|
|
15479
|
+
}
|
|
15480
|
+
: {
|
|
15481
|
+
element: draggedElement,
|
|
15482
|
+
elementToMove: cloneWrapper,
|
|
15483
|
+
},
|
|
15484
|
+
);
|
|
15330
15485
|
// getDropTargetInfo uses gestureInfo.elementImpacted to compute the dragged rect.
|
|
15331
15486
|
// Point it at the clone so drop detection tracks the clone's current position.
|
|
15332
15487
|
dragGesture.gestureInfo.elementImpacted = cloneWrapper;
|
|
@@ -15500,6 +15655,10 @@ const startDragToCarryCopy = (
|
|
|
15500
15655
|
dragGesture.addReleaseCallback(async (gestureInfo) => {
|
|
15501
15656
|
clearDropHintDOM();
|
|
15502
15657
|
dropHintEl?.remove();
|
|
15658
|
+
// Let go of on its way to the hand: it is where the hand is, and from
|
|
15659
|
+
// there it goes wherever the answer sends it — on a translate of its
|
|
15660
|
+
// own, which the flight to the hand must not be holding.
|
|
15661
|
+
cloneWrapper.removeAttribute("data-reaching");
|
|
15503
15662
|
|
|
15504
15663
|
// What THIS release means, from what the element said it can answer. A
|
|
15505
15664
|
// throw is asked about first: it is the more insistent of the two, and a
|
|
@@ -15544,7 +15703,10 @@ const startDragToCarryCopy = (
|
|
|
15544
15703
|
const copyLetGoOf = letCopyBeCaught(
|
|
15545
15704
|
cloneWrapper,
|
|
15546
15705
|
(pointerDownEvent, whenCarried) =>
|
|
15547
|
-
startCarry(pointerDownEvent,
|
|
15706
|
+
startCarry(pointerDownEvent, {
|
|
15707
|
+
cloneWrapperCaught: cloneWrapper,
|
|
15708
|
+
onCarryStart: whenCarried,
|
|
15709
|
+
}),
|
|
15548
15710
|
);
|
|
15549
15711
|
|
|
15550
15712
|
// The copy stops where the hand left it, and the answer is given a way to
|
|
@@ -15648,6 +15810,7 @@ const startDragToCarryCopy = (
|
|
|
15648
15810
|
onPressStart,
|
|
15649
15811
|
onPressCancel,
|
|
15650
15812
|
onPress,
|
|
15813
|
+
handedOver: Boolean(handedTo),
|
|
15651
15814
|
},
|
|
15652
15815
|
);
|
|
15653
15816
|
};
|
|
@@ -15951,9 +16114,23 @@ const liftDragClone = (cloneWrapper, pointerEvent) => {
|
|
|
15951
16114
|
cloneWrapper.firstElementChild.setAttribute("navi-drag-clone", "");
|
|
15952
16115
|
};
|
|
15953
16116
|
|
|
16117
|
+
// From the centre of the element to the pointer, for a copy brought to a hand
|
|
16118
|
+
// that pressed elsewhere (see handedOver): centred rather than held at the point
|
|
16119
|
+
// the finger had on what it pressed, since that was another box.
|
|
16120
|
+
const measureReach = (element, pointer) => {
|
|
16121
|
+
const rect = element.getBoundingClientRect();
|
|
16122
|
+
return {
|
|
16123
|
+
x: pointer.clientX - (rect.left + rect.width / 2),
|
|
16124
|
+
y: pointer.clientY - (rect.top + rect.height / 2),
|
|
16125
|
+
};
|
|
16126
|
+
};
|
|
16127
|
+
|
|
15954
16128
|
let dragCloneCount = 0;
|
|
15955
|
-
const createDragClone = (element,
|
|
16129
|
+
const createDragClone = (element, grabPoint, reach) => {
|
|
15956
16130
|
const rect = element.getBoundingClientRect();
|
|
16131
|
+
// Over the element, or shifted to where the hand is (see measureReach).
|
|
16132
|
+
const left = reach ? rect.left + reach.x : rect.left;
|
|
16133
|
+
const top = reach ? rect.top + reach.y : rect.top;
|
|
15957
16134
|
|
|
15958
16135
|
const wrapper = document.createElement("div");
|
|
15959
16136
|
wrapper.setAttribute("navi-drag-clone-wrapper", "");
|
|
@@ -15965,13 +16142,26 @@ const createDragClone = (element, pointerEvent) => {
|
|
|
15965
16142
|
// Manual: it is opened and closed with the drag, and must survive an Escape
|
|
15966
16143
|
// or a click elsewhere (light dismiss would take it away mid-gesture).
|
|
15967
16144
|
wrapper.setAttribute("popover", "manual");
|
|
15968
|
-
|
|
15969
|
-
|
|
16145
|
+
wrapper.style.setProperty("--clone-top", `${top}px`);
|
|
16146
|
+
wrapper.style.setProperty("--clone-left", `${left}px`);
|
|
16147
|
+
wrapper.style.setProperty("--clone-width", `${rect.width}px`);
|
|
16148
|
+
wrapper.style.setProperty("--clone-height", `${rect.height}px`);
|
|
16149
|
+
if (reach) {
|
|
16150
|
+
// It flies there from the element's box, so the eye follows what was
|
|
16151
|
+
// picked up rather than seeing it appear under the finger (see the
|
|
16152
|
+
// stylesheet).
|
|
16153
|
+
wrapper.style.setProperty(
|
|
16154
|
+
"--clone-reach-from",
|
|
16155
|
+
`${-reach.x}px ${-reach.y}px`,
|
|
16156
|
+
);
|
|
16157
|
+
wrapper.setAttribute("data-reaching", "");
|
|
16158
|
+
}
|
|
16159
|
+
// Grab point within the copy — used as transform-origin so the
|
|
15970
16160
|
// scale expands from where the user clicked, not the element center.
|
|
15971
|
-
// These offsets are
|
|
16161
|
+
// These offsets are copy-relative so viewport coords are correct here.
|
|
15972
16162
|
wrapper.style.setProperty(
|
|
15973
16163
|
"--drag-origin",
|
|
15974
|
-
`${
|
|
16164
|
+
`${grabPoint.clientX - left}px ${grabPoint.clientY - top}px`,
|
|
15975
16165
|
);
|
|
15976
16166
|
const elementClone = element.cloneNode(true);
|
|
15977
16167
|
// A deep copy copies the ids too, and two elements answering to one id is a
|