@tldraw/editor 5.6.0-canary.5bfc37740468 → 5.6.0-canary.5e46744c5daa

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 (66) hide show
  1. package/dist-cjs/index.d.ts +7 -1
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/components/LiveCollaborators.js +3 -3
  4. package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
  5. package/dist-cjs/lib/editor/Editor.js +19 -11
  6. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  7. package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js +10 -3
  8. package/dist-cjs/lib/editor/derivations/shapeIdsInCurrentPage.js.map +2 -2
  9. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +1 -1
  10. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  11. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +19 -2
  12. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +2 -2
  13. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +3 -5
  14. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
  15. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +7 -1
  16. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
  17. package/dist-cjs/lib/hooks/useDocumentEvents.js +28 -3
  18. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  19. package/dist-cjs/lib/license/LicenseManager.js +62 -4
  20. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  21. package/dist-cjs/lib/options.js +1 -1
  22. package/dist-cjs/lib/options.js.map +1 -1
  23. package/dist-cjs/version.js +3 -3
  24. package/dist-cjs/version.js.map +1 -1
  25. package/dist-esm/index.d.mts +7 -1
  26. package/dist-esm/index.mjs +1 -1
  27. package/dist-esm/lib/components/LiveCollaborators.mjs +3 -3
  28. package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
  29. package/dist-esm/lib/editor/Editor.mjs +19 -11
  30. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  31. package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs +10 -3
  32. package/dist-esm/lib/editor/derivations/shapeIdsInCurrentPage.mjs.map +2 -2
  33. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +1 -1
  34. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  35. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +20 -3
  36. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +2 -2
  37. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +3 -5
  38. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
  39. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +7 -1
  40. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
  41. package/dist-esm/lib/hooks/useDocumentEvents.mjs +28 -3
  42. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  43. package/dist-esm/lib/license/LicenseManager.mjs +62 -4
  44. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  45. package/dist-esm/lib/options.mjs +1 -1
  46. package/dist-esm/lib/options.mjs.map +1 -1
  47. package/dist-esm/version.mjs +3 -3
  48. package/dist-esm/version.mjs.map +1 -1
  49. package/editor.css +2 -1
  50. package/package.json +7 -7
  51. package/src/lib/components/LiveCollaborators.tsx +3 -3
  52. package/src/lib/editor/Editor.ts +37 -24
  53. package/src/lib/editor/derivations/shapeIdsInCurrentPage.ts +19 -3
  54. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +17 -0
  55. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +2 -2
  56. package/src/lib/editor/managers/FontManager/FontManager.test.ts +1 -0
  57. package/src/lib/editor/managers/FontManager/FontManager.ts +26 -3
  58. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +32 -0
  59. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +4 -6
  60. package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +16 -7
  61. package/src/lib/hooks/useDocumentEvents.ts +51 -3
  62. package/src/lib/license/LicenseManager.test.ts +204 -0
  63. package/src/lib/license/LicenseManager.ts +88 -4
  64. package/src/lib/options.ts +1 -1
  65. package/src/lib/test/useDocumentEvents.test.tsx +153 -22
  66. package/src/version.ts +3 -3
@@ -1059,7 +1059,7 @@ export declare const defaultTldrawOptions: {
1059
1059
  readonly step: 1;
1060
1060
  }];
1061
1061
  readonly handleRadius: 12;
1062
- readonly hitTestMargin: 3;
1062
+ readonly hitTestMargin: 4.5;
1063
1063
  readonly laserDelayMs: 1200;
1064
1064
  readonly laserFadeoutMs: 500;
1065
1065
  readonly longPressDurationMs: 500;
