@tldraw/editor 3.12.0-canary.3aafabe5ce31 → 3.12.0-canary.485c2dd13354

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.
Files changed (33) hide show
  1. package/dist-cjs/index.js +1 -1
  2. package/dist-cjs/lib/components/Shape.js +8 -12
  3. package/dist-cjs/lib/components/Shape.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +7 -12
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +1 -1
  7. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
  8. package/dist-cjs/lib/hooks/useGestureEvents.js +12 -6
  9. package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
  10. package/dist-cjs/lib/utils/debug-flags.js +2 -1
  11. package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
  12. package/dist-cjs/version.js +3 -3
  13. package/dist-cjs/version.js.map +1 -1
  14. package/dist-esm/index.mjs +1 -1
  15. package/dist-esm/lib/components/Shape.mjs +9 -13
  16. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  17. package/dist-esm/lib/editor/Editor.mjs +7 -12
  18. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  19. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +1 -1
  20. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
  21. package/dist-esm/lib/hooks/useGestureEvents.mjs +12 -6
  22. package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
  23. package/dist-esm/lib/utils/debug-flags.mjs +2 -1
  24. package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
  25. package/dist-esm/version.mjs +3 -3
  26. package/dist-esm/version.mjs.map +1 -1
  27. package/package.json +7 -7
  28. package/src/lib/components/Shape.tsx +13 -17
  29. package/src/lib/editor/Editor.ts +7 -13
  30. package/src/lib/editor/derivations/notVisibleShapes.ts +1 -1
  31. package/src/lib/hooks/useGestureEvents.ts +12 -6
  32. package/src/lib/utils/debug-flags.ts +1 -0
  33. package/src/version.ts +3 -3
@@ -39,7 +39,7 @@ const notVisibleShapes = (editor) => {
39
39
  });
40
40
  return notVisibleShapes2;
41
41
  }
