@tldraw/editor 4.4.0-next.84d68f44c848 → 4.4.0-next.bde73a32273d
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 +277 -30
- package/dist-cjs/index.js +1 -6
- package/dist-cjs/index.js.map +3 -3
- package/dist-cjs/lib/TldrawEditor.js +20 -8
- package/dist-cjs/lib/TldrawEditor.js.map +2 -2
- package/dist-cjs/lib/components/LiveCollaborators.js +14 -24
- package/dist-cjs/lib/components/LiveCollaborators.js.map +2 -2
- package/dist-cjs/lib/components/Shape.js +12 -17
- package/dist-cjs/lib/components/Shape.js.map +2 -2
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js +226 -0
- package/dist-cjs/lib/components/default-components/CanvasShapeIndicators.js.map +7 -0
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js +45 -15
- package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +3 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js +13 -1
- package/dist-cjs/lib/components/default-components/DefaultShapeIndicators.js.map +2 -2
- package/dist-cjs/lib/config/TLUserPreferences.js +9 -3
- package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
- package/dist-cjs/lib/config/createTLStore.js.map +1 -1
- package/dist-cjs/lib/editor/Editor.js +39 -18
- package/dist-cjs/lib/editor/Editor.js.map +2 -2
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +32 -13
- package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +2 -2
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +2 -3
- package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +13 -38
- package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +3 -3
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +378 -89
- package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +8 -3
- package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js +29 -0
- package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
- package/dist-cjs/lib/editor/tools/RootState.js +0 -13
- package/dist-cjs/lib/editor/tools/RootState.js.map +2 -2
- package/dist-cjs/lib/hooks/usePeerIds.js +35 -0
- package/dist-cjs/lib/hooks/usePeerIds.js.map +2 -2
- package/dist-cjs/lib/hooks/useShapeCulling.js +75 -0
- package/dist-cjs/lib/hooks/useShapeCulling.js.map +7 -0
- package/dist-cjs/lib/license/LicenseManager.js +6 -6
- package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
- package/dist-cjs/lib/options.js +7 -1
- package/dist-cjs/lib/options.js.map +2 -2
- package/dist-cjs/lib/utils/collaboratorState.js +42 -0
- package/dist-cjs/lib/utils/collaboratorState.js.map +7 -0
- package/dist-cjs/version.js +3 -3
- package/dist-cjs/version.js.map +1 -1
- package/dist-esm/index.d.mts +277 -30
- package/dist-esm/index.mjs +1 -6
- package/dist-esm/index.mjs.map +2 -2
- package/dist-esm/lib/TldrawEditor.mjs +20 -8
- package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
- package/dist-esm/lib/components/LiveCollaborators.mjs +17 -24
- package/dist-esm/lib/components/LiveCollaborators.mjs.map +2 -2
- package/dist-esm/lib/components/Shape.mjs +12 -17
- package/dist-esm/lib/components/Shape.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs +206 -0
- package/dist-esm/lib/components/default-components/CanvasShapeIndicators.mjs.map +7 -0
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +45 -15
- package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +3 -1
- package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs +13 -1
- package/dist-esm/lib/components/default-components/DefaultShapeIndicators.mjs.map +2 -2
- package/dist-esm/lib/config/TLUserPreferences.mjs +9 -3
- package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
- package/dist-esm/lib/config/createTLStore.mjs.map +1 -1
- package/dist-esm/lib/editor/Editor.mjs +39 -18
- package/dist-esm/lib/editor/Editor.mjs.map +2 -2
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +32 -13
- package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +2 -3
- package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +14 -39
- package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +378 -89
- package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +8 -3
- package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +29 -0
- package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
- package/dist-esm/lib/editor/tools/RootState.mjs +0 -13
- package/dist-esm/lib/editor/tools/RootState.mjs.map +2 -2
- package/dist-esm/lib/hooks/usePeerIds.mjs +39 -1
- package/dist-esm/lib/hooks/usePeerIds.mjs.map +2 -2
- package/dist-esm/lib/hooks/useShapeCulling.mjs +55 -0
- package/dist-esm/lib/hooks/useShapeCulling.mjs.map +7 -0
- package/dist-esm/lib/license/LicenseManager.mjs +6 -6
- package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
- package/dist-esm/lib/options.mjs +7 -1
- package/dist-esm/lib/options.mjs.map +2 -2
- package/dist-esm/lib/utils/collaboratorState.mjs +22 -0
- package/dist-esm/lib/utils/collaboratorState.mjs.map +7 -0
- package/dist-esm/version.mjs +3 -3
- package/dist-esm/version.mjs.map +1 -1
- package/editor.css +28 -11
- package/package.json +8 -11
- package/src/index.ts +2 -5
- package/src/lib/TldrawEditor.tsx +35 -13
- package/src/lib/components/LiveCollaborators.tsx +26 -37
- package/src/lib/components/Shape.tsx +15 -16
- package/src/lib/components/default-components/CanvasShapeIndicators.tsx +288 -0
- package/src/lib/components/default-components/DefaultCanvas.tsx +39 -3
- package/src/lib/components/default-components/DefaultShapeIndicator.tsx +6 -1
- package/src/lib/components/default-components/DefaultShapeIndicators.tsx +16 -1
- package/src/lib/config/TLUserPreferences.test.ts +1 -0
- package/src/lib/config/TLUserPreferences.ts +8 -0
- package/src/lib/config/createTLStore.ts +1 -1
- package/src/lib/editor/Editor.ts +72 -20
- package/src/lib/editor/derivations/notVisibleShapes.ts +39 -17
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +0 -35
- package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +4 -8
- package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +19 -47
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +491 -106
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +24 -0
- package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +8 -0
- package/src/lib/editor/shapes/ShapeUtil.ts +63 -5
- package/src/lib/editor/tools/RootState.ts +0 -16
- package/src/lib/hooks/usePeerIds.ts +53 -1
- package/src/lib/hooks/useShapeCulling.tsx +98 -0
- package/src/lib/license/LicenseManager.ts +6 -6
- package/src/lib/options.ts +48 -2
- package/src/lib/utils/collaboratorState.ts +54 -0
- package/src/version.ts +3 -3
- package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +0 -621
package/dist-esm/lib/options.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fragment } from "react";
|
|
2
|
+
import { DEFAULT_CAMERA_OPTIONS } from "./constants.mjs";
|
|
2
3
|
const defaultTldrawOptions = {
|
|
3
4
|
maxShapesPerPage: 4e3,
|
|
4
5
|
maxFilesAtOnce: 100,
|
|
@@ -43,6 +44,7 @@ const defaultTldrawOptions = {
|
|
|
43
44
|
flattenImageBoundsExpand: 64,
|
|
44
45
|
flattenImageBoundsPadding: 16,
|
|
45
46
|
laserDelayMs: 1200,
|
|
47
|
+
laserFadeoutMs: 500,
|
|
46
48
|
maxExportDelayMs: 5e3,
|
|
47
49
|
tooltipDelayMs: 700,
|
|
48
50
|
temporaryAssetPreviewLifetimeMs: 18e4,
|
|
@@ -56,7 +58,11 @@ const defaultTldrawOptions = {
|
|
|
56
58
|
debouncedZoomThreshold: 500,
|
|
57
59
|
spacebarPanning: true,
|
|
58
60
|
zoomToFitPadding: 128,
|
|
59
|
-
snapThreshold: 8
|
|
61
|
+
snapThreshold: 8,
|
|
62
|
+
camera: DEFAULT_CAMERA_OPTIONS,
|
|
63
|
+
text: {},
|
|
64
|
+
deepLinks: void 0,
|
|
65
|
+
quickZoomPreservesScreenBounds: true
|
|
60
66
|
};
|
|
61
67
|
export {
|
|
62
68
|
defaultTldrawOptions
|
|
@@ -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 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\t/**\n\t * Whether to use debounced zoom level for certain rendering optimizations. When true,\n\t * `editor.
|
|
5
|
-
"mappings": "AAAA,SAAwB,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import { ComponentType, Fragment } from 'react'\nimport { DEFAULT_CAMERA_OPTIONS } from './constants'\nimport { TLCameraOptions } from './editor/types/misc-types'\nimport { TLDeepLinkOptions } from './utils/deepLinks'\nimport { TLTextOptions } from './utils/richText'\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\t/**\n\t * How long (in milliseconds) to fade all laser scribbles after the session ends.\n\t * The total points across all scribbles will be removed proportionally over this duration.\n\t * Defaults to 500ms (0.5 seconds).\n\t */\n\treadonly laserFadeoutMs: 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\t/**\n\t * Whether to use debounced zoom level for certain rendering optimizations. When true,\n\t * `editor.getEfficientZoomLevel()` returns a cached zoom value while the camera is moving,\n\t * reducing re-renders. When false, it always returns the current zoom level.\n\t */\n\treadonly debouncedZoom: boolean\n\t/**\n\t * The number of shapes that must be on the page for the debounced zoom level to be used.\n\t * Defaults to 500 shapes.\n\t */\n\treadonly debouncedZoomThreshold: number\n\t/**\n\t * Whether to allow spacebar panning. When true, the spacebar will pan the camera when held down.\n\t * When false, the spacebar will not pan the camera.\n\t */\n\treadonly spacebarPanning: boolean\n\t/**\n\t * The default padding (in pixels) used when zooming to fit content in the viewport.\n\t * This affects methods like `zoomToFit()`, `zoomToSelection()`, and `zoomToBounds()`.\n\t * The actual padding used is the minimum of this value and 28% of the viewport width.\n\t * Defaults to 128 pixels.\n\t */\n\treadonly zoomToFitPadding: number\n\t/**\n\t * The distance (in screen pixels) at which shapes snap to guides and other shapes.\n\t */\n\treadonly snapThreshold: number\n\t/**\n\t * Options for the editor's camera. These are the initial camera options.\n\t * Use {@link Editor.setCameraOptions} to update camera options at runtime.\n\t */\n\treadonly camera: Partial<TLCameraOptions>\n\t/**\n\t * Options for the editor's text rendering. These include TipTap configuration and\n\t * font handling. These are the initial text options and cannot be changed at runtime.\n\t */\n\treadonly text: TLTextOptions\n\t/**\n\t * Options for syncing the editor's camera state with the URL. Set to `true` to enable\n\t * with default options, or pass an options object to customize behavior.\n\t *\n\t * @example\n\t * ```tsx\n\t * // Enable with defaults\n\t * <Tldraw options={{ deepLinks: true }} />\n\t *\n\t * // Enable with custom options\n\t * <Tldraw options={{ deepLinks: { param: 'd', debounceMs: 500 } }} />\n\t * ```\n\t */\n\treadonly deepLinks: true | TLDeepLinkOptions | undefined\n\t/**\n\t * Whether the quick-zoom brush preserves its screen-pixel size when the user\n\t * zooms the overview. When true, zooming in shrinks the target viewport (higher\n\t * return zoom); zooming out expands it. When false, the brush keeps the original\n\t * viewport's page dimensions regardless of overview zoom changes.\n\t */\n\treadonly quickZoomPreservesScreenBounds: boolean\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\tlaserFadeoutMs: 500,\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\tdebouncedZoom: true,\n\tdebouncedZoomThreshold: 500,\n\tspacebarPanning: true,\n\tzoomToFitPadding: 128,\n\tsnapThreshold: 8,\n\tcamera: DEFAULT_CAMERA_OPTIONS,\n\ttext: {},\n\tdeepLinks: undefined,\n\tquickZoomPreservesScreenBounds: true,\n} as const satisfies TldrawOptions\n"],
|
|
5
|
+
"mappings": "AAAA,SAAwB,gBAAgB;AACxC,SAAS,8BAA8B;AA+JhC,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,gBAAgB;AAAA,EAChB,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;AAAA,EACP,eAAe;AAAA,EACf,wBAAwB;AAAA,EACxB,iBAAiB;AAAA,EACjB,kBAAkB;AAAA,EAClB,eAAe;AAAA,EACf,QAAQ;AAAA,EACR,MAAM,CAAC;AAAA,EACP,WAAW;AAAA,EACX,gCAAgC;AACjC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function getCollaboratorStateFromElapsedTime(editor, elapsed) {
|
|
2
|
+
return elapsed > editor.options.collaboratorInactiveTimeoutMs ? "inactive" : elapsed > editor.options.collaboratorIdleTimeoutMs ? "idle" : "active";
|
|
3
|
+
}
|
|
4
|
+
function shouldShowCollaborator(editor, presence, state) {
|
|
5
|
+
const { followingUserId, highlightedUserIds } = editor.getInstanceState();
|
|
6
|
+
switch (state) {
|
|
7
|
+
case "inactive":
|
|
8
|
+
return followingUserId === presence.userId || highlightedUserIds.includes(presence.userId);
|
|
9
|
+
case "idle":
|
|
10
|
+
if (presence.followingUserId === editor.user.getId()) {
|
|
11
|
+
return !!(presence.chatMessage || highlightedUserIds.includes(presence.userId));
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
case "active":
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
getCollaboratorStateFromElapsedTime,
|
|
20
|
+
shouldShowCollaborator
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=collaboratorState.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/lib/utils/collaboratorState.ts"],
|
|
4
|
+
"sourcesContent": ["import { TLInstancePresence } from '@tldraw/tlschema'\nimport { Editor } from '../editor/Editor'\n\n/** The activity state of a collaborator */\nexport type CollaboratorState = 'active' | 'idle' | 'inactive'\n\n/**\n * Get the activity state of a collaborator based on elapsed time since their last activity.\n *\n * @param editor - The editor instance\n * @param elapsed - Time in milliseconds since the collaborator's last activity\n * @returns The collaborator's activity state\n */\nexport function getCollaboratorStateFromElapsedTime(\n\teditor: Editor,\n\telapsed: number\n): CollaboratorState {\n\treturn elapsed > editor.options.collaboratorInactiveTimeoutMs\n\t\t? 'inactive'\n\t\t: elapsed > editor.options.collaboratorIdleTimeoutMs\n\t\t\t? 'idle'\n\t\t\t: 'active'\n}\n\n/**\n * Determine whether a collaborator should be shown based on their activity state\n * and the current instance state (following, highlighted users, etc.).\n *\n * @param editor - The editor instance\n * @param presence - The collaborator's presence data\n * @param state - The collaborator's activity state\n * @returns Whether the collaborator should be shown\n */\nexport function shouldShowCollaborator(\n\teditor: Editor,\n\tpresence: TLInstancePresence,\n\tstate: CollaboratorState\n): boolean {\n\tconst { followingUserId, highlightedUserIds } = editor.getInstanceState()\n\n\tswitch (state) {\n\t\tcase 'inactive':\n\t\t\t// If they're inactive, only show if we're following them or they're highlighted\n\t\t\treturn followingUserId === presence.userId || highlightedUserIds.includes(presence.userId)\n\t\tcase 'idle':\n\t\t\t// If they're idle and following us, hide them unless they have a chat message or are highlighted\n\t\t\tif (presence.followingUserId === editor.user.getId()) {\n\t\t\t\treturn !!(presence.chatMessage || highlightedUserIds.includes(presence.userId))\n\t\t\t}\n\t\t\treturn true\n\t\tcase 'active':\n\t\t\treturn true\n\t}\n}\n"],
|
|
5
|
+
"mappings": "AAaO,SAAS,oCACf,QACA,SACoB;AACpB,SAAO,UAAU,OAAO,QAAQ,gCAC7B,aACA,UAAU,OAAO,QAAQ,4BACxB,SACA;AACL;AAWO,SAAS,uBACf,QACA,UACA,OACU;AACV,QAAM,EAAE,iBAAiB,mBAAmB,IAAI,OAAO,iBAAiB;AAExE,UAAQ,OAAO;AAAA,IACd,KAAK;AAEJ,aAAO,oBAAoB,SAAS,UAAU,mBAAmB,SAAS,SAAS,MAAM;AAAA,IAC1F,KAAK;AAEJ,UAAI,SAAS,oBAAoB,OAAO,KAAK,MAAM,GAAG;AACrD,eAAO,CAAC,EAAE,SAAS,eAAe,mBAAmB,SAAS,SAAS,MAAM;AAAA,MAC9E;AACA,aAAO;AAAA,IACR,KAAK;AACJ,aAAO;AAAA,EACT;AACD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist-esm/version.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
const version = "4.4.0-next.
|
|
1
|
+
const version = "4.4.0-next.bde73a32273d";
|
|
2
2
|
const publishDates = {
|
|
3
3
|
major: "2025-09-18T14:39:22.803Z",
|
|
4
|
-
minor: "2026-
|
|
5
|
-
patch: "2026-
|
|
4
|
+
minor: "2026-02-11T22:21:46.227Z",
|
|
5
|
+
patch: "2026-02-11T22:21:46.227Z"
|
|
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 = '4.4.0-next.
|
|
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 = '4.4.0-next.bde73a32273d'\nexport const publishDates = {\n\tmajor: '2025-09-18T14:39:22.803Z',\n\tminor: '2026-02-11T22:21:46.227Z',\n\tpatch: '2026-02-11T22:21:46.227Z',\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/editor.css
CHANGED
|
@@ -22,14 +22,25 @@
|
|
|
22
22
|
--tl-radius-3: 9px;
|
|
23
23
|
--tl-radius-4: 11px;
|
|
24
24
|
|
|
25
|
-
/*
|
|
25
|
+
/*
|
|
26
|
+
* Canvas z-index
|
|
27
|
+
*
|
|
28
|
+
* .tl-canvas has `contain: strict` which creates its own stacking context.
|
|
29
|
+
* background, grid, shapes, overlays, and blocker are all children of .tl-canvas,
|
|
30
|
+
* so their z-indices are relative to the canvas, not the container.
|
|
31
|
+
*
|
|
32
|
+
* watermark and canvas-in-front are siblings of .tl-canvas (outside it),
|
|
33
|
+
* so they compete with the UI layer (.tlui-layout at z-index 300).
|
|
34
|
+
* canvas-in-front must be below the UI layer (300) to sit between
|
|
35
|
+
* the canvas and the UI.
|
|
36
|
+
*/
|
|
26
37
|
--tl-layer-canvas-hidden: -999999;
|
|
27
38
|
--tl-layer-canvas-background: 100;
|
|
28
39
|
--tl-layer-canvas-grid: 150;
|
|
29
40
|
--tl-layer-watermark: 200;
|
|
41
|
+
--tl-layer-canvas-in-front: 250;
|
|
30
42
|
--tl-layer-canvas-shapes: 300;
|
|
31
43
|
--tl-layer-canvas-overlays: 500;
|
|
32
|
-
--tl-layer-canvas-in-front: 600;
|
|
33
44
|
--tl-layer-canvas-blocker: 10000;
|
|
34
45
|
|
|
35
46
|
/* Canvas overlays z-index */
|
|
@@ -60,6 +71,7 @@
|
|
|
60
71
|
|
|
61
72
|
/* Misc */
|
|
62
73
|
--tl-zoom: 1;
|
|
74
|
+
--tl-tab-size: 2;
|
|
63
75
|
|
|
64
76
|
/* Cursor SVGs */
|
|
65
77
|
--tl-cursor-none: none;
|
|
@@ -146,6 +158,8 @@
|
|
|
146
158
|
--tl-color-selection-fill: hsl(210, 100%, 56%, 24%);
|
|
147
159
|
--tl-color-selection-stroke: hsl(214, 84%, 56%);
|
|
148
160
|
--tl-color-background: hsl(210, 20%, 98%);
|
|
161
|
+
/* if you ever update --tl-color-background, update the hardcoded values in theme-init.js and globals.css
|
|
162
|
+
they're there to make sure the background color matches the user's preference before the actual app loads*/
|
|
149
163
|
--tl-color-brush-fill: hsl(0, 0%, 56%, 10.2%);
|
|
150
164
|
--tl-color-brush-stroke: hsl(0, 0%, 56%, 25.1%);
|
|
151
165
|
--tl-color-grid: hsl(0, 0%, 43%);
|
|
@@ -202,6 +216,8 @@
|
|
|
202
216
|
--tl-color-selection-fill: hsl(209, 100%, 57%, 20%);
|
|
203
217
|
--tl-color-selection-stroke: hsl(214, 84%, 56%);
|
|
204
218
|
--tl-color-background: hsl(240, 5%, 6.5%);
|
|
219
|
+
/* if you ever update --tl-color-background, update the hardcoded values in theme-init.js and globals.css
|
|
220
|
+
they're there to make sure the background color matches the user's preference before the actual app loads*/
|
|
205
221
|
--tl-color-brush-fill: hsl(0, 0%, 71%, 5.1%);
|
|
206
222
|
--tl-color-brush-stroke: hsl(0, 0%, 71%, 25.1%);
|
|
207
223
|
--tl-color-grid: hsl(0, 0%, 40%);
|
|
@@ -895,6 +911,10 @@ input,
|
|
|
895
911
|
/* white-space: break-spaces; */
|
|
896
912
|
}
|
|
897
913
|
|
|
914
|
+
.tl-rich-text {
|
|
915
|
+
tab-size: var(--tl-tab-size, 2);
|
|
916
|
+
}
|
|
917
|
+
|
|
898
918
|
.tl-rich-text p {
|
|
899
919
|
margin: 0;
|
|
900
920
|
/* Depending on the extensions, <p> tags can be empty, without a <br />. */
|
|
@@ -1162,6 +1182,12 @@ input,
|
|
|
1162
1182
|
contain: size layout;
|
|
1163
1183
|
}
|
|
1164
1184
|
|
|
1185
|
+
.tl-canvas-indicators {
|
|
1186
|
+
position: absolute;
|
|
1187
|
+
inset: 0;
|
|
1188
|
+
pointer-events: none;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1165
1191
|
/* ---------------------- Shape --------------------- */
|
|
1166
1192
|
|
|
1167
1193
|
.tl-shape {
|
|
@@ -1536,15 +1562,6 @@ input,
|
|
|
1536
1562
|
cursor: var(--tl-cursor-text);
|
|
1537
1563
|
}
|
|
1538
1564
|
|
|
1539
|
-
/* If mobile use 16px as font size */
|
|
1540
|
-
/* On iOS, font size under 16px in an input will make the page zoom into the input 🤦♂️ */
|
|
1541
|
-
/* https://css-tricks.com/16px-or-larger-text-prevents-ios-form-zoom/ */
|
|
1542
|
-
@media (max-width: 600px) {
|
|
1543
|
-
.tl-frame-heading {
|
|
1544
|
-
font-size: 16px;
|
|
1545
|
-
}
|
|
1546
|
-
}
|
|
1547
|
-
|
|
1548
1565
|
/* ------------------- Embed Shape ------------------ */
|
|
1549
1566
|
|
|
1550
1567
|
.tl-embed {
|
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": "4.4.0-next.
|
|
4
|
+
"version": "4.4.0-next.bde73a32273d",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tldraw Inc.",
|
|
7
7
|
"email": "hello@tldraw.com"
|
|
@@ -43,23 +43,20 @@
|
|
|
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"
|
|
47
|
-
"context": "yarn run -T tsx ../../internal/scripts/context.ts"
|
|
46
|
+
"lint": "yarn run -T tsx ../../internal/scripts/lint.ts"
|
|
48
47
|
},
|
|
49
48
|
"dependencies": {
|
|
50
49
|
"@tiptap/core": "^3.12.1",
|
|
51
50
|
"@tiptap/pm": "^3.12.1",
|
|
52
51
|
"@tiptap/react": "^3.12.1",
|
|
53
|
-
"@tldraw/state": "4.4.0-next.
|
|
54
|
-
"@tldraw/state-react": "4.4.0-next.
|
|
55
|
-
"@tldraw/store": "4.4.0-next.
|
|
56
|
-
"@tldraw/tlschema": "4.4.0-next.
|
|
57
|
-
"@tldraw/utils": "4.4.0-next.
|
|
58
|
-
"@tldraw/validate": "4.4.0-next.
|
|
59
|
-
"@types/core-js": "^2.5.8",
|
|
52
|
+
"@tldraw/state": "4.4.0-next.bde73a32273d",
|
|
53
|
+
"@tldraw/state-react": "4.4.0-next.bde73a32273d",
|
|
54
|
+
"@tldraw/store": "4.4.0-next.bde73a32273d",
|
|
55
|
+
"@tldraw/tlschema": "4.4.0-next.bde73a32273d",
|
|
56
|
+
"@tldraw/utils": "4.4.0-next.bde73a32273d",
|
|
57
|
+
"@tldraw/validate": "4.4.0-next.bde73a32273d",
|
|
60
58
|
"@use-gesture/react": "^10.3.1",
|
|
61
59
|
"classnames": "^2.5.1",
|
|
62
|
-
"core-js": "^3.40.0",
|
|
63
60
|
"eventemitter3": "^4.0.7",
|
|
64
61
|
"idb": "^7.1.1",
|
|
65
62
|
"is-plain-object": "^5.0.0",
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { registerTldrawLibraryVersion } from '@tldraw/utils'
|
|
2
|
-
import 'core-js/stable/array/at.js'
|
|
3
|
-
import 'core-js/stable/array/flat-map.js'
|
|
4
|
-
import 'core-js/stable/array/flat.js'
|
|
5
|
-
import 'core-js/stable/string/at.js'
|
|
6
|
-
import 'core-js/stable/string/replace-all.js'
|
|
7
2
|
|
|
8
3
|
// eslint-disable-next-line local/no-export-star
|
|
9
4
|
export * from '@tldraw/state'
|
|
@@ -150,6 +145,7 @@ export { InputsManager } from './lib/editor/managers/InputsManager/InputsManager
|
|
|
150
145
|
export {
|
|
151
146
|
ScribbleManager,
|
|
152
147
|
type ScribbleItem,
|
|
148
|
+
type ScribbleSessionOptions,
|
|
153
149
|
} from './lib/editor/managers/ScribbleManager/ScribbleManager'
|
|
154
150
|
export {
|
|
155
151
|
BoundsSnaps,
|
|
@@ -184,6 +180,7 @@ export {
|
|
|
184
180
|
type TLEditStartInfo,
|
|
185
181
|
type TLGeometryOpts,
|
|
186
182
|
type TLHandleDragInfo,
|
|
183
|
+
type TLIndicatorPath,
|
|
187
184
|
type TLResizeInfo,
|
|
188
185
|
type TLResizeMode,
|
|
189
186
|
type TLShapeUtilCanBeLaidOutOpts,
|
package/src/lib/TldrawEditor.tsx
CHANGED
|
@@ -164,18 +164,22 @@ export interface TldrawEditorBaseProps {
|
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* Camera options for the editor.
|
|
167
|
+
*
|
|
168
|
+
* @deprecated Use `options.cameraOptions` instead. This will be removed in a future release.
|
|
167
169
|
*/
|
|
168
170
|
cameraOptions?: Partial<TLCameraOptions>
|
|
169
171
|
|
|
170
172
|
/**
|
|
171
|
-
*
|
|
173
|
+
* Options for the editor.
|
|
172
174
|
*/
|
|
173
|
-
|
|
175
|
+
options?: Partial<TldrawOptions>
|
|
174
176
|
|
|
175
177
|
/**
|
|
176
|
-
*
|
|
178
|
+
* Text options for the editor.
|
|
179
|
+
*
|
|
180
|
+
* @deprecated Use `options.text` instead. This prop will be removed in a future release.
|
|
177
181
|
*/
|
|
178
|
-
|
|
182
|
+
textOptions?: TLTextOptions
|
|
179
183
|
|
|
180
184
|
/**
|
|
181
185
|
* The license key.
|
|
@@ -184,6 +188,8 @@ export interface TldrawEditorBaseProps {
|
|
|
184
188
|
|
|
185
189
|
/**
|
|
186
190
|
* Options for syncing the editor's camera state with the URL.
|
|
191
|
+
*
|
|
192
|
+
* @deprecated Use `options.deepLinks` instead. This prop will be removed in a future release.
|
|
187
193
|
*/
|
|
188
194
|
deepLinks?: true | TLDeepLinkOptions
|
|
189
195
|
|
|
@@ -191,7 +197,7 @@ export interface TldrawEditorBaseProps {
|
|
|
191
197
|
* Provides a way to hide shapes.
|
|
192
198
|
*
|
|
193
199
|
* Hidden shapes will not render in the editor, and they will not be eligible for hit test via
|
|
194
|
-
* {@link Editor
|
|
200
|
+
* {@link @tldraw/editor#Editor.getShapeAtPoint} and {@link @tldraw/editor#Editor.getShapesAtPoint}. But otherwise they will
|
|
195
201
|
* remain in the store and participate in all other operations.
|
|
196
202
|
*
|
|
197
203
|
* @example
|
|
@@ -248,6 +254,10 @@ export const TldrawEditor = memo(function TldrawEditor({
|
|
|
248
254
|
className,
|
|
249
255
|
user: _user,
|
|
250
256
|
options: _options,
|
|
257
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
258
|
+
textOptions: _textOptions,
|
|
259
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
260
|
+
deepLinks: _deepLinks,
|
|
251
261
|
...rest
|
|
252
262
|
}: TldrawEditorProps) {
|
|
253
263
|
const [container, setContainer] = useState<HTMLElement | null>(null)
|
|
@@ -256,6 +266,19 @@ export const TldrawEditor = memo(function TldrawEditor({
|
|
|
256
266
|
const ErrorFallback =
|
|
257
267
|
components?.ErrorFallback === undefined ? DefaultErrorFallback : components?.ErrorFallback
|
|
258
268
|
|
|
269
|
+
// Merge deprecated props with options
|
|
270
|
+
// options values take precedence over the deprecated props
|
|
271
|
+
const mergedOptions = useMemo(() => {
|
|
272
|
+
let result = _options
|
|
273
|
+
if (_textOptions) {
|
|
274
|
+
result = { ...result, text: result?.text ?? _textOptions }
|
|
275
|
+
}
|
|
276
|
+
if (_deepLinks !== undefined) {
|
|
277
|
+
result = { ...result, deepLinks: result?.deepLinks ?? _deepLinks }
|
|
278
|
+
}
|
|
279
|
+
return result
|
|
280
|
+
}, [_options, _textOptions, _deepLinks])
|
|
281
|
+
|
|
259
282
|
// apply defaults. if you're using the bare @tldraw/editor package, we
|
|
260
283
|
// default these to the "tldraw zero" configuration. We have different
|
|
261
284
|
// defaults applied in tldraw.
|
|
@@ -265,7 +288,7 @@ export const TldrawEditor = memo(function TldrawEditor({
|
|
|
265
288
|
bindingUtils: rest.bindingUtils ?? EMPTY_BINDING_UTILS_ARRAY,
|
|
266
289
|
tools: rest.tools ?? EMPTY_TOOLS_ARRAY,
|
|
267
290
|
components,
|
|
268
|
-
options: useShallowObjectIdentity(
|
|
291
|
+
options: useShallowObjectIdentity(mergedOptions),
|
|
269
292
|
}
|
|
270
293
|
|
|
271
294
|
return (
|
|
@@ -397,11 +420,10 @@ function TldrawEditorWithReadyStore({
|
|
|
397
420
|
initialState,
|
|
398
421
|
autoFocus = true,
|
|
399
422
|
inferDarkMode,
|
|
423
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
|
400
424
|
cameraOptions,
|
|
401
|
-
textOptions,
|
|
402
425
|
options,
|
|
403
426
|
licenseKey,
|
|
404
|
-
deepLinks: _deepLinks,
|
|
405
427
|
getShapeVisibility,
|
|
406
428
|
assetUrls,
|
|
407
429
|
}: Required<
|
|
@@ -418,6 +440,7 @@ function TldrawEditorWithReadyStore({
|
|
|
418
440
|
|
|
419
441
|
const canvasRef = useRef<HTMLDivElement | null>(null)
|
|
420
442
|
|
|
443
|
+
const _deepLinks = options?.deepLinks
|
|
421
444
|
const deepLinks = useShallowObjectIdentity(_deepLinks === true ? {} : _deepLinks)
|
|
422
445
|
|
|
423
446
|
// props in this ref can be changed without causing the editor to be recreated.
|
|
@@ -458,7 +481,6 @@ function TldrawEditorWithReadyStore({
|
|
|
458
481
|
autoFocus,
|
|
459
482
|
inferDarkMode,
|
|
460
483
|
cameraOptions,
|
|
461
|
-
textOptions,
|
|
462
484
|
options,
|
|
463
485
|
licenseKey,
|
|
464
486
|
getShapeVisibility,
|
|
@@ -497,7 +519,6 @@ function TldrawEditorWithReadyStore({
|
|
|
497
519
|
setEditor,
|
|
498
520
|
licenseKey,
|
|
499
521
|
getShapeVisibility,
|
|
500
|
-
textOptions,
|
|
501
522
|
assetUrls,
|
|
502
523
|
]
|
|
503
524
|
)
|
|
@@ -510,11 +531,12 @@ function TldrawEditorWithReadyStore({
|
|
|
510
531
|
}, [editor, deepLinks])
|
|
511
532
|
|
|
512
533
|
// keep the editor up to date with the latest camera options
|
|
534
|
+
// options.cameraOptions takes precedence over the deprecated cameraOptions prop
|
|
513
535
|
useLayoutEffect(() => {
|
|
514
|
-
if (editor && cameraOptions) {
|
|
515
|
-
editor.setCameraOptions(cameraOptions)
|
|
536
|
+
if (editor && (cameraOptions || options?.camera)) {
|
|
537
|
+
editor.setCameraOptions({ ...cameraOptions, ...options?.camera })
|
|
516
538
|
}
|
|
517
|
-
}, [editor, cameraOptions])
|
|
539
|
+
}, [editor, cameraOptions, options?.camera])
|
|
518
540
|
|
|
519
541
|
const crashingError = useSyncExternalStore(
|
|
520
542
|
useCallback(
|
|
@@ -6,6 +6,11 @@ import { useEditor } from '../hooks/useEditor'
|
|
|
6
6
|
import { useEditorComponents } from '../hooks/useEditorComponents'
|
|
7
7
|
import { usePeerIds } from '../hooks/usePeerIds'
|
|
8
8
|
import { usePresence } from '../hooks/usePresence'
|
|
9
|
+
import {
|
|
10
|
+
CollaboratorState,
|
|
11
|
+
getCollaboratorStateFromElapsedTime,
|
|
12
|
+
shouldShowCollaborator,
|
|
13
|
+
} from '../utils/collaboratorState'
|
|
9
14
|
|
|
10
15
|
export const LiveCollaborators = track(function Collaborators() {
|
|
11
16
|
const peerIds = usePeerIds()
|
|
@@ -26,30 +31,8 @@ const CollaboratorGuard = track(function CollaboratorGuard({
|
|
|
26
31
|
return null
|
|
27
32
|
}
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const { followingUserId, highlightedUserIds } = editor.getInstanceState()
|
|
32
|
-
// If they're inactive and unless we're following them or they're highlighted, hide them
|
|
33
|
-
if (!(followingUserId === presence.userId || highlightedUserIds.includes(presence.userId))) {
|
|
34
|
-
return null
|
|
35
|
-
}
|
|
36
|
-
break
|
|
37
|
-
}
|
|
38
|
-
case 'idle': {
|
|
39
|
-
const { highlightedUserIds } = editor.getInstanceState()
|
|
40
|
-
// If they're idle and following us and unless they have a chat message or are highlighted, hide them
|
|
41
|
-
if (
|
|
42
|
-
presence.followingUserId === editor.user.getId() &&
|
|
43
|
-
!(presence.chatMessage || highlightedUserIds.includes(presence.userId))
|
|
44
|
-
) {
|
|
45
|
-
return null
|
|
46
|
-
}
|
|
47
|
-
break
|
|
48
|
-
}
|
|
49
|
-
case 'active': {
|
|
50
|
-
// If they're active, show them
|
|
51
|
-
break
|
|
52
|
-
}
|
|
34
|
+
if (!shouldShowCollaborator(editor, presence, collaboratorState)) {
|
|
35
|
+
return null
|
|
53
36
|
}
|
|
54
37
|
|
|
55
38
|
return <Collaborator latestPresence={presence} />
|
|
@@ -137,7 +120,16 @@ const Collaborator = track(function Collaborator({
|
|
|
137
120
|
) : null}
|
|
138
121
|
{CollaboratorShapeIndicator &&
|
|
139
122
|
selectedShapeIds
|
|
140
|
-
.filter((id) =>
|
|
123
|
+
.filter((id) => {
|
|
124
|
+
// Skip hidden shapes
|
|
125
|
+
if (editor.isShapeHidden(id)) return false
|
|
126
|
+
// Only render SVG indicators for shapes that use legacy indicators
|
|
127
|
+
// Canvas-based indicators are handled by CanvasShapeIndicators
|
|
128
|
+
const shape = editor.getShape(id)
|
|
129
|
+
if (!shape) return false
|
|
130
|
+
const util = editor.getShapeUtil(shape)
|
|
131
|
+
return util.useLegacyIndicator()
|
|
132
|
+
})
|
|
141
133
|
.map((shapeId) => (
|
|
142
134
|
<CollaboratorShapeIndicator
|
|
143
135
|
className="tl-collaborator__shape-indicator"
|
|
@@ -152,24 +144,21 @@ const Collaborator = track(function Collaborator({
|
|
|
152
144
|
)
|
|
153
145
|
})
|
|
154
146
|
|
|
155
|
-
function
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
? 'idle'
|
|
160
|
-
: 'active'
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function useCollaboratorState(editor: Editor, latestPresence: TLInstancePresence | null) {
|
|
147
|
+
function useCollaboratorState(
|
|
148
|
+
editor: Editor,
|
|
149
|
+
latestPresence: TLInstancePresence | null
|
|
150
|
+
): CollaboratorState {
|
|
164
151
|
const rLastActivityTimestamp = useRef(latestPresence?.lastActivityTimestamp ?? -1)
|
|
165
152
|
|
|
166
|
-
const [state, setState] = useState<
|
|
167
|
-
|
|
153
|
+
const [state, setState] = useState<CollaboratorState>(() =>
|
|
154
|
+
getCollaboratorStateFromElapsedTime(editor, Date.now() - rLastActivityTimestamp.current)
|
|
168
155
|
)
|
|
169
156
|
|
|
170
157
|
useEffect(() => {
|
|
171
158
|
const interval = editor.timers.setInterval(() => {
|
|
172
|
-
setState(
|
|
159
|
+
setState(
|
|
160
|
+
getCollaboratorStateFromElapsedTime(editor, Date.now() - rLastActivityTimestamp.current)
|
|
161
|
+
)
|
|
173
162
|
}, editor.options.collaboratorCheckIntervalMs)
|
|
174
163
|
|
|
175
164
|
return () => clearInterval(interval)
|
|
@@ -5,6 +5,7 @@ import { memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react'
|
|
|
5
5
|
import { ShapeUtil } from '../editor/shapes/ShapeUtil'
|
|
6
6
|
import { useEditor } from '../hooks/useEditor'
|
|
7
7
|
import { useEditorComponents } from '../hooks/useEditorComponents'
|
|
8
|
+
import { useShapeCulling } from '../hooks/useShapeCulling'
|
|
8
9
|
import { Mat } from '../primitives/Mat'
|
|
9
10
|
import { areShapesContentEqual } from '../utils/areShapesContentEqual'
|
|
10
11
|
import { setStyleProperty } from '../utils/dom'
|
|
@@ -57,7 +58,6 @@ export const Shape = memo(function Shape({
|
|
|
57
58
|
height: 0,
|
|
58
59
|
x: 0,
|
|
59
60
|
y: 0,
|
|
60
|
-
isCulled: false,
|
|
61
61
|
})
|
|
62
62
|
|
|
63
63
|
useQuickReactor(
|
|
@@ -118,22 +118,21 @@ export const Shape = memo(function Shape({
|
|
|
118
118
|
setStyleProperty(bgContainer, 'z-index', backgroundIndex)
|
|
119
119
|
}, [opacity, index, backgroundIndex])
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
121
|
+
// Register container refs with the centralized culling context.
|
|
122
|
+
// This runs on mount and handles initial display state.
|
|
123
|
+
const { register, unregister } = useShapeCulling()
|
|
124
|
+
useLayoutEffect(() => {
|
|
125
|
+
const container = containerRef.current
|
|
126
|
+
if (!container) return
|
|
126
127
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
[editor]
|
|
136
|
-
)
|
|
128
|
+
// Check initial culling state and register with the context
|
|
129
|
+
const isCulled = editor.getCulledShapes().has(id)
|
|
130
|
+
register(id, container, bgContainerRef.current, isCulled)
|
|
131
|
+
|
|
132
|
+
return () => {
|
|
133
|
+
unregister(id)
|
|
134
|
+
}
|
|
135
|
+
}, [editor, id, register, unregister])
|
|
137
136
|
const annotateError = useCallback(
|
|
138
137
|
(error: any) => editor.annotateError(error, { origin: 'shape', willCrashApp: false }),
|
|
139
138
|
[editor]
|