@@ -1922,6 +1922,8 @@ export declare class Editor extends EventEmitter<TLEventMap> {
1922
1922
  /**
1923
1923
  * Generates a reading order for shapes based on rows grouping.
1924
1924
  * Tries to keep a natural reading order (left-to-right, top-to-bottom).
1925
+ * Shapes whose util returns `false` from {@link ShapeUtil.canTabTo} are left out. Locked
1926
+ * shapes are included, so keyboard users can reach them to unlock them.
1925
1927
  *
1926
1928
  * @public
1927
1929
  */
@@ -4734,6 +4736,10 @@ export declare class FontManager {
4734
4736
  loadRequiredFontsForCurrentPage(limit?: number): Promise<void>;
4735
4737
  private readonly fontStates;
4736
4738
  private getFontState;
4739
+ private readonly fontLoadEpoch;
4740
+ /* Excluded from this release type: getFontLoadEpoch */
4741
+ private isFontLoadEpochBumpPending;
4742
+ private setFontState;
4737
4743
  ensureFontIsLoaded(font: TLFontFace): Promise<void>;
4738
4744
  private fontsToLoad;
4739
4745
  requestFonts(fonts: TLFontFace[]): void;
package/dist-cjs/index.js CHANGED
@@ -392,7 +392,7 @@ var import_uniq = require("./lib/utils/uniq");
392
392
  var import_defaultThemes2 = require("./lib/editor/managers/ThemeManager/defaultThemes");
393
393
  (0, import_utils.registerTldrawLibraryVersion)(
394
394
  "@tldraw/editor",
395
- "5.6.0-canary.5bfc37740468",
395
+ "5.6.0-canary.5e46744c5daa",
396
396
  "cjs"
397
397
  );
398
398
  //# sourceMappingURL=index.js.map
@@ -85,15 +85,15 @@ const Collaborator = (0, import_state_react.track)(function Collaborator2({
85
85
  });
86
86
  function CursorDef() {
87
87
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { id: (0, import_useSafeId.useSharedSafeId)("cursor"), children: [
88
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "rgba(0,0,0,.2)", transform: "translate(-11,-11)", children: [
88
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "rgba(0,0,0,.2)", transform: "translate(-11,-9)", children: [
89
89
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z" }),
90
90
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z" })
91
91
  ] }),
92
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "white", transform: "translate(-12,-12)", children: [
92
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "white", transform: "translate(-12,-10)", children: [
93
93
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z" }),
94
94
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z" })
95
95
  ] }),
96
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "currentColor", transform: "translate(-12,-12)", children: [
96
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("g", { fill: "currentColor", transform: "translate(-12,-10)", children: [
97
97
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z" }),
98
98
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m13 10.814v11.188l2.969-2.866.428-.139h4.768z" })
99
99
  ] })
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/components/LiveCollaborators.tsx"],
4
- "sourcesContent": ["import { track, useQuickReactor, useValue } from '@tldraw/state-react'\nimport { TLInstancePresence } from '@tldraw/tlschema'\nimport { useLayoutEffect, useRef } from 'react'\nimport { useEditorComponents } from '../hooks/EditorComponentsContext'\nimport { useEditor } from '../hooks/useEditor'\nimport { useSharedSafeId } from '../hooks/useSafeId'\nimport { isCursorInViewport } from '../utils/collaborators'\nimport { setStyleProperty } from '../utils/dom'\nimport { getHtmlLayerTransform } from '../utils/getHtmlLayerTransform'\n\n/**\n * The collaborator cursor layer: a DOM layer stacked as a sibling of the canvas \u2014 above all canvas\n * content, below the in-front layer and the UI panels \u2014 hosting each visible collaborator's cursor\n * (arrow, name tag, chat message). Off-viewport collaborators are the canvas-drawn hint arrows' job\n * (CollaboratorHintOverlayUtil), not this layer's.\n *\n * Cursors are DOM rather than canvas-drawn so their chrome styles and composes like the rest of\n * the UI. Re-render traffic is kept narrow: per-cursor positioning writes `transform` directly\n * (see `useTransform`), so a pointer move re-renders only the moved cursor; the camera transform\n * is written imperatively below, so a pure pan re-renders only cursors whose viewport visibility\n * flips (an equality-gated boolean per cursor); a zoom change re-renders every visible cursor,\n * because each one rescales by `1/zoom`.\n *\n * @public @react\n */\nexport const LiveCollaborators = track(function LiveCollaborators() {\n\tconst editor = useEditor()\n\tconst { CollaboratorCursor } = useEditorComponents()\n\n\t// The inner layer carries the camera transform, so the cursor components position in page\n\t// space exactly as canvas content does. Unlike the canvas's html layers this one unmounts\n\t// while no collaborators are visible, so the transform is written at two moments: on every\n\t// camera change (the reactor), and after every render (the layout effect, like useTransform\n\t// does per cursor) \u2014 the reactor's last run hit a null ref while the layer was unmounted,\n\t// and without the render-time write a reappearing layer would keep an identity transform\n\t// until the next camera move.\n\tconst rHtmlLayer = useRef<HTMLDivElement | null>(null)\n\tuseLayoutEffect(() => {\n\t\tconst elm = rHtmlLayer.current\n\t\tif (!elm) return\n\t\tsetStyleProperty(elm, 'transform', getHtmlLayerTransform(editor))\n\t})\n\tuseQuickReactor(\n\t\t'position collaborators layer',\n\t\tfunction positionCollaboratorsWhenCameraMoves() {\n\t\t\t// Reads the camera even while the layer is unmounted, keeping the subscription alive.\n\t\t\tconst transform = getHtmlLayerTransform(editor)\n\t\t\tsetStyleProperty(rHtmlLayer.current, 'transform', transform)\n\t\t},\n\t\t[editor]\n\t)\n\n\t// Visibility (activity state, following, highlighting) is handled by the editor.\n\tconst collaborators = editor.getVisibleCollaboratorsOnCurrentPage()\n\tif (collaborators.length === 0) return null\n\tif (!CollaboratorCursor) return null\n\n\treturn (\n\t\t<div className=\"tl-collaborators\">\n\t\t\t<svg className=\"tl-svg-context\" aria-hidden=\"true\">\n\t\t\t\t<defs>\n\t\t\t\t\t<CursorDef />\n\t\t\t\t</defs>\n\t\t\t</svg>\n\t\t\t<div ref={rHtmlLayer} className=\"tl-html-layer\">\n\t\t\t\t{collaborators.map((presence) => (\n\t\t\t\t\t<Collaborator key={presence.userId} latestPresence={presence} />\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n})\n\nconst Collaborator = track(function Collaborator({\n\tlatestPresence,\n}: {\n\tlatestPresence: TLInstancePresence\n}) {\n\tconst editor = useEditor()\n\tconst { CollaboratorCursor } = useEditorComponents()\n\n\tconst { userId, chatMessage, userName, cursor, color } = latestPresence\n\n\t// The viewport read lives inside this equality-gated computed rather than the tracked render:\n\t// pans move the viewport every frame, but this component only needs to know when the cursor\n\t// crosses the edge, so it subscribes to the boolean and re-renders only when it flips.\n\tconst cursorInViewport = useValue(\n\t\t'cursor in viewport',\n\t\t() =>\n\t\t\t!!cursor && isCursorInViewport(cursor, editor.getViewportPageBounds(), editor.getZoomLevel()),\n\t\t[editor, cursor]\n\t)\n\t// The zoom read is tracked directly: the cursor scales by 1/zoom, so zoom changes must\n\t// re-render it. Pure pans leave the zoom value unchanged, so they never invalidate this.\n\tconst zoomLevel = editor.getZoomLevel()\n\n\tif (!cursor) return null\n\n\t// Off-viewport collaborators show as the canvas-drawn hint arrows\n\t// (CollaboratorHintOverlayUtil), which shares this predicate \u2014 only the cursor itself is DOM.\n\tif (!cursorInViewport) return null\n\tif (!CollaboratorCursor) return null\n\treturn (\n\t\t<CollaboratorCursor\n\t\t\tclassName=\"tl-collaborator__cursor\"\n\t\t\tuserId={userId}\n\t\t\tpoint={cursor}\n\t\t\tcolor={color}\n\t\t\tzoom={zoomLevel}\n\t\t\tname={userName !== 'New User' ? userName : null}\n\t\t\tchatMessage={chatMessage ?? ''}\n\t\t/>\n\t)\n})\n\nfunction CursorDef() {\n\treturn (\n\t\t<g id={useSharedSafeId('cursor')}>\n\t\t\t<g fill=\"rgba(0,0,0,.2)\" transform=\"translate(-11,-11)\">\n\t\t\t\t<path d=\"m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z\" />\n\t\t\t\t<path d=\"m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z\" />\n\t\t\t</g>\n\t\t\t<g fill=\"white\" transform=\"translate(-12,-12)\">\n\t\t\t\t<path d=\"m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z\" />\n\t\t\t\t<path d=\"m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z\" />\n\t\t\t</g>\n\t\t\t<g fill=\"currentColor\" transform=\"translate(-12,-12)\">\n\t\t\t\t<path d=\"m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z\" />\n\t\t\t\t<path d=\"m13 10.814v11.188l2.969-2.866.428-.139h4.768z\" />\n\t\t\t</g>\n\t\t</g>\n\t)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0DE;AA1DF,yBAAiD;AAEjD,mBAAwC;AACxC,qCAAoC;AACpC,uBAA0B;AAC1B,uBAAgC;AAChC,2BAAmC;AACnC,iBAAiC;AACjC,mCAAsC;AAiB/B,MAAM,wBAAoB,0BAAM,SAASA,qBAAoB;AACnE,QAAM,aAAS,4BAAU;AACzB,QAAM,EAAE,mBAAmB,QAAI,oDAAoB;AASnD,QAAM,iBAAa,qBAA8B,IAAI;AACrD,oCAAgB,MAAM;AACrB,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,qCAAiB,KAAK,iBAAa,oDAAsB,MAAM,CAAC;AAAA,EACjE,CAAC;AACD;AAAA,IACC;AAAA,IACA,SAAS,uCAAuC;AAE/C,YAAM,gBAAY,oDAAsB,MAAM;AAC9C,uCAAiB,WAAW,SAAS,aAAa,SAAS;AAAA,IAC5D;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AAGA,QAAM,gBAAgB,OAAO,qCAAqC;AAClE,MAAI,cAAc,WAAW,EAAG,QAAO;AACvC,MAAI,CAAC,mBAAoB,QAAO;AAEhC,SACC,6CAAC,SAAI,WAAU,oBACd;AAAA,gDAAC,SAAI,WAAU,kBAAiB,eAAY,QAC3C,sDAAC,UACA,sDAAC,aAAU,GACZ,GACD;AAAA,IACA,4CAAC,SAAI,KAAK,YAAY,WAAU,iBAC9B,wBAAc,IAAI,CAAC,aACnB,4CAAC,gBAAmC,gBAAgB,YAAjC,SAAS,MAAkC,CAC9D,GACF;AAAA,KACD;AAEF,CAAC;AAED,MAAM,mBAAe,0BAAM,SAASC,cAAa;AAAA,EAChD;AACD,GAEG;AACF,QAAM,aAAS,4BAAU;AACzB,QAAM,EAAE,mBAAmB,QAAI,oDAAoB;AAEnD,QAAM,EAAE,QAAQ,aAAa,UAAU,QAAQ,MAAM,IAAI;AAKzD,QAAM,uBAAmB;AAAA,IACxB;AAAA,IACA,MACC,CAAC,CAAC,cAAU,yCAAmB,QAAQ,OAAO,sBAAsB,GAAG,OAAO,aAAa,CAAC;AAAA,IAC7F,CAAC,QAAQ,MAAM;AAAA,EAChB;AAGA,QAAM,YAAY,OAAO,aAAa;AAEtC,MAAI,CAAC,OAAQ,QAAO;AAIpB,MAAI,CAAC,iBAAkB,QAAO;AAC9B,MAAI,CAAC,mBAAoB,QAAO;AAChC,SACC;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,MAAM;AAAA,MACN,MAAM,aAAa,aAAa,WAAW;AAAA,MAC3C,aAAa,eAAe;AAAA;AAAA,EAC7B;AAEF,CAAC;AAED,SAAS,YAAY;AACpB,SACC,6CAAC,OAAE,QAAI,kCAAgB,QAAQ,GAC9B;AAAA,iDAAC,OAAE,MAAK,kBAAiB,WAAU,sBAClC;AAAA,kDAAC,UAAK,GAAE,uDAAsD;AAAA,MAC9D,4CAAC,UAAK,GAAE,0DAAyD;AAAA,OAClE;AAAA,IACA,6CAAC,OAAE,MAAK,SAAQ,WAAU,sBACzB;AAAA,kDAAC,UAAK,GAAE,uDAAsD;AAAA,MAC9D,4CAAC,UAAK,GAAE,0DAAyD;AAAA,OAClE;AAAA,IACA,6CAAC,OAAE,MAAK,gBAAe,WAAU,sBAChC;AAAA,kDAAC,UAAK,GAAE,mDAAkD;AAAA,MAC1D,4CAAC,UAAK,GAAE,iDAAgD;AAAA,OACzD;AAAA,KACD;AAEF;",
4
+ "sourcesContent": ["import { track, useQuickReactor, useValue } from '@tldraw/state-react'\nimport { TLInstancePresence } from '@tldraw/tlschema'\nimport { useLayoutEffect, useRef } from 'react'\nimport { useEditorComponents } from '../hooks/EditorComponentsContext'\nimport { useEditor } from '../hooks/useEditor'\nimport { useSharedSafeId } from '../hooks/useSafeId'\nimport { isCursorInViewport } from '../utils/collaborators'\nimport { setStyleProperty } from '../utils/dom'\nimport { getHtmlLayerTransform } from '../utils/getHtmlLayerTransform'\n\n/**\n * The collaborator cursor layer: a DOM layer stacked as a sibling of the canvas \u2014 above all canvas\n * content, below the in-front layer and the UI panels \u2014 hosting each visible collaborator's cursor\n * (arrow, name tag, chat message). Off-viewport collaborators are the canvas-drawn hint arrows' job\n * (CollaboratorHintOverlayUtil), not this layer's.\n *\n * Cursors are DOM rather than canvas-drawn so their chrome styles and composes like the rest of\n * the UI. Re-render traffic is kept narrow: per-cursor positioning writes `transform` directly\n * (see `useTransform`), so a pointer move re-renders only the moved cursor; the camera transform\n * is written imperatively below, so a pure pan re-renders only cursors whose viewport visibility\n * flips (an equality-gated boolean per cursor); a zoom change re-renders every visible cursor,\n * because each one rescales by `1/zoom`.\n *\n * @public @react\n */\nexport const LiveCollaborators = track(function LiveCollaborators() {\n\tconst editor = useEditor()\n\tconst { CollaboratorCursor } = useEditorComponents()\n\n\t// The inner layer carries the camera transform, so the cursor components position in page\n\t// space exactly as canvas content does. Unlike the canvas's html layers this one unmounts\n\t// while no collaborators are visible, so the transform is written at two moments: on every\n\t// camera change (the reactor), and after every render (the layout effect, like useTransform\n\t// does per cursor) \u2014 the reactor's last run hit a null ref while the layer was unmounted,\n\t// and without the render-time write a reappearing layer would keep an identity transform\n\t// until the next camera move.\n\tconst rHtmlLayer = useRef<HTMLDivElement | null>(null)\n\tuseLayoutEffect(() => {\n\t\tconst elm = rHtmlLayer.current\n\t\tif (!elm) return\n\t\tsetStyleProperty(elm, 'transform', getHtmlLayerTransform(editor))\n\t})\n\tuseQuickReactor(\n\t\t'position collaborators layer',\n\t\tfunction positionCollaboratorsWhenCameraMoves() {\n\t\t\t// Reads the camera even while the layer is unmounted, keeping the subscription alive.\n\t\t\tconst transform = getHtmlLayerTransform(editor)\n\t\t\tsetStyleProperty(rHtmlLayer.current, 'transform', transform)\n\t\t},\n\t\t[editor]\n\t)\n\n\t// Visibility (activity state, following, highlighting) is handled by the editor.\n\tconst collaborators = editor.getVisibleCollaboratorsOnCurrentPage()\n\tif (collaborators.length === 0) return null\n\tif (!CollaboratorCursor) return null\n\n\treturn (\n\t\t<div className=\"tl-collaborators\">\n\t\t\t<svg className=\"tl-svg-context\" aria-hidden=\"true\">\n\t\t\t\t<defs>\n\t\t\t\t\t<CursorDef />\n\t\t\t\t</defs>\n\t\t\t</svg>\n\t\t\t<div ref={rHtmlLayer} className=\"tl-html-layer\">\n\t\t\t\t{collaborators.map((presence) => (\n\t\t\t\t\t<Collaborator key={presence.userId} latestPresence={presence} />\n\t\t\t\t))}\n\t\t\t</div>\n\t\t</div>\n\t)\n})\n\nconst Collaborator = track(function Collaborator({\n\tlatestPresence,\n}: {\n\tlatestPresence: TLInstancePresence\n}) {\n\tconst editor = useEditor()\n\tconst { CollaboratorCursor } = useEditorComponents()\n\n\tconst { userId, chatMessage, userName, cursor, color } = latestPresence\n\n\t// The viewport read lives inside this equality-gated computed rather than the tracked render:\n\t// pans move the viewport every frame, but this component only needs to know when the cursor\n\t// crosses the edge, so it subscribes to the boolean and re-renders only when it flips.\n\tconst cursorInViewport = useValue(\n\t\t'cursor in viewport',\n\t\t() =>\n\t\t\t!!cursor && isCursorInViewport(cursor, editor.getViewportPageBounds(), editor.getZoomLevel()),\n\t\t[editor, cursor]\n\t)\n\t// The zoom read is tracked directly: the cursor scales by 1/zoom, so zoom changes must\n\t// re-render it. Pure pans leave the zoom value unchanged, so they never invalidate this.\n\tconst zoomLevel = editor.getZoomLevel()\n\n\tif (!cursor) return null\n\n\t// Off-viewport collaborators show as the canvas-drawn hint arrows\n\t// (CollaboratorHintOverlayUtil), which shares this predicate \u2014 only the cursor itself is DOM.\n\tif (!cursorInViewport) return null\n\tif (!CollaboratorCursor) return null\n\treturn (\n\t\t<CollaboratorCursor\n\t\t\tclassName=\"tl-collaborator__cursor\"\n\t\t\tuserId={userId}\n\t\t\tpoint={cursor}\n\t\t\tcolor={color}\n\t\t\tzoom={zoomLevel}\n\t\t\tname={userName !== 'New User' ? userName : null}\n\t\t\tchatMessage={chatMessage ?? ''}\n\t\t/>\n\t)\n})\n\nfunction CursorDef() {\n\treturn (\n\t\t<g id={useSharedSafeId('cursor')}>\n\t\t\t<g fill=\"rgba(0,0,0,.2)\" transform=\"translate(-11,-9)\">\n\t\t\t\t<path d=\"m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z\" />\n\t\t\t\t<path d=\"m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z\" />\n\t\t\t</g>\n\t\t\t<g fill=\"white\" transform=\"translate(-12,-10)\">\n\t\t\t\t<path d=\"m12 24.4219v-16.015l11.591 11.619h-6.781l-.411.124z\" />\n\t\t\t\t<path d=\"m21.0845 25.0962-3.605 1.535-4.682-11.089 3.686-1.553z\" />\n\t\t\t</g>\n\t\t\t<g fill=\"currentColor\" transform=\"translate(-12,-10)\">\n\t\t\t\t<path d=\"m19.751 24.4155-1.844.774-3.1-7.374 1.841-.775z\" />\n\t\t\t\t<path d=\"m13 10.814v11.188l2.969-2.866.428-.139h4.768z\" />\n\t\t\t</g>\n\t\t</g>\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA0DE;AA1DF,yBAAiD;AAEjD,mBAAwC;AACxC,qCAAoC;AACpC,uBAA0B;AAC1B,uBAAgC;AAChC,2BAAmC;AACnC,iBAAiC;AACjC,mCAAsC;AAiB/B,MAAM,wBAAoB,0BAAM,SAASA,qBAAoB;AACnE,QAAM,aAAS,4BAAU;AACzB,QAAM,EAAE,mBAAmB,QAAI,oDAAoB;AASnD,QAAM,iBAAa,qBAA8B,IAAI;AACrD,oCAAgB,MAAM;AACrB,UAAM,MAAM,WAAW;AACvB,QAAI,CAAC,IAAK;AACV,qCAAiB,KAAK,iBAAa,oDAAsB,MAAM,CAAC;AAAA,EACjE,CAAC;AACD;AAAA,IACC;AAAA,IACA,SAAS,uCAAuC;AAE/C,YAAM,gBAAY,oDAAsB,MAAM;AAC9C,uCAAiB,WAAW,SAAS,aAAa,SAAS;AAAA,IAC5D;AAAA,IACA,CAAC,MAAM;AAAA,EACR;AAGA,QAAM,gBAAgB,OAAO,qCAAqC;AAClE,MAAI,cAAc,WAAW,EAAG,QAAO;AACvC,MAAI,CAAC,mBAAoB,QAAO;AAEhC,SACC,6CAAC,SAAI,WAAU,oBACd;AAAA,gDAAC,SAAI,WAAU,kBAAiB,eAAY,QAC3C,sDAAC,UACA,sDAAC,aAAU,GACZ,GACD;AAAA,IACA,4CAAC,SAAI,KAAK,YAAY,WAAU,iBAC9B,wBAAc,IAAI,CAAC,aACnB,4CAAC,gBAAmC,gBAAgB,YAAjC,SAAS,MAAkC,CAC9D,GACF;AAAA,KACD;AAEF,CAAC;AAED,MAAM,mBAAe,0BAAM,SAASC,cAAa;AAAA,EAChD;AACD,GAEG;AACF,QAAM,aAAS,4BAAU;AACzB,QAAM,EAAE,mBAAmB,QAAI,oDAAoB;AAEnD,QAAM,EAAE,QAAQ,aAAa,UAAU,QAAQ,MAAM,IAAI;AAKzD,QAAM,uBAAmB;AAAA,IACxB;AAAA,IACA,MACC,CAAC,CAAC,cAAU,yCAAmB,QAAQ,OAAO,sBAAsB,GAAG,OAAO,aAAa,CAAC;AAAA,IAC7F,CAAC,QAAQ,MAAM;AAAA,EAChB;AAGA,QAAM,YAAY,OAAO,aAAa;AAEtC,MAAI,CAAC,OAAQ,QAAO;AAIpB,MAAI,CAAC,iBAAkB,QAAO;AAC9B,MAAI,CAAC,mBAAoB,QAAO;AAChC,SACC;AAAA,IAAC;AAAA;AAAA,MACA,WAAU;AAAA,MACV;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA,MAAM;AAAA,MACN,MAAM,aAAa,aAAa,WAAW;AAAA,MAC3C,aAAa,eAAe;AAAA;AAAA,EAC7B;AAEF,CAAC;AAED,SAAS,YAAY;AACpB,SACC,6CAAC,OAAE,QAAI,kCAAgB,QAAQ,GAC9B;AAAA,iDAAC,OAAE,MAAK,kBAAiB,WAAU,qBAClC;AAAA,kDAAC,UAAK,GAAE,uDAAsD;AAAA,MAC9D,4CAAC,UAAK,GAAE,0DAAyD;AAAA,OAClE;AAAA,IACA,6CAAC,OAAE,MAAK,SAAQ,WAAU,sBACzB;AAAA,kDAAC,UAAK,GAAE,uDAAsD;AAAA,MAC9D,4CAAC,UAAK,GAAE,0DAAyD;AAAA,OAClE;AAAA,IACA,6CAAC,OAAE,MAAK,gBAAe,WAAU,sBAChC;AAAA,kDAAC,UAAK,GAAE,mDAAkD;AAAA,MAC1D,4CAAC,UAAK,GAAE,iDAAgD;AAAA,OACzD;AAAA,KACD;AAEF;",
6
6
  "names": ["LiveCollaborators", "Collaborator"]
7
7
  }
@@ -1616,7 +1616,7 @@ class Editor extends import_eventemitter3.default {
1616
1616
  const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null;
1617
1617
  const isSelectedWithinContainer = firstParentId && selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) && !(0, import_tlschema.isPageId)(firstParentId);
1618
1618
  const filteredShapes = this.getCurrentPageShapes().filter(
1619
- (shape2) => !this.isShapeOrAncestorLocked(shape2) && (isSelectedWithinContainer ? shape2.parentId === firstParentId : (0, import_tlschema.isPageId)(shape2.parentId))
1619
+ (shape2) => isSelectedWithinContainer ? shape2.parentId === firstParentId : (0, import_tlschema.isPageId)(shape2.parentId)
1620
1620
  );
1621
1621
  const readingOrderShapes = this._getShapesInReadingOrder(filteredShapes);
1622
1622
  const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
@@ -1759,6 +1759,11 @@ class Editor extends import_eventemitter3.default {
1759
1759
  this._selectShapesAndZoom([sortedChildren[0].id]);
1760
1760
  }
1761
1761
  _selectShapesAndZoom(ids) {
1762
+ const selectedShapeIds = this.getSelectedShapeIds();
1763
+ const isSelectionChanging = ids.length !== selectedShapeIds.length || ids.some((id) => !selectedShapeIds.includes(id));
1764
+ if (isSelectionChanging) {
1765
+ this.markHistoryStoppingPoint("selecting adjacent shape");
1766
+ }
1762
1767
  this.setSelectedShapes(ids);
1763
1768
  this.zoomToSelectionIfOffscreen(256, {
1764
1769
  animation: {
@@ -5928,9 +5933,10 @@ class Editor extends import_eventemitter3.default {
5928
5933
  }
5929
5934
  }
5930
5935
  let workingShape = null;
5936
+ const initialPagePoint = import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec());
5931
5937
  if (util.onResize && util.canResize(initialShape)) {
5932
5938
  const newPagePoint = this._scalePagePoint(
5933
- import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec(0, 0)),
5939
+ initialPagePoint,
5934
5940
  scaleOrigin,
5935
5941
  scale,
5936
5942
  scaleAxisRotation
@@ -5943,7 +5949,6 @@ class Editor extends import_eventemitter3.default {
5943
5949
  );
5944
5950
  myScale.x = areWidthAndHeightAlignedWithCorrectAxis ? scale.x : scale.y;
5945
5951
  myScale.y = areWidthAndHeightAlignedWithCorrectAxis ? scale.y : scale.x;
5946
- const initialPagePoint = import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec());
5947
5952
  const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint);
5948
5953
  workingShape = initialShape;
5949
5954
  if (!opts.skipStartAndEndCallbacks) {
@@ -5989,24 +5994,26 @@ class Editor extends import_eventemitter3.default {
5989
5994
  scale,
5990
5995
  scaleAxisRotation
5991
5996
  );
5992
- const initialPageCenterInParentSpace = this.getPointInParentSpace(
5997
+ const repositionedPagePoint = import_Vec.Vec.Add(
5998
+ newPageCenter,
5999
+ import_Vec.Vec.Sub(initialPagePoint, initialPageCenter)
6000
+ );
6001
+ const repositionedLocalPoint = this.getPointInParentSpace(
5993
6002
  initialShape.id,
5994
- initialPageCenter
6003
+ repositionedPagePoint
5995
6004
  );
5996
- const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
5997
- const delta = import_Vec.Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
5998
6005
  if (workingShape) {
5999
6006
  return {
6000
6007
  ...workingShape,
6001
- x: initialShape.x + delta.x,
6002
- y: initialShape.y + delta.y
6008
+ x: repositionedLocalPoint.x,
6009
+ y: repositionedLocalPoint.y
6003
6010
  };
6004
6011
  }
6005
6012
  return {
6006
6013
  id,
6007
6014
  type: initialShape.type,
6008
- x: initialShape.x + delta.x,
6009
- y: initialShape.y + delta.y
6015
+ x: repositionedLocalPoint.x,
6016
+ y: repositionedLocalPoint.y
6010
6017
  };
6011
6018
  }
6012
6019
  /** @internal */
@@ -8354,6 +8361,7 @@ class Editor extends import_eventemitter3.default {
8354
8361
  break;
8355
8362
  }
8356
8363
  case "key_repeat": {
8364
+ inputs.keys.add(info.code);
8357
8365
  break;
8358
8366
  }
8359
8367
  }