@jsenv/dom 0.17.81 → 0.17.83
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 +272 -37
- package/package.json +1 -1
package/dist/jsenv_dom.js
CHANGED
|
@@ -10147,6 +10147,11 @@ const dragSourceThatStoodDown = (pressEvent) => {
|
|
|
10147
10147
|
return pressEvent[STOOD_DOWN] || null;
|
|
10148
10148
|
};
|
|
10149
10149
|
|
|
10150
|
+
// How far (px) a press travels before it means drag. Also how far a carry that
|
|
10151
|
+
// was handed over must go before it has gone anywhere (see handedOver in
|
|
10152
|
+
// drag_to.js): that is the same question, asked of the hand holding it.
|
|
10153
|
+
const DRAG_INTENT_THRESHOLD = 5;
|
|
10154
|
+
|
|
10150
10155
|
/**
|
|
10151
10156
|
* Waits for the user to mean it, then starts a drag gesture.
|
|
10152
10157
|
*
|
|
@@ -10183,12 +10188,16 @@ const dragSourceThatStoodDown = (pressEvent) => {
|
|
|
10183
10188
|
* drag_gesture.js). `"manual"` leaves the press to the browser until the
|
|
10184
10189
|
* caller's own gesture says otherwise. A long press waits without refusing
|
|
10185
10190
|
* anything either way (see the stylesheet above).
|
|
10191
|
+
* @param {boolean} [options.handedOver=false]
|
|
10192
|
+
* The press was held on something else, which handed it to this drag (see
|
|
10193
|
+
* `handedOver` in drag_to.js): the hold that did so established the intent,
|
|
10194
|
+
* so the gesture starts at once, as it does from a dedicated handle.
|
|
10186
10195
|
*/
|
|
10187
10196
|
const dragAfterIntent = (
|
|
10188
10197
|
grabEvent,
|
|
10189
10198
|
dragGestureInitializer,
|
|
10190
10199
|
{
|
|
10191
|
-
threshold =
|
|
10200
|
+
threshold = DRAG_INTENT_THRESHOLD,
|
|
10192
10201
|
longPress = "if-touch",
|
|
10193
10202
|
longPressDelay = 400,
|
|
10194
10203
|
longPressSlop = 8,
|
|
@@ -10196,6 +10205,7 @@ const dragAfterIntent = (
|
|
|
10196
10205
|
onPressCancel,
|
|
10197
10206
|
onPress,
|
|
10198
10207
|
selection = "auto",
|
|
10208
|
+
handedOver = false,
|
|
10199
10209
|
} = {},
|
|
10200
10210
|
) => {
|
|
10201
10211
|
if (!isPrimaryButtonEvent(grabEvent)) {
|
|
@@ -10204,7 +10214,7 @@ const dragAfterIntent = (
|
|
|
10204
10214
|
const target = grabEvent.target;
|
|
10205
10215
|
const isDedicatedHandle =
|
|
10206
10216
|
target.closest && target.closest("[data-drag-handle]");
|
|
10207
|
-
if (isDedicatedHandle) {
|
|
10217
|
+
if (isDedicatedHandle || handedOver) {
|
|
10208
10218
|
startDragGesture(dragGestureInitializer);
|
|
10209
10219
|
return;
|
|
10210
10220
|
}
|
|
@@ -10836,6 +10846,82 @@ const getDragCoordinates = (
|
|
|
10836
10846
|
return [leftRelativeToScrollContainer, topRelativeToScrollContainer];
|
|
10837
10847
|
};
|
|
10838
10848
|
|
|
10849
|
+
/**
|
|
10850
|
+
* Which presses are still down, and where each one is now.
|
|
10851
|
+
*
|
|
10852
|
+
* A press is read by whoever it landed on, from its `pointerdown` to its
|
|
10853
|
+
* `pointerup`. Some are handed over halfway: a hold opens a popup, and
|
|
10854
|
+
* something inside it takes the press the finger is still making (see
|
|
10855
|
+
* `handedOver` in drag_to.js). Whoever receives it was not listening when it
|
|
10856
|
+
* began, so it cannot know whether the pointer has let go since, nor where it
|
|
10857
|
+
* is now — the `pointerdown` it is handed says where the finger WAS. Listened
|
|
10858
|
+
* for from the start instead, on the window in capture so that nothing lower
|
|
10859
|
+
* can hide a press from it.
|
|
10860
|
+
*
|
|
10861
|
+
* Keyed by the `pointerdown` itself and not by the pointer: the same finger
|
|
10862
|
+
* lifted and put down again is another press, and a press handed over late
|
|
10863
|
+
* must not be answered by the next one.
|
|
10864
|
+
*/
|
|
10865
|
+
|
|
10866
|
+
const pressDownByPointerId = new Map();
|
|
10867
|
+
|
|
10868
|
+
/**
|
|
10869
|
+
* Where the pointer of `pressEvent` is now, while that press is still down.
|
|
10870
|
+
*
|
|
10871
|
+
* @param {PointerEvent} pressEvent A `pointerdown`.
|
|
10872
|
+
* @returns {{ clientX: number, clientY: number } | null} `null` once that press
|
|
10873
|
+
* has ended — let go of, or cancelled by the browser.
|
|
10874
|
+
*/
|
|
10875
|
+
const readPressDown = (pressEvent) => {
|
|
10876
|
+
const pressDown = pressDownByPointerId.get(pressEvent.pointerId);
|
|
10877
|
+
if (!pressDown || pressDown.pressEvent !== pressEvent) {
|
|
10878
|
+
return null;
|
|
10879
|
+
}
|
|
10880
|
+
return { clientX: pressDown.clientX, clientY: pressDown.clientY };
|
|
10881
|
+
};
|
|
10882
|
+
|
|
10883
|
+
const onPointerMove = (pointerMoveEvent) => {
|
|
10884
|
+
const pressDown = pressDownByPointerId.get(pointerMoveEvent.pointerId);
|
|
10885
|
+
if (!pressDown) {
|
|
10886
|
+
return;
|
|
10887
|
+
}
|
|
10888
|
+
pressDown.clientX = pointerMoveEvent.clientX;
|
|
10889
|
+
pressDown.clientY = pointerMoveEvent.clientY;
|
|
10890
|
+
};
|
|
10891
|
+
const onPointerEnd = (pointerEndEvent) => {
|
|
10892
|
+
pressDownByPointerId.delete(pointerEndEvent.pointerId);
|
|
10893
|
+
if (pressDownByPointerId.size === 0) {
|
|
10894
|
+
// A mouse moves all the time without being pressed: nothing is read from
|
|
10895
|
+
// it between presses.
|
|
10896
|
+
window.removeEventListener("pointermove", onPointerMove, true);
|
|
10897
|
+
}
|
|
10898
|
+
};
|
|
10899
|
+
window.addEventListener(
|
|
10900
|
+
"pointerdown",
|
|
10901
|
+
(pointerDownEvent) => {
|
|
10902
|
+
if (pressDownByPointerId.size === 0) {
|
|
10903
|
+
window.addEventListener("pointermove", onPointerMove, {
|
|
10904
|
+
capture: true,
|
|
10905
|
+
passive: true,
|
|
10906
|
+
});
|
|
10907
|
+
}
|
|
10908
|
+
pressDownByPointerId.set(pointerDownEvent.pointerId, {
|
|
10909
|
+
pressEvent: pointerDownEvent,
|
|
10910
|
+
clientX: pointerDownEvent.clientX,
|
|
10911
|
+
clientY: pointerDownEvent.clientY,
|
|
10912
|
+
});
|
|
10913
|
+
},
|
|
10914
|
+
{ capture: true, passive: true },
|
|
10915
|
+
);
|
|
10916
|
+
window.addEventListener("pointerup", onPointerEnd, {
|
|
10917
|
+
capture: true,
|
|
10918
|
+
passive: true,
|
|
10919
|
+
});
|
|
10920
|
+
window.addEventListener("pointercancel", onPointerEnd, {
|
|
10921
|
+
capture: true,
|
|
10922
|
+
passive: true,
|
|
10923
|
+
});
|
|
10924
|
+
|
|
10839
10925
|
installImportMetaCssBuild(import.meta);
|
|
10840
10926
|
|
|
10841
10927
|
const css$4 = /* css */ `.navi_constraint_feedback_line {
|
|
@@ -14324,6 +14410,16 @@ const css$1 = /* css */ `.navi_drop_hint {
|
|
|
14324
14410
|
opacity: 0;
|
|
14325
14411
|
}
|
|
14326
14412
|
|
|
14413
|
+
[navi-drag-clone-wrapper][data-reaching] {
|
|
14414
|
+
transition: translate .2s ease-out;
|
|
14415
|
+
}
|
|
14416
|
+
|
|
14417
|
+
@starting-style {
|
|
14418
|
+
[navi-drag-clone-wrapper][data-reaching] {
|
|
14419
|
+
translate: var(--clone-reach-from);
|
|
14420
|
+
}
|
|
14421
|
+
}
|
|
14422
|
+
|
|
14327
14423
|
[navi-drag-clone] {
|
|
14328
14424
|
box-shadow: var(--drag-clone-shadow, 0 12px 28px #00000038);
|
|
14329
14425
|
transform: scale(var(--drag-clone-scale, 1.03));
|
|
@@ -14740,6 +14836,11 @@ const createDragToMoveGestureController = ({
|
|
|
14740
14836
|
element,
|
|
14741
14837
|
referenceElement,
|
|
14742
14838
|
elementToMove,
|
|
14839
|
+
// How far from `element` what moves starts, when it does not start over it
|
|
14840
|
+
// (a copy brought to a hand that pressed elsewhere, see handedOver). The
|
|
14841
|
+
// layout is then the box the hand holds, so constraints and auto-scroll
|
|
14842
|
+
// read what is seen; the translate is unaffected, it counts from the grab.
|
|
14843
|
+
grabOffset,
|
|
14743
14844
|
event,
|
|
14744
14845
|
...rest
|
|
14745
14846
|
} = {}) => {
|
|
@@ -14752,8 +14853,12 @@ const createDragToMoveGestureController = ({
|
|
|
14752
14853
|
const dragGesture = grab({
|
|
14753
14854
|
element,
|
|
14754
14855
|
scrollContainer,
|
|
14755
|
-
layoutScrollableLeft:
|
|
14756
|
-
|
|
14856
|
+
layoutScrollableLeft: grabOffset
|
|
14857
|
+
? elementScrollableLeft + grabOffset.x
|
|
14858
|
+
: elementScrollableLeft,
|
|
14859
|
+
layoutScrollableTop: grabOffset
|
|
14860
|
+
? elementScrollableTop + grabOffset.y
|
|
14861
|
+
: elementScrollableTop,
|
|
14757
14862
|
event,
|
|
14758
14863
|
...rest,
|
|
14759
14864
|
});
|
|
@@ -14847,6 +14952,27 @@ const createDragToMoveGestureController = ({
|
|
|
14847
14952
|
* for: one without the other is moving the thing while hesitating, and nothing is
|
|
14848
14953
|
* thrown away on a hesitation. A throw is judged before any landing; a release
|
|
14849
14954
|
* with no place under it is `leave`'s, not a toss — there is no speed to it.
|
|
14955
|
+
* @param {boolean} [options.handedOver=false]
|
|
14956
|
+
* `event` is a press held on something ELSE, handed to this element: a hold
|
|
14957
|
+
* opened a popup, and what the popup holds is to be carried by the finger
|
|
14958
|
+
* still down (see HANDED OVER below). Nothing happens when that press has
|
|
14959
|
+
* ended in the meantime.
|
|
14960
|
+
*
|
|
14961
|
+
* HANDED OVER. The press did not land on the element, and the element may not
|
|
14962
|
+
* have existed when it did, so the three things a press on it would have said
|
|
14963
|
+
* are said otherwise. Where it landed is none of the element's business (no
|
|
14964
|
+
* opted-out area is looked for). Whether the hand means it was proved by the
|
|
14965
|
+
* hold that handed it over, so the carry starts at once. And where the hand is
|
|
14966
|
+
* has nothing to do with where the element stands, so the copy is brought to
|
|
14967
|
+
* the hand — centred on the finger, flying there from the element's box —
|
|
14968
|
+
* rather than following it from a distance. Where it was brought then stands
|
|
14969
|
+
* for the element's own place: over whatever the finger happened to be on, so
|
|
14970
|
+
* nothing counts as under it until the hand has taken it further than
|
|
14971
|
+
* `threshold`, and a release before that is a hand that changed its mind. The
|
|
14972
|
+
* pointer is taken on the element, away from what the finger first touched.
|
|
14973
|
+
* Only a copy can be brought
|
|
14974
|
+
* like that: `move` carries the element itself, which would leave its place
|
|
14975
|
+
* just by being handed a press, and is not started.
|
|
14850
14976
|
*
|
|
14851
14977
|
* Everything else is forwarded to `createDragToMoveGestureController`
|
|
14852
14978
|
* (`areaConstraint`, `autoScrollAreaPadding`, `direction`…) and to `dragAfterIntent`
|
|
@@ -14868,8 +14994,9 @@ const startDragTo = (
|
|
|
14868
14994
|
{ draggedElement = event.currentTarget, ...options } = {},
|
|
14869
14995
|
) => {
|
|
14870
14996
|
// 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
|
-
|
|
14997
|
+
// owns the gesture, a callout): the press there is none of our business. A
|
|
14998
|
+
// press handed over landed outside the element by construction.
|
|
14999
|
+
if (!options.handedOver && isPressIgnored(event.target, draggedElement)) {
|
|
14873
15000
|
return undefined;
|
|
14874
15001
|
}
|
|
14875
15002
|
// A secondary button (right click and friends) is a context menu, not a grab.
|
|
@@ -14896,6 +15023,9 @@ const startDragTo = (
|
|
|
14896
15023
|
...options,
|
|
14897
15024
|
});
|
|
14898
15025
|
}
|
|
15026
|
+
if (options.handedOver) {
|
|
15027
|
+
return undefined;
|
|
15028
|
+
}
|
|
14899
15029
|
return startDragToMoveElement(event, {
|
|
14900
15030
|
draggedElement,
|
|
14901
15031
|
canMove,
|
|
@@ -15195,6 +15325,10 @@ const resolveDropMeaning = ({
|
|
|
15195
15325
|
canLeave,
|
|
15196
15326
|
tossDistance = TOSS_DISTANCE_TO_COMMIT,
|
|
15197
15327
|
tossSpeed = TOSS_SPEED_TO_COMMIT,
|
|
15328
|
+
// How far it may have been taken and still have been taken nowhere: not at
|
|
15329
|
+
// all for a carry that starts over its own place, the drag threshold for one
|
|
15330
|
+
// brought to a hand (see handedOver).
|
|
15331
|
+
stillWithin = 0,
|
|
15198
15332
|
}) => {
|
|
15199
15333
|
if (gestureInfo.cancelled) {
|
|
15200
15334
|
// Nobody let go of anything: the gesture was taken away mid-air (the
|
|
@@ -15220,7 +15354,7 @@ const resolveDropMeaning = ({
|
|
|
15220
15354
|
// It has to have gone somewhere to be put anywhere, or away from anything:
|
|
15221
15355
|
// picked up and put straight back down is a hand that changed its mind.
|
|
15222
15356
|
const { xDelta, yDelta } = gestureInfo.layout;
|
|
15223
|
-
if (
|
|
15357
|
+
if (Math.hypot(xDelta, yDelta) <= stillWithin) {
|
|
15224
15358
|
return "cancel";
|
|
15225
15359
|
}
|
|
15226
15360
|
if (canLeave && releasedOutside) {
|
|
@@ -15278,30 +15412,44 @@ const startDragToCarryCopy = (
|
|
|
15278
15412
|
direction = canLand || canLeave
|
|
15279
15413
|
? { x: true, y: true }
|
|
15280
15414
|
: { x: false, y: true },
|
|
15281
|
-
|
|
15415
|
+
// Defaulted here rather than left to dragAfterIntent: a carry handed over
|
|
15416
|
+
// reads it too (see stillWithin).
|
|
15417
|
+
threshold = DRAG_INTENT_THRESHOLD,
|
|
15282
15418
|
longPress,
|
|
15283
15419
|
longPressDelay,
|
|
15284
15420
|
longPressSlop,
|
|
15285
15421
|
onPressStart,
|
|
15286
15422
|
onPressCancel,
|
|
15287
15423
|
onPress,
|
|
15424
|
+
handedOver,
|
|
15288
15425
|
...options
|
|
15289
15426
|
},
|
|
15290
15427
|
) => {
|
|
15291
15428
|
// An area that opted out of dragging (a text one wants to select, a control
|
|
15292
15429
|
// that owns the gesture, a callout): the press there is none of our business.
|
|
15293
|
-
if (isPressIgnored(event.target, draggedElement)) {
|
|
15430
|
+
if (!handedOver && isPressIgnored(event.target, draggedElement)) {
|
|
15294
15431
|
return undefined;
|
|
15295
15432
|
}
|
|
15296
15433
|
// A secondary button (right click and friends) is a context menu, not a grab.
|
|
15297
15434
|
if (!isPrimaryButtonEvent(event)) {
|
|
15298
15435
|
return undefined;
|
|
15299
15436
|
}
|
|
15437
|
+
// Where the hand is, for a press handed over: its `pointerdown` says where it
|
|
15438
|
+
// WAS, before the hold and whatever the hold opened. Let go of meanwhile, it
|
|
15439
|
+
// is not picked up after the fact.
|
|
15440
|
+
const handedPointer = handedOver ? readPressDown(event) : null;
|
|
15441
|
+
if (handedOver && !handedPointer) {
|
|
15442
|
+
return undefined;
|
|
15443
|
+
}
|
|
15300
15444
|
// One press, one carry — and the same carry over again when the hand comes back
|
|
15301
15445
|
// for the copy while it is still flying home (see settleCloneBack). Nothing is
|
|
15302
15446
|
// made twice in that case: it is the same copy, taken in hand again where it
|
|
15303
|
-
// had got to.
|
|
15304
|
-
const startCarry = (
|
|
15447
|
+
// had got to — by a press ON it, so never a press handed over.
|
|
15448
|
+
const startCarry = (
|
|
15449
|
+
pointerEvent,
|
|
15450
|
+
{ cloneWrapperCaught, onCarryStart } = {},
|
|
15451
|
+
) => {
|
|
15452
|
+
const handedTo = cloneWrapperCaught ? null : handedPointer;
|
|
15305
15453
|
pointerEvent.preventDefault();
|
|
15306
15454
|
return dragAfterIntent(
|
|
15307
15455
|
pointerEvent,
|
|
@@ -15310,8 +15458,21 @@ const startDragToCarryCopy = (
|
|
|
15310
15458
|
// one moment both ways in (a finger held still, a mouse travelled)
|
|
15311
15459
|
// agree on.
|
|
15312
15460
|
onCarryStart?.();
|
|
15461
|
+
// From the element's centre to the finger: the copy is brought that far,
|
|
15462
|
+
// since the hand that pressed elsewhere has nothing to follow it from.
|
|
15463
|
+
const reach = handedTo
|
|
15464
|
+
? measureReach(draggedElement, handedTo)
|
|
15465
|
+
: undefined;
|
|
15466
|
+
// …and has been taken nowhere until it is further from there than a
|
|
15467
|
+
// press travels to mean drag.
|
|
15468
|
+
const stillWithin = handedTo ? threshold : 0;
|
|
15469
|
+
const hasNotLeftHand = (gestureInfo) =>
|
|
15470
|
+
Boolean(handedTo) &&
|
|
15471
|
+
Math.hypot(gestureInfo.layout.xDelta, gestureInfo.layout.yDelta) <=
|
|
15472
|
+
stillWithin;
|
|
15313
15473
|
const cloneWrapper =
|
|
15314
|
-
cloneWrapperCaught ||
|
|
15474
|
+
cloneWrapperCaught ||
|
|
15475
|
+
createDragClone(draggedElement, handedTo || pointerEvent, reach);
|
|
15315
15476
|
if (cloneWrapperCaught) {
|
|
15316
15477
|
liftDragClone(cloneWrapperCaught, pointerEvent);
|
|
15317
15478
|
}
|
|
@@ -15323,10 +15484,26 @@ const startDragToCarryCopy = (
|
|
|
15323
15484
|
areaConstraint,
|
|
15324
15485
|
...options,
|
|
15325
15486
|
});
|
|
15326
|
-
const dragGesture = gestureController.grabViaPointer(
|
|
15327
|
-
|
|
15328
|
-
|
|
15329
|
-
|
|
15487
|
+
const dragGesture = gestureController.grabViaPointer(
|
|
15488
|
+
pointerEvent,
|
|
15489
|
+
handedTo
|
|
15490
|
+
? {
|
|
15491
|
+
element: draggedElement,
|
|
15492
|
+
elementToMove: cloneWrapper,
|
|
15493
|
+
// Counted from where the finger is now, so a release that
|
|
15494
|
+
// never moved it is still a hand that changed its mind.
|
|
15495
|
+
grabX: handedTo.clientX,
|
|
15496
|
+
grabY: handedTo.clientY,
|
|
15497
|
+
grabOffset: reach,
|
|
15498
|
+
// Off what the finger first touched, which the popup now
|
|
15499
|
+
// covers: the pointer is the carry's from here.
|
|
15500
|
+
pointerCaptureElement: draggedElement,
|
|
15501
|
+
}
|
|
15502
|
+
: {
|
|
15503
|
+
element: draggedElement,
|
|
15504
|
+
elementToMove: cloneWrapper,
|
|
15505
|
+
},
|
|
15506
|
+
);
|
|
15330
15507
|
// getDropTargetInfo uses gestureInfo.elementImpacted to compute the dragged rect.
|
|
15331
15508
|
// Point it at the clone so drop detection tracks the clone's current position.
|
|
15332
15509
|
dragGesture.gestureInfo.elementImpacted = cloneWrapper;
|
|
@@ -15385,6 +15562,16 @@ const startDragToCarryCopy = (
|
|
|
15385
15562
|
if (!dropHintEl) {
|
|
15386
15563
|
return;
|
|
15387
15564
|
}
|
|
15565
|
+
// Brought to the hand, the copy starts over whatever the finger is on,
|
|
15566
|
+
// and a place found there is one it was never taken to — the release
|
|
15567
|
+
// frame included, which is how a hold let go of without moving would
|
|
15568
|
+
// land. Around where it was brought is its own place, as the element's
|
|
15569
|
+
// box is for a carry that starts there: nothing is under it yet.
|
|
15570
|
+
if (hasNotLeftHand(gestureInfo)) {
|
|
15571
|
+
clearDropHint();
|
|
15572
|
+
gestureInfo.dropTargetInfo = null;
|
|
15573
|
+
return;
|
|
15574
|
+
}
|
|
15388
15575
|
const allItems = [];
|
|
15389
15576
|
const items = [];
|
|
15390
15577
|
for (const el of containerElement.querySelectorAll(itemSelector)) {
|
|
@@ -15500,6 +15687,10 @@ const startDragToCarryCopy = (
|
|
|
15500
15687
|
dragGesture.addReleaseCallback(async (gestureInfo) => {
|
|
15501
15688
|
clearDropHintDOM();
|
|
15502
15689
|
dropHintEl?.remove();
|
|
15690
|
+
// Let go of on its way to the hand: it is where the hand is, and from
|
|
15691
|
+
// there it goes wherever the answer sends it — on a translate of its
|
|
15692
|
+
// own, which the flight to the hand must not be holding.
|
|
15693
|
+
cloneWrapper.removeAttribute("data-reaching");
|
|
15503
15694
|
|
|
15504
15695
|
// What THIS release means, from what the element said it can answer. A
|
|
15505
15696
|
// throw is asked about first: it is the more insistent of the two, and a
|
|
@@ -15527,6 +15718,7 @@ const startDragToCarryCopy = (
|
|
|
15527
15718
|
canLeave,
|
|
15528
15719
|
tossDistance,
|
|
15529
15720
|
tossSpeed,
|
|
15721
|
+
stillWithin,
|
|
15530
15722
|
});
|
|
15531
15723
|
// The hand has let go, and what that means is already known — the
|
|
15532
15724
|
// answer to it has not run yet. Told, not asked: nothing here waits on
|
|
@@ -15544,7 +15736,10 @@ const startDragToCarryCopy = (
|
|
|
15544
15736
|
const copyLetGoOf = letCopyBeCaught(
|
|
15545
15737
|
cloneWrapper,
|
|
15546
15738
|
(pointerDownEvent, whenCarried) =>
|
|
15547
|
-
startCarry(pointerDownEvent,
|
|
15739
|
+
startCarry(pointerDownEvent, {
|
|
15740
|
+
cloneWrapperCaught: cloneWrapper,
|
|
15741
|
+
onCarryStart: whenCarried,
|
|
15742
|
+
}),
|
|
15548
15743
|
);
|
|
15549
15744
|
|
|
15550
15745
|
// The copy stops where the hand left it, and the answer is given a way to
|
|
@@ -15648,6 +15843,7 @@ const startDragToCarryCopy = (
|
|
|
15648
15843
|
onPressStart,
|
|
15649
15844
|
onPressCancel,
|
|
15650
15845
|
onPress,
|
|
15846
|
+
handedOver: Boolean(handedTo),
|
|
15651
15847
|
},
|
|
15652
15848
|
);
|
|
15653
15849
|
};
|
|
@@ -15951,9 +16147,23 @@ const liftDragClone = (cloneWrapper, pointerEvent) => {
|
|
|
15951
16147
|
cloneWrapper.firstElementChild.setAttribute("navi-drag-clone", "");
|
|
15952
16148
|
};
|
|
15953
16149
|
|
|
16150
|
+
// From the centre of the element to the pointer, for a copy brought to a hand
|
|
16151
|
+
// that pressed elsewhere (see handedOver): centred rather than held at the point
|
|
16152
|
+
// the finger had on what it pressed, since that was another box.
|
|
16153
|
+
const measureReach = (element, pointer) => {
|
|
16154
|
+
const rect = element.getBoundingClientRect();
|
|
16155
|
+
return {
|
|
16156
|
+
x: pointer.clientX - (rect.left + rect.width / 2),
|
|
16157
|
+
y: pointer.clientY - (rect.top + rect.height / 2),
|
|
16158
|
+
};
|
|
16159
|
+
};
|
|
16160
|
+
|
|
15954
16161
|
let dragCloneCount = 0;
|
|
15955
|
-
const createDragClone = (element,
|
|
16162
|
+
const createDragClone = (element, grabPoint, reach) => {
|
|
15956
16163
|
const rect = element.getBoundingClientRect();
|
|
16164
|
+
// Over the element, or shifted to where the hand is (see measureReach).
|
|
16165
|
+
const left = reach ? rect.left + reach.x : rect.left;
|
|
16166
|
+
const top = reach ? rect.top + reach.y : rect.top;
|
|
15957
16167
|
|
|
15958
16168
|
const wrapper = document.createElement("div");
|
|
15959
16169
|
wrapper.setAttribute("navi-drag-clone-wrapper", "");
|
|
@@ -15965,13 +16175,26 @@ const createDragClone = (element, pointerEvent) => {
|
|
|
15965
16175
|
// Manual: it is opened and closed with the drag, and must survive an Escape
|
|
15966
16176
|
// or a click elsewhere (light dismiss would take it away mid-gesture).
|
|
15967
16177
|
wrapper.setAttribute("popover", "manual");
|
|
15968
|
-
|
|
15969
|
-
|
|
16178
|
+
wrapper.style.setProperty("--clone-top", `${top}px`);
|
|
16179
|
+
wrapper.style.setProperty("--clone-left", `${left}px`);
|
|
16180
|
+
wrapper.style.setProperty("--clone-width", `${rect.width}px`);
|
|
16181
|
+
wrapper.style.setProperty("--clone-height", `${rect.height}px`);
|
|
16182
|
+
if (reach) {
|
|
16183
|
+
// It flies there from the element's box, so the eye follows what was
|
|
16184
|
+
// picked up rather than seeing it appear under the finger (see the
|
|
16185
|
+
// stylesheet).
|
|
16186
|
+
wrapper.style.setProperty(
|
|
16187
|
+
"--clone-reach-from",
|
|
16188
|
+
`${-reach.x}px ${-reach.y}px`,
|
|
16189
|
+
);
|
|
16190
|
+
wrapper.setAttribute("data-reaching", "");
|
|
16191
|
+
}
|
|
16192
|
+
// Grab point within the copy — used as transform-origin so the
|
|
15970
16193
|
// scale expands from where the user clicked, not the element center.
|
|
15971
|
-
// These offsets are
|
|
16194
|
+
// These offsets are copy-relative so viewport coords are correct here.
|
|
15972
16195
|
wrapper.style.setProperty(
|
|
15973
16196
|
"--drag-origin",
|
|
15974
|
-
`${
|
|
16197
|
+
`${grabPoint.clientX - left}px ${grabPoint.clientY - top}px`,
|
|
15975
16198
|
);
|
|
15976
16199
|
const elementClone = element.cloneNode(true);
|
|
15977
16200
|
// A deep copy copies the ids too, and two elements answering to one id is a
|
|
@@ -21996,33 +22219,45 @@ const measureWidestChildRow = (el) => {
|
|
|
21996
22219
|
const borderLeft = parseFloat(containerStyle.borderLeftWidth);
|
|
21997
22220
|
const borderRight = parseFloat(containerStyle.borderRightWidth);
|
|
21998
22221
|
|
|
21999
|
-
//
|
|
22000
|
-
|
|
22222
|
+
// Rows are found by vertical overlap, not by top: in an "align-items: center"
|
|
22223
|
+
// row, a child taller than its neighbours (a 1px border is enough) starts
|
|
22224
|
+
// higher than them and would open a row of its own.
|
|
22225
|
+
const rows = [];
|
|
22001
22226
|
for (const child of children) {
|
|
22002
22227
|
const rect = child.getBoundingClientRect();
|
|
22003
22228
|
if (rect.width === 0 && rect.height === 0) {
|
|
22004
22229
|
continue;
|
|
22005
22230
|
}
|
|
22006
|
-
const
|
|
22007
|
-
|
|
22008
|
-
|
|
22009
|
-
|
|
22010
|
-
|
|
22011
|
-
|
|
22012
|
-
|
|
22013
|
-
}
|
|
22014
|
-
|
|
22015
|
-
|
|
22016
|
-
|
|
22231
|
+
const row = rows.find((candidate) => sharesLine(candidate, rect));
|
|
22232
|
+
if (row === undefined) {
|
|
22233
|
+
rows.push({
|
|
22234
|
+
top: rect.top,
|
|
22235
|
+
bottom: rect.bottom,
|
|
22236
|
+
left: rect.left,
|
|
22237
|
+
right: rect.right,
|
|
22238
|
+
});
|
|
22239
|
+
continue;
|
|
22240
|
+
}
|
|
22241
|
+
if (rect.top < row.top) {
|
|
22242
|
+
row.top = rect.top;
|
|
22243
|
+
}
|
|
22244
|
+
if (rect.bottom > row.bottom) {
|
|
22245
|
+
row.bottom = rect.bottom;
|
|
22246
|
+
}
|
|
22247
|
+
if (rect.left < row.left) {
|
|
22248
|
+
row.left = rect.left;
|
|
22249
|
+
}
|
|
22250
|
+
if (rect.right > row.right) {
|
|
22251
|
+
row.right = rect.right;
|
|
22017
22252
|
}
|
|
22018
22253
|
}
|
|
22019
22254
|
|
|
22020
|
-
if (
|
|
22255
|
+
if (rows.length <= 1) {
|
|
22021
22256
|
return null;
|
|
22022
22257
|
}
|
|
22023
22258
|
|
|
22024
22259
|
let widestRowWidth = 0;
|
|
22025
|
-
for (const { left, right } of
|
|
22260
|
+
for (const { left, right } of rows) {
|
|
22026
22261
|
const rowWidth = right - left;
|
|
22027
22262
|
if (rowWidth > widestRowWidth) {
|
|
22028
22263
|
widestRowWidth = rowWidth;
|