@tldraw/editor 3.16.0-canary.da857364642e → 3.16.0-canary.dbaaa1b0049c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cjs/index.d.ts +4 -0
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/components/Shape.js +7 -10
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +2 -21
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
- package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +1 -1
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/editor/Editor.js +10 -1
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +1 -1
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/options.js +6 -0
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +4 -0
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/components/Shape.mjs +7 -10
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +2 -21
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
- package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +1 -1
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/editor/Editor.mjs +10 -1
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +1 -1
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +6 -0
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/package.json +14 -37
- package/src/lib/components/Shape.tsx +6 -12
- package/src/lib/components/default-components/DefaultCanvas.tsx +2 -21
- package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
- package/src/lib/config/TLUserPreferences.ts +1 -1
- package/src/lib/editor/Editor.test.ts +12 -11
- package/src/lib/editor/Editor.ts +11 -1
- package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +15 -14
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +16 -15
- package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +49 -48
- package/src/lib/editor/managers/FontManager/FontManager.test.ts +24 -23
- package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +7 -6
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +12 -11
- package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +57 -50
- package/src/lib/editor/managers/TextManager/TextManager.test.ts +51 -26
- package/src/lib/editor/managers/TickManager/TickManager.test.ts +14 -13
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +21 -26
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +1 -1
- package/src/lib/license/LicenseManager.test.ts +3 -1
- package/src/lib/license/Watermark.test.tsx +2 -1
- package/src/lib/options.ts +6 -0
- package/src/lib/utils/sync/LocalIndexedDb.test.ts +2 -1
- package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
- package/src/version.ts +3 -3
- package/dist-cjs/lib/utils/nearestMultiple.js +0 -34
- package/dist-cjs/lib/utils/nearestMultiple.js.map +0 -7
- package/dist-esm/lib/utils/nearestMultiple.mjs +0 -14
- package/dist-esm/lib/utils/nearestMultiple.mjs.map +0 -7
- package/src/lib/utils/nearestMultiple.ts +0 -13
|
@@ -57,7 +57,7 @@ class UserPreferencesManager {
|
|
|
57
57
|
__runInitializers(_init, 5, this);
|
|
58
58
|
__publicField(this, "systemColorScheme", atom("systemColorScheme", "light"));
|
|
59
59
|
__publicField(this, "disposables", /* @__PURE__ */ new Set());
|
|
60
|
-
if (typeof window === "undefined" || !
|
|
60
|
+
if (typeof window === "undefined" || !window.matchMedia) return;
|
|
61
61
|
const darkModeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
62
62
|
if (darkModeMediaQuery?.matches) {
|
|
63
63
|
this.systemColorScheme.set("dark");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts"],
|
|
4
|
-
"sourcesContent": ["import { atom, computed } from '@tldraw/state'\nimport { TLUserPreferences, defaultUserPreferences } from '../../../config/TLUserPreferences'\nimport { TLUser } from '../../../config/createTLUser'\n\n/** @public */\nexport class UserPreferencesManager {\n\tsystemColorScheme = atom<'dark' | 'light'>('systemColorScheme', 'light')\n\tdisposables = new Set<() => void>()\n\tdispose() {\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\tconstructor(\n\t\tprivate readonly user: TLUser,\n\t\tprivate readonly inferDarkMode: boolean\n\t) {\n\t\tif (typeof window === 'undefined' || !
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,MAAM,gBAAgB;AAC/B,SAA4B,8BAA8B;AAqCzD,2BAAC,WAiBD,sBAAC,WAgBD,2BAAC,WAID,0BAAC,WAID,uCAAC,WAOD,cAAC,WAID,gBAAC,WAID,kBAAC,WAID,iBAAC,WAID,sBAAC,WAID,sBAAC,WAID,+BAAC,WAMD,+BAAC,WAOD,wBAAC;AAtHK,MAAM,uBAAuB;AAAA,EAMnC,YACkB,MACA,eAChB;AAFgB;AACA;AARZ;AACN,6CAAoB,KAAuB,qBAAqB,OAAO;AACvE,uCAAc,oBAAI,IAAgB;AAQjC,QAAI,OAAO,WAAW,eAAe,
|
|
4
|
+
"sourcesContent": ["import { atom, computed } from '@tldraw/state'\nimport { TLUserPreferences, defaultUserPreferences } from '../../../config/TLUserPreferences'\nimport { TLUser } from '../../../config/createTLUser'\n\n/** @public */\nexport class UserPreferencesManager {\n\tsystemColorScheme = atom<'dark' | 'light'>('systemColorScheme', 'light')\n\tdisposables = new Set<() => void>()\n\tdispose() {\n\t\tthis.disposables.forEach((d) => d())\n\t}\n\tconstructor(\n\t\tprivate readonly user: TLUser,\n\t\tprivate readonly inferDarkMode: boolean\n\t) {\n\t\tif (typeof window === 'undefined' || !window.matchMedia) return\n\n\t\tconst darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')\n\t\tif (darkModeMediaQuery?.matches) {\n\t\t\tthis.systemColorScheme.set('dark')\n\t\t}\n\t\tconst handleChange = (e: MediaQueryListEvent) => {\n\t\t\tif (e.matches) {\n\t\t\t\tthis.systemColorScheme.set('dark')\n\t\t\t} else {\n\t\t\t\tthis.systemColorScheme.set('light')\n\t\t\t}\n\t\t}\n\t\tdarkModeMediaQuery?.addEventListener('change', handleChange)\n\t\tthis.disposables.add(() => darkModeMediaQuery?.removeEventListener('change', handleChange))\n\t}\n\n\tupdateUserPreferences(userPreferences: Partial<TLUserPreferences>) {\n\t\tthis.user.setUserPreferences({\n\t\t\t...this.user.userPreferences.get(),\n\t\t\t...userPreferences,\n\t\t})\n\t}\n\t@computed getUserPreferences() {\n\t\treturn {\n\t\t\tid: this.getId(),\n\t\t\tname: this.getName(),\n\t\t\tlocale: this.getLocale(),\n\t\t\tcolor: this.getColor(),\n\t\t\tanimationSpeed: this.getAnimationSpeed(),\n\t\t\tareKeyboardShortcutsEnabled: this.getAreKeyboardShortcutsEnabled(),\n\t\t\tisSnapMode: this.getIsSnapMode(),\n\t\t\tcolorScheme: this.user.userPreferences.get().colorScheme,\n\t\t\tisDarkMode: this.getIsDarkMode(),\n\t\t\tisWrapMode: this.getIsWrapMode(),\n\t\t\tisDynamicResizeMode: this.getIsDynamicResizeMode(),\n\t\t\tshowUiLabels: this.getShowUiLabels(),\n\t\t}\n\t}\n\n\t@computed getIsDarkMode() {\n\t\tswitch (this.user.userPreferences.get().colorScheme) {\n\t\t\tcase 'dark':\n\t\t\t\treturn true\n\t\t\tcase 'light':\n\t\t\t\treturn false\n\t\t\tcase 'system':\n\t\t\t\treturn this.systemColorScheme.get() === 'dark'\n\t\t\tdefault:\n\t\t\t\treturn this.inferDarkMode ? this.systemColorScheme.get() === 'dark' : false\n\t\t}\n\t}\n\n\t/**\n\t * The speed at which the user can scroll by dragging toward the edge of the screen.\n\t */\n\t@computed getEdgeScrollSpeed() {\n\t\treturn this.user.userPreferences.get().edgeScrollSpeed ?? defaultUserPreferences.edgeScrollSpeed\n\t}\n\n\t@computed getAnimationSpeed() {\n\t\treturn this.user.userPreferences.get().animationSpeed ?? defaultUserPreferences.animationSpeed\n\t}\n\n\t@computed getAreKeyboardShortcutsEnabled() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().areKeyboardShortcutsEnabled ??\n\t\t\tdefaultUserPreferences.areKeyboardShortcutsEnabled\n\t\t)\n\t}\n\n\t@computed getId() {\n\t\treturn this.user.userPreferences.get().id\n\t}\n\n\t@computed getName() {\n\t\treturn this.user.userPreferences.get().name?.trim() ?? defaultUserPreferences.name\n\t}\n\n\t@computed getLocale() {\n\t\treturn this.user.userPreferences.get().locale ?? defaultUserPreferences.locale\n\t}\n\n\t@computed getColor() {\n\t\treturn this.user.userPreferences.get().color ?? defaultUserPreferences.color\n\t}\n\n\t@computed getIsSnapMode() {\n\t\treturn this.user.userPreferences.get().isSnapMode ?? defaultUserPreferences.isSnapMode\n\t}\n\n\t@computed getIsWrapMode() {\n\t\treturn this.user.userPreferences.get().isWrapMode ?? defaultUserPreferences.isWrapMode\n\t}\n\n\t@computed getIsDynamicResizeMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isDynamicSizeMode ?? defaultUserPreferences.isDynamicSizeMode\n\t\t)\n\t}\n\n\t@computed getIsPasteAtCursorMode() {\n\t\treturn (\n\t\t\tthis.user.userPreferences.get().isPasteAtCursorMode ??\n\t\t\tdefaultUserPreferences.isPasteAtCursorMode\n\t\t)\n\t}\n\n\t@computed getShowUiLabels() {\n\t\treturn this.user.userPreferences.get().showUiLabels ?? defaultUserPreferences.showUiLabels\n\t}\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/lib/options.mjs
CHANGED
|
@@ -11,6 +11,12 @@ const defaultTldrawOptions = {
|
|
|
11
11
|
// 6 squared
|
|
12
12
|
dragDistanceSquared: 16,
|
|
13
13
|
// 4 squared
|
|
14
|
+
uiDragDistanceSquared: 16,
|
|
15
|
+
// 4 squared
|
|
16
|
+
// it's really easy to accidentally drag from the toolbar on mobile, so we use a much larger
|
|
17
|
+
// threshold than usual here to try and prevent accidental drags.
|
|
18
|
+
uiCoarseDragDistanceSquared: 625,
|
|
19
|
+
// 25 squared
|
|
14
20
|
defaultSvgPadding: 32,
|
|
15
21
|
cameraSlideFriction: 0.09,
|
|
16
22
|
gridSteps: [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/lib/options.ts"],
|
|
4
|
-
"sourcesContent": ["import { ComponentType, Fragment } from 'react'\n\n/**\n * Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.\n *\n * @example\n * ```tsx\n * const options: Partial<TldrawOptions> = {\n * maxPages: 3,\n * maxShapesPerPage: 1000,\n * }\n *\n * function MyTldrawComponent() {\n * return <Tldraw options={options} />\n * }\n * ```\n *\n * @public\n */\nexport interface TldrawOptions {\n\treadonly maxShapesPerPage: number\n\treadonly maxFilesAtOnce: number\n\treadonly maxPages: number\n\treadonly animationMediumMs: number\n\treadonly followChaseViewportSnap: number\n\treadonly doubleClickDurationMs: number\n\treadonly multiClickDurationMs: number\n\treadonly coarseDragDistanceSquared: number\n\treadonly dragDistanceSquared: number\n\treadonly defaultSvgPadding: number\n\treadonly cameraSlideFriction: number\n\treadonly gridSteps: readonly {\n\t\treadonly min: number\n\t\treadonly mid: number\n\t\treadonly step: number\n\t}[]\n\treadonly collaboratorInactiveTimeoutMs: number\n\treadonly collaboratorIdleTimeoutMs: number\n\treadonly collaboratorCheckIntervalMs: number\n\treadonly cameraMovingTimeoutMs: number\n\treadonly hitTestMargin: number\n\treadonly edgeScrollDelay: number\n\treadonly edgeScrollEaseDuration: number\n\treadonly edgeScrollSpeed: number\n\treadonly edgeScrollDistance: number\n\treadonly coarsePointerWidth: number\n\treadonly coarseHandleRadius: number\n\treadonly handleRadius: number\n\treadonly longPressDurationMs: number\n\treadonly textShadowLod: number\n\treadonly adjacentShapeMargin: number\n\treadonly flattenImageBoundsExpand: number\n\treadonly flattenImageBoundsPadding: number\n\treadonly laserDelayMs: number\n\treadonly maxExportDelayMs: number\n\treadonly tooltipDelayMs: number\n\t/**\n\t * How long should previews created by {@link Editor.createTemporaryAssetPreview} last before\n\t * they expire? Defaults to 3 minutes.\n\t */\n\treadonly temporaryAssetPreviewLifetimeMs: number\n\treadonly actionShortcutsLocation: 'menu' | 'toolbar' | 'swap'\n\treadonly createTextOnCanvasDoubleClick: boolean\n\t/**\n\t * The react provider to use when exporting an image. This is useful if your shapes depend on\n\t * external context providers. By default, this is `React.Fragment`.\n\t */\n\treadonly exportProvider: ComponentType<{ children: React.ReactNode }>\n\t/**\n\t * By default, the toolbar items are accessible via number shortcuts according to their order. To disable this, set this option to false.\n\t */\n\treadonly enableToolbarKeyboardShortcuts: boolean\n\t/**\n\t * The maximum number of fonts that will be loaded while blocking the main rendering of the\n\t * canvas. If there are more than this number of fonts needed, we'll just show the canvas right\n\t * away and let the fonts load in in the background.\n\t */\n\treadonly maxFontsToLoadBeforeRender: number\n\t/**\n\t * If you have a CSP policy that blocks inline styles, you can use this prop to provide a\n\t * nonce to use in the editor's styles.\n\t */\n\treadonly nonce: string | undefined\n\t/**\n\t * Branding name of the app, currently only used for adding aria-label for the application.\n\t */\n\treadonly branding?: string\n}\n\n/** @public */\nexport const defaultTldrawOptions = {\n\tmaxShapesPerPage: 4000,\n\tmaxFilesAtOnce: 100,\n\tmaxPages: 40,\n\tanimationMediumMs: 320,\n\tfollowChaseViewportSnap: 2,\n\tdoubleClickDurationMs: 450,\n\tmultiClickDurationMs: 200,\n\tcoarseDragDistanceSquared: 36, // 6 squared\n\tdragDistanceSquared: 16, // 4 squared\n\tdefaultSvgPadding: 32,\n\tcameraSlideFriction: 0.09,\n\tgridSteps: [\n\t\t{ min: -1, mid: 0.15, step: 64 },\n\t\t{ min: 0.05, mid: 0.375, step: 16 },\n\t\t{ min: 0.15, mid: 1, step: 4 },\n\t\t{ min: 0.7, mid: 2.5, step: 1 },\n\t],\n\tcollaboratorInactiveTimeoutMs: 60000,\n\tcollaboratorIdleTimeoutMs: 3000,\n\tcollaboratorCheckIntervalMs: 1200,\n\tcameraMovingTimeoutMs: 64,\n\thitTestMargin: 8,\n\tedgeScrollDelay: 200,\n\tedgeScrollEaseDuration: 200,\n\tedgeScrollSpeed: 25,\n\tedgeScrollDistance: 8,\n\tcoarsePointerWidth: 12,\n\tcoarseHandleRadius: 20,\n\thandleRadius: 12,\n\tlongPressDurationMs: 500,\n\ttextShadowLod: 0.35,\n\tadjacentShapeMargin: 10,\n\tflattenImageBoundsExpand: 64,\n\tflattenImageBoundsPadding: 16,\n\tlaserDelayMs: 1200,\n\tmaxExportDelayMs: 5000,\n\ttooltipDelayMs: 700,\n\ttemporaryAssetPreviewLifetimeMs: 180000,\n\tactionShortcutsLocation: 'swap',\n\tcreateTextOnCanvasDoubleClick: true,\n\texportProvider: Fragment,\n\tenableToolbarKeyboardShortcuts: true,\n\tmaxFontsToLoadBeforeRender: Infinity,\n\tnonce: undefined,\n} as const satisfies TldrawOptions\n"],
|
|
5
|
-
"mappings": "AAAA,SAAwB,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import { ComponentType, Fragment } from 'react'\n\n/**\n * Options for configuring tldraw. For defaults, see {@link defaultTldrawOptions}.\n *\n * @example\n * ```tsx\n * const options: Partial<TldrawOptions> = {\n * maxPages: 3,\n * maxShapesPerPage: 1000,\n * }\n *\n * function MyTldrawComponent() {\n * return <Tldraw options={options} />\n * }\n * ```\n *\n * @public\n */\nexport interface TldrawOptions {\n\treadonly maxShapesPerPage: number\n\treadonly maxFilesAtOnce: number\n\treadonly maxPages: number\n\treadonly animationMediumMs: number\n\treadonly followChaseViewportSnap: number\n\treadonly doubleClickDurationMs: number\n\treadonly multiClickDurationMs: number\n\treadonly coarseDragDistanceSquared: number\n\treadonly dragDistanceSquared: number\n\treadonly uiDragDistanceSquared: number\n\treadonly uiCoarseDragDistanceSquared: number\n\treadonly defaultSvgPadding: number\n\treadonly cameraSlideFriction: number\n\treadonly gridSteps: readonly {\n\t\treadonly min: number\n\t\treadonly mid: number\n\t\treadonly step: number\n\t}[]\n\treadonly collaboratorInactiveTimeoutMs: number\n\treadonly collaboratorIdleTimeoutMs: number\n\treadonly collaboratorCheckIntervalMs: number\n\treadonly cameraMovingTimeoutMs: number\n\treadonly hitTestMargin: number\n\treadonly edgeScrollDelay: number\n\treadonly edgeScrollEaseDuration: number\n\treadonly edgeScrollSpeed: number\n\treadonly edgeScrollDistance: number\n\treadonly coarsePointerWidth: number\n\treadonly coarseHandleRadius: number\n\treadonly handleRadius: number\n\treadonly longPressDurationMs: number\n\treadonly textShadowLod: number\n\treadonly adjacentShapeMargin: number\n\treadonly flattenImageBoundsExpand: number\n\treadonly flattenImageBoundsPadding: number\n\treadonly laserDelayMs: number\n\treadonly maxExportDelayMs: number\n\treadonly tooltipDelayMs: number\n\t/**\n\t * How long should previews created by {@link Editor.createTemporaryAssetPreview} last before\n\t * they expire? Defaults to 3 minutes.\n\t */\n\treadonly temporaryAssetPreviewLifetimeMs: number\n\treadonly actionShortcutsLocation: 'menu' | 'toolbar' | 'swap'\n\treadonly createTextOnCanvasDoubleClick: boolean\n\t/**\n\t * The react provider to use when exporting an image. This is useful if your shapes depend on\n\t * external context providers. By default, this is `React.Fragment`.\n\t */\n\treadonly exportProvider: ComponentType<{ children: React.ReactNode }>\n\t/**\n\t * By default, the toolbar items are accessible via number shortcuts according to their order. To disable this, set this option to false.\n\t */\n\treadonly enableToolbarKeyboardShortcuts: boolean\n\t/**\n\t * The maximum number of fonts that will be loaded while blocking the main rendering of the\n\t * canvas. If there are more than this number of fonts needed, we'll just show the canvas right\n\t * away and let the fonts load in in the background.\n\t */\n\treadonly maxFontsToLoadBeforeRender: number\n\t/**\n\t * If you have a CSP policy that blocks inline styles, you can use this prop to provide a\n\t * nonce to use in the editor's styles.\n\t */\n\treadonly nonce: string | undefined\n\t/**\n\t * Branding name of the app, currently only used for adding aria-label for the application.\n\t */\n\treadonly branding?: string\n}\n\n/** @public */\nexport const defaultTldrawOptions = {\n\tmaxShapesPerPage: 4000,\n\tmaxFilesAtOnce: 100,\n\tmaxPages: 40,\n\tanimationMediumMs: 320,\n\tfollowChaseViewportSnap: 2,\n\tdoubleClickDurationMs: 450,\n\tmultiClickDurationMs: 200,\n\tcoarseDragDistanceSquared: 36, // 6 squared\n\tdragDistanceSquared: 16, // 4 squared\n\tuiDragDistanceSquared: 16, // 4 squared\n\t// it's really easy to accidentally drag from the toolbar on mobile, so we use a much larger\n\t// threshold than usual here to try and prevent accidental drags.\n\tuiCoarseDragDistanceSquared: 625, // 25 squared\n\tdefaultSvgPadding: 32,\n\tcameraSlideFriction: 0.09,\n\tgridSteps: [\n\t\t{ min: -1, mid: 0.15, step: 64 },\n\t\t{ min: 0.05, mid: 0.375, step: 16 },\n\t\t{ min: 0.15, mid: 1, step: 4 },\n\t\t{ min: 0.7, mid: 2.5, step: 1 },\n\t],\n\tcollaboratorInactiveTimeoutMs: 60000,\n\tcollaboratorIdleTimeoutMs: 3000,\n\tcollaboratorCheckIntervalMs: 1200,\n\tcameraMovingTimeoutMs: 64,\n\thitTestMargin: 8,\n\tedgeScrollDelay: 200,\n\tedgeScrollEaseDuration: 200,\n\tedgeScrollSpeed: 25,\n\tedgeScrollDistance: 8,\n\tcoarsePointerWidth: 12,\n\tcoarseHandleRadius: 20,\n\thandleRadius: 12,\n\tlongPressDurationMs: 500,\n\ttextShadowLod: 0.35,\n\tadjacentShapeMargin: 10,\n\tflattenImageBoundsExpand: 64,\n\tflattenImageBoundsPadding: 16,\n\tlaserDelayMs: 1200,\n\tmaxExportDelayMs: 5000,\n\ttooltipDelayMs: 700,\n\ttemporaryAssetPreviewLifetimeMs: 180000,\n\tactionShortcutsLocation: 'swap',\n\tcreateTextOnCanvasDoubleClick: true,\n\texportProvider: Fragment,\n\tenableToolbarKeyboardShortcuts: true,\n\tmaxFontsToLoadBeforeRender: Infinity,\n\tnonce: undefined,\n} as const satisfies TldrawOptions\n"],
|
|
5
|
+
"mappings": "AAAA,SAAwB,gBAAgB;AA4FjC,MAAM,uBAAuB;AAAA,EACnC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,sBAAsB;AAAA,EACtB,2BAA2B;AAAA;AAAA,EAC3B,qBAAqB;AAAA;AAAA,EACrB,uBAAuB;AAAA;AAAA;AAAA;AAAA,EAGvB,6BAA6B;AAAA;AAAA,EAC7B,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,WAAW;AAAA,IACV,EAAE,KAAK,IAAI,KAAK,MAAM,MAAM,GAAG;AAAA,IAC/B,EAAE,KAAK,MAAM,KAAK,OAAO,MAAM,GAAG;AAAA,IAClC,EAAE,KAAK,MAAM,KAAK,GAAG,MAAM,EAAE;AAAA,IAC7B,EAAE,KAAK,KAAK,KAAK,KAAK,MAAM,EAAE;AAAA,EAC/B;AAAA,EACA,+BAA+B;AAAA,EAC/B,2BAA2B;AAAA,EAC3B,6BAA6B;AAAA,EAC7B,uBAAuB;AAAA,EACvB,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,qBAAqB;AAAA,EACrB,0BAA0B;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EAChB,iCAAiC;AAAA,EACjC,yBAAyB;AAAA,EACzB,+BAA+B;AAAA,EAC/B,gBAAgB;AAAA,EAChB,gCAAgC;AAAA,EAChC,4BAA4B;AAAA,EAC5B,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "3.16.0-canary.
|
|
1
|
+
const version = "3.16.0-canary.dbaaa1b0049c";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2024-09-13T14:36:29.063Z",
|
|
4
|
-
minor: "2025-08-
|
|
5
|
-
patch: "2025-08-
|
|
4
|
+
minor: "2025-08-20T10:00:26.481Z",
|
|
5
|
+
patch: "2025-08-20T10:00:26.481Z"
|
|
6
6
|
};
|
|
7
7
|
export {
|
|
8
8
|
publishDates,
|
package/dist-esm/version.mjs.map
CHANGED
|
@@ -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.16.0-canary.
|
|
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.16.0-canary.dbaaa1b0049c'\nexport const publishDates = {\n\tmajor: '2024-09-13T14:36:29.063Z',\n\tminor: '2025-08-20T10:00:26.481Z',\n\tpatch: '2025-08-20T10:00:26.481Z',\n}\n"],
|
|
5
5
|
"mappings": "AAGO,MAAM,UAAU;AAChB,MAAM,eAAe;AAAA,EAC3B,OAAO;AAAA,EACP,OAAO;AAAA,EACP,OAAO;AACR;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tldraw/editor",
|
|
3
3
|
"description": "tldraw infinite canvas SDK (editor).",
|
|
4
|
-
"version": "3.16.0-canary.
|
|
4
|
+
"version": "3.16.0-canary.dbaaa1b0049c",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -34,27 +34,28 @@
|
|
|
34
34
|
"src"
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
|
-
"test-ci": "
|
|
38
|
-
"test": "yarn run -T
|
|
37
|
+
"test-ci": "yarn run -T vitest run --passWithNoTests",
|
|
38
|
+
"test": "yarn run -T vitest --passWithNoTests",
|
|
39
39
|
"benchmark": "yarn run -T tsx ./internal/scripts/benchmark.ts",
|
|
40
|
-
"test-coverage": "
|
|
40
|
+
"test-coverage": "yarn run -T vitest run --coverage --passWithNoTests",
|
|
41
41
|
"build": "yarn run -T tsx ../../internal/scripts/build-package.ts",
|
|
42
42
|
"build-api": "yarn run -T tsx ../../internal/scripts/build-api.ts",
|
|
43
43
|
"prepack": "yarn run -T tsx ../../internal/scripts/prepack.ts",
|
|
44
44
|
"postpack": "../../internal/scripts/postpack.sh",
|
|
45
45
|
"pack-tarball": "yarn pack",
|
|
46
|
-
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
46
|
+
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts",
|
|
47
|
+
"context": "yarn run -T tsx ../../internal/scripts/context.ts"
|
|
47
48
|
},
|
|
48
49
|
"dependencies": {
|
|
49
50
|
"@tiptap/core": "^2.9.1",
|
|
50
51
|
"@tiptap/pm": "^2.9.1",
|
|
51
52
|
"@tiptap/react": "^2.9.1",
|
|
52
|
-
"@tldraw/state": "3.16.0-canary.
|
|
53
|
-
"@tldraw/state-react": "3.16.0-canary.
|
|
54
|
-
"@tldraw/store": "3.16.0-canary.
|
|
55
|
-
"@tldraw/tlschema": "3.16.0-canary.
|
|
56
|
-
"@tldraw/utils": "3.16.0-canary.
|
|
57
|
-
"@tldraw/validate": "3.16.0-canary.
|
|
53
|
+
"@tldraw/state": "3.16.0-canary.dbaaa1b0049c",
|
|
54
|
+
"@tldraw/state-react": "3.16.0-canary.dbaaa1b0049c",
|
|
55
|
+
"@tldraw/store": "3.16.0-canary.dbaaa1b0049c",
|
|
56
|
+
"@tldraw/tlschema": "3.16.0-canary.dbaaa1b0049c",
|
|
57
|
+
"@tldraw/utils": "3.16.0-canary.dbaaa1b0049c",
|
|
58
|
+
"@tldraw/validate": "3.16.0-canary.dbaaa1b0049c",
|
|
58
59
|
"@types/core-js": "^2.5.8",
|
|
59
60
|
"@use-gesture/react": "^10.3.1",
|
|
60
61
|
"classnames": "^2.5.1",
|
|
@@ -69,41 +70,17 @@
|
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
72
|
"@peculiar/webcrypto": "^1.5.0",
|
|
72
|
-
"@testing-library/jest-dom": "^5.17.0",
|
|
73
73
|
"@testing-library/react": "^15.0.7",
|
|
74
74
|
"@types/benchmark": "^2.1.5",
|
|
75
75
|
"@types/react": "^18.3.18",
|
|
76
76
|
"@types/wicg-file-system-access": "^2020.9.8",
|
|
77
77
|
"benchmark": "^2.1.4",
|
|
78
78
|
"fake-indexeddb": "^4.0.2",
|
|
79
|
-
"jest-canvas-mock": "^2.5.2",
|
|
80
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
81
79
|
"lazyrepo": "0.0.0-alpha.27",
|
|
82
80
|
"react": "^18.3.1",
|
|
83
81
|
"react-dom": "^18.3.1",
|
|
84
|
-
"resize-observer-polyfill": "^1.5.1"
|
|
85
|
-
|
|
86
|
-
"jest": {
|
|
87
|
-
"preset": "../../internal/config/jest/node/jest-preset.js",
|
|
88
|
-
"testEnvironment": "../../../packages/utils/patchedJestJsDom.js",
|
|
89
|
-
"fakeTimers": {
|
|
90
|
-
"enableGlobally": true
|
|
91
|
-
},
|
|
92
|
-
"testPathIgnorePatterns": [
|
|
93
|
-
"^.+\\.*.css$"
|
|
94
|
-
],
|
|
95
|
-
"moduleNameMapper": {
|
|
96
|
-
"^~(.*)": "<rootDir>/src/$1",
|
|
97
|
-
"\\.(css|less|scss|sass)$": "identity-obj-proxy"
|
|
98
|
-
},
|
|
99
|
-
"setupFiles": [
|
|
100
|
-
"raf/polyfill",
|
|
101
|
-
"jest-canvas-mock",
|
|
102
|
-
"<rootDir>/setupTests.js"
|
|
103
|
-
],
|
|
104
|
-
"setupFilesAfterEnv": [
|
|
105
|
-
"../../internal/config/setupJest.ts"
|
|
106
|
-
]
|
|
82
|
+
"resize-observer-polyfill": "^1.5.1",
|
|
83
|
+
"vitest": "^3.2.4"
|
|
107
84
|
},
|
|
108
85
|
"module": "dist-esm/index.mjs",
|
|
109
86
|
"source": "src/index.ts",
|
|
@@ -28,7 +28,6 @@ export const Shape = memo(function Shape({
|
|
|
28
28
|
index,
|
|
29
29
|
backgroundIndex,
|
|
30
30
|
opacity,
|
|
31
|
-
dprMultiple,
|
|
32
31
|
}: {
|
|
33
32
|
id: TLShapeId
|
|
34
33
|
shape: TLShape
|
|
@@ -36,7 +35,6 @@ export const Shape = memo(function Shape({
|
|
|
36
35
|
index: number
|
|
37
36
|
backgroundIndex: number
|
|
38
37
|
opacity: number
|
|
39
|
-
dprMultiple: number
|
|
40
38
|
}) {
|
|
41
39
|
const editor = useEditor()
|
|
42
40
|
|
|
@@ -91,18 +89,14 @@ export const Shape = memo(function Shape({
|
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
// Width / Height
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const widthRemainder = bounds.w % dprMultiple
|
|
97
|
-
const heightRemainder = bounds.h % dprMultiple
|
|
98
|
-
const width = widthRemainder === 0 ? bounds.w : bounds.w + (dprMultiple - widthRemainder)
|
|
99
|
-
const height = heightRemainder === 0 ? bounds.h : bounds.h + (dprMultiple - heightRemainder)
|
|
92
|
+
const width = Math.max(bounds.width, 1)
|
|
93
|
+
const height = Math.max(bounds.height, 1)
|
|
100
94
|
|
|
101
95
|
if (width !== prev.width || height !== prev.height) {
|
|
102
|
-
setStyleProperty(containerRef.current, 'width',
|
|
103
|
-
setStyleProperty(containerRef.current, 'height',
|
|
104
|
-
setStyleProperty(bgContainerRef.current, 'width',
|
|
105
|
-
setStyleProperty(bgContainerRef.current, 'height',
|
|
96
|
+
setStyleProperty(containerRef.current, 'width', width + 'px')
|
|
97
|
+
setStyleProperty(containerRef.current, 'height', height + 'px')
|
|
98
|
+
setStyleProperty(bgContainerRef.current, 'width', width + 'px')
|
|
99
|
+
setStyleProperty(bgContainerRef.current, 'height', height + 'px')
|
|
106
100
|
prev.width = width
|
|
107
101
|
prev.height = height
|
|
108
102
|
}
|
|
@@ -22,7 +22,6 @@ import { Vec } from '../../primitives/Vec'
|
|
|
22
22
|
import { toDomPrecision } from '../../primitives/utils'
|
|
23
23
|
import { debugFlags } from '../../utils/debug-flags'
|
|
24
24
|
import { setStyleProperty } from '../../utils/dom'
|
|
25
|
-
import { nearestMultiple } from '../../utils/nearestMultiple'
|
|
26
25
|
import { GeometryDebuggingView } from '../GeometryDebuggingView'
|
|
27
26
|
import { LiveCollaborators } from '../LiveCollaborators'
|
|
28
27
|
import { MenuClickCapture } from '../MenuClickCapture'
|
|
@@ -390,18 +389,9 @@ function ShapesWithSVGs() {
|
|
|
390
389
|
|
|
391
390
|
const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])
|
|
392
391
|
|
|
393
|
-
const dprMultiple = useValue(
|
|
394
|
-
'dpr multiple',
|
|
395
|
-
() =>
|
|
396
|
-
// dprMultiple is the smallest number we can multiply dpr by to get an integer
|
|
397
|
-
// it's usually 1, 2, or 4 (for e.g. dpr of 2, 2.5 and 2.25 respectively)
|
|
398
|
-
nearestMultiple(Math.floor(editor.getInstanceState().devicePixelRatio * 100) / 100),
|
|
399
|
-
[editor]
|
|
400
|
-
)
|
|
401
|
-
|
|
402
392
|
return renderingShapes.map((result) => (
|
|
403
393
|
<Fragment key={result.id + '_fragment'}>
|
|
404
|
-
<Shape {...result}
|
|
394
|
+
<Shape {...result} />
|
|
405
395
|
<DebugSvgCopy id={result.id} mode="iframe" />
|
|
406
396
|
</Fragment>
|
|
407
397
|
))
|
|
@@ -436,19 +426,10 @@ function ShapesToDisplay() {
|
|
|
436
426
|
|
|
437
427
|
const renderingShapes = useValue('rendering shapes', () => editor.getRenderingShapes(), [editor])
|
|
438
428
|
|
|
439
|
-
const dprMultiple = useValue(
|
|
440
|
-
'dpr multiple',
|
|
441
|
-
() =>
|
|
442
|
-
// dprMultiple is the smallest number we can multiply dpr by to get an integer
|
|
443
|
-
// it's usually 1, 2, or 4 (for e.g. dpr of 2, 2.5 and 2.25 respectively)
|
|
444
|
-
nearestMultiple(Math.floor(editor.getInstanceState().devicePixelRatio * 100) / 100),
|
|
445
|
-
[editor]
|
|
446
|
-
)
|
|
447
|
-
|
|
448
429
|
return (
|
|
449
430
|
<>
|
|
450
431
|
{renderingShapes.map((result) => (
|
|
451
|
-
<Shape key={result.id + '_shape'} {...result}
|
|
432
|
+
<Shape key={result.id + '_shape'} {...result} />
|
|
452
433
|
))}
|
|
453
434
|
{tlenv.isSafari && <ReflowIfNeeded />}
|
|
454
435
|
</>
|
|
@@ -75,7 +75,7 @@ export const DefaultErrorFallback: TLErrorFallbackComponent = ({ error, editor }
|
|
|
75
75
|
|
|
76
76
|
// if we can't find a theme class from the app or from a parent, we have
|
|
77
77
|
// to fall back on using a media query:
|
|
78
|
-
if (typeof window !== 'undefined' &&
|
|
78
|
+
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
79
79
|
setIsDarkMode(window.matchMedia('(prefers-color-scheme: dark)').matches)
|
|
80
80
|
}
|
|
81
81
|
}, [isDarkModeFromApp])
|
|
@@ -135,7 +135,7 @@ function getRandomColor() {
|
|
|
135
135
|
|
|
136
136
|
/** @internal */
|
|
137
137
|
export function userPrefersReducedMotion() {
|
|
138
|
-
if (typeof window !== 'undefined' &&
|
|
138
|
+
if (typeof window !== 'undefined' && window.matchMedia) {
|
|
139
139
|
return window.matchMedia?.('(prefers-reduced-motion: reduce)')?.matches ?? false
|
|
140
140
|
}
|
|
141
141
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { vi } from 'vitest'
|
|
1
2
|
import {
|
|
2
3
|
Box,
|
|
3
4
|
Geometry2d,
|
|
@@ -59,8 +60,8 @@ beforeEach(() => {
|
|
|
59
60
|
getContainer: () => document.body,
|
|
60
61
|
})
|
|
61
62
|
editor.setCameraOptions({ isLocked: true })
|
|
62
|
-
editor.setCamera =
|
|
63
|
-
editor.user.getAnimationSpeed =
|
|
63
|
+
editor.setCamera = vi.fn()
|
|
64
|
+
editor.user.getAnimationSpeed = vi.fn()
|
|
64
65
|
})
|
|
65
66
|
|
|
66
67
|
describe('centerOnPoint', () => {
|
|
@@ -94,13 +95,13 @@ describe('updateShape', () => {
|
|
|
94
95
|
|
|
95
96
|
describe('zoomToFit', () => {
|
|
96
97
|
it('no-op when isLocked is set', () => {
|
|
97
|
-
editor.getCurrentPageShapeIds =
|
|
98
|
+
editor.getCurrentPageShapeIds = vi.fn(() => new Set([createShapeId('box1')]))
|
|
98
99
|
editor.zoomToFit()
|
|
99
100
|
expect(editor.setCamera).not.toHaveBeenCalled()
|
|
100
101
|
})
|
|
101
102
|
|
|
102
103
|
it('sets camera when isLocked is set and force flag is set', () => {
|
|
103
|
-
editor.getCurrentPageShapeIds =
|
|
104
|
+
editor.getCurrentPageShapeIds = vi.fn(() => new Set([createShapeId('box1')]))
|
|
104
105
|
editor.zoomToFit({ force: true })
|
|
105
106
|
expect(editor.setCamera).toHaveBeenCalled()
|
|
106
107
|
})
|
|
@@ -144,13 +145,13 @@ describe('zoomOut', () => {
|
|
|
144
145
|
|
|
145
146
|
describe('zoomToSelection', () => {
|
|
146
147
|
it('no-op when isLocked is set', () => {
|
|
147
|
-
editor.getSelectionPageBounds =
|
|
148
|
+
editor.getSelectionPageBounds = vi.fn(() => Box.From({ x: 0, y: 0, w: 100, h: 100 }))
|
|
148
149
|
editor.zoomToSelection()
|
|
149
150
|
expect(editor.setCamera).not.toHaveBeenCalled()
|
|
150
151
|
})
|
|
151
152
|
|
|
152
153
|
it('sets camera when isLocked is set and force flag is set', () => {
|
|
153
|
-
editor.getSelectionPageBounds =
|
|
154
|
+
editor.getSelectionPageBounds = vi.fn(() => Box.From({ x: 0, y: 0, w: 100, h: 100 }))
|
|
154
155
|
editor.zoomToSelection({ force: true })
|
|
155
156
|
expect(editor.setCamera).toHaveBeenCalled()
|
|
156
157
|
})
|
|
@@ -286,7 +287,7 @@ describe('getShapesAtPoint', () => {
|
|
|
286
287
|
|
|
287
288
|
it('filters out hidden shapes', () => {
|
|
288
289
|
// Create a spy to mock isShapeHidden
|
|
289
|
-
const isShapeHiddenSpy =
|
|
290
|
+
const isShapeHiddenSpy = vi.spyOn(editor, 'isShapeHidden')
|
|
290
291
|
isShapeHiddenSpy.mockImplementation((shape) => {
|
|
291
292
|
return typeof shape === 'string' ? shape === ids.shape3 : shape.id === ids.shape3
|
|
292
293
|
})
|
|
@@ -352,7 +353,7 @@ describe('getShapesAtPoint', () => {
|
|
|
352
353
|
|
|
353
354
|
it('returns empty array when all shapes are hidden', () => {
|
|
354
355
|
// Mock all shapes as hidden
|
|
355
|
-
const isShapeHiddenSpy =
|
|
356
|
+
const isShapeHiddenSpy = vi.spyOn(editor, 'isShapeHidden')
|
|
356
357
|
isShapeHiddenSpy.mockReturnValue(true)
|
|
357
358
|
|
|
358
359
|
const shapes = editor.getShapesAtPoint({ x: 50, y: 50 })
|
|
@@ -692,7 +693,7 @@ describe('selectAll', () => {
|
|
|
692
693
|
const initialSelectedIds = editor.getSelectedShapeIds()
|
|
693
694
|
|
|
694
695
|
// Spy on setSelectedShapes to verify it's not called
|
|
695
|
-
const setSelectedShapesSpy =
|
|
696
|
+
const setSelectedShapesSpy = vi.spyOn(editor, 'setSelectedShapes')
|
|
696
697
|
|
|
697
698
|
// Call selectAll
|
|
698
699
|
editor.selectAll()
|
|
@@ -713,7 +714,7 @@ describe('selectAll', () => {
|
|
|
713
714
|
const initialSelectedIds = editor.getSelectedShapeIds()
|
|
714
715
|
|
|
715
716
|
// Spy on setSelectedShapes to verify it's not called
|
|
716
|
-
const setSelectedShapesSpy =
|
|
717
|
+
const setSelectedShapesSpy = vi.spyOn(editor, 'setSelectedShapes')
|
|
717
718
|
|
|
718
719
|
// Call selectAll
|
|
719
720
|
editor.selectAll()
|
|
@@ -818,7 +819,7 @@ describe('selectAll', () => {
|
|
|
818
819
|
const initialSelectedIds = Array.from(editor.getSelectedShapeIds())
|
|
819
820
|
|
|
820
821
|
// Spy on setSelectedShapes to verify it's not called
|
|
821
|
-
const setSelectedShapesSpy =
|
|
822
|
+
const setSelectedShapesSpy = vi.spyOn(editor, 'setSelectedShapes')
|
|
822
823
|
|
|
823
824
|
// Call selectAll
|
|
824
825
|
editor.selectAll()
|
package/src/lib/editor/Editor.ts
CHANGED
|
@@ -6333,7 +6333,17 @@ export class Editor extends EventEmitter<TLEventMap> {
|
|
|
6333
6333
|
|
|
6334
6334
|
this.createShapes(shapesToCreate)
|
|
6335
6335
|
this.createBindings(bindingsToCreate)
|
|
6336
|
-
|
|
6336
|
+
|
|
6337
|
+
this.setSelectedShapes(
|
|
6338
|
+
compact(
|
|
6339
|
+
ids.map((oldId) => {
|
|
6340
|
+
const newId = shapeIds.get(oldId)
|
|
6341
|
+
if (!newId) return null
|
|
6342
|
+
if (!this.getShape(newId)) return null
|
|
6343
|
+
return newId
|
|
6344
|
+
})
|
|
6345
|
+
)
|
|
6346
|
+
)
|
|
6337
6347
|
|
|
6338
6348
|
if (offset !== undefined) {
|
|
6339
6349
|
// If we've offset the duplicated shapes, check to see whether their new bounds is entirely
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
+
import { Mocked, vi } from 'vitest'
|
|
1
2
|
import { Editor } from '../../Editor'
|
|
2
3
|
import { TLClickEventInfo, TLPointerEventInfo } from '../../types/event-types'
|
|
3
4
|
import { ClickManager } from './ClickManager'
|
|
4
5
|
|
|
5
6
|
// Mock the Editor class
|
|
6
|
-
|
|
7
|
+
vi.mock('../../Editor')
|
|
7
8
|
|
|
8
9
|
describe('ClickManager', () => {
|
|
9
|
-
let editor:
|
|
10
|
+
let editor: Mocked<Editor>
|
|
10
11
|
let clickManager: ClickManager
|
|
11
12
|
let mockTimers: any
|
|
12
13
|
|
|
@@ -29,14 +30,14 @@ describe('ClickManager', () => {
|
|
|
29
30
|
})
|
|
30
31
|
|
|
31
32
|
beforeEach(() => {
|
|
32
|
-
|
|
33
|
+
vi.useFakeTimers()
|
|
33
34
|
mockTimers = {
|
|
34
|
-
setTimeout:
|
|
35
|
+
setTimeout: vi.fn((fn, delay) => setTimeout(fn, delay)),
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
editor = {
|
|
38
39
|
timers: mockTimers,
|
|
39
|
-
dispatch:
|
|
40
|
+
dispatch: vi.fn(),
|
|
40
41
|
options: {
|
|
41
42
|
doubleClickDurationMs: 300,
|
|
42
43
|
multiClickDurationMs: 300,
|
|
@@ -46,7 +47,7 @@ describe('ClickManager', () => {
|
|
|
46
47
|
inputs: {
|
|
47
48
|
currentScreenPoint: { x: 0, y: 0 },
|
|
48
49
|
},
|
|
49
|
-
getInstanceState:
|
|
50
|
+
getInstanceState: vi.fn(() => ({
|
|
50
51
|
isCoarsePointer: false,
|
|
51
52
|
})),
|
|
52
53
|
} as any
|
|
@@ -55,8 +56,8 @@ describe('ClickManager', () => {
|
|
|
55
56
|
})
|
|
56
57
|
|
|
57
58
|
afterEach(() => {
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
vi.useRealTimers()
|
|
60
|
+
vi.clearAllMocks()
|
|
60
61
|
})
|
|
61
62
|
|
|
62
63
|
describe('constructor and initial state', () => {
|
|
@@ -100,7 +101,7 @@ describe('ClickManager', () => {
|
|
|
100
101
|
clickManager.handlePointerEvent(pointerEvent)
|
|
101
102
|
expect(clickManager.clickState).toBe('pendingDouble')
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
vi.advanceTimersByTime(350)
|
|
104
105
|
|
|
105
106
|
expect(clickManager.clickState).toBe('idle')
|
|
106
107
|
})
|
|
@@ -141,7 +142,7 @@ describe('ClickManager', () => {
|
|
|
141
142
|
clickManager.handlePointerEvent(firstDown)
|
|
142
143
|
clickManager.handlePointerEvent(secondDown)
|
|
143
144
|
|
|
144
|
-
|
|
145
|
+
vi.advanceTimersByTime(350)
|
|
145
146
|
|
|
146
147
|
expect(editor.dispatch).toHaveBeenCalledWith(
|
|
147
148
|
expect.objectContaining({
|
|
@@ -235,7 +236,7 @@ describe('ClickManager', () => {
|
|
|
235
236
|
clickManager.handlePointerEvent(pointerDown) // second
|
|
236
237
|
clickManager.handlePointerEvent(pointerDown) // third
|
|
237
238
|
|
|
238
|
-
|
|
239
|
+
vi.advanceTimersByTime(350)
|
|
239
240
|
|
|
240
241
|
expect(editor.dispatch).toHaveBeenCalledWith(
|
|
241
242
|
expect.objectContaining({
|
|
@@ -255,7 +256,7 @@ describe('ClickManager', () => {
|
|
|
255
256
|
clickManager.handlePointerEvent(pointerDown) // third
|
|
256
257
|
clickManager.handlePointerEvent(pointerDown) // fourth
|
|
257
258
|
|
|
258
|
-
|
|
259
|
+
vi.advanceTimersByTime(350)
|
|
259
260
|
|
|
260
261
|
expect(editor.dispatch).toHaveBeenCalledWith(
|
|
261
262
|
expect.objectContaining({
|
|
@@ -277,7 +278,7 @@ describe('ClickManager', () => {
|
|
|
277
278
|
editor.options.doubleClickDurationMs
|
|
278
279
|
)
|
|
279
280
|
|
|
280
|
-
|
|
281
|
+
vi.clearAllMocks()
|
|
281
282
|
|
|
282
283
|
// Second click - should use multiClickDurationMs
|
|
283
284
|
clickManager.handlePointerEvent(pointerDown)
|
|
@@ -392,7 +393,7 @@ describe('ClickManager', () => {
|
|
|
392
393
|
clickManager.cancelDoubleClickTimeout()
|
|
393
394
|
|
|
394
395
|
// Advance time - should not dispatch settle event
|
|
395
|
-
|
|
396
|
+
vi.advanceTimersByTime(350)
|
|
396
397
|
|
|
397
398
|
expect(editor.dispatch).not.toHaveBeenCalled()
|
|
398
399
|
expect(clickManager.clickState).toBe('idle')
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
+
import { Mock, Mocked, vi } from 'vitest'
|
|
1
2
|
import { Box } from '../../../primitives/Box'
|
|
2
3
|
import { Vec } from '../../../primitives/Vec'
|
|
3
4
|
import { Editor } from '../../Editor'
|
|
4
5
|
import { EdgeScrollManager } from './EdgeScrollManager'
|
|
5
6
|
|
|
6
7
|
// Mock the Editor class
|
|
7
|
-
|
|
8
|
+
vi.mock('../../Editor')
|
|
8
9
|
|
|
9
10
|
describe('EdgeScrollManager', () => {
|
|
10
|
-
let editor:
|
|
11
|
+
let editor: Mocked<
|
|
11
12
|
Editor & {
|
|
12
|
-
user: { getEdgeScrollSpeed:
|
|
13
|
-
getCamera:
|
|
14
|
-
getCameraOptions:
|
|
15
|
-
getZoomLevel:
|
|
16
|
-
getViewportScreenBounds:
|
|
13
|
+
user: { getEdgeScrollSpeed: Mock }
|
|
14
|
+
getCamera: Mock
|
|
15
|
+
getCameraOptions: Mock
|
|
16
|
+
getZoomLevel: Mock
|
|
17
|
+
getViewportScreenBounds: Mock
|
|
17
18
|
}
|
|
18
19
|
>
|
|
19
20
|
let edgeScrollManager: EdgeScrollManager
|
|
@@ -33,33 +34,33 @@ describe('EdgeScrollManager', () => {
|
|
|
33
34
|
isPanning: false,
|
|
34
35
|
},
|
|
35
36
|
user: {
|
|
36
|
-
getEdgeScrollSpeed:
|
|
37
|
+
getEdgeScrollSpeed: vi.fn(() => 1),
|
|
37
38
|
},
|
|
38
|
-
getViewportScreenBounds:
|
|
39
|
-
getInstanceState:
|
|
39
|
+
getViewportScreenBounds: vi.fn(() => new Box(0, 0, 1000, 600)),
|
|
40
|
+
getInstanceState: vi.fn(
|
|
40
41
|
() =>
|
|
41
42
|
({
|
|
42
43
|
isCoarsePointer: false,
|
|
43
44
|
insets: [false, false, false, false], // [top, right, bottom, left]
|
|
44
45
|
}) as any
|
|
45
46
|
),
|
|
46
|
-
getCameraOptions:
|
|
47
|
+
getCameraOptions: vi.fn(() => ({
|
|
47
48
|
isLocked: false,
|
|
48
49
|
panSpeed: 1,
|
|
49
50
|
zoomSpeed: 1,
|
|
50
51
|
zoomSteps: [1],
|
|
51
52
|
wheelBehavior: 'pan' as const,
|
|
52
53
|
})),
|
|
53
|
-
getZoomLevel:
|
|
54
|
-
getCamera:
|
|
55
|
-
setCamera:
|
|
54
|
+
getZoomLevel: vi.fn(() => 1),
|
|
55
|
+
getCamera: vi.fn(() => new Vec(0, 0, 1)),
|
|
56
|
+
setCamera: vi.fn(),
|
|
56
57
|
} as any
|
|
57
58
|
|
|
58
59
|
edgeScrollManager = new EdgeScrollManager(editor as any)
|
|
59
60
|
})
|
|
60
61
|
|
|
61
62
|
afterEach(() => {
|
|
62
|
-
|
|
63
|
+
vi.clearAllMocks()
|
|
63
64
|
})
|
|
64
65
|
|
|
65
66
|
describe('constructor and initialization', () => {
|