@weasel-js/core 1.4.1 → 1.4.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,58 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - bfb0595: Run the last four drags in the kit on `openPointerSession`. Capture, pointer identity, teardown and recovery from a release that never arrives are now decided in one place for every pointerdown-to-pointerup lifecycle in the kit.
8
+
9
+ Fix a drag that silently dropped its commit. `openPointerSession` treated `lostpointercapture` as the end of the gesture, and Chrome releases capture implicitly a beat *before* it delivers `pointerup` — so a release already on its way arrived after the session had torn down its listeners, and the gesture ended as a cancel instead of a commit. Roughly three drags in four were lost this way in one measured consumer. Losing capture now ends a session only once the origin has left the document, which is the case the rule was written for: the session listens on the document, so capture is what retargets events, not what delivers them.
10
+
11
+ The gesture dispatcher opens a session per held pointer instead of tracking pointers itself. Two behavior changes come with that: a drag released outside the canvas now ends, where before only pointer capture made that work; and a fresh press on a pointer still believed held cancels the stale gesture rather than committing it at the new press's coordinates, since where it actually ended is unknown.
12
+
13
+ Two small breaking changes. `ThresholdDragOptions.onCancel` now fires only when a gesture ends without a release — a release below the threshold calls the new `onClick`. And in labkit, `useDragDrop`'s `startDrag` and `Palette`'s `onDragStart` take the React pointerdown event in place of a `Point`; a cancelled palette drag now drops nothing, where before it had no cancel path at all.
14
+
15
+ `startThresholdDrag` also takes an `origin` element, for a list whose grabbed row unmounts mid-drag and drops capture with it. `useReorderDragList` uses it and no longer carries its own copy of the threshold logic.
16
+ - 3b07b13: A scene write repaints the canvas instead of re-rendering `SceneCanvas`.
17
+
18
+ `SceneCanvas` held a `useSyncExternalStore` on the scene's version whose only
19
+ effect was to force a render — it discarded the value. Every mutation therefore
20
+ committed the whole canvas subtree, including for hosts that had asked not to
21
+ be re-rendered: `useScene(..., { subscribe: false })` gated the host's own
22
+ subscription but was invisible to `SceneCanvas`, which subscribed anyway. A
23
+ frame loop writing poses paid a React render per write.
24
+
25
+ It now subscribes for a repaint, the way the pose-override channel beside it
26
+ already did. The layers read the scene at paint time and `contentVersion` is a
27
+ getter, so nothing about drawing the new content needed the commit.
28
+
29
+ **This changes when scene-derived DOM updates.** DOM now lands on the render of
30
+ whoever subscribed for it, rather than riding along on the canvas's. In practice
31
+ every consumer already subscribes: `useScene` does by default, `SelectionPanel`
32
+ subscribes itself, and panels an app hangs beside the canvas re-render with the
33
+ host that owns the scene. A consumer that renders node data as DOM while
34
+ holding no subscription of its own — reading a `Scene` it got from somewhere
35
+ other than `useScene`, and relying on the canvas to re-render it — needs to
36
+ subscribe. Selection is unaffected: it reaches the render body through
37
+ `useSelection`'s own store subscription and still commits.
38
+
39
+ `docs/concepts.md` said a scene change leads with DOM. It no longer does, and
40
+ that section is rewritten.
41
+ - 8e9eb1d: Export `SpritesDrawCommand` and `SPRITE_STRIDE` from the main barrel.
42
+
43
+ They shipped in 1.4.1 reachable only from the `@weasel-js/core/renderer` subpath, because `src/index.ts` re-exports the renderer by name rather than with a star and only the renderer's own barrel was updated. Every other `DrawCommand` variant is nameable from `@weasel-js/core`, and a consumer cannot pack a sprite run without the stride constant.
44
+
45
+ `index.barrel.test.ts` now asserts that every `*DrawCommand` the renderer barrel names is named on the main barrel too, so the next variant cannot land half-exported.
46
+ - Updated dependencies [c93aa91]
47
+ - @weasel-js/text@1.4.2
48
+ - @weasel-js/cursor@1.4.2
49
+ - @weasel-js/font@1.4.2
50
+ - @weasel-js/geom@1.4.2
51
+ - @weasel-js/gestures@1.4.2
52
+ - @weasel-js/history@1.4.2
53
+ - @weasel-js/modes@1.4.2
54
+ - @weasel-js/paint@1.4.2
55
+
3
56
  ## 1.4.1
