@weasel-js/routing 1.5.2 → 1.6.1

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/react.js CHANGED
@@ -1,4 +1,4 @@
1
- import { createDispatcher, buildDepsFromRequires, validateActionId, validateActionDefaultBinding, scopeBindings, liveScope, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, isDev, reportRouteConflicts, dlog, isEditableTarget, clientToCanvasRect, openPointerSession, pointerGestureId, itemsFromDataTransfer, itemsFromClipboardData } from './chunk-H5AGTB2J.js';
1
+ import { createDispatcher, buildDepsFromRequires, validateActionId, validateActionDefaultBinding, scopeBindings, liveScope, offhandKeyFor, makeToolOffhandAction, buildToolOffhandBindings, isDev, reportRouteConflicts, dlog, isEditableTarget, clientToCanvasRect, openPointerSession, pointerGestureId, itemsFromDataTransfer, itemsFromClipboardData } from './chunk-VEC3ACV5.js';
2
2
  import { createContext, useState, useCallback, useMemo, useContext, useRef, useEffect } from 'react';
3
3
  import { jsx, Fragment } from 'react/jsx-runtime';
4
4
  import { resolveCursorTier } from '@weasel-js/cursor';
@@ -137,6 +137,7 @@ function useGestureDispatcher(opts) {
137
137
  const { canvasRef, actions, toolsById, enabled = true, keyboard = true, affordanceAt, classifyTarget, dispatcher: dispatcherOpt, clientToWorld, requestRedraw, paintedCursor, getRuleCtx, onDoubleClick, views, channels } = opts;
138
138
  const pointerChannel = channels?.pointer !== false;
139
139
  const wheelChannel = channels?.wheel !== false;
140
+ const pinchChannel = channels?.pinch !== false;
140
141
  const contextMenuChannel = channels?.contextMenu !== false;
141
142
  const ingestChannel = channels?.ingest !== false;
142
143
  const onDoubleClickRef = useRef(onDoubleClick);
@@ -232,7 +233,8 @@ function useGestureDispatcher(opts) {
232
233
  const ctxNow = () => ({
233
234
  ...ctxRef.current,
234
235
  depRegistry: routedDeps,
235
- getRuleCtx: routedRuleCtx
236
+ getRuleCtx: routedRuleCtx,
237
+ viewId: target().id
236
238
  });
237
239
  const canvas = canvasRef.current;
238
240
  const toWorld = (cx, cy) => {
@@ -261,6 +263,14 @@ function useGestureDispatcher(opts) {
261
263
  );
262
264
  return { centroid: toCanvasLocal(centroid), spread };
263
265
  };
266
+ let pinchLive = false;
267
+ let pinchScale = 1;
268
+ let pinchRotation = 0;
269
+ const endPinch = () => {
270
+ pinchLive = false;
271
+ pinchScale = 1;
272
+ pinchRotation = 0;
273
+ };
264
274
  let multiTouchStart = null;
265
275
  const TAP_THRESHOLD_PX = 8;
266
276
  const DRAG_THRESHOLD_PX = 4;
@@ -359,6 +369,7 @@ function useGestureDispatcher(opts) {
359
369
  heldKeys.delete(e.key);
360
370
  };
361
371
  const onWindowBlur = () => {
372
+ endPinch();
362
373
  for (const p of [...held.values()]) p.session.cancel();
363
374
  for (const key of heldKeys) {
364
375
  const ev = {
@@ -375,6 +386,11 @@ function useGestureDispatcher(opts) {
375
386
  heldKeys.clear();
376
387
  };
377
388
  const onWheel = (e) => {
389
+ if (pinchLive && e.ctrlKey) {
390
+ e.preventDefault();
391
+ e.stopPropagation();
392
+ return;
393
+ }
378
394
  routeAt(null, e.clientX, e.clientY);
379
395
  const rect = canvas?.getBoundingClientRect();
380
396
  const [localX, localY] = rect ? clientToCanvasRect(rect, e.clientX, e.clientY) : [e.clientX, e.clientY];
@@ -401,6 +417,57 @@ function useGestureDispatcher(opts) {
401
417
  e.stopPropagation();
402
418
  }
403
419
  };
420
+ const pinchEventOf = (e, scale, rotation) => {
421
+ const g = e;
422
+ const rect = canvas?.getBoundingClientRect();
423
+ const cx = typeof g.clientX === "number" ? g.clientX : rect ? rect.left + rect.width / 2 : 0;
424
+ const cy = typeof g.clientY === "number" ? g.clientY : rect ? rect.top + rect.height / 2 : 0;
425
+ routeAt(null, cx, cy);
426
+ const [localX, localY] = rect ? clientToCanvasRect(rect, cx, cy) : [cx, cy];
427
+ const hitPoint = toWorld(cx, cy);
428
+ const affordance = target().affordanceAt?.(hitPoint) ?? void 0;
429
+ const body = target().classifyTarget?.(hitPoint);
430
+ return {
431
+ kind: "pinch",
432
+ altKey: g.altKey === true,
433
+ ctrlKey: g.ctrlKey === true,
434
+ metaKey: g.metaKey === true,
435
+ shiftKey: g.shiftKey === true,
436
+ scale,
437
+ rotation,
438
+ clientX: localX,
439
+ clientY: localY,
440
+ ...affordance !== void 0 ? { affordance } : {},
441
+ ...body?.body !== void 0 ? { bodyTarget: body.body } : {},
442
+ ...body?.kind !== void 0 ? { bodyKind: body.kind } : {}
443
+ };
444
+ };
445
+ const onGestureStart = (e) => {
446
+ endPinch();
447
+ const probe = pinchEventOf(e, 1, 0);
448
+ if (dispatcherNow().resolveOnly(probe, ctxNow()) === null) return;
449
+ pinchLive = true;
450
+ e.preventDefault();
451
+ };
452
+ const onGestureChange = (e) => {
453
+ const g = e;
454
+ const scale = typeof g.scale === "number" && g.scale > 0 ? g.scale : pinchScale;
455
+ const rotation = typeof g.rotation === "number" ? g.rotation : pinchRotation;
456
+ const step = scale / pinchScale;
457
+ const turn = rotation - pinchRotation;
458
+ pinchScale = scale;
459
+ pinchRotation = rotation;
460
+ if (dispatch(pinchEventOf(e, step, turn)) === "handled") {
461
+ pinchLive = true;
462
+ e.preventDefault();
463
+ } else if (pinchLive) {
464
+ e.preventDefault();
465
+ }
466
+ };
467
+ const onGestureEnd = (e) => {
468
+ if (pinchLive) e.preventDefault();
469
+ endPinch();
470
+ };
404
471
  const onPointerDown = (e) => {
405
472
  if ((e.button ?? 0) !== 0) return;
406
473
  if (!canvas) return;
@@ -858,6 +925,11 @@ function useGestureDispatcher(opts) {
858
925
  canvas?.addEventListener("pointermove", onHoverMove);
859
926
  }
860
927
  if (wheelChannel) canvas?.addEventListener("wheel", onWheel, { passive: false });
928
+ if (pinchChannel) {
929
+ canvas?.addEventListener("gesturestart", onGestureStart);
930
+ canvas?.addEventListener("gesturechange", onGestureChange);
931
+ canvas?.addEventListener("gestureend", onGestureEnd);
932
+ }
861
933
  if (contextMenuChannel) canvas?.addEventListener("contextmenu", onContextMenu);
862
934
  if (ingestChannel) {
863
935
  canvas?.addEventListener("dragenter", onDragOver);
@@ -876,6 +948,9 @@ function useGestureDispatcher(opts) {
876
948
  window.removeEventListener("keyup", scheduleHoverCursorRefresh);
877
949
  canvas?.removeEventListener("pointerleave", onHoverPointerLeave);
878
950
  canvas?.removeEventListener("wheel", onWheel);
951
+ canvas?.removeEventListener("gesturestart", onGestureStart);
952
+ canvas?.removeEventListener("gesturechange", onGestureChange);
953
+ canvas?.removeEventListener("gestureend", onGestureEnd);
879
954
  canvas?.removeEventListener("pointerdown", onPointerDown);
880
955
  canvas?.removeEventListener("pointermove", onHoverMove);
881
956
  canvas?.removeEventListener("contextmenu", onContextMenu);
@@ -892,7 +967,7 @@ function useGestureDispatcher(opts) {
892
967
  held.clear();
893
968
  for (const d of allDispatchers()) d.cancelAll("cancel");
894
969
  };
895
- }, [enabled, keyboard, canvasRef, pointerChannel, wheelChannel, contextMenuChannel, ingestChannel]);
970
+ }, [enabled, keyboard, canvasRef, pointerChannel, wheelChannel, pinchChannel, contextMenuChannel, ingestChannel]);
896
971
  }
897
972
  var ActionsContext = createContext(null);
898
973
  function useMuted(base) {
@@ -1117,6 +1192,39 @@ function useAction(action) {
1117
1192
  return reg.register(action);
1118
1193
  }, [reg, action]);
1119
1194
  }
1195
+ function useOngoingAction(actionId) {
1196
+ const reg = useActionsRegistry();
1197
+ const regRef = useRef(reg);
1198
+ regRef.current = reg;
1199
+ const idRef = useRef(actionId);
1200
+ idRef.current = actionId;
1201
+ const ctrlRef = useRef(null);
1202
+ const edit = useMemo(() => {
1203
+ const end = (reason) => {
1204
+ const ctrl = ctrlRef.current;
1205
+ ctrlRef.current = null;
1206
+ ctrl?.end(reason);
1207
+ };
1208
+ return {
1209
+ input(params) {
1210
+ if (ctrlRef.current) ctrlRef.current.update(params);
1211
+ else ctrlRef.current = regRef.current?.begin(idRef.current, params) ?? null;
1212
+ },
1213
+ commit(params) {
1214
+ if (params !== void 0) {
1215
+ if (ctrlRef.current) ctrlRef.current.update(params);
1216
+ else ctrlRef.current = regRef.current?.begin(idRef.current, params) ?? null;
1217
+ }
1218
+ end("commit");
1219
+ },
1220
+ cancel() {
1221
+ end("cancel");
1222
+ }
1223
+ };
1224
+ }, []);
1225
+ useEffect(() => () => edit.commit(), [edit, actionId]);
1226
+ return edit;
1227
+ }
1120
1228
  function useContributions(opts) {
1121
1229
  const ctx = useActiveToolContext();
1122
1230
  const actionsRegistry = useActionsRegistry();
@@ -1313,6 +1421,6 @@ function useTools(opts) {
1313
1421
  );
1314
1422
  }
1315
1423
 
1316
- export { ActionsProvider, ActionsScope, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, DepRegistryProvider, useAction, useActionsRegistry, useActiveToolContext, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useOptionalActiveToolContext, useOptionalDepRegistry, useTools };
1424
+ export { ActionsProvider, ActionsScope, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, DepRegistryProvider, useAction, useActionsRegistry, useActiveToolContext, useContributions, useDepRegistry, useDepSource, useGestureDispatcher, useOngoingAction, useOptionalActiveToolContext, useOptionalDepRegistry, useTools };
1317
1425
  //# sourceMappingURL=react.js.map
1318
1426
  //# sourceMappingURL=react.js.map