@jsenv/navi 0.29.31 → 0.29.32

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.
@@ -12304,6 +12304,30 @@ const swipeTypeOf = (axis, pulled) => {
12304
12304
  * `view-transition-name` must be unique per document, so only the application can
12305
12305
  * name what moves.
12306
12306
  *
12307
+ * WHEN THE PRESS BECOMES A HOLD: `grab`.
12308
+ *
12309
+ * interactions={{ toss: remove, grab: () => navigator.vibrate?.(10) }}
12310
+ *
12311
+ * The three above all answer the RELEASE, and between the press and the release
12312
+ * there is one instant that counts for the hand making the gesture: the one where
12313
+ * the object stops being pressed and starts being held. `grab` is that instant,
12314
+ * and it is the same one whichever way the drag was entered — a finger held still,
12315
+ * a mouse travelled a few pixels.
12316
+ *
12317
+ * It matters most where it is least visible. On a screen the held object is under
12318
+ * the thumb that hides it, so the only feedback available is the one that is felt;
12319
+ * without it the hand waits, doubts the press was heard, and lets go too early. A
12320
+ * vibration is the usual answer, but nothing here is about vibration — a sound, a
12321
+ * class, a measure are the same moment.
12322
+ *
12323
+ * It is told, not asked: `grab` reports, so what it returns is not waited on and
12324
+ * preventing its event does not call the gesture off. And it is not an interaction
12325
+ * on its own — declared without one of the three above there is no gesture for it
12326
+ * to be the beginning of.
12327
+ *
12328
+ * A `longpress` needs nothing of this: it already happens at the moment the hold
12329
+ * is acquired rather than at the release (see interaction_press.js).
12330
+ *
12307
12331
  * What the copy LOOKS like is the application's too. A copy of a transparent
12308
12332
  * element is invisible — a row usually gets its background from the list around it,
12309
12333
  * which the copy has left — so it is dressed through the attributes the gesture
@@ -12314,6 +12338,8 @@ const swipeTypeOf = (axis, pulled) => {
12314
12338
  const MOVE = "move";
12315
12339
  const REORDER = "reorder";
12316
12340
  const TOSS = "toss";
12341
+ // The moment the press stops being a press and becomes a hold on the object.
12342
+ const GRAB = "grab";
12317
12343
 
12318
12344
  // What makes an element a place something can land, written by the detector itself.
12319
12345
  const REORDERABLE_ATTRIBUTE = "data-reorderable";
@@ -12329,11 +12355,16 @@ const TOSS_SPEED_ATTRIBUTE = "data-toss-speed";
12329
12355
 
12330
12356
  defineInteractionDetector({
12331
12357
  name: "drag",
12332
- claims: (type) => type === MOVE || type === REORDER || type === TOSS,
12358
+ claims: (type) =>
12359
+ type === MOVE || type === REORDER || type === TOSS || type === GRAB,
12333
12360
  setup: (element, trigger, { types, readConfig }) => {
12334
12361
  const canMove = types.includes(MOVE);
12335
12362
  const canReorder = types.includes(REORDER);
12336
12363
  const canToss = types.includes(TOSS);
12364
+ if (!canMove && !canReorder && !canToss) {
12365
+ return undefined;
12366
+ }
12367
+ const tellsWhenGrabbed = types.includes(GRAB);
12337
12368
  // Read at setup rather than at the press: a container can say it, and it is
12338
12369
  // what the gesture is about rather than something it discovers.
12339
12370
  const axisHolder = element.closest(`[${AXIS_ATTRIBUTE}]`);
@@ -12352,11 +12383,15 @@ defineInteractionDetector({
12352
12383
  // SURROUNDINGS scroll on, which for a list is the axis the list runs on.
12353
12384
  element.setAttribute("data-drag-source", axes === "x" ? "x" : "");
12354
12385
 
12386
+ // What a release can mean, which is not all of what was declared: "grab" is a
12387
+ // moment, not an outcome, and the gesture must not read it as one.
12388
+ const effects = types.filter((type) => type !== GRAB);
12389
+
12355
12390
  const onPointerDown = (pointerDownEvent) => {
12356
12391
  // What this element says a release can mean. The gesture then runs only what
12357
12392
  // those need — no copy for a move, no drop hint for something that can only
12358
12393
  // be thrown away.
12359
- startDragTo(pointerDownEvent, types, {
12394
+ startDragTo(pointerDownEvent, effects, {
12360
12395
  draggedElement: element,
12361
12396
  // Nothing to land on when nothing reorders.
12362
12397
  itemSelector: canReorder ? `[${REORDERABLE_ATTRIBUTE}]` : undefined,
@@ -12377,6 +12412,19 @@ defineInteractionDetector({
12377
12412
  longPressSlop: readConfig(SLOP_ATTRIBUTE, undefined),
12378
12413
  tossDistance: readConfig(TOSS_DISTANCE_ATTRIBUTE, undefined),
12379
12414
  tossSpeed: readConfig(TOSS_SPEED_ATTRIBUTE, undefined),
12415
+ // The one moment the gesture has that is not a release. Said here rather
12416
+ // than from the press that led to it, because the press is only one of the
12417
+ // two ways in: a finger holds still, a mouse travels a few pixels, and it
12418
+ // is the same instant — the object is now held. Nothing is done with what
12419
+ // comes back: this says something happened, it does not ask for work.
12420
+ onDragStart: tellsWhenGrabbed
12421
+ ? (gestureInfo) => {
12422
+ trigger(GRAB, pointerDownEvent, {
12423
+ pointerType: pointerDownEvent.pointerType,
12424
+ gestureInfo,
12425
+ });
12426
+ }
12427
+ : undefined,
12380
12428
  // Handed straight back in all three cases: what `trigger` returns is a
12381
12429
  // promise while the answer is still going, which is what the gesture waits
12382
12430
  // on before it lets go of what it carries.