@jsenv/navi 0.29.194 → 0.29.195
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/dev/jsenv_navi.js +160 -74
- package/dist/dev/jsenv_navi.js.map +6 -3
- package/dist/jsenv_navi.js +139 -48
- package/dist/jsenv_navi.js.map +6 -3
- package/docs/drag_to_travel.md +2 -2
- package/docs/interactions.md +133 -51
- package/package.json +2 -2
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { installImportMetaCssBuild, windowHeightSignal, windowWidthSignal, visualViewportHeightSignal, visualViewportWidthSignal, getAppHeight, getAppWidth, coarsePointerSignal, smallTouchScreenSignal } from "./jsenv_navi_side_effects.js";
|
|
6
6
|
export { disableVirtualKeyboardOverlay } from "./jsenv_navi_side_effects.js";
|
|
7
|
-
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, scrollIntoViewThroughScrollables, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, keepTouchRefusable, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, scrollIntoViewScoped, initFocusGroup, isTouchDrivenEvent, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, getVirtualKeyboardOverlayHeight, onAncestorReopen, isPressDisputedByDrag, canScroll, measureWidestChildRow, performTabNavigation, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
7
|
+
import { elementIsFocusable, createIterableWeakSet, dispatchInternalCustomEvent, dispatchCustomEvent, getVisuallyVisibleInfo, getFirstVisuallyVisibleAncestor, getElementSignature, createPubSub, findEvent, createValueEffect, findFocusDelegateTarget, findFocusable, scrollIntoViewThroughScrollables, allowWheelThrough, dispatchPublicCustomEvent, resolveCSSColor, ELEMENT_SIZE_CHANGE, findSelfOrAncestorFixedPosition, visibleRectEffect, pickPositionRelativeTo, getBorderSizes, getPaddingSizes, applyNewPosition, measureLongestVisualLineWidth, chainEvent, keepTouchRefusable, waitForPressHeld, suppressClickAfterGesture, startDragToTravel, markDragSource, startDragTo, installPanZoom, createEventGroupLogger, getKeyboardEventDefaultAction, activeElementSignal, normalizeStyle, mergeOneStyle, getPositionedParent, normalizeStyles, createGroupTransitionController, getBorderRadius, preventIntermediateScrollbar, createOpacityTransition, watchWheelTravel, scrollRoomTowards, getScrollContainer, closestOpenableAncestor, isAncestorOpen, isDisplayedDespiteClosedAncestor, observeAncestorOpenState, getAncestorOpenType, findBefore, findAfter, resolveCSSSize, hasCSSSizeUnit, releaseWheelGesture, getScrollIntoViewScopedOffsets, wheelGestureIsTakenFrom, claimWheelGesture, scrollIntoViewScoped, initFocusGroup, isTouchDrivenEvent, stringifyStyle as stringifyStyle$1, resolveOklchLightness, contrastColor, parsePositionArea, snapToPixel, trapFocusInside, trapScrollInside, getVirtualKeyboardOverlayHeight, onAncestorReopen, isPressDisputedByDrag, canScroll, measureWidestChildRow, performTabNavigation, dragAfterIntent, stickyAsRelativeCoords, createDragToMoveGestureController, getDropTargetInfo, setStyles, useActiveElement } from "@jsenv/dom";
|
|
8
8
|
export { chainEvent, clickIsSuppressed, contrastColor, createDragGestureController, dragAfterIntent, findEvent, markDragSource, startDragTo } from "@jsenv/dom";
|
|
9
9
|
import { signal, computed, effect, untracked, batch, useComputed, useSignal } from "@preact/signals";
|
|
10
10
|
import { isValidElement, createContext, render, h, toChildArray, options, cloneElement, Fragment as Fragment$1 } from "preact";
|
|
@@ -10500,26 +10500,31 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10500
10500
|
};
|
|
10501
10501
|
|
|
10502
10502
|
/**
|
|
10503
|
-
* `move`, `reorder`, `land`, `toss` — one grab, and what letting go of
|
|
10503
|
+
* `move`, `reorder`, `land`, `toss`, `leave` — one grab, and what letting go of
|
|
10504
|
+
* it means.
|
|
10504
10505
|
*
|
|
10505
|
-
* All
|
|
10506
|
+
* All five are the same gesture: the element is picked up and carried. What
|
|
10506
10507
|
* differs is the answer at the release, so one detector reads them all — it is one
|
|
10507
10508
|
* press, and something has to arbitrate it.
|
|
10508
10509
|
*
|
|
10509
10510
|
* interactions={{ reorder: moveBefore, toss: remove }}
|
|
10510
10511
|
* interactions={{ land: swapPlaces }}
|
|
10511
|
-
* interactions={{ move: remember }}
|
|
10512
|
+
* interactions={{ move: remember, leave: remove }}
|
|
10512
10513
|
*
|
|
10513
|
-
* `toss`
|
|
10514
|
-
* changes places, the same task thrown far and fast is gotten rid
|
|
10515
|
-
*
|
|
10516
|
-
*
|
|
10517
|
-
*
|
|
10514
|
+
* `toss` and `leave` each combine with `reorder` and with `land`: a task dragged
|
|
10515
|
+
* onto another changes places, the same task thrown far and fast is gotten rid
|
|
10516
|
+
* of, a marker let go of off its plan is removed. `leave` combines with `move` as
|
|
10517
|
+
* well. `move`, `reorder` and `land` do not combine with each other — an element
|
|
10518
|
+
* either goes where it is put, takes a place in a list, or comes down on a place,
|
|
10519
|
+
* and no two of those answers can both be true of one release.
|
|
10518
10520
|
*
|
|
10519
10521
|
* `move` carries the element ITSELF and leaves it where it was put; the others
|
|
10520
10522
|
* carry a copy and put the original back. That is the same difference said in
|
|
10521
10523
|
* layout terms: something moved has a new place of its own, something reordered
|
|
10522
|
-
* had its place taken by the list.
|
|
10524
|
+
* had its place taken by the list. Where that place is KEPT is the answer's:
|
|
10525
|
+
* an application that redraws the element from state while answering (a new
|
|
10526
|
+
* `left`/`top`) owns the position from then on, and the drag's own translate
|
|
10527
|
+
* goes; one that draws nothing leaves it to the element, where it is baked in.
|
|
10523
10528
|
*
|
|
10524
10529
|
* `reorder` VS `land`: both come down on an item, and what separates them is what
|
|
10525
10530
|
* a place IS. A row of a list is a place BETWEEN two others — free by construction,
|
|
@@ -10535,9 +10540,8 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10535
10540
|
* }}}
|
|
10536
10541
|
*
|
|
10537
10542
|
* `toId` is an element and never null: a copy over nothing is a release that meant
|
|
10538
|
-
* nothing, and the interaction does not happen at all — unless the element
|
|
10539
|
-
* `
|
|
10540
|
-
* meaning of its own.
|
|
10543
|
+
* nothing, and the interaction does not happen at all — unless the element
|
|
10544
|
+
* declares `leave` (see below), which gives that release a meaning of its own.
|
|
10541
10545
|
*
|
|
10542
10546
|
* WHERE ON IT, in `x`, `y`, `width`, `height`: the box the copy came down in,
|
|
10543
10547
|
* measured inside the place — its border and its scroll taken out. A place that is
|
|
@@ -10574,15 +10578,30 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10574
10578
|
* <Plan id="plan" data-droppable>…</Plan>
|
|
10575
10579
|
* </div>
|
|
10576
10580
|
*
|
|
10577
|
-
*
|
|
10578
|
-
*
|
|
10579
|
-
*
|
|
10580
|
-
*
|
|
10581
|
-
*
|
|
10582
|
-
*
|
|
10583
|
-
* that ends ON it has not asked for the
|
|
10584
|
-
*
|
|
10585
|
-
*
|
|
10581
|
+
* LET GO OF AWAY FROM EVERY PLACE: `leave`. A throw is a GESTURE — far and fast,
|
|
10582
|
+
* the flick that gets rid of a row, judged before any landing. A release outside
|
|
10583
|
+
* is a PLACE — the hand let go with nothing under the thing, judged after a
|
|
10584
|
+
* landing was looked for. They share the outcome an application usually attaches
|
|
10585
|
+
* to them and nothing else, so each has its name: `toss` is the throw, `leave` is
|
|
10586
|
+
* the release outside, and neither reads the other's rules — there is no speed to
|
|
10587
|
+
* a release, and on a plan a fast drag that ends ON it has not asked for the
|
|
10588
|
+
* thing to go.
|
|
10589
|
+
*
|
|
10590
|
+
* interactions={{
|
|
10591
|
+
* move: (event) => remember(event.detail.x, event.detail.y),
|
|
10592
|
+
* leave: () => remove(id),
|
|
10593
|
+
* }}
|
|
10594
|
+
*
|
|
10595
|
+
* Beside `land` or `reorder`, "outside" is away from every place. Beside `move`
|
|
10596
|
+
* — the element itself travels, and nothing is a place — it is outside the
|
|
10597
|
+
* surface the element stands in: the nearest `data-droppable` ancestor, or,
|
|
10598
|
+
* without one, what can be seen of the scroll container. Either way it is judged
|
|
10599
|
+
* on the element's box no longer overlapping it, not on the pointer, which is
|
|
10600
|
+
* still well inside the frame when a 30px marker has just left it. The detail is
|
|
10601
|
+
* `toss`'s, `{ id, x, y }`, the distance travelled being what an exit is animated
|
|
10602
|
+
* with. A refused `leave` travels back, as a refused `move` does; picked up and
|
|
10603
|
+
* put straight back down stays a cancel — it has to have gone somewhere to be
|
|
10604
|
+
* away from anything.
|
|
10586
10605
|
*
|
|
10587
10606
|
* Nothing of the gesture is decided here. `startDragTo` owns all of it — the
|
|
10588
10607
|
* copy carried above the page while the original keeps its place in the layout, the
|
|
@@ -10630,7 +10649,7 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10630
10649
|
*
|
|
10631
10650
|
* interactions={{ toss: remove, grab: () => navigator.vibrate?.(10) }}
|
|
10632
10651
|
*
|
|
10633
|
-
* The
|
|
10652
|
+
* The five above all answer the RELEASE, and between the press and the release
|
|
10634
10653
|
* there is one instant that counts for the hand making the gesture: the one where
|
|
10635
10654
|
* the object stops being pressed and starts being held. `grab` is that instant,
|
|
10636
10655
|
* and it is the same one whichever way the drag was entered — a finger held still,
|
|
@@ -10644,7 +10663,7 @@ const swipeTypeOf = (axis, pulled) => {
|
|
|
10644
10663
|
*
|
|
10645
10664
|
* It is told, not asked: `grab` reports, so what it returns is not waited on and
|
|
10646
10665
|
* preventing its event does not call the gesture off. And it is not an interaction
|
|
10647
|
-
* on its own — declared without one of the
|
|
10666
|
+
* on its own — declared without one of the five above there is no gesture for it
|
|
10648
10667
|
* to be the beginning of.
|
|
10649
10668
|
*
|
|
10650
10669
|
* A `longpress` needs nothing of this: it already happens at the moment the hold
|
|
@@ -10664,6 +10683,8 @@ const REORDER = "reorder";
|
|
|
10664
10683
|
// for a file being dropped on the page would get this one and read it as such.
|
|
10665
10684
|
const LAND = "land";
|
|
10666
10685
|
const TOSS = "toss";
|
|
10686
|
+
// Let go of away from every place — not a throw, which is judged on its speed.
|
|
10687
|
+
const LEAVE = "leave";
|
|
10667
10688
|
// The moment the press stops being a press and becomes a hold on the object.
|
|
10668
10689
|
const GRAB = "grab";
|
|
10669
10690
|
|
|
@@ -10680,14 +10701,9 @@ const DROP_CONTAINER_ATTRIBUTE = "data-drop-container";
|
|
|
10680
10701
|
const AXIS_ATTRIBUTE = "data-drag-axis";
|
|
10681
10702
|
const DELAY_ATTRIBUTE = "data-drag-delay";
|
|
10682
10703
|
const SLOP_ATTRIBUTE = "data-drag-slop";
|
|
10683
|
-
const THRESHOLD_ATTRIBUTE = "data-drag-threshold";
|
|
10704
|
+
const THRESHOLD_ATTRIBUTE$1 = "data-drag-threshold";
|
|
10684
10705
|
const TOSS_DISTANCE_ATTRIBUTE = "data-toss-distance";
|
|
10685
10706
|
const TOSS_SPEED_ATTRIBUTE = "data-toss-speed";
|
|
10686
|
-
// How a toss is made here: "throw" (far and fast), "release-outside" (let go of
|
|
10687
|
-
// away from every place), or both.
|
|
10688
|
-
const TOSS_BY_ATTRIBUTE = "data-toss-by";
|
|
10689
|
-
const TOSS_BY_DEFAULT = "throw";
|
|
10690
|
-
const TOSS_WAYS = ["throw", "release-outside"];
|
|
10691
10707
|
|
|
10692
10708
|
defineInteractionDetector({
|
|
10693
10709
|
name: "drag",
|
|
@@ -10696,6 +10712,7 @@ defineInteractionDetector({
|
|
|
10696
10712
|
type === REORDER ||
|
|
10697
10713
|
type === LAND ||
|
|
10698
10714
|
type === TOSS ||
|
|
10715
|
+
type === LEAVE ||
|
|
10699
10716
|
type === GRAB,
|
|
10700
10717
|
// The press is the beginning of the gesture, not an answer: nothing may read
|
|
10701
10718
|
// it until it is known whether the hand is dragging or just pressing.
|
|
@@ -10705,12 +10722,13 @@ defineInteractionDetector({
|
|
|
10705
10722
|
const canReorder = types.includes(REORDER);
|
|
10706
10723
|
const canLand = types.includes(LAND);
|
|
10707
10724
|
const canToss = types.includes(TOSS);
|
|
10708
|
-
|
|
10725
|
+
const canLeave = types.includes(LEAVE);
|
|
10726
|
+
if (!canMove && !canReorder && !canLand && !canToss && !canLeave) {
|
|
10709
10727
|
// Only "grab": there is no gesture to be taken by, so there is no moment to
|
|
10710
10728
|
// be told about either.
|
|
10711
10729
|
{
|
|
10712
10730
|
console.warn(
|
|
10713
|
-
`interactions: "${GRAB}" says when a drag takes hold, so it needs a drag to say it about. Declare it beside "${MOVE}", "${REORDER}", "${LAND}" or "${
|
|
10731
|
+
`interactions: "${GRAB}" says when a drag takes hold, so it needs a drag to say it about. Declare it beside "${MOVE}", "${REORDER}", "${LAND}", "${TOSS}" or "${LEAVE}".`,
|
|
10714
10732
|
);
|
|
10715
10733
|
}
|
|
10716
10734
|
return undefined;
|
|
@@ -10726,7 +10744,7 @@ defineInteractionDetector({
|
|
|
10726
10744
|
const other = canLand ? LAND : canReorder ? REORDER : TOSS;
|
|
10727
10745
|
const instead =
|
|
10728
10746
|
other === TOSS
|
|
10729
|
-
? ` Something that
|
|
10747
|
+
? ` Something that moves in place AND goes away when dragged off its surface declares "${LEAVE}" beside "${MOVE}": a release outside the surface is what "${LEAVE}" answers, and it is not a throw.`
|
|
10730
10748
|
: "";
|
|
10731
10749
|
console.warn(
|
|
10732
10750
|
`interactions: "${MOVE}" and "${other}" cannot both answer one release — "${MOVE}" leaves the element where the hand put it, "${other}" carries a copy and puts the original back. "${other}" wins here, so the element never travels.${instead}`,
|
|
@@ -10744,34 +10762,23 @@ defineInteractionDetector({
|
|
|
10744
10762
|
axisHolder?.getAttribute(AXIS_ATTRIBUTE) ||
|
|
10745
10763
|
// A list runs one way, and reordering walks it. Anything else goes wherever
|
|
10746
10764
|
// the hand takes it: a board has places all around, a thing put somewhere has
|
|
10747
|
-
// two axes to be put along,
|
|
10748
|
-
|
|
10749
|
-
|
|
10750
|
-
//
|
|
10751
|
-
// gesture is about, and it is what holds the two sides of it
|
|
10765
|
+
// two axes to be put along, a throw goes where it was thrown and a thing
|
|
10766
|
+
// that leaves goes out by whichever edge.
|
|
10767
|
+
(canReorder && !canLand && !canToss && !canLeave ? "y" : "xy");
|
|
10768
|
+
// Where the places are, read at setup for the same reason as the axes: they
|
|
10769
|
+
// are what the gesture is about, and it is what holds the two sides of it
|
|
10770
|
+
// that says them.
|
|
10752
10771
|
const dropContainer = element.closest(`[${DROP_CONTAINER_ATTRIBUTE}]`);
|
|
10753
|
-
|
|
10754
|
-
|
|
10755
|
-
|
|
10756
|
-
|
|
10757
|
-
.
|
|
10758
|
-
|
|
10759
|
-
|
|
10760
|
-
|
|
10761
|
-
|
|
10762
|
-
|
|
10763
|
-
`interactions: "${way}" is not a way a toss is made. ${TOSS_BY_ATTRIBUTE} takes "${TOSS_WAYS.join('", "')}", or both.`,
|
|
10764
|
-
);
|
|
10765
|
-
}
|
|
10766
|
-
}
|
|
10767
|
-
if (
|
|
10768
|
-
tossBy.includes("release-outside") &&
|
|
10769
|
-
(!canToss || (!canReorder && !canLand))
|
|
10770
|
-
) {
|
|
10771
|
-
console.warn(
|
|
10772
|
-
`interactions: ${TOSS_BY_ATTRIBUTE}="release-outside" makes a release away from every place mean the thing is gotten rid of, so it needs both "${TOSS}" and places to be away from. Declare "${TOSS}" beside "${REORDER}" or "${LAND}".`,
|
|
10773
|
-
);
|
|
10774
|
-
}
|
|
10772
|
+
// What a `leave` is outside of when nothing is a place: the surface the
|
|
10773
|
+
// element stands in. Looked for above the parent — the element itself may be
|
|
10774
|
+
// a place of its own (a piece that receives), which is not what it is inside.
|
|
10775
|
+
const outsideOf =
|
|
10776
|
+
element.parentElement.closest(`[${DROPPABLE_ATTRIBUTE}]`) || undefined;
|
|
10777
|
+
if (canLeave && !canLand && !canReorder && !outsideOf) {
|
|
10778
|
+
console.warn(
|
|
10779
|
+
`interactions: "${LEAVE}" is judged against the surface this element stands in, and nothing above it is marked ${DROPPABLE_ATTRIBUTE} — so it is judged against what can be seen of the scroll container, which on a page is the window. Mark the surface it leaves.`,
|
|
10780
|
+
element,
|
|
10781
|
+
);
|
|
10775
10782
|
}
|
|
10776
10783
|
|
|
10777
10784
|
if (canReorder) {
|
|
@@ -10795,7 +10802,7 @@ defineInteractionDetector({
|
|
|
10795
10802
|
const onPointerDown = (pointerDownEvent) => {
|
|
10796
10803
|
if (canLand && !placesLookedFor) {
|
|
10797
10804
|
placesLookedFor = true;
|
|
10798
|
-
warnWhenNothingToLandOn(element, dropContainer,
|
|
10805
|
+
warnWhenNothingToLandOn(element, dropContainer, canLeave);
|
|
10799
10806
|
}
|
|
10800
10807
|
// What this element says a release can mean. The gesture then runs only what
|
|
10801
10808
|
// those need — no copy for a move, no drop hint for something that can only
|
|
@@ -10809,6 +10816,7 @@ defineInteractionDetector({
|
|
|
10809
10816
|
? `[${REORDERABLE_ATTRIBUTE}]`
|
|
10810
10817
|
: undefined,
|
|
10811
10818
|
containerElement: dropContainer || undefined,
|
|
10819
|
+
outsideOf,
|
|
10812
10820
|
getItemId: (itemElement) => itemElement.id,
|
|
10813
10821
|
direction: { x: axes.includes("x"), y: axes.includes("y") },
|
|
10814
10822
|
// Where it may go, said in the DOM. A thing that is put somewhere stays
|
|
@@ -10816,21 +10824,20 @@ defineInteractionDetector({
|
|
|
10816
10824
|
// the scrollable area can be far larger than the box, and "inside the box"
|
|
10817
10825
|
// is what a hand expects). `data-drag-free` lifts that, and so does a
|
|
10818
10826
|
// named container of places: they are somewhere else by construction, and
|
|
10819
|
-
// a copy kept in its own scroll area could never reach them.
|
|
10820
|
-
//
|
|
10821
|
-
//
|
|
10827
|
+
// a copy kept in its own scroll area could never reach them. So does
|
|
10828
|
+
// "leave": a thing let go of outside has to be able to get there. Left
|
|
10829
|
+
// alone for a throw, which frees the area on its own.
|
|
10822
10830
|
areaConstraint:
|
|
10823
|
-
dropContainer || element.closest(`[data-drag-free]`)
|
|
10831
|
+
dropContainer || element.closest(`[data-drag-free]`) || canLeave
|
|
10824
10832
|
? "none"
|
|
10825
10833
|
: canMove
|
|
10826
10834
|
? "scrollport"
|
|
10827
10835
|
: undefined,
|
|
10828
|
-
threshold: readConfig(THRESHOLD_ATTRIBUTE, undefined),
|
|
10836
|
+
threshold: readConfig(THRESHOLD_ATTRIBUTE$1, undefined),
|
|
10829
10837
|
longPressDelay: readConfig(DELAY_ATTRIBUTE, undefined),
|
|
10830
10838
|
longPressSlop: readConfig(SLOP_ATTRIBUTE, undefined),
|
|
10831
10839
|
tossDistance: readConfig(TOSS_DISTANCE_ATTRIBUTE, undefined),
|
|
10832
10840
|
tossSpeed: readConfig(TOSS_SPEED_ATTRIBUTE, undefined),
|
|
10833
|
-
tossBy,
|
|
10834
10841
|
// The one moment the gesture has that is not a release. Said here rather
|
|
10835
10842
|
// than from the press that led to it, because the press is only one of the
|
|
10836
10843
|
// two ways in: a finger holds still, a mouse travels a few pixels, and it
|
|
@@ -10844,7 +10851,7 @@ defineInteractionDetector({
|
|
|
10844
10851
|
});
|
|
10845
10852
|
}
|
|
10846
10853
|
: undefined,
|
|
10847
|
-
// Handed straight back in
|
|
10854
|
+
// Handed straight back in every case: what `trigger` returns is a
|
|
10848
10855
|
// promise while the answer is still going, which is what the gesture waits
|
|
10849
10856
|
// on before it lets go of what it carries.
|
|
10850
10857
|
onReorder: (fromId, toId, syncCloneWithDropTarget) =>
|
|
@@ -10861,6 +10868,8 @@ defineInteractionDetector({
|
|
|
10861
10868
|
x: gestureInfo.layout.xDelta,
|
|
10862
10869
|
y: gestureInfo.layout.yDelta,
|
|
10863
10870
|
}),
|
|
10871
|
+
onLeave: ({ x, y }) =>
|
|
10872
|
+
trigger(LEAVE, pointerDownEvent, { id: element.id, x, y }),
|
|
10864
10873
|
onMove: ({ x, y }) => trigger(MOVE, pointerDownEvent, { x, y }),
|
|
10865
10874
|
});
|
|
10866
10875
|
};
|
|
@@ -10876,10 +10885,9 @@ defineInteractionDetector({
|
|
|
10876
10885
|
|
|
10877
10886
|
// A place is looked for INSIDE the container and nowhere else, so the surface a
|
|
10878
10887
|
// piece already stands on is not one of them — a search never finds what it starts
|
|
10879
|
-
// from. Nothing then happens at all, and
|
|
10880
|
-
//
|
|
10881
|
-
|
|
10882
|
-
const warnWhenNothingToLandOn = (element, dropContainer, tossBy) => {
|
|
10888
|
+
// from. Nothing then happens at all, and beside `leave` it is worse than nothing:
|
|
10889
|
+
// every release is away from every place, so every release is a leave.
|
|
10890
|
+
const warnWhenNothingToLandOn = (element, dropContainer, canLeave) => {
|
|
10883
10891
|
const container = dropContainer || element.parentElement;
|
|
10884
10892
|
if (!container) {
|
|
10885
10893
|
return;
|
|
@@ -10891,8 +10899,8 @@ const warnWhenNothingToLandOn = (element, dropContainer, tossBy) => {
|
|
|
10891
10899
|
return;
|
|
10892
10900
|
}
|
|
10893
10901
|
}
|
|
10894
|
-
const consequence =
|
|
10895
|
-
? ` Every release is then away from every place, which ${
|
|
10902
|
+
const consequence = canLeave
|
|
10903
|
+
? ` Every release is then away from every place, which "${LEAVE}" answers.`
|
|
10896
10904
|
: " Nothing answers a release.";
|
|
10897
10905
|
const droppableAround = element.parentElement?.closest(
|
|
10898
10906
|
`[${DROPPABLE_ATTRIBUTE}]`,
|
|
@@ -10910,6 +10918,71 @@ const warnWhenNothingToLandOn = (element, dropContainer, tossBy) => {
|
|
|
10910
10918
|
);
|
|
10911
10919
|
};
|
|
10912
10920
|
|
|
10921
|
+
/**
|
|
10922
|
+
* `pan`, `zoom` — a surface under the hand.
|
|
10923
|
+
*
|
|
10924
|
+
* <Box
|
|
10925
|
+
* interactions={{
|
|
10926
|
+
* pan: (event) => moveCenterBy(event.detail), // { x, y } since the last one
|
|
10927
|
+
* zoom: (event) => zoomBy(event.detail), // { factor, x, y }
|
|
10928
|
+
* }}
|
|
10929
|
+
* />
|
|
10930
|
+
*
|
|
10931
|
+
* Neither is an outcome: both are a stream, reported on every frame while the
|
|
10932
|
+
* hand is still moving, and navi otherwise names only what happens once (see
|
|
10933
|
+
* "A gesture whose product is a value" in docs/interactions.md). They are named
|
|
10934
|
+
* here because of what has to be settled BEFORE the press, which is what
|
|
10935
|
+
* `interactions` exists for: `touch-action` on the surface, said from a
|
|
10936
|
+
* stylesheet since a browser decides what a touch may do when it lands; the pan
|
|
10937
|
+
* stepping back for what is carried ACROSS the surface (a marker declaring
|
|
10938
|
+
* `move`, a handle) and for what answers the pointer on its own; the pinch not
|
|
10939
|
+
* beginning as a pan under its first finger; the wheel and the pinch writing
|
|
10940
|
+
* one `zoom`. A handle turned, a sun dragged around a plan have none of that to
|
|
10941
|
+
* arbitrate — the handle is the whole surface of the gesture — and stay
|
|
10942
|
+
* unnamed.
|
|
10943
|
+
*
|
|
10944
|
+
* `pan`'s detail is the movement since the previous `pan`, in px. `zoom`'s is
|
|
10945
|
+
* the factor (above 1 is in) and the point of the surface it is around,
|
|
10946
|
+
* measured inside its border — the point between the fingers, or under the
|
|
10947
|
+
* wheel. What a pixel of pan means in the application's coordinates, and
|
|
10948
|
+
* whether the zoom is continuous or stepped, is the application's.
|
|
10949
|
+
*
|
|
10950
|
+
* Declared alone, `zoom` leaves one pointer to whatever else reads it and takes
|
|
10951
|
+
* only two fingers and the wheel; `pan` alone leaves the wheel to the page.
|
|
10952
|
+
*
|
|
10953
|
+
* Nothing of the gesture is decided here — `installPanZoom` in @jsenv/dom owns
|
|
10954
|
+
* the pointers, the capture, the wheel burst and the click left behind. This
|
|
10955
|
+
* says which names the element answers with, and hands the numbers over.
|
|
10956
|
+
*/
|
|
10957
|
+
|
|
10958
|
+
|
|
10959
|
+
const PAN = "pan";
|
|
10960
|
+
const ZOOM = "zoom";
|
|
10961
|
+
// The same attribute a carried element reads: how far a pointer travels before
|
|
10962
|
+
// it is a gesture rather than a press.
|
|
10963
|
+
const THRESHOLD_ATTRIBUTE = "data-drag-threshold";
|
|
10964
|
+
|
|
10965
|
+
defineInteractionDetector({
|
|
10966
|
+
name: "surface",
|
|
10967
|
+
claims: (type) => type === PAN || type === ZOOM,
|
|
10968
|
+
// A press on the surface may be a tap, a hold or the beginning of a pan, and
|
|
10969
|
+
// nothing may read it as the first until the pointer has said which.
|
|
10970
|
+
disputesPress: true,
|
|
10971
|
+
setup: (element, trigger, { types, readConfig }) => {
|
|
10972
|
+
const canPan = types.includes(PAN);
|
|
10973
|
+
const canZoom = types.includes(ZOOM);
|
|
10974
|
+
return installPanZoom(element, {
|
|
10975
|
+
threshold: readConfig(THRESHOLD_ATTRIBUTE, undefined),
|
|
10976
|
+
onPan: canPan
|
|
10977
|
+
? ({ event, x, y }) => trigger(PAN, event, { x, y })
|
|
10978
|
+
: undefined,
|
|
10979
|
+
onZoom: canZoom
|
|
10980
|
+
? ({ event, factor, x, y }) => trigger(ZOOM, event, { factor, x, y })
|
|
10981
|
+
: undefined,
|
|
10982
|
+
});
|
|
10983
|
+
},
|
|
10984
|
+
});
|
|
10985
|
+
|
|
10913
10986
|
// used by form elements such as <input>, <select>, <textarea> to have their own action bound to a single parameter
|
|
10914
10987
|
// when inside a <form> the form params are updated when the form element single param is updated
|
|
10915
10988
|
const useActionBoundToOneParam = (action, paramsSignal) => {
|
|
@@ -20206,9 +20279,14 @@ const PSEUDO_STATE_CHILD_PROP_SET = new Set(["tabIndex", "tabindex"]);
|
|
|
20206
20279
|
* preventInitialTransition?: boolean,
|
|
20207
20280
|
* separator?: import("ignore:preact").ComponentChildren | ((index: number) => import("ignore:preact").ComponentChildren),
|
|
20208
20281
|
* selfInteractions?: string,
|
|
20282
|
+
* interactions?: { [type: string]: "request_action" | "request_ui_action" | ((event: Event) => void) | false | null | undefined },
|
|
20209
20283
|
* children?: import("ignore:preact").ComponentChildren,
|
|
20210
20284
|
* [key: string]: any,
|
|
20211
20285
|
* }>}
|
|
20286
|
+
* @param {object} [interactions] What this box answers, by interaction name
|
|
20287
|
+
* (see docs/interactions.md). A plain box has no wiring of its own: it does
|
|
20288
|
+
* nothing with `action` (that is a control's prop), so a click on it is
|
|
20289
|
+
* declared here like any other interaction: `interactions={{ click: fn }}`.
|
|
20212
20290
|
*/
|
|
20213
20291
|
const Box = props => {
|
|
20214
20292
|
const {
|
|
@@ -20348,6 +20426,14 @@ const computeBox = (props, parentBoxFlow) => {
|
|
|
20348
20426
|
rest[SELF_INTERACTIONS_ATTRIBUTE] = selfInteractionsAttributeValue(selfInteractions);
|
|
20349
20427
|
}
|
|
20350
20428
|
let as = asProp;
|
|
20429
|
+
if (Object.hasOwn(rest, "action")) {
|
|
20430
|
+
// A control (Button, Link, a field) takes `action` off its props before
|
|
20431
|
+
// reaching here, so an `action` still present is one nothing will run. A
|
|
20432
|
+
// string is a form's own attribute and stays.
|
|
20433
|
+
if (typeof rest.action !== "string") {
|
|
20434
|
+
console.warn(`Box: "action" is a control's prop and a plain box does nothing with it. To answer a click, declare it as an interaction: interactions={{ click: fn }}.`);
|
|
20435
|
+
}
|
|
20436
|
+
}
|
|
20351
20437
|
|
|
20352
20438
|
// A box that scrolls is what gives header/footer/body their meaning, and
|
|
20353
20439
|
// saying overflow="auto" is already saying it — no second prop for the same
|