4
57
 
5
58
  ### Patch Changes
@@ -25,7 +25,7 @@ import { createHistory } from '@weasel-js/history';
25
25
  export * from '@weasel-js/history';
26
26
 
27
27
  // src/version.ts
28
- var VERSION = "1.4.1" ;
28
+ var VERSION = "1.4.2" ;
29
29
 
30
30
  // src/features/grid/roundToCell.ts
31
31
  function roundToCell(value, cellSize) {
@@ -6204,7 +6204,7 @@ function clientToCanvasRect(rect, clientX, clientY) {
6204
6204
  return [clientX - rect.left, clientY - rect.top];
6205
6205
  }
6206
6206
 
6207
- // src/interactions/gestures/pointerSession/recovery.ts
6207
+ // src/interactions/gestures/pointerSession/pointerSession.ts
6208
6208
  var LOST_CAPTURE_EVENT = "lostpointercapture";
6209
6209
  function reportsButtons(down) {
6210
6210
  return !!down.buttons;
@@ -6212,8 +6212,6 @@ function reportsButtons(down) {
6212
6212
  function isMissedRelease(move) {
6213
6213
  return move.buttons === 0;
6214
6214
  }
6215
-
6216
- // src/interactions/gestures/pointerSession/pointerSession.ts
6217
6215
  function openPointerSession(origin, down, cb, opts = {}) {
6218
6216
  const pointerId = down.pointerId;
6219
6217
  const doc = origin.ownerDocument ?? document;
@@ -6262,7 +6260,8 @@ function openPointerSession(origin, down, cb, opts = {}) {
6262
6260
  if (mine(e)) abort("superseded");
6263
6261
  }
6264
6262
  function onLostCapture(e) {
6265
- if (e.pointerId === pointerId) abort("lostcapture");
6263
+ if (e.pointerId !== pointerId) return;
6264
+ if (!origin.isConnected) abort("lostcapture");
6266
6265
  }
6267
6266
  if (opts.capture !== false) {
6268
6267
  try {
@@ -6510,14 +6509,14 @@ function startThresholdDrag(e, opts) {
6510
6509
  activated = true;
6511
6510
  opts.onActivate?.(ev);
6512
6511
  };
6513
- const session = openPointerSession(e.currentTarget, e, {
6512
+ const session = openPointerSession(opts.origin ?? e.currentTarget, e, {
6514
6513
  onMove: (ev) => {
6515
6514
  maybeActivate(ev);
6516
6515
  if (activated) opts.onMove(ev);
6517
6516
  },
6518
6517
  onEnd: (ev) => {
6519
6518
  if (activated) opts.onCommit(ev);
6520
- else opts.onCancel?.();
6519
+ else opts.onClick?.(ev);
6521
6520
  },
6522
6521
  onCancel: () => {
6523
6522
  opts.onCancel?.();
@@ -13472,7 +13471,7 @@ function withViewDeps(base, overlay) {
13472
13471
  };
13473
13472
  }
13474
13473
  function computeMultiTouchGeometry(positions) {
13475
- const pts = [...positions.values()];
13474
+ const pts = [...positions];
13476
13475
  if (pts.length < 2) {
13477
13476
  return { centroid: { x: 0, y: 0 }, spread: 0 };
13478
13477
  }
@@ -13599,14 +13598,13 @@ function useGestureDispatcher(opts) {
13599
13598
  return result;
13600
13599
  };
13601
13600
  const heldKeys = /* @__PURE__ */ new Set();
13602
- const activePointers = /* @__PURE__ */ new Set();
13603
- const buttonsReportedFor = /* @__PURE__ */ new Set();
13604
- const pointerPositions = /* @__PURE__ */ new Map();
13601
+ const held = /* @__PURE__ */ new Map();
13602
+ const heldGeometry = () => computeMultiTouchGeometry(
13603
+ [...held.values()].map((p) => p.pos)
13604
+ );
13605
13605
  let multiTouchStart = null;
13606
13606
  const TAP_THRESHOLD_PX = 8;
13607
13607
  const DRAG_THRESHOLD_PX = 4;
13608
- const bufferedDown = /* @__PURE__ */ new Map();
13609
- const lastPointerDown = /* @__PURE__ */ new Map();
13610
13608
  const LONG_PRESS_MS = 500;
13611
13609
  const longPressTimers = /* @__PURE__ */ new Map();
13612
13610
  const cancelLongPress = (pointerId) => {
@@ -13621,7 +13619,7 @@ function useGestureDispatcher(opts) {
13621
13619
  longPressTimers.clear();
13622
13620
  };
13623
13621
  const fireLongPress = (pointerId) => {
13624
- const down = lastPointerDown.get(pointerId);
13622
+ const down = held.get(pointerId)?.down;
13625
13623
  if (!down) return;
13626
13624
  const shared = {
13627
13625
  target: down.target,
@@ -13743,15 +13741,8 @@ function useGestureDispatcher(opts) {
13743
13741
  };
13744
13742
  const onPointerDown = (e) => {
13745
13743
  if ((e.button ?? 0) !== 0) return;
13746
- if (activePointers.has(e.pointerId)) onPointerUp(e);
13744
+ if (!canvas) return;
13747
13745
  routeDown(e.pointerId, e.clientX, e.clientY);
13748
- activePointers.add(e.pointerId);
13749
- if (reportsButtons(e)) buttonsReportedFor.add(e.pointerId);
13750
- pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
13751
- try {
13752
- canvas?.setPointerCapture?.(e.pointerId);
13753
- } catch {
13754
- }
13755
13746
  const worldPoint = { x: e.clientX, y: e.clientY };
13756
13747
  const affordance = target().affordanceAt?.(worldPoint) ?? void 0;
13757
13748
  const body = target().classifyTarget?.(worldPoint);
@@ -13775,23 +13766,35 @@ function useGestureDispatcher(opts) {
13775
13766
  ...bodyTarget !== void 0 ? { bodyTarget } : {},
13776
13767
  ...bodyKind !== void 0 ? { bodyKind } : {}
13777
13768
  };
13778
- bufferedDown.set(e.pointerId, { ev, clientX: e.clientX, clientY: e.clientY });
13779
- dispatch2({ ...ev, stage: "press" });
13780
- lastPointerDown.set(e.pointerId, {
13781
- target: e.target,
13782
- clientX: e.clientX,
13783
- clientY: e.clientY,
13784
- worldX: w.x,
13785
- worldY: w.y,
13786
- affordance,
13787
- bodyTarget,
13788
- bodyKind,
13789
- altKey: e.altKey,
13790
- ctrlKey: e.ctrlKey,
13791
- metaKey: e.metaKey,
13792
- shiftKey: e.shiftKey
13769
+ held.set(e.pointerId, {
13770
+ session: openPointerSession(canvas, e, {
13771
+ onMove: onPointerMove,
13772
+ onEnd: onPointerUp,
13773
+ onCancel: () => {
13774
+ onPointerCancel(e.pointerId);
13775
+ }
13776
+ }),
13777
+ pos: { x: e.clientX, y: e.clientY },
13778
+ // Deferred until the first past-threshold pointermove: a bare
13779
+ // press-and-release should fire `click`, not start a drag action.
13780
+ buffered: { ev, clientX: e.clientX, clientY: e.clientY },
13781
+ down: {
13782
+ target: e.target,
13783
+ clientX: e.clientX,
13784
+ clientY: e.clientY,
13785
+ worldX: w.x,
13786
+ worldY: w.y,
13787
+ affordance,
13788
+ bodyTarget,
13789
+ bodyKind,
13790
+ altKey: e.altKey,
13791
+ ctrlKey: e.ctrlKey,
13792
+ metaKey: e.metaKey,
13793
+ shiftKey: e.shiftKey
13794
+ }
13793
13795
  });
13794
- if ((e.pointerType === "touch" || e.pointerType === "pen") && activePointers.size === 1) {
13796
+ dispatch2({ ...ev, stage: "press" });
13797
+ if ((e.pointerType === "touch" || e.pointerType === "pen") && held.size === 1) {
13795
13798
  cancelLongPress(e.pointerId);
13796
13799
  longPressTimers.set(
13797
13800
  e.pointerId,
@@ -13802,18 +13805,18 @@ function useGestureDispatcher(opts) {
13802
13805
  }, LONG_PRESS_MS)
13803
13806
  );
13804
13807
  }
13805
- if (activePointers.size >= 2) {
13808
+ if (held.size >= 2) {
13806
13809
  cancelAllLongPress();
13807
- for (const id of activePointers) bufferedDown.delete(id);
13808
- const { centroid, spread } = computeMultiTouchGeometry(pointerPositions);
13810
+ for (const p of held.values()) p.buffered = null;
13811
+ const { centroid, spread } = heldGeometry();
13809
13812
  if (!multiTouchStart) {
13810
- multiTouchStart = { fingers: activePointers.size, centroid: { ...centroid } };
13813
+ multiTouchStart = { fingers: held.size, centroid: { ...centroid } };
13811
13814
  } else {
13812
- multiTouchStart.fingers = activePointers.size;
13815
+ multiTouchStart.fingers = held.size;
13813
13816
  }
13814
13817
  const mt = {
13815
13818
  kind: "multitouch",
13816
- fingers: activePointers.size,
13819
+ fingers: held.size,
13817
13820
  altKey: e.altKey,
13818
13821
  ctrlKey: e.ctrlKey,
13819
13822
  metaKey: e.metaKey,
@@ -13825,30 +13828,25 @@ function useGestureDispatcher(opts) {
13825
13828
  }
13826
13829
  };
13827
13830
  const onPointerMove = (e) => {
13828
- if (activePointers.has(e.pointerId) && buttonsReportedFor.has(e.pointerId) && isMissedRelease(e)) {
13829
- onPointerUp(e);
13830
- return;
13831
- }
13832
13831
  routeAt(e.pointerId, e.clientX, e.clientY);
13833
- if (activePointers.has(e.pointerId)) {
13834
- pointerPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
13835
- }
13836
- const buffered = bufferedDown.get(e.pointerId);
13837
- if (buffered) {
13832
+ const rec = held.get(e.pointerId);
13833
+ if (rec) rec.pos = { x: e.clientX, y: e.clientY };
13834
+ const buffered = rec?.buffered;
13835
+ if (rec && buffered) {
13838
13836
  const dx = e.clientX - buffered.clientX;
13839
13837
  const dy = e.clientY - buffered.clientY;
13840
13838
  if (Math.hypot(dx, dy) >= DRAG_THRESHOLD_PX) {
13841
- bufferedDown.delete(e.pointerId);
13839
+ rec.buffered = null;
13842
13840
  cancelLongPress(e.pointerId);
13843
13841
  dispatch2(buffered.ev);
13844
13842
  }
13845
13843
  }
13846
- const mtGestureId = `multitouch-${activePointers.size}`;
13847
- if (activePointers.size >= 2 && dispatcherNow().inFlight().has(mtGestureId)) {
13848
- const { centroid, spread } = computeMultiTouchGeometry(pointerPositions);
13844
+ const mtGestureId = `multitouch-${held.size}`;
13845
+ if (held.size >= 2 && dispatcherNow().inFlight().has(mtGestureId)) {
13846
+ const { centroid, spread } = heldGeometry();
13849
13847
  const mtEv = {
13850
13848
  kind: "multitouch",
13851
- fingers: activePointers.size,
13849
+ fingers: held.size,
13852
13850
  altKey: e.altKey,
13853
13851
  ctrlKey: e.ctrlKey,
13854
13852
  metaKey: e.metaKey,
@@ -13920,7 +13918,7 @@ function useGestureDispatcher(opts) {
13920
13918
  }
13921
13919
  function resolveHoverCursor() {
13922
13920
  if (!canvas || !lastHover) return;
13923
- if (activePointers.size > 0 || dispatcherNow().inFlight().size > 0) {
13921
+ if (held.size > 0 || dispatcherNow().inFlight().size > 0) {
13924
13922
  applyHoverCursor(dispatcherNow().inFlightCursor());
13925
13923
  return;
13926
13924
  }
@@ -13968,6 +13966,10 @@ function useGestureDispatcher(opts) {
13968
13966
  if (!disposed) refreshHoverCursor();
13969
13967
  }, 0);
13970
13968
  };
13969
+ const onHoverMove = (e) => {
13970
+ if (held.has(e.pointerId)) return;
13971
+ onPointerMove(e);
13972
+ };
13971
13973
  const onHoverPointerLeave = () => {
13972
13974
  lastHover = null;
13973
13975
  paintedCursorRef.current?.()?.clearPointer();
@@ -13976,21 +13978,21 @@ function useGestureDispatcher(opts) {
13976
13978
  const onPointerUp = (e) => {
13977
13979
  routeAt(e.pointerId, e.clientX, e.clientY);
13978
13980
  cancelLongPress(e.pointerId);
13979
- const prevSize = activePointers.size;
13980
- activePointers.delete(e.pointerId);
13981
- buttonsReportedFor.delete(e.pointerId);
13982
- pointerPositions.delete(e.pointerId);
13983
- const staysUnderThreshold = bufferedDown.delete(e.pointerId);
13984
- if (prevSize >= 2 && activePointers.size < 2) {
13981
+ const prevSize = held.size;
13982
+ const rec = held.get(e.pointerId);
13983
+ held.delete(e.pointerId);
13984
+ const staysUnderThreshold = rec?.buffered != null;
13985
+ if (prevSize >= 2 && held.size < 2) {
13985
13986
  const mtGestureId = `multitouch-${prevSize}`;
13986
13987
  if (dispatcherNow().inFlight().has(mtGestureId)) {
13987
13988
  dispatcherNow().cancelAll("commit");
13988
13989
  }
13989
13990
  const start = multiTouchStart;
13990
13991
  if (start) {
13991
- const finalPositions = new Map(pointerPositions);
13992
- finalPositions.set(e.pointerId, { x: e.clientX, y: e.clientY });
13993
- const { centroid } = computeMultiTouchGeometry(finalPositions);
13992
+ const { centroid } = computeMultiTouchGeometry([
13993
+ ...[...held.values()].map((p) => p.pos),
13994
+ { x: e.clientX, y: e.clientY }
13995
+ ]);
13994
13996
  const dx = centroid.x - start.centroid.x;
13995
13997
  const dy = centroid.y - start.centroid.y;
13996
13998
  if (Math.hypot(dx, dy) <= TAP_THRESHOLD_PX) {
@@ -14007,8 +14009,7 @@ function useGestureDispatcher(opts) {
14007
14009
  multiTouchStart = null;
14008
14010
  }
14009
14011
  }
14010
- const downForClick = lastPointerDown.get(e.pointerId);
14011
- const movedDuringDrag = downForClick ? downForClick.clientX !== e.clientX || downForClick.clientY !== e.clientY : true;
14012
+ const movedDuringDrag = rec ? rec.down.clientX !== e.clientX || rec.down.clientY !== e.clientY : true;
14012
14013
  const hadDragInFlight = dispatcherNow().inFlight().has(pointerGestureId(e.pointerId)) && movedDuringDrag;
14013
14014
  const wUp = toWorld2(e.clientX, e.clientY);
14014
14015
  const ev = {
@@ -14024,8 +14025,7 @@ function useGestureDispatcher(opts) {
14024
14025
  shiftKey: e.shiftKey
14025
14026
  };
14026
14027
  dispatch2(ev);
14027
- const down = lastPointerDown.get(e.pointerId);
14028
- lastPointerDown.delete(e.pointerId);
14028
+ const down = rec?.down;
14029
14029
  if (!hadDragInFlight && staysUnderThreshold && down) {
14030
14030
  const wClick = toWorld2(e.clientX, e.clientY);
14031
14031
  const clickEv = {
@@ -14082,30 +14082,24 @@ function useGestureDispatcher(opts) {
14082
14082
  if (!disposed) refreshHoverCursor();
14083
14083
  }, 0);
14084
14084
  };
14085
- const onPointerCancel = (e) => {
14086
- routeAt(e.pointerId, e.clientX, e.clientY);
14087
- cancelLongPress(e.pointerId);
14088
- activePointers.delete(e.pointerId);
14089
- buttonsReportedFor.delete(e.pointerId);
14090
- pointerPositions.delete(e.pointerId);
14091
- lastPointerDown.delete(e.pointerId);
14092
- bufferedDown.delete(e.pointerId);
14085
+ const onPointerCancel = (pointerId) => {
14086
+ if (disposed) return;
14087
+ const rec = held.get(pointerId);
14088
+ if (!rec) return;
14089
+ held.delete(pointerId);
14090
+ routeAt(pointerId, rec.pos.x, rec.pos.y);
14091
+ cancelLongPress(pointerId);
14093
14092
  multiTouchStart = null;
14094
14093
  const ev = {
14095
14094
  kind: "pointercancel",
14096
- pointerId: e.pointerId,
14097
- altKey: e.altKey,
14098
- ctrlKey: e.ctrlKey,
14099
- metaKey: e.metaKey,
14100
- shiftKey: e.shiftKey
14095
+ pointerId,
14096
+ altKey: rec.down.altKey,
14097
+ ctrlKey: rec.down.ctrlKey,
14098
+ metaKey: rec.down.metaKey,
14099
+ shiftKey: rec.down.shiftKey
14101
14100
  };
14102
14101
  dispatch2(ev);
14103
- routeRelease(e.pointerId);
14104
- };
14105
- const onLostCapture = (e) => {
14106
- const pe = e;
14107
- if (!activePointers.has(pe.pointerId)) return;
14108
- onPointerCancel(pe);
14102
+ routeRelease(pointerId);
14109
14103
  };
14110
14104
  const onContextMenu = (e) => {
14111
14105
  e.preventDefault();
@@ -14193,10 +14187,7 @@ function useGestureDispatcher(opts) {
14193
14187
  canvas?.addEventListener("pointerleave", onHoverPointerLeave);
14194
14188
  canvas?.addEventListener("wheel", onWheel, { passive: false });
14195
14189
  canvas?.addEventListener("pointerdown", onPointerDown);
14196
- canvas?.addEventListener("pointermove", onPointerMove);
14197
- canvas?.addEventListener("pointerup", onPointerUp);
14198
- canvas?.addEventListener("pointercancel", onPointerCancel);
14199
- canvas?.addEventListener(LOST_CAPTURE_EVENT, onLostCapture);
14190
+ canvas?.addEventListener("pointermove", onHoverMove);
14200
14191
  canvas?.addEventListener("contextmenu", onContextMenu);
14201
14192
  canvas?.addEventListener("dragenter", onDragOver);
14202
14193
  canvas?.addEventListener("dragover", onDragOver);
@@ -14214,10 +14205,7 @@ function useGestureDispatcher(opts) {
14214
14205
  canvas?.removeEventListener("pointerleave", onHoverPointerLeave);
14215
14206
  canvas?.removeEventListener("wheel", onWheel);
14216
14207
  canvas?.removeEventListener("pointerdown", onPointerDown);
14217
- canvas?.removeEventListener("pointermove", onPointerMove);
14218
- canvas?.removeEventListener("pointerup", onPointerUp);
14219
- canvas?.removeEventListener("pointercancel", onPointerCancel);
14220
- canvas?.removeEventListener(LOST_CAPTURE_EVENT, onLostCapture);
14208
+ canvas?.removeEventListener("pointermove", onHoverMove);
14221
14209
  canvas?.removeEventListener("contextmenu", onContextMenu);
14222
14210
  canvas?.removeEventListener("dragenter", onDragOver);
14223
14211
  canvas?.removeEventListener("dragover", onDragOver);
@@ -14228,6 +14216,8 @@ function useGestureDispatcher(opts) {
14228
14216
  clearHoverCursor();
14229
14217
  cancelAllLongPress();
14230
14218
  disposed = true;
14219
+ for (const p of held.values()) p.session.cancel();
14220
+ held.clear();
14231
14221
  for (const d of allDispatchers()) d.cancelAll("cancel");
14232
14222
  };
14233
14223
  }, [enabled, keyboard, canvasRef]);
@@ -25639,7 +25629,6 @@ function SceneCanvasInner(props, ref) {
25639
25629
  () => isSerialized(sceneInput) ? sceneFromJSON(sceneInput, {}) : null
25640
25630
  );
25641
25631
  const scene = bakedScene ?? sceneInput;
25642
- useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);
25643
25632
  const { view: viewProp, onViewChange: onViewChangeProp, defaultView, ...restProps } = rest;
25644
25633
  const internalCanvasRef = useRef(null);
25645
25634
  const canvasApiRef = useRef(null);
@@ -25670,6 +25659,9 @@ function SceneCanvasInner(props, ref) {
25670
25659
  useEffect(() => scene.overrides.subscribe(() => {
25671
25660
  canvasApiRef.current?.requestRedraw?.();
25672
25661
  }), [scene]);
25662
+ useEffect(() => scene.subscribe(() => {
25663
+ canvasApiRef.current?.requestRedraw?.();
25664
+ }), [scene]);
25673
25665
  const currentViewRef = useRef(
25674
25666
  viewProp ?? defaultView ?? { x: 0, y: 0, scale: { x: 1, y: 1 } }
25675
25667
  );
@@ -31268,5 +31260,5 @@ function mergeContributions(...bundles) {
31268
31260
  }
31269
31261
 
31270
31262
  export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, CanvasView, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_JOINT, IDENTITY_POSE_COMPOSITION, ImageIcon, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SPRITE_STRIDE, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TOOL_PREF_KINDS, TextIcon, UnionIcon, UnknownIcon, VERSION, VIEW_ANIMATION_KEY, WeaselProvider, WeaselRenderer, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createPaintedCursorState, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createVelocityTracker, createViewResolver, createViewportLayer, cubicBezierEasing, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, drawOneLayer, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, forEachCoalesced, frameRect, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, interpolateView, isBuiltinToolPref, isEditableTarget2 as isEditableTarget, isGradientFill, isLayerPainted, isLayerVisible, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linear, listMarkers, listPaintKinds, liveScope, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, mat3, matchAlignment, matchesKeyBinding, meanScale, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, openPointerSession, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerMarker, registerNodeShape, registerPaintKind, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveEasing, resolveFillPattern, resolveMarkerSize, resolveParams, resolvePatternSpec, resolveSkeleton, resolveStrokeWidth, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solid, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textCommandFromRuns, tileGrid, toHex8, translatePoseViaDescriptor, translateRectPose, trimPolyline, tweenPose, tweenVertexColors, unionAABB, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useVisibleRaf, useZoom, viewToMat3, viewToTransform, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, visualBoundsViaDescriptor, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
31271
- //# sourceMappingURL=chunk-NU7D64RL.js.map
31272
- //# sourceMappingURL=chunk-NU7D64RL.js.map
31263
+ //# sourceMappingURL=chunk-KIVJXUYE.js.map
31264
+ //# sourceMappingURL=chunk-KIVJXUYE.js.map