diff --git a/apps/docs/content/getting-started/releases.mdx b/apps/docs/content/getting-started/releases.mdx index 894e7b6a745d..6b7583f3898c 100644 --- a/apps/docs/content/getting-started/releases.mdx +++ b/apps/docs/content/getting-started/releases.mdx @@ -17,6 +17,12 @@ Unlike many JavaScript packages distributed on [NPM](https://www.npmjs.com/), th - Minor version bumps are released on a regular cadence, approximately monthly. **They may contain breaking changes**. We aim to make breaking changes as minimally disruptive as possible, but tldraw is actively evolving as we add new features. We recommend updating at a similar pace and checking the release notes. - Patch version bumps are for bugfixes and hotfixes that can't wait for the next cadence release. +## Latest tldraw versions + +- Run `npm install tldraw` to get the latest minor version of tldraw +- Use `npm install tldraw@next` to get the latest version of tldraw that is used on [tldraw.com](https://www.tldraw.com) +- The latest changes to the `main` branch of tldraw are available to test through our [pre-release canary builds](https://www.npmjs.com/package/tldraw?activeTab=versions). + ## Next - [next](/releases/next) - Changes for the upcoming release. diff --git a/apps/docs/content/releases/next.mdx b/apps/docs/content/releases/next.mdx index 60cfba39498e..ef32d4847eaa 100644 --- a/apps/docs/content/releases/next.mdx +++ b/apps/docs/content/releases/next.mdx @@ -2,19 +2,19 @@ title: Next release description: Changes coming in the next release author: tldraw -date: 03/18/2026 +date: 05/01/2026 order: 0 status: published last_version: v4.5.10 --- -This release adds a first-class theme system with display values for customizing default shapes, a new canvas overlay system that replaces React component overrides with Canvas 2D rendering, extensible asset types via a new `AssetUtil` system, shape attribution with a new `TLUserStore` provider and extensible user records, clipboard hooks for intercepting copy, cut, and paste, custom record types to the store, a new `@tldraw/mermaid` package for converting Mermaid diagrams to native shapes, WebSocket hibernation support for tlsync, a new `@tldraw/editor-controller` package for scripting and automation, RTL language support in the UI, cross-window embedding support, arbitrary iframe embed pasting, a paste-as-plain-text keyboard shortcut, smarter export trimming, frame-like behavior for custom shapes, custom geo shape types, right-click panning, and editor performance measurement hooks. It also includes various other improvements and bug fixes. +This major release introduces a first-class theme system with display values, a new `OverlayUtil` system for canvas overlays, and extensibility APIs for custom record types, asset types, geo shapes, and frame-like shapes. Two new packages ship alongside it: `@tldraw/driver` for imperative editor control and `@tldraw/mermaid` for converting Mermaid diagrams into native shapes. It also adds a shape attribution system with the `TLUserStore` provider, clipboard and performance-measurement hooks, WebSocket hibernation in tlsync, RTL support, cross-window embedding, and various other improvements and bug fixes. ## What's new -### 💥 Theme system with display values ([#8410](https://github.com/tldraw/tldraw/pull/8410)) +### 💥 Custom themes with display values ([#8410](https://github.com/tldraw/tldraw/pull/8410)) -A new first-class theme system replaces the previous approach where colors were hardcoded and resolved inline. Themes are now named, registered objects that shape utils consume via a structured display values pipeline. +A new first-class theme system replaces the previous approach where colors were hardcoded and resolved inline. Themes are named, registered objects that shape utils consume via a structured display values pipeline. Register custom themes via `TLThemes` module augmentation for type-safe IDs, add or remove palette colors via `TLThemeDefaultColors` and `TLRemovedDefaultThemeColors`, and pass themes to the editor via the `themes` and `initialTheme` props: @@ -32,8 +32,6 @@ const MyDrawShapeUtil = DrawShapeUtil.configure({ }) ``` -New editor methods include `getCurrentTheme()`, `setCurrentTheme()`, `getThemes()`, `updateTheme()`, `updateThemes()`, and `getColorMode()`. -
Migration guide @@ -70,123 +68,127 @@ const colors = theme.colors[editor.getColorMode()]
-### Custom record types ([#8213](https://github.com/tldraw/tldraw/pull/8213)) +### 💥 Custom overlays ([#8469](https://github.com/tldraw/tldraw/pull/8469)) -You can now register custom record types in the tldraw store for persisting and synchronizing domain-specific data that doesn't fit into shapes, bindings, or assets. Custom records support scoping (document/session/presence), validation, migrations, and default properties. +A new `OverlayUtil` system unifies canvas overlays. Built-in brushes, handles, scribbles, snap indicators, selection foreground, collaborator cursors, and arrow hints are now implemented as overlay utils and can be customized or extended via the `overlayUtils` prop. -```tsx -import { createTLSchema, createCustomRecordId } from 'tldraw' - -const schema = createTLSchema({ - records: [ - { - typeName: 'marker', - scope: 'document', - validator: markerValidator, - }, - ], -}) -``` +Overlays now render in front of indicators in a unified `CanvasOverlays` layer, and the legacy default component implementations and their CSS have been removed. -TypeScript module augmentation via `TLGlobalRecordPropsMap` lets custom record types participate in the `TLRecord` union. +
+Migration guide -### WebSocket hibernation in tlsync ([#8070](https://github.com/tldraw/tldraw/pull/8070)) +The legacy overlay components have been removed from `TLEditorComponents`. Canvas overlays are now rendered directly to a 2D canvas context by `OverlayUtil` classes, and customization happens by subclassing the default util rather than swapping a React component. -`TLSocketRoom` now supports session resume and snapshot APIs for WebSocket hibernation environments like Cloudflare Durable Objects. Sessions can be suspended and restored without losing state, and the `sync-cloudflare` template has been updated to use the WebSocket Hibernation API. +**Customizing a built-in overlay:** extend the default util and give it the same `static type`; it replaces the built-in when passed via `overlayUtils`: -New APIs include `handleSocketResume()` for restoring sessions from snapshots, `getSessionSnapshot()` for capturing session state, and an `onSessionSnapshot` callback for persisting snapshots to WebSocket attachments. +```tsx +// Before +const components: TLEditorComponents = { + Brush: MyBrushComponent, +} -### @tldraw/editor-controller ([#7952](https://github.com/tldraw/tldraw/pull/7952)) + -A new `@tldraw/editor-controller` package provides an imperative API for driving the tldraw editor programmatically. `EditorController` wraps an `Editor` instance and exposes event dispatch, selection transforms, clipboard operations, and shape queries with fluent chaining. +// After +import { Tldraw, BrushOverlayUtil, type TLBrushOverlay } from 'tldraw' -```tsx -import { EditorController } from '@tldraw/editor-controller' +class MyBrushOverlayUtil extends BrushOverlayUtil { + override render(ctx: CanvasRenderingContext2D, overlays: TLBrushOverlay[]) { + const overlay = overlays[0] + if (!overlay) return + const { x, y, w, h } = overlay.props + const zoom = this.editor.getEfficientZoomLevel() + ctx.fillStyle = 'rgba(0, 0, 255, 0.1)' + ctx.strokeStyle = 'blue' + ctx.lineWidth = 1 / zoom + ctx.beginPath() + ctx.rect(x, y, w, h) + ctx.fill() + ctx.stroke() + } +} -const controller = new EditorController(editor) -controller.pointerMove(100, 100).pointerDown().pointerMove(200, 200).pointerUp() + ``` -This is useful for scripting, automation, agent workflows, and REPL-style interaction. The release includes a Scripter example demonstrating the package. +The following slots have been removed from `TLEditorComponents`. Subclass the matching default overlay util instead: -### RTL support ([#8033](https://github.com/tldraw/tldraw/pull/8033)) +- `Brush`, `ZoomBrush` → `BrushOverlayUtil`, `ZoomBrushOverlayUtil` +- `Scribble` → `ScribbleOverlayUtil` +- `SnapIndicator` → `SnapIndicatorOverlayUtil` +- `Handle`, `Handles` → `ShapeHandleOverlayUtil` +- `SelectionForeground`, `SelectionBackground` → `SelectionForegroundOverlayUtil` +- `CollaboratorHint` → `CollaboratorHintOverlayUtil` (collaborator cursors/brushes/scribbles have their own utils too) -The tldraw UI now supports right-to-left languages like Arabic. A new `useDirection()` hook returns `'ltr'` or `'rtl'` from the current translation context, and all Radix UI components and CSS have been updated to respect text direction. The `dir` attribute is set on `.tl-container`, and CSS uses logical properties (`margin-inline-start`, `inset-inline-end`, etc.) instead of physical ones. +The corresponding `Default*` exports and `LiveCollaborators` have also been removed. -### @tldraw/mermaid ([#8194](https://github.com/tldraw/tldraw/pull/8194), [#8285](https://github.com/tldraw/tldraw/pull/8285), [#8322](https://github.com/tldraw/tldraw/pull/8322)) +Customizing shape indicators — `ShapeIndicator`, `ShapeIndicators`, and `ShapeIndicatorErrorFallback` are gone. Indicators now render through each shape util's `getIndicatorPath()`. Override it to change how a shape's indicator is drawn. -A new `@tldraw/mermaid` package converts Mermaid diagram syntax into native tldraw shapes. Paste Mermaid text to create flowcharts, sequence diagrams, state diagrams, and mind maps as editable shapes on the canvas. +Overlays cannot render React; they draw into a 2D canvas context. For React-based overlays, render an HTML layer above the canvas via a regular `TLEditorComponents` slot like `InFrontOfTheCanvas`. -```tsx -import { createMermaidDiagram } from '@tldraw/mermaid' +Overlay colors come from `TLTheme`, not CSS variables. Read them inside `render()` via `this.editor.getCurrentTheme().colors[this.editor.getColorMode()]` so overlays follow light/dark mode automatically. -await createMermaidDiagram( - editor, - ` - graph TD - A[Start] --> B{Decision} - B -->|Yes| C[Action] - B -->|No| D[End] -` -) -``` +These CSS variables have been removed: `--tl-color-snap`, `--tl-color-brush-fill`, `--tl-color-brush-stroke`, `--tl-color-laser`, `--tl-layer-overlays-custom`. -The package parses Mermaid syntax, extracts layout from the rendered SVG, and produces a diagram-agnostic blueprint that gets rendered into geo shapes, arrows, and groups. +Overriding them (or the removed selectors `.tl-brush`, `.tl-scribble`, `.tl-snap-indicator`, `.tl-handle*`, `.tl-selection__fg__outline`, `.tl-corner-handle`, `.tl-text-handle`, `.tl-corner-crop-handle`, `.tl-mobile-rotate__*`) no longer has any effect. Port these to `TLTheme` entries or to the overlay util's `render()`. -Node creation is extensible: pass `mapNodeToRenderSpec` per diagram type to map diagram nodes to different shapes, or use `createShape` in `BlueprintRenderingOptions` to take full control of how nodes are created on the canvas. +
-### Clipboard hooks ([#8290](https://github.com/tldraw/tldraw/pull/8290)) +### Custom record types ([#8213](https://github.com/tldraw/tldraw/pull/8213)) -New `TldrawOptions` hooks let you intercept and customize clipboard copy, cut, and paste. `onBeforeCopyToClipboard` filters or transforms serialized content before it hits the clipboard, `onBeforePasteFromClipboard` filters parsed paste payloads before shapes are created, and `onClipboardPasteRaw` handles raw clipboard data before tldraw's default paste pipeline. +You can now register custom record types in the tldraw store for persisting and synchronizing domain-specific data that doesn't fit into shapes, bindings, or assets. Custom records support scoping (document/session/presence), validation, migrations, and default properties. ```tsx -const options: Partial = { - onBeforeCopyToClipboard(info, content) { - // filter shapes or transform content before copy/cut - return content - }, - onBeforePasteFromClipboard(info, content) { - // filter or transform parsed paste content - return content - }, - onClipboardPasteRaw(info) { - // handle raw clipboard data yourself; return false to cancel tldraw handling - return false - }, -} -``` +import { createTLSchema, createCustomRecordId } from 'tldraw' -### Shape attribution and TLUserStore ([#8147](https://github.com/tldraw/tldraw/pull/8147)) +const schema = createTLSchema({ + records: [ + { + typeName: 'marker', + scope: 'document', + validator: markerValidator, + }, + ], +}) +``` -A new shape attribution system tracks who created and last edited shapes. The `TLUserStore` provider interface connects tldraw to your auth system with reactive `Signal`-based methods: `getCurrentUser()` returns the active user for presence and attribution, while `resolve(userId)` resolves any user ID to display info. +TypeScript module augmentation via `TLGlobalRecordPropsMap` lets custom record types participate in the `TLRecord` union. -```tsx - currentUserSignal, - resolve: (userId) => resolvedUserSignal(userId), - }} -/> -``` +### Extensible geo shapes ([#8543](https://github.com/tldraw/tldraw/pull/8543)) -User records are now document-scoped via the unified `TLUser` record type. SDK users can extend user records with custom validated metadata through `createTLSchema`: +`GeoShapeUtil` now supports custom geo types via a `customGeoTypes` option on `configure()`. Previously, adding a new geo type required forking or monkey-patching `GeoShapeUtil`; now custom types plug into the existing system and inherit labels, resizing, fill/dash/color styling, SVG export, and hyperlink support — while supplying their own path geometry, snap behavior, creation size, and style panel icon. ```tsx -const schema = createTLSchema({ - user: { - meta: { - isAdmin: T.boolean, - department: T.string, +import { GeoShapeUtil, PathBuilder } from 'tldraw' + +const MyGeoShapeUtil = GeoShapeUtil.configure({ + customGeoTypes: { + 'rounded-rect': { + getPath: (w, h, shape) => { + const r = Math.min(w, h) * 0.2 + return new PathBuilder() + .moveTo(r, 0, { geometry: { isFilled: shape.props.fill !== 'none' } }) + .lineTo(w - r, 0) + .circularArcTo(r, false, true, w, r) + .lineTo(w, h - r) + .circularArcTo(r, false, true, w - r, h) + .lineTo(r, h) + .circularArcTo(r, false, true, 0, h - r) + .lineTo(0, r) + .circularArcTo(r, false, true, r, 0) + .close() + }, + snapType: 'polygon', + icon: 'geo-rectangle', + defaultSize: { w: 200, h: 150 }, }, }, }) -``` -Note shapes now track and display a "first edited by" attribution label in the bottom-right corner, showing who first added text to the note. - -### Arbitrary iframe embeds ([#8306](https://github.com/tldraw/tldraw/pull/8306)) + +``` -Paste any `