Bot releases are visible (Hide)
Published by huppy-bot[bot] about 1 month ago
👉 See our 3.0 release notes.
@tldraw/editor
, @tldraw/state-react
, @tldraw/state
, @tldraw/store
, @tldraw/tlschema
, @tldraw/utils
, @tldraw/validate
Published by huppy-bot[bot] about 1 month ago
Welcome to the 3.0.0 release of the tldraw SDK. This release includes a number of new features, improved features, and bug fixes.
The biggest change, and the reason for a new major version, is our new watermark and licenses. See the New licenses section below.
Thank you also to all of our first-time contributors: Alex (@qwertyu-alex), @dimitriadamou, Ravi theja (@raviteja83), & Zachary Wood (@zacwood9).
This release includes new licenses for the tldraw SDK. These are meant to make the SDK more accessible to small teams and independent developers with commercial products.
Previously, the tldraw SDK was provided under a non-commercial license, with commercial licenses available for purchase separately. In this version, the tldraw SDK's new license permits use in both commercial non-commercial projects so long as our "Made with tldraw" watermark is visible.
If you wish to use the tldraw SDK without the watermark, you can purchase a Business License. You'll receive a License Key that hides the watermark while the license is active. For more information, or to request a business license, visit tldraw.dev.
The watermark is a link to tldraw.dev. It becomes active after a short delay, ensuring that users don't accidentally click on it while trying to perform other actions on the canvas.
If you don't have a business license, then you must preserve the watermark as it is and not obscure it, disable it, or otherwise make it inaccessible to your users.
If you have questions or comments, let us know at [email protected].
'Deep Links' are URLs that point to a specific part of a document, like a particular shape or a particular part of a page. We added some APIs to help creating and using deep links, and for updating the current page's URL as the user navigates around the document.
See the Deep Links documentation for more information and example code.
(#4333)
Tldraw lets you convert the contents of your canvas to a PNG or SVG image. Previously, this relied on each shape implementing a method that would render it as an SVG. If your shape is complex with lots of HTML/CSS UI, this isn't an easy thing to do.
Now, custom shapes are supported in image exports by default. This relies on embedding HTML/CSS into an SVG which does have some issues, so it's worth reading about image exports in tldraw and testing the feature for yourself.
(#4403)
Tldraw supports including content from other websites (e.g. YouTube, Google Maps, CodeSandbox) via the embed
shape. Previously the list of supported websites was hard-coded. This release includes support to fully customize the list of supported websites. This means you can now add your own custom embeds, or remove existing ones.
(#4326)
getText
APIPreviously there was no reliable way to get the human-readable text from a shape. This is now possible with the new getText
API.
The main intended usage of this API is to implement text search in your application. We provide a basic example of how to go about that here
While holding the space bar, use the arrow keys to move the viewport.
Removes the TLRotationSnapshot
type. This was exported by mistake and should not have been useful to SDK users.
The onEditorMount
option to createTLStore
is now called onMount
. (#4320)
Editor.mark()
was deprecated in favour of Editor.markHistoryStoppingPoint()
. (#4250)
In most cases you can treat this as a renamed method. However if you previously passed an ID to Editor.mark()
, you should now use the return value of Editor.markHistoryStoppingPoint()
as the mark ID instead.
Rename TLSvgOptions
to TLImageExportOptions
(#4442)
Setting editor.updateInstanceState({isFocused: true})
no longer triggers a focus
event on the canvas container. Use editor.focus()
and editor.blur()
instead.
loadSnapshot
to preserve page state like camera position and current page if no session snapshot is provided. (#4392)<TldrawImage />
component to accept custom asset URLs. (#4465)rotateShapesBy
work with any shapes, not just the currently selected shapes. (#4385)DefaultToolbar
(#4321)registerDefaultSideEffects
and registerDefaultExternalContentHandler
(#4323)Published by huppy-bot[bot] 2 months ago
@tldraw/editor
, @tldraw/sync
, tldraw
, @tldraw/tlschema
Published by huppy-bot[bot] 3 months ago
@tldraw/editor
, @tldraw/sync-core
, @tldraw/sync
, tldraw
, @tldraw/utils
Published by huppy-bot[bot] 3 months ago
Published by huppy-bot[bot] 3 months ago
Welcome to the 2.4.0 release of the tldraw SDK. This month we’ve been working to bring our sync engine (the backend we developed for tldraw.com) into the SDK as a technology for general use. This release also includes new animation options for shapes, support for image flipping, and a long list of bug fixes and developer experience enhancements. Read on for the highlights and see the bottom of these notes for the list of significant fixes and changes.
Thank you also to our first-time contributors Albert Brand (@AlbertBrand) and Guillaume Grossetie (@ggrossetie)!
For the first time, we’re releasing our real-time collaboration engine—the one we developed for tldraw.com—as a general library that developers can use for their own projects. The SDK will of course still support any backend for collaboration, however we hope this will be the best and easiest for developers to use alongside the rest of the tldraw SDK. While we’re shipping the code in this release, we still have some work to do on our messaging and our documentation, so keep an eye out for an announcement in the coming weeks. For now, see the new sync
package in the repository and the new multiplayer-demo example in the tldraw repository.
Did you know that tldraw has basic support for animation? You can use the Editor.animateShapes
method to animate shapes on the canvas, but up to now only the position and rotation properties would be animated. In this release, we’ve given the ShapeUtil
class a new getInterpolatedProps
method. You can use this to describe how your custom shape’s other properties should be animated. We’ve only started to implement this feature for our own shapes, but check our BaseBoxShapeUtil
as an example.
override getInterpolatedProps(startShape: Shape, endShape: Shape, t: number): Shape['props'] {
return {
...endShape.props,
w: lerp(startShape.props.w, endShape.props.w, t),
h: lerp(startShape.props.h, endShape.props.h, t),
}
}
Editor.run
You can use the new Editor.run
method to run a function within some additional context. By default, the function will be run inside of a transaction, meaning that all changes made during the transaction will be settled at once. This improves performance and avoids unnecessary renders in the user interface. You can also use Editor.run
’s contextual options to ignore history or ignore locked shapes.
editor.run(
() => {
editor.createShapes(myShapes)
editor.sendToBack(myShapes)
editor.selectNone()
},
{ history: 'ignore' }
)
As part of our work on sync, we have a new system for handling large assets like images and videos. You can provide a TLAssetStore
to control how assets are uploaded and retrieved.
In your own shapes & tools, these options are available through the new Editor.uploadAsset
and Editor.resolveAssetURL
methods.
editor.history.ignore(cb)
has been replaced with editor.run(cb, {history: ‘ignore’})
editor.batch
is deprecated, replaced with editor.run
@tldraw/state
directly, the track
function and all hooks (e.g. useValue
) have moved to @tldraw/state-react
.ShapeIndicators
component to add custom logic about when to display indicators. (#4083)@tldraw/state
library is now split into @tldraw/state
and @tldraw/state-react
. (#4170)DefaultMenuPanel
. (#4193)fileSize
property of TLImageAsset
and TLVideoAsset
is now optional. (#4206)TLEditorSnapshot
to TldrawImage
and useTLStore
. (#4190)EffectScheduler
and useStateTracking
are now public. (#4155)]setDefaultValue
to StyleProp
. (#4044)ShapeUtil.getInterpolatedProps
. (#4162)Editor.run
, replacing Editor.batch
(#4042)force
flag is now taken into account for additional camera methods. (#4214)cameraOptions
via react no longer causes the editor to re-mount. (#4089)createTLStore
. (#4233
InFrontOfTheCanvas
component is displayed at the right stack-order. (#4024)Published by huppy-bot[bot] 4 months ago
When using a local-only storage of the whiteboard, we now store the images and videos in a separate indexedDB table. This is instead of storing them as base64-encoded blobs in the room's JSON. That wasn't very performant and blew up the size of the room's JSON quite a bit. This separates out those assets into a separate retrieval mechanism for better separation-of-concerns.
We improved our out-of-the-box/batteries-included CDN for our assets (fonts/icons). We were using unpkg before but now we're just using Cloudflare directly for more fine-grained control.
We've been working on something we call 'level-of-detail' internally for images. We're testing this currently on tldraw.com where for higher-resolution images (over a couple megabytes), the image will get transformed to an appropriate size depending on things like your viewport, zoom level, current network speed, among other considerations. This helps with bandwidth usage and browser memory usage especially when you have multiple high-res images on the board.
@steveruizok worked on adding being able to select multiple shapes and flatten them into an image. For those moments when you need to press 🙏, clamp 🗜️, and squeeze things together. 🪗
@SomeHats did a ton of unglorious work to make our documentation much more manageable. So sparkly ✨
We locked down our referrer network requests in #3884 and #3881 to make sure we weren't leaking tldraw rooms to external media/iframe requests.
Alt
-F
) #3966 (@steveruizok)ArrowBindingUtil
public. #3913 (@ds300)referrerpolicy
#3884 (@mimecuvalo)tldraw.com
. #3927 (@mimecuvalo) (@steveruizok)getSnapshot
and loadSnapshot
on Editor
class #3912 (@ds300)isAnimated
checks when adding an image to a shared room. #3967 (@mimecuvalo)indexedDB
#3954 (@mimecuvalo)CardShapeUtil
name in the custom shape example documentation. #3998 (@bholmesdev)color-scheme
to theme
#3991 (@mimecuvalo)@internal
#4014 (@mimecuvalo)store
package. #3990 (@MitjaBezensek)Published by huppy-bot[bot] 4 months ago
tldraw
Published by huppy-bot[bot] 4 months ago
tldraw
Published by huppy-bot[bot] 4 months ago
ArrowBindingUtil
public (#3913)editor.getSnapshot()
and editor.loadSnapshot
(#3912)@tldraw/editor
, tldraw
Published by huppy-bot[bot] 4 months ago
Bindings allow you to create relationships between shapes. Our default arrow shapes are a great example of this: each end of the arrow can bind to the shape it's pointing to. When that shape moves, so does the arrow. Before this change, it wasn't possible to build things like arrows on top of the tldraw sdk - arrows were hard-coded into the library. Now, with bindings, you can create arrows, constraint systems, visual programming environments, and much more.
Check out the bindings guide for more information. (#3326, #3780, #3797, #3800, #3871)
You can now limit the camera in tldraw to a certain fixed area of the canvas. This is useful for creating experiences that don't quite fit the "infinite canvas" paradigm: document annotators, image editor, slideshow creators, etc.
See the camera constraints guide for more information. (#3282, #3747, #3814, #3828, #3844, #3863)
You can now override many options which were previously hard-coded constants. Pass an options
prop into the tldraw component to change the maximum number of pages, grid steps, or other previously hard-coded values.
See TldrawOptions
for details. (#3799, #3900)
canBind
flag now accepts an options object instead of just the shape in question. If you're relying on its arguments, check out TLShapeUtilCanBindOpts
for its replacement.editor.sideEffects.registerBatchCompleteHandler
has been replaced with editor.sideEffects.registerOperationCompleteHandler
(#3748)editor.getArrowInfo(shape)
has been replaced with getArrowInfo(editor, shape)
editor.getArrowsBoundTo(shape)
has been removed. Instead, use editor.getBindingsToShape(shape, 'arrow')
and follow the fromId
of each binding to the corresponding arrow shape@tldraw/editor
to tldraw
:
TLArcInfo
TLArrowInfo
TLArrowPoint
start
and end
properties on TLArrowShape
no longer have type: point | binding
. Instead, they're always a point, which may be out of date if a binding exists. To check for & retrieve arrow bindings, use getArrowBindings(editor, shape)
instead.getArrowTerminalsInArrowSpace
must be passed a TLArrowBindings
as a third argument: getArrowTerminalsInArrowSpace(editor, shape, getArrowBindings(editor, shape))
ShapeProps
-> RecordProps
ShapePropsType
-> RecordPropsType
TLShapePropsMigrations
-> TLPropsMigrations
SchemaShapeInfo
-> SchemaPropsInfo
Previously, some (not all!) commands accepted a history options object with squashing
, ephemeral
, and preserveRedoStack
flags. Squashing enabled/disabled a memory optimisation (storing individual commands vs squashing them together). Ephemeral stopped a command from affecting the undo/redo stack at all. Preserve redo stack stopped commands from wiping the redo stack. These flags were never available consistently - some commands had them and others didn't.
In this version, most of these flags have been removed. squashing
is gone entirely (everything squashes & does so much faster than before). There were a couple of commands that had a special default - for example, updateInstanceState
used to default to being ephemeral
. Those maintain the defaults, but the options look a little different now - {ephemeral: true}
is now {history: 'ignore'}
and {preserveRedoStack: true}
is now {history: 'record-preserveRedoStack'}
.
If you were previously using these options in places where they've now been removed, you can use wrap them with editor.history.ignore(fn)
or editor.history.batch(fn, {history: 'record-preserveRedoStack'})
. For example,
editor.nudgeShapes(..., { ephemeral: true })
can now be written as
editor.history.ignore(() => {
editor.nudgeShapes(...)
})
Previously, only commands (e.g. editor.updateShapes
and things that use it) were added to the undo/redo stack. Everything else (e.g. editor.store.put
) wasn't. Now, everything that touches the store is recorded in the undo/redo stack (unless it's part of mergeRemoteChanges
). You can use editor.history.ignore(fn)
as above if you want to make other changes to the store that aren't recorded - this is short for editor.history.batch(fn, {history: 'ignore'})
When upgrading to this version of tldraw, you shouldn't need to change anything unless you're using store.put
, store.remove
, or store.applyDiff
outside of store.mergeRemoteChanges
. If you are, you can preserve the functionality of those not being recorded by wrapping them either in mergeRemoteChanges
(if they're multiplayer-related) or history.ignore
as appropriate.
Before this diff, any changes in side-effects weren't captured by the undo-redo stack. This was actually the motivation for this change in the first place! But it's a pretty big change, and if you're using side effects we recommend you double-check how they interact with undo/redo before/after this change. To get the old behaviour back, wrap your side effects in editor.history.ignore
.
Previously, editor.mark(id)
accepted two additional boolean parameters: onUndo
and onRedo
. If these were set to false, then when undoing or redoing we'd skip over that mark and keep going until we found one with those values set to true. We've removed those options - if you're using them, let us know and we'll figure out an alternative!
.tldr
file. (#3689)editor.blur
method. (#3875)createTLStore
. (#3886)getSnapshot
and loadSnapshot
for easier loading/saving of tldraw documents. Read more here. (#3811)select
option to Editor.groupShapes
and Editor.ungroupShapes
. (#3690)InFrontOfTheCanvas
now has access to the editor's UI context (#3782)useEditor
and other context-based hooks will now throw an error when used out-of-context, instead of returning a fake value. (#3750)defaultShapeSchemas
which can be passed directly to createTLSchema
.(#3613)Published by huppy-bot[bot] 6 months ago
@tldraw/editor
, tldraw
Published by huppy-bot[bot] 6 months ago
Previously, we weren't exporting migrations & validators for our default shapes. This meant that it wasn't possible to make your own tlschema with both our default shapes and some of your own (e.g. for custom multiplayer). This fixes that by exposing all the migrations, validators, and versions from tlschema, plus defaultShapeSchemas
which can be passed directly to createTLSchema
Published by huppy-bot[bot] 6 months ago
This performance optimisation introduced a regression where sometimes computed caches wouldn't get invalidated at the correct time, leading to stale data causing crashes. We're reverting the change for now.
Published by huppy-bot[bot] 6 months ago
We were missing an export createShapePropsMigrationIds
, part of the new migrations API introduced in v2.1.0. This release fixes that, and also adds exports for a few extra APIs that we were using in our examples, but weren't exporting properly: defaultEditorAssetUrls
, PORTRAIT_BREAKPOINT
, useDefaultColorTheme
, & getPerfectDashProps
v2.1.x