42
- return (0, import_state.computed)("getCulledShapes", (prevValue) => {
42
+ return (0, import_state.computed)("notVisibleShapes", (prevValue) => {
43
43
  if ((0, import_state.isUninitialized)(prevValue)) {
44
44
  return fromScratch(editor);
45
45
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/editor/derivations/notVisibleShapes.ts"],
4
- "sourcesContent": ["import { computed, isUninitialized } from '@tldraw/state'\nimport { TLShapeId } from '@tldraw/tlschema'\nimport { Box } from '../../primitives/Box'\nimport { Editor } from '../Editor'\n\nfunction isShapeNotVisible(editor: Editor, id: TLShapeId, viewportPageBounds: Box): boolean {\n\tconst maskedPageBounds = editor.getShapeMaskedPageBounds(id)\n\t// if the shape is fully outside of its parent's clipping bounds...\n\tif (maskedPageBounds === undefined) return true\n\n\t// if the shape is fully outside of the viewport page bounds...\n\treturn !viewportPageBounds.includes(maskedPageBounds)\n}\n\n/**\n * Incremental derivation of not visible shapes.\n * Non visible shapes are shapes outside of the viewport page bounds and shapes outside of parent's clipping bounds.\n *\n * @param editor - Instance of the tldraw Editor.\n * @returns Incremental derivation of non visible shapes.\n */\nexport const notVisibleShapes = (editor: Editor) => {\n\tfunction fromScratch(editor: Editor): Set<TLShapeId> {\n\t\tconst shapes = editor.getCurrentPageShapeIds()\n\t\tconst viewportPageBounds = editor.getViewportPageBounds()\n\t\tconst notVisibleShapes = new Set<TLShapeId>()\n\t\tshapes.forEach((id) => {\n\t\t\tif (isShapeNotVisible(editor, id, viewportPageBounds)) {\n\t\t\t\tnotVisibleShapes.add(id)\n\t\t\t}\n\t\t})\n\t\treturn notVisibleShapes\n\t}\n\treturn computed<Set<TLShapeId>>('getCulledShapes', (prevValue) => {\n\t\tif (isUninitialized(prevValue)) {\n\t\t\treturn fromScratch(editor)\n\t\t}\n\n\t\tconst nextValue = fromScratch(editor)\n\n\t\tif (prevValue.size !== nextValue.size) return nextValue\n\t\tfor (const prev of prevValue) {\n\t\t\tif (!nextValue.has(prev)) {\n\t\t\t\treturn nextValue\n\t\t\t}\n\t\t}\n\t\treturn prevValue\n\t})\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0C;AAK1C,SAAS,kBAAkB,QAAgB,IAAe,oBAAkC;AAC3F,QAAM,mBAAmB,OAAO,yBAAyB,EAAE;AAE3D,MAAI,qBAAqB,OAAW,QAAO;AAG3C,SAAO,CAAC,mBAAmB,SAAS,gBAAgB;AACrD;AASO,MAAM,mBAAmB,CAAC,WAAmB;AACnD,WAAS,YAAYA,SAAgC;AACpD,UAAM,SAASA,QAAO,uBAAuB;AAC7C,UAAM,qBAAqBA,QAAO,sBAAsB;AACxD,UAAMC,oBAAmB,oBAAI,IAAe;AAC5C,WAAO,QAAQ,CAAC,OAAO;AACtB,UAAI,kBAAkBD,SAAQ,IAAI,kBAAkB,GAAG;AACtD,QAAAC,kBAAiB,IAAI,EAAE;AAAA,MACxB;AAAA,IACD,CAAC;AACD,WAAOA;AAAA,EACR;AACA,aAAO,uBAAyB,mBAAmB,CAAC,cAAc;AACjE,YAAI,8BAAgB,SAAS,GAAG;AAC/B,aAAO,YAAY,MAAM;AAAA,IAC1B;AAEA,UAAM,YAAY,YAAY,MAAM;AAEpC,QAAI,UAAU,SAAS,UAAU,KAAM,QAAO;AAC9C,eAAW,QAAQ,WAAW;AAC7B,UAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACzB,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR,CAAC;AACF;",
4
+ "sourcesContent": ["import { computed, isUninitialized } from '@tldraw/state'\nimport { TLShapeId } from '@tldraw/tlschema'\nimport { Box } from '../../primitives/Box'\nimport { Editor } from '../Editor'\n\nfunction isShapeNotVisible(editor: Editor, id: TLShapeId, viewportPageBounds: Box): boolean {\n\tconst maskedPageBounds = editor.getShapeMaskedPageBounds(id)\n\t// if the shape is fully outside of its parent's clipping bounds...\n\tif (maskedPageBounds === undefined) return true\n\n\t// if the shape is fully outside of the viewport page bounds...\n\treturn !viewportPageBounds.includes(maskedPageBounds)\n}\n\n/**\n * Incremental derivation of not visible shapes.\n * Non visible shapes are shapes outside of the viewport page bounds and shapes outside of parent's clipping bounds.\n *\n * @param editor - Instance of the tldraw Editor.\n * @returns Incremental derivation of non visible shapes.\n */\nexport const notVisibleShapes = (editor: Editor) => {\n\tfunction fromScratch(editor: Editor): Set<TLShapeId> {\n\t\tconst shapes = editor.getCurrentPageShapeIds()\n\t\tconst viewportPageBounds = editor.getViewportPageBounds()\n\t\tconst notVisibleShapes = new Set<TLShapeId>()\n\t\tshapes.forEach((id) => {\n\t\t\tif (isShapeNotVisible(editor, id, viewportPageBounds)) {\n\t\t\t\tnotVisibleShapes.add(id)\n\t\t\t}\n\t\t})\n\t\treturn notVisibleShapes\n\t}\n\treturn computed<Set<TLShapeId>>('notVisibleShapes', (prevValue) => {\n\t\tif (isUninitialized(prevValue)) {\n\t\t\treturn fromScratch(editor)\n\t\t}\n\n\t\tconst nextValue = fromScratch(editor)\n\n\t\tif (prevValue.size !== nextValue.size) return nextValue\n\t\tfor (const prev of prevValue) {\n\t\t\tif (!nextValue.has(prev)) {\n\t\t\t\treturn nextValue\n\t\t\t}\n\t\t}\n\t\treturn prevValue\n\t})\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAA0C;AAK1C,SAAS,kBAAkB,QAAgB,IAAe,oBAAkC;AAC3F,QAAM,mBAAmB,OAAO,yBAAyB,EAAE;AAE3D,MAAI,qBAAqB,OAAW,QAAO;AAG3C,SAAO,CAAC,mBAAmB,SAAS,gBAAgB;AACrD;AASO,MAAM,mBAAmB,CAAC,WAAmB;AACnD,WAAS,YAAYA,SAAgC;AACpD,UAAM,SAASA,QAAO,uBAAuB;AAC7C,UAAM,qBAAqBA,QAAO,sBAAsB;AACxD,UAAMC,oBAAmB,oBAAI,IAAe;AAC5C,WAAO,QAAQ,CAAC,OAAO;AACtB,UAAI,kBAAkBD,SAAQ,IAAI,kBAAkB,GAAG;AACtD,QAAAC,kBAAiB,IAAI,EAAE;AAAA,MACxB;AAAA,IACD,CAAC;AACD,WAAOA;AAAA,EACR;AACA,aAAO,uBAAyB,oBAAoB,CAAC,cAAc;AAClE,YAAI,8BAAgB,SAAS,GAAG;AAC/B,aAAO,YAAY,MAAM;AAAA,IAC1B;AAEA,UAAM,YAAY,YAAY,MAAM;AAEpC,QAAI,UAAU,SAAS,UAAU,KAAM,QAAO;AAC9C,eAAW,QAAQ,WAAW;AAC7B,UAAI,CAAC,UAAU,IAAI,IAAI,GAAG;AACzB,eAAO;AAAA,MACR;AAAA,IACD;AACA,WAAO;AAAA,EACR,CAAC;AACF;",
6
6
  "names": ["editor", "notVisibleShapes"]
7
7
  }
@@ -96,7 +96,6 @@ function useGestureEvents(ref) {
96
96
  };
97
97
  let initDistanceBetweenFingers = 1;
98
98
  let initZoom = 1;
99
- let currZoom = 1;
100
99
  let currDistanceBetweenFingers = 0;
101
100
  const initPointBetweenFingers = new import_Vec.Vec();
102
101
  const prevPointBetweenFingers = new import_Vec.Vec();
@@ -164,7 +163,7 @@ function useGestureEvents(ref) {
164
163
  updatePinchState(isSafariTrackpadPinch);
165
164
  switch (pinchState) {
166
165
  case "zooming": {
167
- currZoom = offset[0];
166
+ const currZoom = offset[0] ** editor.getCameraOptions().zoomSpeed;
168
167
  editor.dispatch({
169
168
  type: "pinch",
170
169
  name: "pinch",
@@ -199,7 +198,7 @@ function useGestureEvents(ref) {
199
198
  const { event, origin, offset } = gesture;
200
199
  if (event instanceof WheelEvent) return;
201
200
  if (!(event.target === elm || elm?.contains(event.target))) return;
202
- const scale = offset[0];
201
+ const scale = offset[0] ** editor.getCameraOptions().zoomSpeed;
203
202
  pinchState = "not sure";
204
203
  editor.timers.requestAnimationFrame(() => {
205
204
  editor.dispatch({
@@ -226,14 +225,21 @@ function useGestureEvents(ref) {
226
225
  target: ref,
227
226
  eventOptions: { passive: false },
228
227
  pinch: {
229
- from: () => [editor.getZoomLevel(), 0],
228
+ from: () => {
229
+ const { zoomSpeed } = editor.getCameraOptions();
230
+ const level = editor.getZoomLevel() ** (1 / zoomSpeed);
231
+ return [level, 0];
232
+ },
230
233
  // Return the camera z to use when pinch starts
231
234
  scaleBounds: () => {
232
235
  const baseZoom = editor.getBaseZoom();
233
- const zoomSteps = editor.getCameraOptions().zoomSteps;
236
+ const { zoomSteps, zoomSpeed } = editor.getCameraOptions();
234
237
  const zoomMin = zoomSteps[0] * baseZoom;
235
238
  const zoomMax = zoomSteps[zoomSteps.length - 1] * baseZoom;
236
- return { from: editor.getZoomLevel(), max: zoomMax, min: zoomMin };
239
+ return {
240
+ max: zoomMax ** (1 / zoomSpeed),
241
+ min: zoomMin ** (1 / zoomSpeed)
242
+ };
237
243
  }
238
244
  }
239
245
  });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/hooks/useGestureEvents.ts"],
4
- "sourcesContent": ["import type { AnyHandlerEventTypes, EventTypes, GestureKey, Handler } from '@use-gesture/core/types'\nimport { createUseGesture, pinchAction, wheelAction } from '@use-gesture/react'\nimport * as React from 'react'\nimport { TLWheelEventInfo } from '../editor/types/event-types'\nimport { Vec } from '../primitives/Vec'\nimport { preventDefault, stopEventPropagation } from '../utils/dom'\nimport { isAccelKey } from '../utils/keyboard'\nimport { normalizeWheel } from '../utils/normalizeWheel'\nimport { useEditor } from './useEditor'\n\n/*\n\n# How does pinching work?\n\nThe pinching handler is fired under two circumstances: \n- when a user is on a MacBook trackpad and is ZOOMING with a two-finger pinch\n- when a user is on a touch device and is ZOOMING with a two-finger pinch\n- when a user is on a touch device and is PANNING with two fingers\n\nZooming is much more expensive than panning (because it causes shapes to render), \nso we want to be sure that we don't zoom while two-finger panning. \n\nIn order to do this, we keep track of a \"pinchState\", which is either:\n- \"zooming\"\n- \"panning\"\n- \"not sure\"\n\nIf a user is on a trackpad, the pinchState will be set to \"zooming\". \n\nIf the user is on a touch screen, then we start in the \"not sure\" state and switch back and forth\nbetween \"zooming\", \"panning\", and \"not sure\" based on what the user is doing with their fingers.\n\nIn the \"not sure\" state, we examine whether the user has moved the center of the gesture far enough\nto suggest that they're panning; or else that they've moved their fingers further apart or closer\ntogether enough to suggest that they're zooming. \n\nIn the \"panning\" state, we check whether the user's fingers have moved far enough apart to suggest\nthat they're zooming. If they have, we switch to the \"zooming\" state.\n\nIn the \"zooming\" state, we just stay zooming\u2014it's not YET possible to switch back to panning.\n\ntodo: compare velocities of change in order to determine whether the user has switched back to panning\n*/\n\ntype check<T extends AnyHandlerEventTypes, Key extends GestureKey> = undefined extends T[Key]\n\t? EventTypes[Key]\n\t: T[Key]\ntype PinchHandler = Handler<'pinch', check<EventTypes, 'pinch'>>\n\nconst useGesture = createUseGesture([wheelAction, pinchAction])\n\n/**\n * GOTCHA\n *\n * UseGesture fires a wheel event 140ms after the gesture actually ends, with a momentum-adjusted\n * delta. This creates a messed up interaction where after you stop scrolling suddenly the dang page\n * jumps a tick. why do they do this? you are asking the wrong person. it seems intentional though.\n * anyway we want to ignore that last event, but there's no way to directly detect it so we need to\n * keep track of timestamps. Yes this is awful, I am sorry.\n */\nlet lastWheelTime = undefined as undefined | number\n\nconst isWheelEndEvent = (time: number) => {\n\tif (lastWheelTime === undefined) {\n\t\tlastWheelTime = time\n\t\treturn false\n\t}\n\n\tif (time - lastWheelTime > 120 && time - lastWheelTime < 160) {\n\t\tlastWheelTime = time\n\t\treturn true\n\t}\n\n\tlastWheelTime = time\n\treturn false\n}\n\nexport function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {\n\tconst editor = useEditor()\n\n\tconst events = React.useMemo(() => {\n\t\tlet pinchState = 'not sure' as 'not sure' | 'zooming' | 'panning'\n\n\t\tconst onWheel: Handler<'wheel', WheelEvent> = ({ event }) => {\n\t\t\tif (!editor.getInstanceState().isFocused) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpinchState = 'not sure'\n\n\t\t\tif (isWheelEndEvent(Date.now())) {\n\t\t\t\t// ignore wheelEnd events\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Awful tht we need to put this logic here, but basically\n\t\t\t// we don't want to handle the the wheel event (or call prevent\n\t\t\t// default on the evnet) if the user is wheeling over an a shape\n\t\t\t// that is scrollable which they're currently editing.\n\n\t\t\tconst editingShapeId = editor.getEditingShapeId()\n\t\t\tif (editingShapeId) {\n\t\t\t\tconst shape = editor.getShape(editingShapeId)\n\t\t\t\tif (shape) {\n\t\t\t\t\tconst util = editor.getShapeUtil(shape)\n\t\t\t\t\tif (util.canScroll(shape)) {\n\t\t\t\t\t\tconst bounds = editor.getShapePageBounds(editingShapeId)\n\t\t\t\t\t\tif (bounds?.containsPoint(editor.inputs.currentPagePoint)) {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpreventDefault(event)\n\t\t\tstopEventPropagation(event)\n\t\t\tconst delta = normalizeWheel(event)\n\n\t\t\tif (delta.x === 0 && delta.y === 0) return\n\n\t\t\tconst info: TLWheelEventInfo = {\n\t\t\t\ttype: 'wheel',\n\t\t\t\tname: 'wheel',\n\t\t\t\tdelta,\n\t\t\t\tpoint: new Vec(event.clientX, event.clientY),\n\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\taltKey: event.altKey,\n\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t}\n\n\t\t\teditor.dispatch(info)\n\t\t}\n\n\t\tlet initDistanceBetweenFingers = 1 // the distance between the two fingers when the pinch starts\n\t\tlet initZoom = 1 // the browser's zoom level when the pinch starts\n\t\tlet currZoom = 1 // the current zoom level according to the pinch gesture recognizer\n\t\tlet currDistanceBetweenFingers = 0\n\t\tconst initPointBetweenFingers = new Vec()\n\t\tconst prevPointBetweenFingers = new Vec()\n\n\t\tconst onPinchStart: PinchHandler = (gesture) => {\n\t\t\tconst elm = ref.current\n\t\t\tpinchState = 'not sure'\n\n\t\t\tconst { event, origin, da } = gesture\n\n\t\t\tif (event instanceof WheelEvent) return\n\t\t\tif (!(event.target === elm || elm?.contains(event.target as Node))) return\n\n\t\t\tprevPointBetweenFingers.x = origin[0]\n\t\t\tprevPointBetweenFingers.y = origin[1]\n\t\t\tinitPointBetweenFingers.x = origin[0]\n\t\t\tinitPointBetweenFingers.y = origin[1]\n\t\t\tinitDistanceBetweenFingers = da[0]\n\t\t\tinitZoom = editor.getZoomLevel()\n\n\t\t\teditor.dispatch({\n\t\t\t\ttype: 'pinch',\n\t\t\t\tname: 'pinch_start',\n\t\t\t\tpoint: { x: origin[0], y: origin[1], z: editor.getZoomLevel() },\n\t\t\t\tdelta: { x: 0, y: 0 },\n\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\taltKey: event.altKey,\n\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t})\n\t\t}\n\n\t\t// let timeout: any\n\t\tconst updatePinchState = (isSafariTrackpadPinch: boolean) => {\n\t\t\tif (isSafariTrackpadPinch) {\n\t\t\t\tpinchState = 'zooming'\n\t\t\t}\n\n\t\t\tif (pinchState === 'zooming') {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Initial: [touch]-------origin-------[touch]\n\t\t\t// Current: [touch]-----------origin----------[touch]\n\t\t\t// |----| |------------|\n\t\t\t// originDistance ^ ^ touchDistance\n\n\t\t\t// How far have the two touch points moved towards or away from eachother?\n\t\t\tconst touchDistance = Math.abs(currDistanceBetweenFingers - initDistanceBetweenFingers)\n\t\t\t// How far has the point between the touches moved?\n\t\t\tconst originDistance = Vec.Dist(initPointBetweenFingers, prevPointBetweenFingers)\n\n\t\t\tswitch (pinchState) {\n\t\t\t\tcase 'not sure': {\n\t\t\t\t\tif (touchDistance > 24) {\n\t\t\t\t\t\tpinchState = 'zooming'\n\t\t\t\t\t} else if (originDistance > 16) {\n\t\t\t\t\t\tpinchState = 'panning'\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'panning': {\n\t\t\t\t\t// Slightly more touch distance needed to go from panning to zooming\n\t\t\t\t\tif (touchDistance > 64) {\n\t\t\t\t\t\tpinchState = 'zooming'\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst onPinch: PinchHandler = (gesture) => {\n\t\t\tconst elm = ref.current\n\t\t\tconst { event, origin, offset, da } = gesture\n\n\t\t\tif (event instanceof WheelEvent) return\n\t\t\tif (!(event.target === elm || elm?.contains(event.target as Node))) return\n\n\t\t\t// In (desktop) Safari, a two finger trackpad pinch will be a \"gesturechange\" event\n\t\t\t// and will have 0 touches; on iOS, a two-finger pinch will be a \"pointermove\" event\n\t\t\t// with two touches.\n\t\t\tconst isSafariTrackpadPinch =\n\t\t\t\tgesture.type === 'gesturechange' || gesture.type === 'gestureend'\n\n\t\t\t// The distance between the two touch points\n\t\t\tcurrDistanceBetweenFingers = da[0]\n\n\t\t\t// Only update the zoom if the pointers are far enough apart;\n\t\t\t// a very small touchDistance means that the user has probably\n\t\t\t// pinched out and their fingers are touching; this produces\n\t\t\t// very unstable zooming behavior.\n\n\t\t\tconst dx = origin[0] - prevPointBetweenFingers.x\n\t\t\tconst dy = origin[1] - prevPointBetweenFingers.y\n\n\t\t\tprevPointBetweenFingers.x = origin[0]\n\t\t\tprevPointBetweenFingers.y = origin[1]\n\n\t\t\tupdatePinchState(isSafariTrackpadPinch)\n\n\t\t\tswitch (pinchState) {\n\t\t\t\tcase 'zooming': {\n\t\t\t\t\tcurrZoom = offset[0]\n\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pinch',\n\t\t\t\t\t\tname: 'pinch',\n\t\t\t\t\t\tpoint: { x: origin[0], y: origin[1], z: currZoom },\n\t\t\t\t\t\tdelta: { x: dx, y: dy },\n\t\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t\t\t})\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'panning': {\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pinch',\n\t\t\t\t\t\tname: 'pinch',\n\t\t\t\t\t\tpoint: { x: origin[0], y: origin[1], z: initZoom },\n\t\t\t\t\t\tdelta: { x: dx, y: dy },\n\t\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t\t\t})\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst onPinchEnd: PinchHandler = (gesture) => {\n\t\t\tconst elm = ref.current\n\t\t\tconst { event, origin, offset } = gesture\n\n\t\t\tif (event instanceof WheelEvent) return\n\t\t\tif (!(event.target === elm || elm?.contains(event.target as Node))) return\n\n\t\t\tconst scale = offset[0]\n\n\t\t\tpinchState = 'not sure'\n\n\t\t\teditor.timers.requestAnimationFrame(() => {\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pinch',\n\t\t\t\t\tname: 'pinch_end',\n\t\t\t\t\tpoint: { x: origin[0], y: origin[1], z: scale },\n\t\t\t\t\tdelta: { x: origin[0], y: origin[1] },\n\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\n\t\treturn {\n\t\t\tonWheel,\n\t\t\tonPinchStart,\n\t\t\tonPinchEnd,\n\t\t\tonPinch,\n\t\t}\n\t}, [editor, ref])\n\n\tuseGesture(events, {\n\t\ttarget: ref,\n\t\teventOptions: { passive: false },\n\t\tpinch: {\n\t\t\tfrom: () => [editor.getZoomLevel(), 0], // Return the camera z to use when pinch starts\n\t\t\tscaleBounds: () => {\n\t\t\t\tconst baseZoom = editor.getBaseZoom()\n\t\t\t\tconst zoomSteps = editor.getCameraOptions().zoomSteps\n\t\t\t\tconst zoomMin = zoomSteps[0] * baseZoom\n\t\t\t\tconst zoomMax = zoomSteps[zoomSteps.length - 1] * baseZoom\n\n\t\t\t\treturn { from: editor.getZoomLevel(), max: zoomMax, min: zoomMin }\n\t\t\t},\n\t\t},\n\t})\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { AnyHandlerEventTypes, EventTypes, GestureKey, Handler } from '@use-gesture/core/types'\nimport { createUseGesture, pinchAction, wheelAction } from '@use-gesture/react'\nimport * as React from 'react'\nimport { TLWheelEventInfo } from '../editor/types/event-types'\nimport { Vec } from '../primitives/Vec'\nimport { preventDefault, stopEventPropagation } from '../utils/dom'\nimport { isAccelKey } from '../utils/keyboard'\nimport { normalizeWheel } from '../utils/normalizeWheel'\nimport { useEditor } from './useEditor'\n\n/*\n\n# How does pinching work?\n\nThe pinching handler is fired under two circumstances: \n- when a user is on a MacBook trackpad and is ZOOMING with a two-finger pinch\n- when a user is on a touch device and is ZOOMING with a two-finger pinch\n- when a user is on a touch device and is PANNING with two fingers\n\nZooming is much more expensive than panning (because it causes shapes to render), \nso we want to be sure that we don't zoom while two-finger panning. \n\nIn order to do this, we keep track of a \"pinchState\", which is either:\n- \"zooming\"\n- \"panning\"\n- \"not sure\"\n\nIf a user is on a trackpad, the pinchState will be set to \"zooming\". \n\nIf the user is on a touch screen, then we start in the \"not sure\" state and switch back and forth\nbetween \"zooming\", \"panning\", and \"not sure\" based on what the user is doing with their fingers.\n\nIn the \"not sure\" state, we examine whether the user has moved the center of the gesture far enough\nto suggest that they're panning; or else that they've moved their fingers further apart or closer\ntogether enough to suggest that they're zooming. \n\nIn the \"panning\" state, we check whether the user's fingers have moved far enough apart to suggest\nthat they're zooming. If they have, we switch to the \"zooming\" state.\n\nIn the \"zooming\" state, we just stay zooming\u2014it's not YET possible to switch back to panning.\n\ntodo: compare velocities of change in order to determine whether the user has switched back to panning\n*/\n\ntype check<T extends AnyHandlerEventTypes, Key extends GestureKey> = undefined extends T[Key]\n\t? EventTypes[Key]\n\t: T[Key]\ntype PinchHandler = Handler<'pinch', check<EventTypes, 'pinch'>>\n\nconst useGesture = createUseGesture([wheelAction, pinchAction])\n\n/**\n * GOTCHA\n *\n * UseGesture fires a wheel event 140ms after the gesture actually ends, with a momentum-adjusted\n * delta. This creates a messed up interaction where after you stop scrolling suddenly the dang page\n * jumps a tick. why do they do this? you are asking the wrong person. it seems intentional though.\n * anyway we want to ignore that last event, but there's no way to directly detect it so we need to\n * keep track of timestamps. Yes this is awful, I am sorry.\n */\nlet lastWheelTime = undefined as undefined | number\n\nconst isWheelEndEvent = (time: number) => {\n\tif (lastWheelTime === undefined) {\n\t\tlastWheelTime = time\n\t\treturn false\n\t}\n\n\tif (time - lastWheelTime > 120 && time - lastWheelTime < 160) {\n\t\tlastWheelTime = time\n\t\treturn true\n\t}\n\n\tlastWheelTime = time\n\treturn false\n}\n\nexport function useGestureEvents(ref: React.RefObject<HTMLDivElement>) {\n\tconst editor = useEditor()\n\n\tconst events = React.useMemo(() => {\n\t\tlet pinchState = 'not sure' as 'not sure' | 'zooming' | 'panning'\n\n\t\tconst onWheel: Handler<'wheel', WheelEvent> = ({ event }) => {\n\t\t\tif (!editor.getInstanceState().isFocused) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpinchState = 'not sure'\n\n\t\t\tif (isWheelEndEvent(Date.now())) {\n\t\t\t\t// ignore wheelEnd events\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Awful tht we need to put this logic here, but basically\n\t\t\t// we don't want to handle the the wheel event (or call prevent\n\t\t\t// default on the evnet) if the user is wheeling over an a shape\n\t\t\t// that is scrollable which they're currently editing.\n\n\t\t\tconst editingShapeId = editor.getEditingShapeId()\n\t\t\tif (editingShapeId) {\n\t\t\t\tconst shape = editor.getShape(editingShapeId)\n\t\t\t\tif (shape) {\n\t\t\t\t\tconst util = editor.getShapeUtil(shape)\n\t\t\t\t\tif (util.canScroll(shape)) {\n\t\t\t\t\t\tconst bounds = editor.getShapePageBounds(editingShapeId)\n\t\t\t\t\t\tif (bounds?.containsPoint(editor.inputs.currentPagePoint)) {\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tpreventDefault(event)\n\t\t\tstopEventPropagation(event)\n\t\t\tconst delta = normalizeWheel(event)\n\n\t\t\tif (delta.x === 0 && delta.y === 0) return\n\n\t\t\tconst info: TLWheelEventInfo = {\n\t\t\t\ttype: 'wheel',\n\t\t\t\tname: 'wheel',\n\t\t\t\tdelta,\n\t\t\t\tpoint: new Vec(event.clientX, event.clientY),\n\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\taltKey: event.altKey,\n\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t}\n\n\t\t\teditor.dispatch(info)\n\t\t}\n\n\t\tlet initDistanceBetweenFingers = 1 // the distance between the two fingers when the pinch starts\n\t\tlet initZoom = 1 // the browser's zoom level when the pinch starts\n\t\tlet currDistanceBetweenFingers = 0\n\t\tconst initPointBetweenFingers = new Vec()\n\t\tconst prevPointBetweenFingers = new Vec()\n\n\t\tconst onPinchStart: PinchHandler = (gesture) => {\n\t\t\tconst elm = ref.current\n\t\t\tpinchState = 'not sure'\n\n\t\t\tconst { event, origin, da } = gesture\n\n\t\t\tif (event instanceof WheelEvent) return\n\t\t\tif (!(event.target === elm || elm?.contains(event.target as Node))) return\n\n\t\t\tprevPointBetweenFingers.x = origin[0]\n\t\t\tprevPointBetweenFingers.y = origin[1]\n\t\t\tinitPointBetweenFingers.x = origin[0]\n\t\t\tinitPointBetweenFingers.y = origin[1]\n\t\t\tinitDistanceBetweenFingers = da[0]\n\t\t\tinitZoom = editor.getZoomLevel()\n\n\t\t\teditor.dispatch({\n\t\t\t\ttype: 'pinch',\n\t\t\t\tname: 'pinch_start',\n\t\t\t\tpoint: { x: origin[0], y: origin[1], z: editor.getZoomLevel() },\n\t\t\t\tdelta: { x: 0, y: 0 },\n\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\taltKey: event.altKey,\n\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t})\n\t\t}\n\n\t\t// let timeout: any\n\t\tconst updatePinchState = (isSafariTrackpadPinch: boolean) => {\n\t\t\tif (isSafariTrackpadPinch) {\n\t\t\t\tpinchState = 'zooming'\n\t\t\t}\n\n\t\t\tif (pinchState === 'zooming') {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Initial: [touch]-------origin-------[touch]\n\t\t\t// Current: [touch]-----------origin----------[touch]\n\t\t\t// |----| |------------|\n\t\t\t// originDistance ^ ^ touchDistance\n\n\t\t\t// How far have the two touch points moved towards or away from eachother?\n\t\t\tconst touchDistance = Math.abs(currDistanceBetweenFingers - initDistanceBetweenFingers)\n\t\t\t// How far has the point between the touches moved?\n\t\t\tconst originDistance = Vec.Dist(initPointBetweenFingers, prevPointBetweenFingers)\n\n\t\t\tswitch (pinchState) {\n\t\t\t\tcase 'not sure': {\n\t\t\t\t\tif (touchDistance > 24) {\n\t\t\t\t\t\tpinchState = 'zooming'\n\t\t\t\t\t} else if (originDistance > 16) {\n\t\t\t\t\t\tpinchState = 'panning'\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'panning': {\n\t\t\t\t\t// Slightly more touch distance needed to go from panning to zooming\n\t\t\t\t\tif (touchDistance > 64) {\n\t\t\t\t\t\tpinchState = 'zooming'\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst onPinch: PinchHandler = (gesture) => {\n\t\t\tconst elm = ref.current\n\t\t\tconst { event, origin, offset, da } = gesture\n\n\t\t\tif (event instanceof WheelEvent) return\n\t\t\tif (!(event.target === elm || elm?.contains(event.target as Node))) return\n\n\t\t\t// In (desktop) Safari, a two finger trackpad pinch will be a \"gesturechange\" event\n\t\t\t// and will have 0 touches; on iOS, a two-finger pinch will be a \"pointermove\" event\n\t\t\t// with two touches.\n\t\t\tconst isSafariTrackpadPinch =\n\t\t\t\tgesture.type === 'gesturechange' || gesture.type === 'gestureend'\n\n\t\t\t// The distance between the two touch points\n\t\t\tcurrDistanceBetweenFingers = da[0]\n\n\t\t\t// Only update the zoom if the pointers are far enough apart;\n\t\t\t// a very small touchDistance means that the user has probably\n\t\t\t// pinched out and their fingers are touching; this produces\n\t\t\t// very unstable zooming behavior.\n\n\t\t\tconst dx = origin[0] - prevPointBetweenFingers.x\n\t\t\tconst dy = origin[1] - prevPointBetweenFingers.y\n\n\t\t\tprevPointBetweenFingers.x = origin[0]\n\t\t\tprevPointBetweenFingers.y = origin[1]\n\n\t\t\tupdatePinchState(isSafariTrackpadPinch)\n\n\t\t\tswitch (pinchState) {\n\t\t\t\tcase 'zooming': {\n\t\t\t\t\tconst currZoom = offset[0] ** editor.getCameraOptions().zoomSpeed\n\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pinch',\n\t\t\t\t\t\tname: 'pinch',\n\t\t\t\t\t\tpoint: { x: origin[0], y: origin[1], z: currZoom },\n\t\t\t\t\t\tdelta: { x: dx, y: dy },\n\t\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t\t\t})\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'panning': {\n\t\t\t\t\teditor.dispatch({\n\t\t\t\t\t\ttype: 'pinch',\n\t\t\t\t\t\tname: 'pinch',\n\t\t\t\t\t\tpoint: { x: origin[0], y: origin[1], z: initZoom },\n\t\t\t\t\t\tdelta: { x: dx, y: dy },\n\t\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t\t\t})\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst onPinchEnd: PinchHandler = (gesture) => {\n\t\t\tconst elm = ref.current\n\t\t\tconst { event, origin, offset } = gesture\n\n\t\t\tif (event instanceof WheelEvent) return\n\t\t\tif (!(event.target === elm || elm?.contains(event.target as Node))) return\n\n\t\t\tconst scale = offset[0] ** editor.getCameraOptions().zoomSpeed\n\n\t\t\tpinchState = 'not sure'\n\n\t\t\teditor.timers.requestAnimationFrame(() => {\n\t\t\t\teditor.dispatch({\n\t\t\t\t\ttype: 'pinch',\n\t\t\t\t\tname: 'pinch_end',\n\t\t\t\t\tpoint: { x: origin[0], y: origin[1], z: scale },\n\t\t\t\t\tdelta: { x: origin[0], y: origin[1] },\n\t\t\t\t\tshiftKey: event.shiftKey,\n\t\t\t\t\taltKey: event.altKey,\n\t\t\t\t\tctrlKey: event.metaKey || event.ctrlKey,\n\t\t\t\t\tmetaKey: event.metaKey,\n\t\t\t\t\taccelKey: isAccelKey(event),\n\t\t\t\t})\n\t\t\t})\n\t\t}\n\n\t\treturn {\n\t\t\tonWheel,\n\t\t\tonPinchStart,\n\t\t\tonPinchEnd,\n\t\t\tonPinch,\n\t\t}\n\t}, [editor, ref])\n\n\tuseGesture(events, {\n\t\ttarget: ref,\n\t\teventOptions: { passive: false },\n\t\tpinch: {\n\t\t\tfrom: () => {\n\t\t\t\tconst { zoomSpeed } = editor.getCameraOptions()\n\t\t\t\tconst level = editor.getZoomLevel() ** (1 / zoomSpeed)\n\t\t\t\treturn [level, 0]\n\t\t\t}, // Return the camera z to use when pinch starts\n\t\t\tscaleBounds: () => {\n\t\t\t\tconst baseZoom = editor.getBaseZoom()\n\t\t\t\tconst { zoomSteps, zoomSpeed } = editor.getCameraOptions()\n\t\t\t\tconst zoomMin = zoomSteps[0] * baseZoom\n\t\t\t\tconst zoomMax = zoomSteps[zoomSteps.length - 1] * baseZoom\n\n\t\t\t\treturn {\n\t\t\t\t\tmax: zoomMax ** (1 / zoomSpeed),\n\t\t\t\t\tmin: zoomMin ** (1 / zoomSpeed),\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t})\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -65,7 +65,8 @@ const debugFlags = {
65
65
  forceSrgb: createDebugValue("forceSrgbColors", { defaults: { all: false } }),
66
66
  debugGeometry: createDebugValue("debugGeometry", { defaults: { all: false } }),
67
67
  hideShapes: createDebugValue("hideShapes", { defaults: { all: false } }),
68
- editOnType: createDebugValue("editOnType", { defaults: { all: false } })
68
+ editOnType: createDebugValue("editOnType", { defaults: { all: false } }),
69
+ a11y: createDebugValue("a11y", { defaults: { all: false } })
69
70
  };
70
71
  if (typeof Element !== "undefined") {
71
72
  const nativeElementRemoveChild = Element.prototype.removeChild;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/utils/debug-flags.ts"],
4
- "sourcesContent": ["import { Atom, atom, react } from '@tldraw/state'\nimport { deleteFromSessionStorage, getFromSessionStorage, setInSessionStorage } from '@tldraw/utils'\n\n// --- 1. DEFINE ---\n//\n// Define your debug values and feature flags here. Use `createDebugValue` to\n// create an arbitrary value with defaults for production, staging, and\n// development. Use `createFeatureFlag` to create a boolean flag which will be\n// `true` by default in development and staging, and `false` in production.\n/** @internal */\nexport const featureFlags: Record<string, DebugFlag<boolean>> = {}\n\n/** @internal */\nexport const pointerCaptureTrackingObject = createDebugValue(\n\t'pointerCaptureTrackingObject',\n\t// ideally we wouldn't store this mutable value in an atom but it's not\n\t// a big deal for debug values\n\t{\n\t\tdefaults: { all: new Map<Element, number>() },\n\t\tshouldStoreForSession: false,\n\t}\n)\n\n/** @internal */\nexport const debugFlags = {\n\t// --- DEBUG VALUES ---\n\tlogPreventDefaults: createDebugValue('logPreventDefaults', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogPointerCaptures: createDebugValue('logPointerCaptures', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogElementRemoves: createDebugValue('logElementRemoves', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugSvg: createDebugValue('debugSvg', {\n\t\tdefaults: { all: false },\n\t}),\n\tshowFps: createDebugValue('showFps', {\n\t\tdefaults: { all: false },\n\t}),\n\tmeasurePerformance: createDebugValue('measurePerformance', { defaults: { all: false } }),\n\tthrowToBlob: createDebugValue('throwToBlob', {\n\t\tdefaults: { all: false },\n\t}),\n\treconnectOnPing: createDebugValue('reconnectOnPing', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugCursors: createDebugValue('debugCursors', {\n\t\tdefaults: { all: false },\n\t}),\n\tforceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),\n\tdebugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }),\n\thideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),\n\teditOnType: createDebugValue('editOnType', { defaults: { all: false } }),\n} as const\n\ndeclare global {\n\tinterface Window {\n\t\ttldrawLog(message: any): void\n\t}\n}\n\n// --- 2. USE ---\n// In normal code, read from debug flags directly by calling .value on them:\n// if (debugFlags.preventDefaultLogging.value) { ... }\n//\n// In react, wrap your reads in `useValue` (or your component in `track`)\n// so they react to changes:\n// const shouldLog = useValue(debugFlags.preventDefaultLogging)\n\n// --- 3. GET FUNKY ---\n// If you need to do fun stuff like monkey-patching in response to flag changes,\n// add that here. Make sure you wrap your code in `react` so it runs\n// automatically when values change!\n\nif (typeof Element !== 'undefined') {\n\tconst nativeElementRemoveChild = Element.prototype.removeChild\n\treact('element removal logging', () => {\n\t\tif (debugFlags.logElementRemoves.get()) {\n\t\t\tElement.prototype.removeChild = function <T extends Node>(this: any, child: Node): T {\n\t\t\t\tconsole.warn('[tldraw] removing child:', child)\n\t\t\t\treturn nativeElementRemoveChild.call(this, child) as T\n\t\t\t}\n\t\t} else {\n\t\t\tElement.prototype.removeChild = nativeElementRemoveChild\n\t\t}\n\t})\n}\n\n// --- IMPLEMENTATION ---\n// you probably don't need to read this if you're just using the debug values system\nfunction createDebugValue<T>(\n\tname: string,\n\t{\n\t\tdefaults,\n\t\tshouldStoreForSession = true,\n\t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n) {\n\treturn createDebugValueBase({\n\t\tname,\n\t\tdefaults,\n\t\tshouldStoreForSession,\n\t})\n}\n\n// function createFeatureFlag<T>(\n// \tname: string,\n// \t{\n// \t\tdefaults,\n// \t\tshouldStoreForSession = true,\n// \t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n// ) {\n// \treturn createDebugValueBase({\n// \t\tname,\n// \t\tdefaults,\n// \t\tshouldStoreForSession,\n// \t})\n// }\n\nfunction createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {\n\tconst defaultValue = getDefaultValue(def)\n\tconst storedValue = def.shouldStoreForSession\n\t\t? (getStoredInitialValue(def.name) as T | null)\n\t\t: null\n\tconst valueAtom = atom(`debug:${def.name}`, storedValue ?? defaultValue)\n\n\tif (typeof window !== 'undefined') {\n\t\tif (def.shouldStoreForSession) {\n\t\t\treact(`debug:${def.name}`, () => {\n\t\t\t\tconst currentValue = valueAtom.get()\n\t\t\t\tif (currentValue === defaultValue) {\n\t\t\t\t\tdeleteFromSessionStorage(`tldraw_debug:${def.name}`)\n\t\t\t\t} else {\n\t\t\t\t\tsetInSessionStorage(`tldraw_debug:${def.name}`, JSON.stringify(currentValue))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tObject.defineProperty(window, `tldraw${def.name.replace(/^[a-z]/, (l) => l.toUpperCase())}`, {\n\t\t\tget() {\n\t\t\t\treturn valueAtom.get()\n\t\t\t},\n\t\t\tset(newValue) {\n\t\t\t\tvalueAtom.set(newValue)\n\t\t\t},\n\t\t\tconfigurable: true,\n\t\t})\n\t}\n\n\treturn Object.assign(valueAtom, def)\n}\n\nfunction getStoredInitialValue(name: string) {\n\ttry {\n\t\treturn JSON.parse(getFromSessionStorage(`tldraw_debug:${name}`) ?? 'null')\n\t} catch {\n\t\treturn null\n\t}\n}\n\n// process.env might not be defined, but we can't access it using optional\n// chaining because some bundlers search for `process.env.SOMETHING` as a string\n// and replace it with its value.\nfunction readEnv(fn: () => string | undefined) {\n\ttry {\n\t\treturn fn()\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction getDefaultValue<T>(def: DebugFlagDef<T>): T {\n\tconst env =\n\t\treadEnv(() => process.env.TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.VERCEL_PUBLIC_TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.NEXT_PUBLIC_TLDRAW_ENV) ??\n\t\t// default to production because if we don't have one of these, this is probably a library use\n\t\t'production'\n\n\tswitch (env) {\n\t\tcase 'production':\n\t\t\treturn def.defaults.production ?? def.defaults.all\n\t\tcase 'preview':\n\t\tcase 'staging':\n\t\t\treturn def.defaults.staging ?? def.defaults.all\n\t\tdefault:\n\t\t\treturn def.defaults.development ?? def.defaults.all\n\t}\n}\n\n/** @internal */\nexport interface DebugFlagDefaults<T> {\n\tdevelopment?: T\n\tstaging?: T\n\tproduction?: T\n\tall: T\n}\n\n/** @internal */\nexport interface DebugFlagDef<T> {\n\tname: string\n\tdefaults: DebugFlagDefaults<T>\n\tshouldStoreForSession: boolean\n}\n\n/** @internal */\nexport type DebugFlag<T> = DebugFlagDef<T> & Atom<T>\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Atom, atom, react } from '@tldraw/state'\nimport { deleteFromSessionStorage, getFromSessionStorage, setInSessionStorage } from '@tldraw/utils'\n\n// --- 1. DEFINE ---\n//\n// Define your debug values and feature flags here. Use `createDebugValue` to\n// create an arbitrary value with defaults for production, staging, and\n// development. Use `createFeatureFlag` to create a boolean flag which will be\n// `true` by default in development and staging, and `false` in production.\n/** @internal */\nexport const featureFlags: Record<string, DebugFlag<boolean>> = {}\n\n/** @internal */\nexport const pointerCaptureTrackingObject = createDebugValue(\n\t'pointerCaptureTrackingObject',\n\t// ideally we wouldn't store this mutable value in an atom but it's not\n\t// a big deal for debug values\n\t{\n\t\tdefaults: { all: new Map<Element, number>() },\n\t\tshouldStoreForSession: false,\n\t}\n)\n\n/** @internal */\nexport const debugFlags = {\n\t// --- DEBUG VALUES ---\n\tlogPreventDefaults: createDebugValue('logPreventDefaults', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogPointerCaptures: createDebugValue('logPointerCaptures', {\n\t\tdefaults: { all: false },\n\t}),\n\tlogElementRemoves: createDebugValue('logElementRemoves', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugSvg: createDebugValue('debugSvg', {\n\t\tdefaults: { all: false },\n\t}),\n\tshowFps: createDebugValue('showFps', {\n\t\tdefaults: { all: false },\n\t}),\n\tmeasurePerformance: createDebugValue('measurePerformance', { defaults: { all: false } }),\n\tthrowToBlob: createDebugValue('throwToBlob', {\n\t\tdefaults: { all: false },\n\t}),\n\treconnectOnPing: createDebugValue('reconnectOnPing', {\n\t\tdefaults: { all: false },\n\t}),\n\tdebugCursors: createDebugValue('debugCursors', {\n\t\tdefaults: { all: false },\n\t}),\n\tforceSrgb: createDebugValue('forceSrgbColors', { defaults: { all: false } }),\n\tdebugGeometry: createDebugValue('debugGeometry', { defaults: { all: false } }),\n\thideShapes: createDebugValue('hideShapes', { defaults: { all: false } }),\n\teditOnType: createDebugValue('editOnType', { defaults: { all: false } }),\n\ta11y: createDebugValue('a11y', { defaults: { all: false } }),\n} as const\n\ndeclare global {\n\tinterface Window {\n\t\ttldrawLog(message: any): void\n\t}\n}\n\n// --- 2. USE ---\n// In normal code, read from debug flags directly by calling .value on them:\n// if (debugFlags.preventDefaultLogging.value) { ... }\n//\n// In react, wrap your reads in `useValue` (or your component in `track`)\n// so they react to changes:\n// const shouldLog = useValue(debugFlags.preventDefaultLogging)\n\n// --- 3. GET FUNKY ---\n// If you need to do fun stuff like monkey-patching in response to flag changes,\n// add that here. Make sure you wrap your code in `react` so it runs\n// automatically when values change!\n\nif (typeof Element !== 'undefined') {\n\tconst nativeElementRemoveChild = Element.prototype.removeChild\n\treact('element removal logging', () => {\n\t\tif (debugFlags.logElementRemoves.get()) {\n\t\t\tElement.prototype.removeChild = function <T extends Node>(this: any, child: Node): T {\n\t\t\t\tconsole.warn('[tldraw] removing child:', child)\n\t\t\t\treturn nativeElementRemoveChild.call(this, child) as T\n\t\t\t}\n\t\t} else {\n\t\t\tElement.prototype.removeChild = nativeElementRemoveChild\n\t\t}\n\t})\n}\n\n// --- IMPLEMENTATION ---\n// you probably don't need to read this if you're just using the debug values system\nfunction createDebugValue<T>(\n\tname: string,\n\t{\n\t\tdefaults,\n\t\tshouldStoreForSession = true,\n\t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n) {\n\treturn createDebugValueBase({\n\t\tname,\n\t\tdefaults,\n\t\tshouldStoreForSession,\n\t})\n}\n\n// function createFeatureFlag<T>(\n// \tname: string,\n// \t{\n// \t\tdefaults,\n// \t\tshouldStoreForSession = true,\n// \t}: { defaults: DebugFlagDefaults<T>; shouldStoreForSession?: boolean }\n// ) {\n// \treturn createDebugValueBase({\n// \t\tname,\n// \t\tdefaults,\n// \t\tshouldStoreForSession,\n// \t})\n// }\n\nfunction createDebugValueBase<T>(def: DebugFlagDef<T>): DebugFlag<T> {\n\tconst defaultValue = getDefaultValue(def)\n\tconst storedValue = def.shouldStoreForSession\n\t\t? (getStoredInitialValue(def.name) as T | null)\n\t\t: null\n\tconst valueAtom = atom(`debug:${def.name}`, storedValue ?? defaultValue)\n\n\tif (typeof window !== 'undefined') {\n\t\tif (def.shouldStoreForSession) {\n\t\t\treact(`debug:${def.name}`, () => {\n\t\t\t\tconst currentValue = valueAtom.get()\n\t\t\t\tif (currentValue === defaultValue) {\n\t\t\t\t\tdeleteFromSessionStorage(`tldraw_debug:${def.name}`)\n\t\t\t\t} else {\n\t\t\t\t\tsetInSessionStorage(`tldraw_debug:${def.name}`, JSON.stringify(currentValue))\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\tObject.defineProperty(window, `tldraw${def.name.replace(/^[a-z]/, (l) => l.toUpperCase())}`, {\n\t\t\tget() {\n\t\t\t\treturn valueAtom.get()\n\t\t\t},\n\t\t\tset(newValue) {\n\t\t\t\tvalueAtom.set(newValue)\n\t\t\t},\n\t\t\tconfigurable: true,\n\t\t})\n\t}\n\n\treturn Object.assign(valueAtom, def)\n}\n\nfunction getStoredInitialValue(name: string) {\n\ttry {\n\t\treturn JSON.parse(getFromSessionStorage(`tldraw_debug:${name}`) ?? 'null')\n\t} catch {\n\t\treturn null\n\t}\n}\n\n// process.env might not be defined, but we can't access it using optional\n// chaining because some bundlers search for `process.env.SOMETHING` as a string\n// and replace it with its value.\nfunction readEnv(fn: () => string | undefined) {\n\ttry {\n\t\treturn fn()\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction getDefaultValue<T>(def: DebugFlagDef<T>): T {\n\tconst env =\n\t\treadEnv(() => process.env.TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.VERCEL_PUBLIC_TLDRAW_ENV) ??\n\t\treadEnv(() => process.env.NEXT_PUBLIC_TLDRAW_ENV) ??\n\t\t// default to production because if we don't have one of these, this is probably a library use\n\t\t'production'\n\n\tswitch (env) {\n\t\tcase 'production':\n\t\t\treturn def.defaults.production ?? def.defaults.all\n\t\tcase 'preview':\n\t\tcase 'staging':\n\t\t\treturn def.defaults.staging ?? def.defaults.all\n\t\tdefault:\n\t\t\treturn def.defaults.development ?? def.defaults.all\n\t}\n}\n\n/** @internal */\nexport interface DebugFlagDefaults<T> {\n\tdevelopment?: T\n\tstaging?: T\n\tproduction?: T\n\tall: T\n}\n\n/** @internal */\nexport interface DebugFlagDef<T> {\n\tname: string\n\tdefaults: DebugFlagDefaults<T>\n\tshouldStoreForSession: boolean\n}\n\n/** @internal */\nexport type DebugFlag<T> = DebugFlagDef<T> & Atom<T>\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -22,10 +22,10 @@ __export(version_exports, {
22
22
  version: () => version
23
23
  });
24
24
  module.exports = __toCommonJS(version_exports);
25
- const version = "3.12.0-canary.3aafabe5ce31";
25
+ const version = "3.12.0-canary.485c2dd13354";
26
26
  const publishDates = {
27
27
  major: "2024-09-13T14:36:29.063Z",
28
- minor: "2025-03-27T14:35:47.263Z",
29
- patch: "2025-03-27T14:35:47.263Z"
28
+ minor: "2025-03-31T15:17:39.601Z",
29
+ patch: "2025-03-31T15:17:39.601Z"
30
30
  };
31
31
  //# sourceMappingURL=version.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/version.ts"],
4
- "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.12.0-canary.3aafabe5ce31'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-03-27T14:35:47.263Z',\n\tpatch: '2025-03-27T14:35:47.263Z',\n}\n"],
4
+ "sourcesContent": ["// This file is automatically generated by internal/scripts/refresh-assets.ts.\n// Do not edit manually. Or do, I'm a comment, not a cop.\n\nexport const version = '3.12.0-canary.485c2dd13354'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-03-31T15:17:39.601Z',\n\tpatch: '2025-03-31T15:17:39.601Z',\n}\n"],
5
5
  "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
6
6
  "names": []
7
7
  }
@@ -299,7 +299,7 @@ function debugEnableLicensing() {
299
299
  }
300
300
  registerTldrawLibraryVersion(
301
301
  "@tldraw/editor",
302
- "3.12.0-canary.3aafabe5ce31",
302
+ "3.12.0-canary.485c2dd13354",
303
303
  "esm"
304
304
  );
305
305
  export {
@@ -1,7 +1,7 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { react } from "@tldraw/state";
3
3
  import { useQuickReactor, useStateTracking } from "@tldraw/state-react";
4
- import { memo, useCallback, useEffect, useRef } from "react";
4
+ import { memo, useCallback, useEffect, useLayoutEffect, useRef } from "react";
5
5
  import { useEditor } from "../hooks/useEditor.mjs";
6
6
  import { useEditorComponents } from "../hooks/useEditorComponents.mjs";
7
7
  import { Mat } from "../primitives/Mat.mjs";
@@ -67,18 +67,14 @@ const Shape = memo(function Shape2({
67
67
  },
68
68
  [editor]
69
69
  );
70
- useQuickReactor(
71
- "set opacity and z-index",
72
- () => {
73
- const container = containerRef.current;
74
- const bgContainer = bgContainerRef.current;
75
- setStyleProperty(container, "opacity", opacity);
76
- setStyleProperty(bgContainer, "opacity", opacity);
77
- setStyleProperty(container, "z-index", index);
78
- setStyleProperty(bgContainer, "z-index", backgroundIndex);
79
- },
80
- [opacity, index, backgroundIndex]
81
- );
70
+ useLayoutEffect(() => {
71
+ const container = containerRef.current;
72
+ const bgContainer = bgContainerRef.current;
73
+ setStyleProperty(container, "opacity", opacity);
74
+ setStyleProperty(bgContainer, "opacity", opacity);
75
+ setStyleProperty(container, "z-index", index);
76
+ setStyleProperty(bgContainer, "z-index", backgroundIndex);
77
+ }, [opacity, index, backgroundIndex]);
82
78
  useQuickReactor(
83
79
  "set display",
84
80
  () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/components/Shape.tsx"],
4
- "sourcesContent": ["import { react } from '@tldraw/state'\nimport { useQuickReactor, useStateTracking } from '@tldraw/state-react'\nimport { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { memo, useCallback, useEffect, useRef } from 'react'\nimport { ShapeUtil } from '../editor/shapes/ShapeUtil'\nimport { useEditor } from '../hooks/useEditor'\nimport { useEditorComponents } from '../hooks/useEditorComponents'\nimport { Mat } from '../primitives/Mat'\nimport { setStyleProperty } from '../utils/dom'\nimport { OptionalErrorBoundary } from './ErrorBoundary'\n\n/*\nThis component renders shapes on the canvas. There are two stages: positioning\nand styling the shape's container using CSS, and then rendering the shape's \nJSX using its shape util's render method. Rendering the \"inside\" of a shape is\nmore expensive than positioning it or changing its color, so we use memo\nto wrap the inner shape and only re-render it when the shape's props change. \n\nThe shape also receives props for its index and opacity. The index is used to\ndetermine the z-index of the shape, and the opacity is used to set the shape's\nopacity based on its own opacity and that of its parent's.\n*/\nexport const Shape = memo(function Shape({\n\tid,\n\tshape,\n\tutil,\n\tindex,\n\tbackgroundIndex,\n\topacity,\n}: {\n\tid: TLShapeId\n\tshape: TLShape\n\tutil: ShapeUtil\n\tindex: number\n\tbackgroundIndex: number\n\topacity: number\n}) {\n\tconst editor = useEditor()\n\n\tconst { ShapeErrorFallback } = useEditorComponents()\n\n\tconst containerRef = useRef<HTMLDivElement>(null)\n\tconst bgContainerRef = useRef<HTMLDivElement>(null)\n\n\tuseEffect(() => {\n\t\treturn react('load fonts', () => {\n\t\t\tconst fonts = editor.fonts.getShapeFontFaces(id)\n\t\t\teditor.fonts.requestFonts(fonts)\n\t\t})\n\t}, [editor, id])\n\n\tconst memoizedStuffRef = useRef({\n\t\ttransform: '',\n\t\tclipPath: 'none',\n\t\twidth: 0,\n\t\theight: 0,\n\t\tx: 0,\n\t\ty: 0,\n\t\tisCulled: false,\n\t})\n\n\tuseQuickReactor(\n\t\t'set shape stuff',\n\t\t() => {\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) return // probably the shape was just deleted\n\n\t\t\tconst prev = memoizedStuffRef.current\n\n\t\t\t// Clip path\n\t\t\tconst clipPath = editor.getShapeClipPath(id) ?? 'none'\n\t\t\tif (clipPath !== prev.clipPath) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'clip-path', clipPath)\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'clip-path', clipPath)\n\t\t\t\tprev.clipPath = clipPath\n\t\t\t}\n\n\t\t\t// Page transform\n\t\t\tconst pageTransform = editor.getShapePageTransform(id)\n\t\t\tconst transform = Mat.toCssString(pageTransform)\n\t\t\tconst bounds = editor.getShapeGeometry(shape).bounds\n\n\t\t\t// Update if the tranform has changed\n\t\t\tif (transform !== prev.transform) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'transform', transform)\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'transform', transform)\n\t\t\t\tprev.transform = transform\n\t\t\t}\n\n\t\t\t// Width / Height\n\t\t\tconst width = Math.max(bounds.width, 1)\n\t\t\tconst height = Math.max(bounds.height, 1)\n\n\t\t\tif (width !== prev.width || height !== prev.height) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'width', width + 'px')\n\t\t\t\tsetStyleProperty(containerRef.current, 'height', height + 'px')\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'width', width + 'px')\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'height', height + 'px')\n\t\t\t\tprev.width = width\n\t\t\t\tprev.height = height\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\n\t// This stuff changes pretty infrequently, so we can change them together\n\tuseQuickReactor(\n\t\t'set opacity and z-index',\n\t\t() => {\n\t\t\tconst container = containerRef.current\n\t\t\tconst bgContainer = bgContainerRef.current\n\n\t\t\t// Opacity\n\t\t\tsetStyleProperty(container, 'opacity', opacity)\n\t\t\tsetStyleProperty(bgContainer, 'opacity', opacity)\n\n\t\t\t// Z-Index\n\t\t\tsetStyleProperty(container, 'z-index', index)\n\t\t\tsetStyleProperty(bgContainer, 'z-index', backgroundIndex)\n\t\t},\n\t\t[opacity, index, backgroundIndex]\n\t)\n\n\tuseQuickReactor(\n\t\t'set display',\n\t\t() => {\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) return // probably the shape was just deleted\n\n\t\t\tconst culledShapes = editor.getCulledShapes()\n\t\t\tconst isCulled = culledShapes.has(id)\n\t\t\tif (isCulled !== memoizedStuffRef.current.isCulled) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'display', isCulled ? 'none' : 'block')\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'display', isCulled ? 'none' : 'block')\n\t\t\t\tmemoizedStuffRef.current.isCulled = isCulled\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\tconst annotateError = useCallback(\n\t\t(error: any) => editor.annotateError(error, { origin: 'shape', willCrashApp: false }),\n\t\t[editor]\n\t)\n\n\tif (!shape) return null\n\n\tconst isFilledShape = 'fill' in shape.props && shape.props.fill !== 'none'\n\n\treturn (\n\t\t<>\n\t\t\t{util.backgroundComponent && (\n\t\t\t\t<div\n\t\t\t\t\tref={bgContainerRef}\n\t\t\t\t\tclassName=\"tl-shape tl-shape-background\"\n\t\t\t\t\tdata-shape-type={shape.type}\n\t\t\t\t\tdata-shape-id={shape.id}\n\t\t\t\t\tdraggable={false}\n\t\t\t\t>\n\t\t\t\t\t<OptionalErrorBoundary fallback={ShapeErrorFallback} onError={annotateError}>\n\t\t\t\t\t\t<InnerShapeBackground shape={shape} util={util} />\n\t\t\t\t\t</OptionalErrorBoundary>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"tl-shape\"\n\t\t\t\tdata-shape-type={shape.type}\n\t\t\t\tdata-shape-is-filled={isFilledShape}\n\t\t\t\tdata-shape-id={shape.id}\n\t\t\t\tdraggable={false}\n\t\t\t>\n\t\t\t\t<OptionalErrorBoundary fallback={ShapeErrorFallback as any} onError={annotateError}>\n\t\t\t\t\t<InnerShape shape={shape} util={util} />\n\t\t\t\t</OptionalErrorBoundary>\n\t\t\t</div>\n\t\t</>\n\t)\n})\n\nexport const InnerShape = memo(\n\tfunction InnerShape<T extends TLShape>({ shape, util }: { shape: T; util: ShapeUtil<T> }) {\n\t\treturn useStateTracking(\n\t\t\t'InnerShape:' + shape.type,\n\t\t\t() =>\n\t\t\t\t// always fetch the latest shape from the store even if the props/meta have not changed, to avoid\n\t\t\t\t// calling the render method with stale data.\n\t\t\t\tutil.component(util.editor.store.unsafeGetWithoutCapture(shape.id) as T),\n\t\t\t[util, shape.id]\n\t\t)\n\t},\n\t(prev, next) =>\n\t\tprev.shape.props === next.shape.props &&\n\t\tprev.shape.meta === next.shape.meta &&\n\t\tprev.util === next.util\n)\n\nexport const InnerShapeBackground = memo(\n\tfunction InnerShapeBackground<T extends TLShape>({\n\t\tshape,\n\t\tutil,\n\t}: {\n\t\tshape: T\n\t\tutil: ShapeUtil<T>\n\t}) {\n\t\treturn useStateTracking(\n\t\t\t'InnerShape:' + shape.type,\n\t\t\t() =>\n\t\t\t\t// always fetch the latest shape from the store even if the props/meta have not changed, to avoid\n\t\t\t\t// calling the render method with stale data.\n\t\t\t\tutil.backgroundComponent?.(util.editor.store.unsafeGetWithoutCapture(shape.id) as T),\n\t\t\t[util, shape.id]\n\t\t)\n\t},\n\t(prev, next) =>\n\t\tprev.shape.props === next.shape.props &&\n\t\tprev.shape.meta === next.shape.meta &&\n\t\tprev.util === next.util\n)\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { react } from '@tldraw/state'\nimport { useQuickReactor, useStateTracking } from '@tldraw/state-react'\nimport { TLShape, TLShapeId } from '@tldraw/tlschema'\nimport { memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react'\nimport { ShapeUtil } from '../editor/shapes/ShapeUtil'\nimport { useEditor } from '../hooks/useEditor'\nimport { useEditorComponents } from '../hooks/useEditorComponents'\nimport { Mat } from '../primitives/Mat'\nimport { setStyleProperty } from '../utils/dom'\nimport { OptionalErrorBoundary } from './ErrorBoundary'\n\n/*\nThis component renders shapes on the canvas. There are two stages: positioning\nand styling the shape's container using CSS, and then rendering the shape's \nJSX using its shape util's render method. Rendering the \"inside\" of a shape is\nmore expensive than positioning it or changing its color, so we use memo\nto wrap the inner shape and only re-render it when the shape's props change. \n\nThe shape also receives props for its index and opacity. The index is used to\ndetermine the z-index of the shape, and the opacity is used to set the shape's\nopacity based on its own opacity and that of its parent's.\n*/\nexport const Shape = memo(function Shape({\n\tid,\n\tshape,\n\tutil,\n\tindex,\n\tbackgroundIndex,\n\topacity,\n}: {\n\tid: TLShapeId\n\tshape: TLShape\n\tutil: ShapeUtil\n\tindex: number\n\tbackgroundIndex: number\n\topacity: number\n}) {\n\tconst editor = useEditor()\n\n\tconst { ShapeErrorFallback } = useEditorComponents()\n\n\tconst containerRef = useRef<HTMLDivElement>(null)\n\tconst bgContainerRef = useRef<HTMLDivElement>(null)\n\n\tuseEffect(() => {\n\t\treturn react('load fonts', () => {\n\t\t\tconst fonts = editor.fonts.getShapeFontFaces(id)\n\t\t\teditor.fonts.requestFonts(fonts)\n\t\t})\n\t}, [editor, id])\n\n\tconst memoizedStuffRef = useRef({\n\t\ttransform: '',\n\t\tclipPath: 'none',\n\t\twidth: 0,\n\t\theight: 0,\n\t\tx: 0,\n\t\ty: 0,\n\t\tisCulled: false,\n\t})\n\n\tuseQuickReactor(\n\t\t'set shape stuff',\n\t\t() => {\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) return // probably the shape was just deleted\n\n\t\t\tconst prev = memoizedStuffRef.current\n\n\t\t\t// Clip path\n\t\t\tconst clipPath = editor.getShapeClipPath(id) ?? 'none'\n\t\t\tif (clipPath !== prev.clipPath) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'clip-path', clipPath)\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'clip-path', clipPath)\n\t\t\t\tprev.clipPath = clipPath\n\t\t\t}\n\n\t\t\t// Page transform\n\t\t\tconst pageTransform = editor.getShapePageTransform(id)\n\t\t\tconst transform = Mat.toCssString(pageTransform)\n\t\t\tconst bounds = editor.getShapeGeometry(shape).bounds\n\n\t\t\t// Update if the tranform has changed\n\t\t\tif (transform !== prev.transform) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'transform', transform)\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'transform', transform)\n\t\t\t\tprev.transform = transform\n\t\t\t}\n\n\t\t\t// Width / Height\n\t\t\tconst width = Math.max(bounds.width, 1)\n\t\t\tconst height = Math.max(bounds.height, 1)\n\n\t\t\tif (width !== prev.width || height !== prev.height) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'width', width + 'px')\n\t\t\t\tsetStyleProperty(containerRef.current, 'height', height + 'px')\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'width', width + 'px')\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'height', height + 'px')\n\t\t\t\tprev.width = width\n\t\t\t\tprev.height = height\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\n\t// This stuff changes pretty infrequently, so we can change them together\n\tuseLayoutEffect(() => {\n\t\tconst container = containerRef.current\n\t\tconst bgContainer = bgContainerRef.current\n\n\t\t// Opacity\n\t\tsetStyleProperty(container, 'opacity', opacity)\n\t\tsetStyleProperty(bgContainer, 'opacity', opacity)\n\n\t\t// Z-Index\n\t\tsetStyleProperty(container, 'z-index', index)\n\t\tsetStyleProperty(bgContainer, 'z-index', backgroundIndex)\n\t}, [opacity, index, backgroundIndex])\n\n\tuseQuickReactor(\n\t\t'set display',\n\t\t() => {\n\t\t\tconst shape = editor.getShape(id)\n\t\t\tif (!shape) return // probably the shape was just deleted\n\n\t\t\tconst culledShapes = editor.getCulledShapes()\n\t\t\tconst isCulled = culledShapes.has(id)\n\t\t\tif (isCulled !== memoizedStuffRef.current.isCulled) {\n\t\t\t\tsetStyleProperty(containerRef.current, 'display', isCulled ? 'none' : 'block')\n\t\t\t\tsetStyleProperty(bgContainerRef.current, 'display', isCulled ? 'none' : 'block')\n\t\t\t\tmemoizedStuffRef.current.isCulled = isCulled\n\t\t\t}\n\t\t},\n\t\t[editor]\n\t)\n\tconst annotateError = useCallback(\n\t\t(error: any) => editor.annotateError(error, { origin: 'shape', willCrashApp: false }),\n\t\t[editor]\n\t)\n\n\tif (!shape) return null\n\n\tconst isFilledShape = 'fill' in shape.props && shape.props.fill !== 'none'\n\n\treturn (\n\t\t<>\n\t\t\t{util.backgroundComponent && (\n\t\t\t\t<div\n\t\t\t\t\tref={bgContainerRef}\n\t\t\t\t\tclassName=\"tl-shape tl-shape-background\"\n\t\t\t\t\tdata-shape-type={shape.type}\n\t\t\t\t\tdata-shape-id={shape.id}\n\t\t\t\t\tdraggable={false}\n\t\t\t\t>\n\t\t\t\t\t<OptionalErrorBoundary fallback={ShapeErrorFallback} onError={annotateError}>\n\t\t\t\t\t\t<InnerShapeBackground shape={shape} util={util} />\n\t\t\t\t\t</OptionalErrorBoundary>\n\t\t\t\t</div>\n\t\t\t)}\n\t\t\t<div\n\t\t\t\tref={containerRef}\n\t\t\t\tclassName=\"tl-shape\"\n\t\t\t\tdata-shape-type={shape.type}\n\t\t\t\tdata-shape-is-filled={isFilledShape}\n\t\t\t\tdata-shape-id={shape.id}\n\t\t\t\tdraggable={false}\n\t\t\t>\n\t\t\t\t<OptionalErrorBoundary fallback={ShapeErrorFallback as any} onError={annotateError}>\n\t\t\t\t\t<InnerShape shape={shape} util={util} />\n\t\t\t\t</OptionalErrorBoundary>\n\t\t\t</div>\n\t\t</>\n\t)\n})\n\nexport const InnerShape = memo(\n\tfunction InnerShape<T extends TLShape>({ shape, util }: { shape: T; util: ShapeUtil<T> }) {\n\t\treturn useStateTracking(\n\t\t\t'InnerShape:' + shape.type,\n\t\t\t() =>\n\t\t\t\t// always fetch the latest shape from the store even if the props/meta have not changed, to avoid\n\t\t\t\t// calling the render method with stale data.\n\t\t\t\tutil.component(util.editor.store.unsafeGetWithoutCapture(shape.id) as T),\n\t\t\t[util, shape.id]\n\t\t)\n\t},\n\t(prev, next) =>\n\t\tprev.shape.props === next.shape.props &&\n\t\tprev.shape.meta === next.shape.meta &&\n\t\tprev.util === next.util\n)\n\nexport const InnerShapeBackground = memo(\n\tfunction InnerShapeBackground<T extends TLShape>({\n\t\tshape,\n\t\tutil,\n\t}: {\n\t\tshape: T\n\t\tutil: ShapeUtil<T>\n\t}) {\n\t\treturn useStateTracking(\n\t\t\t'InnerShape:' + shape.type,\n\t\t\t() =>\n\t\t\t\t// always fetch the latest shape from the store even if the props/meta have not changed, to avoid\n\t\t\t\t// calling the render method with stale data.\n\t\t\t\tutil.backgroundComponent?.(util.editor.store.unsafeGetWithoutCapture(shape.id) as T),\n\t\t\t[util, shape.id]\n\t\t)\n\t},\n\t(prev, next) =>\n\t\tprev.shape.props === next.shape.props &&\n\t\tprev.shape.meta === next.shape.meta &&\n\t\tprev.util === next.util\n)\n"],
5
+ "mappings": "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",
6
6
  "names": ["Shape", "shape", "InnerShape", "InnerShapeBackground"]
7
7
  }
@@ -7241,12 +7241,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7241
7241
  this.stopFollowingUser();
7242
7242
  }
7243
7243
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7244
- const { panSpeed, zoomSpeed } = cameraOptions;
7244
+ const { panSpeed } = cameraOptions;
7245
7245
  this._setCamera(
7246
7246
  new Vec(
7247
- cx + dx * panSpeed / cz - x / cz + x / (z * zoomSpeed),
7248
- cy + dy * panSpeed / cz - y / cz + y / (z * zoomSpeed),
7249
- z * zoomSpeed
7247
+ cx + dx * panSpeed / cz - x / cz + x / z,
7248
+ cy + dy * panSpeed / cz - y / cz + y / z,
7249
+ z
7250
7250
  ),
7251
7251
  { immediate: true }
7252
7252
  );
@@ -7297,14 +7297,9 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7297
7297
  }
7298
7298
  }
7299
7299
  const zoom = cz + (delta ?? 0) * zoomSpeed * cz;
7300
- this._setCamera(
7301
- new Vec(
7302
- cx + (x / zoom - x) - (x / cz - x),
7303
- cy + (y / zoom - y) - (y / cz - y),
7304
- zoom
7305
- ),
7306
- { immediate: true }
7307
- );
7300
+ this._setCamera(new Vec(cx + x / zoom - x / cz, cy + y / zoom - y / cz, zoom), {
7301
+ immediate: true
7302
+ });
7308
7303
  this.maybeTrackPerformance("Zooming");
7309
7304
  return;
7310
7305
  }