This PR cleans up exports from TldrawUi, unifying types under `TLUi` and
removing many items from exports / marking others as internal.
### Change Type
- [x] `major` — Breaking Change
### Release Notes
- [editor] clean up / unify types
This PR renames `App`, `app` and all appy names to `Editor`, `editor`,
and editorry names.
### Change Type
- [x] `major` — Breaking Change
### Release Notes
- Rename `App` to `Editor` and many other things that reference `app` to
`editor`.
This PR adds some things that we need for the Project Name feature on
tldraw.com.
It should be reviewed alongside
https://github.com/tldraw/tldraw-lite/pull/1814
## Name Property
This PR adds a `name` property to `TLDocument`. We use this to store a
project's name.
<img width="454" alt="Screenshot 2023-05-09 at 15 47 26"
src="https://github.com/tldraw/tldraw/assets/15892272/f3be438e-aa0f-4dec-8f51-8dfd9f9d0ced">
## Top Zone
This PR adds a `topZone` area of the UI that we can add stuff to,
similar to how `shareZone` works.
It also adds an example to show where the `topZone` and `shareZone` are:
<img width="1511" alt="Screenshot 2023-05-12 at 10 57 40"
src="https://github.com/tldraw/tldraw/assets/15892272/f5e1cd33-017e-4aaf-bfee-4d85119e2974">
## Breakpoints
This PR change's the UI's breakpoints a little bit.
It moves the action bar to the bottom a little bit earlier.
(This gives us more space at the top for the project name).
![2023-05-12 at 11 08 26 - Fuchsia
Bison](https://github.com/tldraw/tldraw/assets/15892272/34563cea-b1d1-47be-ac5e-5650ee0ba02d)
![2023-05-12 at 13 45 04 - Tan
Mole](https://github.com/tldraw/tldraw/assets/15892272/ab190bd3-51d4-4a8b-88de-c72ab14bcba6)
## Input Blur
This PR adds an `onBlur` parameter to `Input`.
This was needed because 'clicking off' the input wasn't firing
`onComplete` or `onCancel`.
<img width="620" alt="Screenshot 2023-05-09 at 16 12 58"
src="https://github.com/tldraw/tldraw/assets/15892272/3b28da74-0a74-4063-8053-e59e47027caf">
## Create Project Name
This PR adds an internal `createProjectName` property to
`TldrawEditorConfig`.
Similar to `derivePresenceState`, you can pass a custom function to it.
It lets you control what gets used as the default project name. We use
it to set different names in our local projects compared to shared
projects.
In the future, when we add more advanced project features, we could
handle this better within the UI.
<img width="454" alt="Screenshot 2023-05-09 at 15 47 26"
src="https://github.com/tldraw/tldraw/assets/15892272/da9a4699-ac32-40d9-a97c-6c682acfac41">
### Test Plan
1. Gradually reduce the width of the browser window.
2. Check that the actions menu jumps to the bottom before the style
panel moves to the bottom.
---
1. In the examples app, open the `/zones` example.
2. Check that there's a 'top zone' at the top.
- [ ] Unit Tests
- [ ] Webdriver tests
### Release Note
- [dev] Added a `topZone` area where you can put stuff.
- [dev] Added a `name` property to `TLDocument` - and `app` methods for
it.
- [dev] Added an internal `createProjectName` config property for
controlling the default project name.
- [dev] Added an `onBlur` parameter to `Input`.
- Moved the actions bar to the bottom on medium-sized screens.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Add support for locking shapes.
How it works right now:
- You can lock / unlock shapes from the context menu.
- You can also lock shapes with `⇧⌘L` keyboard shortcut.
- You cannot select locked shapes: clicking on the shape, double click
to edit, select all, brush select,... should not work.
- You cannot change props of locked shapes.
- You cannot delete locked shapes.
- If a shape is grouped or within the frame the same rules apply.
- If you delete a group, that contains locked shape it will also delete
those shapes. This seems to be what other apps use as well.
Solves #1445
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Insert a shape
2. Right click on it and lock it.
3. Test that you cannot select it, change its properties, delete it.
4. Do the same with locked groups.
5. Do the same with locked frames.
- [x] Unit Tests
- [ ] Webdriver tests
### Release Notes
- Add support for locking shapes.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR replaces our `console.log` with `nicelog` so that I can more
easily grep for errant console.logs.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package (will not publish a new version)
This PR updates our user-facing APIs for the Tldraw and TldrawEditor
components, as well as the Editor (App). It mainly incorporates surface
changes from #1450 without any changes to validators or migrators,
incorporating feedback / discussion with @SomeHats and @ds300.
Here we:
- remove the TldrawEditorConfig
- bring back a loose version of shape definitions
- make a separation between "core" shapes and "default" shapes
- do not allow custom shapes, migrators or validators to overwrite core
shapes
- but _do_ allow new shapes
## `<Tldraw>` component
In this PR, the `Tldraw` component wraps both the `TldrawEditor`
component and our `TldrawUi` component. It accepts a union of props for
both components. Previously, this component also added local syncing via
a `useLocalSyncClient` hook call, however that has been pushed down to
the `TldrawEditor` component.
## `<TldrawEditor>` component
The `TldrawEditor` component now more neatly wraps up the different ways
that the editor can be configured.
## The store prop (`TldrawEditorProps.store`)
There are three main ways for the `TldrawEditor` component to be run:
1. with an externally defined store
2. with an externally defined syncing store (local or remote)
3. with an internally defined store
4. with an internally defined locally syncing store
The `store` prop allows for these configurations.
If the `store` prop is defined, it may be defined either as a `TLStore`
or as a `SyncedStore`. If the store is a `TLStore`, then the Editor will
assume that the store is ready to go; if it is defined as a SyncedStore,
then the component will display the loading / error screens as needed,
or the final editor once the store's status is "synced".
When the store is left undefined, then the `TldrawEditor` will create
its own internal store using the optional `instanceId`, `initialData`,
or `shapes` props to define the store / store schema.
If the `persistenceKey` prop is left undefined, then the store will not
be synced. If the `persistenceKey` is defined, then the store will be
synced locally. In the future, we may also here accept the API key /
roomId / etc for creating a remotely synced store.
The `SyncedStore` type has been expanded to also include types used for
remote syncing, e.g. with `ConnectionStatus`.
## Tools
By default, the App has two "baked-in" tools: the select tool and the
zoom tool. These cannot (for now) be replaced or removed. The default
tools are used by default, but may be replaced by other tools if
provided.
## Shapes
By default, the App has a set of "core" shapes:
- group
- embed
- bookmark
- image
- video
- text
That cannot by overwritten because they're created by the app at
different moments, such as when double clicking on the canvas or via a
copy and paste event. In follow up PRs, we'll split these out so that
users can replace parts of the code where these shapes are created.
### Change Type
- [x] `major` — Breaking Change
### Test Plan
- [x] Unit Tests
This diff modifies our canvas/rendering code to support shapes rendering
into a "background layer". The background layer isn't a layer in the
sense of our own html/svg/indicator layers, but is instead part of the
HTML canvas layer and is created by allocating z-indexes to shapes below
all others.
For most shapes, the background starts at the canvas. If a shape is in a
frame, then the frame is treated as the background.
![Kapture 2023-05-19 at 11 38
12](https://github.com/tldraw/tldraw/assets/1489520/3ab6e0c0-f71e-4bfd-a996-c5411be28a71)
Exports now use the `renderingShapes` algorithm which fixed a small bug
with exports where opacity wouldn't get correctly propagated down
through child shapes.
### The plan
1. initial highlighter shape/tool #1401
2. sandwich rendering for highlighter shapes #1418 **>you are here<**
3. shape styling - new colours and sizes, lightweight perfect freehand
changes
### Change Type
- [x] `minor` — New Feature
### Test Plan
not yet!
- [x] Unit Tests
### Release Notes
[not yet!]
This diff adds an initial version of the highlighter shape. At this
stage, it's a complete copy of the draw tool minus the following
features:
* Fills
* Stroke types
* Closed shapes
I've created a new shape util (a copy-paste of the draw one with stuff
renamed/deleted) but reused the state chart nodes for the draw shape.
Currently this new tool looks exactly like the draw tool, but that'll be
changing soon!
![Kapture 2023-05-17 at 15 37
33](https://github.com/tldraw/tldraw/assets/1489520/982e78f4-6495-4a68-aa51-c8f7b5bcdd01)
The UI here is extremely WIP. The highlighter tool is behind a feature
flag, but once enabled is accessible through the tool bar. There's a
first-draft highlighter icon (i didn't spend much time on this, it's not
super legible on non-retina displays yet imo), and the tool is bound to
the `i` key (any better suggestions? `h` is taken by the hand tool)
### The plan
1. initial highlighter shape/tool #1401 **>you are here<**
2. sandwich rendering for highlighter shapes #1418
3. shape styling - new colours and sizes, lightweight perfect freehand
changes
### Change Type
- [x] `minor` — New Feature
### Test Plan
(not yet)
### Release Notes
[internal only change layout ground work for highlighter]
This PR removes unused scripts related to benchmarking, and some other
unused dependencies.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package (will not publish a new version)
This PR adds a user preference to reduce motion. When enabled the app
will not animate the camera (and perhaps skip other animations in the
future). It's actual implementation is as an `animateSpeed` property, so
we can also use it to speed up or slow down our animations if that's
something we want to do!
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Turn on reduce motion
2. Use minimap / camera features to zoom in / out / etc
- [x] Unit Tests
### Release Notes
- [editor] Add `reduceMotion` user preference
- Add reduce motion option to preferences
This PR adds `getSnapshot` and `loadSnapshot` to the `Store`, sanding
down a rough corner that existed when persisting and loading data.
Avoids learning about stores vs schemas vs migrations until a little
later.
### Change Type
- [x] `minor` — New Feature
### Test Plan
- [x] Unit Tests
### Release Notes
- [tlstore] adds `getSnapshot` and `loadSnapshot`
This PR replaces our webdriver end to end tests with playwright tests.
It:
- replaces our webdriver workflow with a new e2e workflow based on
playwright
- removes the webdriver project
- adds e2e tests to our examples app
- replaces all `data-wd` attributes with `data-testid`
### Coverage
Most of the tests from our previous e2e tests are reproduced here,
though there are some related to our gestures that will need to be done
in a different way—or not at all. I've also added a handful of new
tests, too.
### Where are they
The tests are now part of our examples app rather than being in its own
different app. This should help us test our different examples too. As
far as I can tell there are no downsides here in terms of the regular
developer experience, though they might complicate any CodeSandbox
projects that are hooked into the examples app.
### Change Type
- [x] `tests` — Changes to any testing-related code only (will not
publish a new version)
As part of my highlighter work, I've been writing a few test cases
around rendering with different combinations of nested frames and
groups. Writing these test cases using `createShapes` is really hard,
and reading them is even harder. I wanted to see if there was an easier
way for us to define shapes for test cases, and turns out... there is!
This diff introduces a JSX-based DSL for defining test cases. It looks
something like this:
```tsx
// create some shapes
const ids = app.createShapesFromJsx([
<TL.geo ref="A" x={100} y={100} w={100} h={100} />,
<TL.frame ref="B" x={200} y={200} w={300} h={300}>
<TL.geo ref="C" x={200} y={200} w={50} h={50} />
<TL.text ref="D" x={1000} y={1000} text="Hello, world!" align="end" />
</TL.frame>,
])
// refer to shape IDs according to their `ref`
app.select(ids.C)
```
It's probably not worth trying to migrate everything possible to this,
but i picked a few random tests to convert over to show how it works
(and because i wanted this diff to end up red overall)
In the future, I'd like to use this with visual regression testing to
test rendering/exports on some complex combinations of shapes too.
### Change Type
- [x] `tests` — Changes to any testing-related code only (will not
publish a new version)
### Release Notes
[internal only change]
This diff tweaks our `debugFlags` framework to support setting different
default value for different environments, makes it easier to define
feature flags, and makes feature flags show up in the debug menu by
default. With this change, feature flags will default to being enabled
in dev and preview environments, but disabled in production.
Specify a feature flag like this:
```ts
const featureFlags = {
myCoolNewFeature: createFeatureFlag('myCoolNewFeature')
}
```
optionally, pass a second value to control its defaults:
```ts
const featureFlags = {
featureEnabledInProduction: createFeatureFlag('someFeature', { all: true }),
customEnabled: createFeatureFlag('otherFeature', {development: true, staging: false, production: false}),
}
```
In code, the value can be read using `featureFlags.myFeature.value`.
Remember to wrap reading it in a reactive context!
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
-
### Release Notes
[internal only change]
This PR adds an `isPageId` helper.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package (will not publish a new version)
### Release Notes
- [tlschema] Add `isPageId`
This PR marks internal APIs as internal in `tlsync-client`.
### Change Type
- [x] `major` — Breaking Change
### Release Notes
- Removes internal APIs from `@tldraw/tlsync-client`
This PR renames our record types to avoid a type collision with the type
that they are based on. For example `TLCamera` is both a type and a
record; after this PR, we use `CameraRecordType` for the camera's record
type.
### Change Type
- [x] `major` — Breaking Change
### Release Notes
- [editor] rename record types
Previously, we had a bunch of special-casing around paste to support
safari quirks on desktop and ios.
Since upgrading radix-ui and useGesture, these are no longer needed and
were actually causing issues. This diff removes the special casing for
paste and makes it a normal action that get triggered the same way as
any other.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Copy text outside of tldraw, paste in tldraw with the context menu,
edit menu, and keyboard shortcut
2. Repeat for images outside of tldraw
3. Repeat for shapes inside of tldraw
### Release Notes
[fixes a regression introduced during this release]
Disable `g` keyboard shortcut in readonly mode. Show laser tool in
toolbar when in readonly mode.
Resolves [#1936](https://github.com/tldraw/brivate/issues/1936)
Resolves [#1935](https://github.com/tldraw/brivate/issues/1935)
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Open a readonly room.
2. Press `g` and make sure it doesn't switch to it.
3. Laser tool should be visible in the toolbar in readonly rooms.
### Release Notes
- Disable geo tool shortcut in readonly mode. Show laser on the toolbar.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR fixes the people menu button's border being misaligned on
android.
There is a still a tiny tiny tiny sliver visible through the border,
which could be fixed in a future PR.
![image](https://github.com/tldraw/tldraw/assets/15892272/d84cac26-33e4-4089-b0e0-1fa480b57286)
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Open a shared project on Android.
2. Place a visible *behind* the people menu button, so that you can
'see' the background-coloured border around the button.
3. Make sure the border is centered around the people menu button.
This PR adds a colored box around the current window when following
another user.
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Follow a user
2. Check out the box
### Release Notes
- Adds viewport following indicator
fixes#1464
The user preference changes were not broadcasting correctly in firefox
because it has a race condition wherein the broadcast message was being
received by a peer tab before the localStorage data was ready to be
consumed in that tab.
### Change Type
<!-- 💡 Indicate the type of change your pull request is. -->
<!-- 🤷♀️ If you're not sure, don't select anything -->
<!-- ✂️ Feel free to delete unselected options -->
<!-- To select one, put an x in the box: [x] -->
- [x] `patch` — Bug Fix
- [ ] `minor` — New Feature
- [ ] `major` — Breaking Change
- [ ] `dependencies` — Dependency Update (publishes a `patch` release,
for devDependencies use `internal`)
- [ ] `documentation` — Changes to the documentation only (will not
publish a new version)
- [ ] `tests` — Changes to any testing-related code only (will not
publish a new version)
- [ ] `internal` — Any other changes that don't affect the published
package (will not publish a new version)
### Test Plan
1. in firefox, have two tabs open in the same user context.
2. toggle dark mode.
3. the change should propagate to the other tab
This PR removes the laser tool toggleShapeLocked button.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Select laser tool.
2. Confirm that the toggle shape locked button is not visible.
Adds laser keyboard shortcut to the keyboard shortcuts dialog. Fixes
[#1465](https://github.com/tldraw/tldraw/issues/1465)
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Open the keyboard shortcuts dialog from the help menu.
2. Laser tool should be listed.
This PR makes the "follow" button visible on iPad where hover is not
available.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. View the people menu on iPad
2. See that the follow person button is visible
This PR fixes a bug that would effect the page item submenu. With the
`useMenuIsOpen` hook, it's important that multiple menus have unique
ids. In this case each page was using `page sub menu` and so each open
menu would be closed by the not-open menu effects.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Create two pages
2. Open the submenus on each page
This PR fixes the default custom cursor being slightly out-of-position
compared to MacOS cursor.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. On Mac, right-click on the canvas.
2. When the cursor swaps out for the OS cursor... it should stay in the
same position.
This PR changes the pointer cursor back to white (from black).
I made it black to do some debugging, and I forgot to change it back.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Make a bookmark shape by pasting a link.
2. Hover the hyperlink of the bookmark.
3. Check that the 'pointer' cursor is white.
- Remove TLUser, TLUserPresence
- Add first-class support for user preferences that persists across
rooms and tabs
### Change Type
<!-- 💡 Indicate the type of change your pull request is. -->
<!-- 🤷♀️ If you're not sure, don't select anything -->
<!-- ✂️ Feel free to delete unselected options -->
<!-- To select one, put an x in the box: [x] -->
- [ ] `patch` — Bug Fix
- [ ] `minor` — New Feature
- [x] `major` — Breaking Change
- [ ] `dependencies` — Dependency Update (publishes a `patch` release,
for devDependencies use `internal`)
- [ ] `documentation` — Changes to the documentation only (will not
publish a new version)
- [ ] `tests` — Changes to any testing-related code only (will not
publish a new version)
- [ ] `internal` — Any other changes that don't affect the published
package (will not publish a new version)
### Test Plan
1. Add a step-by-step description of how to test your PR here.
2.
- [ ] Unit Tests
- [ ] Webdriver tests
### Release Notes
- Add a brief release note for your PR here.
This PR adds translations for the "Leave shared project" action for
tldraw.com
It's for a brivate PR: https://github.com/tldraw/brivate/pull/1870
### Change Type
- [x] `patch` — Translations
### Release Notes
- None
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Bumps use-gesture. Should fix#1393
### Change Type
<!-- 💡 Indicate the type of change your pull request is. -->
<!-- 🤷♀️ If you're not sure, don't select anything -->
<!-- ✂️ Feel free to delete unselected options -->
<!-- To select one, put an x in the box: [x] -->
- [ ] `patch` — Bug Fix
- [ ] `minor` — New Feature
- [ ] `major` — Breaking Change
- [x] `dependencies` — Dependency Update (publishes a `patch` release,
for devDependencies use `internal`)
- [ ] `documentation` — Changes to the documentation only (will not
publish a new version)
- [ ] `tests` — Changes to any testing-related code only (will not
publish a new version)
- [ ] `internal` — Any other changes that don't affect the published
package (will not publish a new version)
### Test Plan
1. on iPad, with no shapes selected, long press on the canvas to open
the context menu.
2. tap outside of the menu to dismiss it
3. you should still be able to pan and pinch normally and select shapes
and everything.
### Release Notes
- Updates use-gesture to fix pinch gesture bug on iPad.
This adds a migration to migrate existing alignment options to their
legacy counter parts (`start` -> `start-legacy`, `end` -> `end-legacy`,
`middle` -> `middle-legacy`).
With this change the legacy options don't show any align as active in
the Styles panel:
![CleanShot 2023-05-23 at 19 53
45](https://github.com/tldraw/tldraw/assets/2523721/4017e03a-9492-4a02-b991-ac206f40ae17)
I think this is probably what we want.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Use some old preview link to create Geo and Note shapes with old
alignment options. You can use this one:
https://examples-kzwtf68jr-tldraw.vercel.app/
2. Copy and paste these shapes over to staging. Nothing should change
visually.
3. Also try out exporting to svg (with both old and new alignment
options)
- [x] Unit Tests
- [ ] Webdriver tests
### Release Notes
- Add support for legacy alignment options.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
We noticed that when inferring the type of a shape from its ID, it was
getting inferred as `any` which was hiding some issues. This diff
switches `BaseRecord`'s automatic ID to an explicit one, which lets us
pass in our correct `TLShapeId` definition and still have it play nicely
with other places.
### Change Type
- [x] `patch` — Bug Fix
### Release Notes
[internal only, covered by #1432 changelog]
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR restores `createTLSchema`.
It also:
- removes `TldrawEditorConfig.default`
- makes `config` a required property of `<TldrawEditor>`, though it's
created automatically in `<Tldraw>`.
- makes `config` a required property of `App`
- removes `TLShapeType` and replaces the rare usage with
`TLShape["type"]`
- adds `TLDefaultShape` for a union of our default shapes
- makes `TLShape` a union of `TLDefaultShape` and `TLUnknownShape`
### Change Type
- [x] `major` — Breaking Change
### Release Notes
- [editor] Simplifies custom shape definition
- [tldraw] Updates props for <TldrawEditor> component to require a
`TldrawEditorConfig`.
This PR fixes cursor shadow getting clipped in some cases.
Kap doesn't record the error so you'll have to take my word on this one!
### Change Type
- [x] `patch` — Bug Fix
### Release Notes
- Fixed a bug where custom cursors could have their shadow clipped.
Fixes#1410
This PR adds custom SVGs for all cursor types.
This will unblock some upcoming collaboration features!
It also adds some basic debugging for custom cursors.
![2023-05-19 at 11 02 57 - Coffee
Shrimp](https://github.com/tldraw/tldraw/assets/15892272/dbc84d04-604f-43e5-acd2-69df956e5784)
It uses custom cursors for any shape-related UI, like links.
![2023-05-19 at 11 07 04 - Amaranth
Aphid](https://github.com/tldraw/tldraw/assets/15892272/7eb25f6a-0552-47bd-b2b9-f6c3dc2fca70)
But it sticks with the default browser cursors for the non-canvas UI.
![2023-05-23 at 15 06 29 - Apricot
Bovid](https://github.com/tldraw/tldraw/assets/15892272/2fe35afb-095a-4454-a6c3-aa8337b71506)
### Change Type
- [x] `minor`
### Test Plan
1. Enable debug mode.
2. From the debug menu, enable "Debug cursors".
3. Hover the cursor over the shapes that appear.
4. Check that the cursor appears correctly over each one.
5. (Don't forget to turn off "Debug cursors" after use).
### Release Notes
- Added consistent custom cursors.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR removes `createTLSchema`, now that the default shapes / utils
are in the editor's `TldrawEditorConfig`. There were a few places that
still called `createTLSchema`, though they would have been missing many
parts of the
### Change Type
- [x] `major` — Breaking Change
### Test Plan
- [x] Unit Tests
### Release Notes
- [tlschema] Removes `createTLSchema` in favor of `TldrawEditorConfig`
This PR removes `TLShapeDef` and associated helpers / references.
It purposely loosens the configuration and typings to better support
customization.
### Change Type
- [x] `major` — Breaking Change
### Test Plan
1. Use the app!
### Release Notes
- [tlschema] Update props of `createTLSchema`
- [editor] Update props of `TldrawEditorConfig`
- [editor] Remove `App.getShapeUtilByType`
- [editor] Update `App.getShapeUtil` to take a type rather than a shape
---------
Co-authored-by: alex <alex@dytry.ch>
This PR stops collaborator cursors wobbling while viewport-following.
It's a **new wobble** that we haven't seen before! (It crept in at some
point)
It happens when these three things happen at the same time:
* You're following someone
* They're panning
* They're not moving their pointer
eg: This happens when they're trackpad-panning.
So this is *not* the **old wobble** that we fixed before! That one is
still fixed.
---
The **new wobble** looks like this:
![2023-05-22 at 12 08 51 - Magenta
Urial](https://github.com/tldraw/tldraw/assets/15892272/4b738766-cde3-4a9c-9169-76d622bec3bf)
It's sometimes hard-to-spot because of the _smoothing_ that we do.
When we drastically increase the strength of smoothing... the **new
wobble** is less noticeable:
![2023-05-22 at 12 12 40 - Rose
Goat](https://github.com/tldraw/tldraw/assets/15892272/4ece229a-60e8-4923-89f8-4a0f9b702491)
But we can do better!
So for demonstration purposes... let's turn off _smoothing_ to let us
see the **new wobble** more clearly.
![2023-05-22 at 12 16 02 - Gold
Macaw](https://github.com/tldraw/tldraw/assets/15892272/9030cf2a-bdf3-47f0-87f0-a1195ab2fcbf)
Now we can clearly see what's going on...
The cursor is updating every animation **frame**.
The camera is updating every **tick**.
Depending on your screen's refresh rate, these _might be different_!
Let's test that theory by throttling the **tick** further.
As expected, it increases the **new wobble**:
![2023-05-22 at 14 16 21 - Blush
Caterpillar](https://github.com/tldraw/tldraw/assets/15892272/c70ee08c-8fd3-40ae-a4b3-95637c08acc7)
Let's test the theory again by trying on a screen where the _tick_ and
_frame_ are in sync.
As expected, the **new wobble** doesn't happen _most of the time_.
However, _frame_ and _tick_ can still get out of sync! Which causes the
occasional wobble:
![2023-05-22 at 14 38 21 - Lime
Eagle](https://github.com/tldraw/tldraw/assets/15892272/2a9d8c98-194f-4b73-a7ea-ee85ac1fa28f)
So let's fix both cases...
Instead of making the following-camera update every _tick_...
Let's make it update every _frame_!
![2023-05-22 at 15 28 47 - Salmon
Smelt](https://github.com/tldraw/tldraw/assets/15892272/e9f5c10c-d421-4611-b049-7a961218c087)
The perceptive among you might notice a slight wobble that's still
there...
This is an entirely **different wobble** caused by different things.
We can get to it in the future! But we're back at our original
wobble-quota for now.
![2023-05-22 at 14 32 18 - Brown
Tern](https://github.com/tldraw/tldraw/assets/15892272/e1250715-0bf2-4b87-b6e7-a357bccf4106)
When we turn smoothing back on, things look better than before 👍
![2023-05-22 at 14 42 48 - Cyan
Roundworm](https://github.com/tldraw/tldraw/assets/15892272/f3616c6f-7969-4a8d-80b1-26ee44e6f451)
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Open a single shared project in two different browser sessions.
2. Make one session's user follow the other.
3. Trackpad-pan the leader's camera around.
4. Check that the wobble has reduced.
This PR removes comments from our record types, makes initial version
optional, and unifies the order of initial / current version.
- Initial versions are zero by default
- If no current version is provided to `defineMigrations`, migrations
should be undefined
- Fixes TypeScript quirks in versioning (e.g. only initial version)
This PR also:
- Makes migrations optional when empty
- Removes reference to empty migrations
### Change Type
- [x] `major` — Breaking Change
### Test Plan
- [x] Unit Tests
- [ ] Webdriver tests
### Release Notes
- [tlschema] Improve `defineMigrations`
- [editor] Simplify migration definitions
This diff fixes a number of issues with text export by completely
overhauling how we approach laying out text in exports.
Currently, we try to carefully replicate in-browser behaviour around
line breaks and whitespace collapsing. We do this using an iterative
algorithm that forces the browser to perform a layout for each word, and
attempting to re-implement how the browser does things like whitespace
collapsing & finding line break opportunities. Lots of export issues
come from the fact that this is almost impossible to do well (short of
sending a complete text layout algorithm & full unicode lookup tables).
Luckily, the browser already has a complete text layout algorithm and
full unicode lookup tables! In the new approach, we ask the browser to
lay the text out once. Then, we use the
[`Range`](https://developer.mozilla.org/en-US/docs/Web/API/Range) API to
loop over every character in the rendered text and measure its position.
These character positions are then grouped into "spans". A span is a
contiguous range of either whitespace or non-whitespace characters,
uninterrupted by any browser-inserting line breaks. When we come to
render the SVG, each span gets its own `<tspan>` element, absolutely
positioned according to where it ended up in the user's browser.
This fixes a bunch of issues:
**Misaligned text due to whitespace collapsing at line breaks**
![Kapture 2023-05-17 at 12 07
30](https://github.com/tldraw/tldraw/assets/1489520/5ab66fe0-6ceb-45bb-8787-90ccb124664a)
**Hyphenated text (or text with non-trivial/whitespace-based breaking
rules like Thai) not splitting correctly**
![Kapture 2023-05-17 at 12 21
40](https://github.com/tldraw/tldraw/assets/1489520/d2d5fd13-3e79-48c4-8e76-ae2c70a6471e)
**Weird alignment issues in note shapes**
![Kapture 2023-05-17 at 12 24
59](https://github.com/tldraw/tldraw/assets/1489520/a0e51d57-7c1c-490e-9952-b92417ffdf9e)
**Frame labels not respecting multiple spaces & not truncating
correctly**
![Kapture 2023-05-17 at 12 27
27](https://github.com/tldraw/tldraw/assets/1489520/39b2f53c-0180-460e-b10a-9fd955a6fa78)
#### Quick note on browser compatibility
This approach works well across all browsers, but in some cases actually
_increases_ x-browser variance. Consider these screenshots of the same
element (original above, export below):
![image](https://github.com/tldraw/tldraw/assets/1489520/5633b041-8cb3-4c92-bef6-4f3c202305de)
Notice how on chrome, the whitespace at the end of each line of
right-aligned text is preserved. On safari, it's collapsed. The safari
option looks better - so our manual line-breaking/white-space-collapsing
algorithm preferred safari's approach. That meant that in-app, this
shape looks very slightly different from browser to browser. But out of
the app, the exports would have been the same (although also note that
hyphenation is broken). Now, because these shapes look different across
browsers, the exports now look different across browsers too. We're
relying on the host-browsers text layout algorithm, which means we'll
faithfully reproduce any quirks/inconsistencies of that algorithm. I
think this is an acceptable tradeoff.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
* Comprehensive testing of text in exports, paying close attention to
details around white-space, line-breaking and alignment
* Consider setting `tldrawDebugSvg = true`
* Check text shapes, geo shapes with labels, arrow shapes with labels,
note shapes, frame labels
* Check different alignments and fonts (including vertical alignment)
### Release Notes
- Add a brief release note for your PR here.
This PR makes two improvements to the laser pointer:
- it increases the opacity of collaborator lasers
- it fixes a case where a scribble could have no points
### Change Type
- [x] `patch` — Bug Fix
This PR moves our "fractical indices" library into its own package.
- [x] `major` — Breaking Change
### Release Notes
- [@tldraw/editor] Remove fractional indices code into `@tldraw/indices`
- [@tldraw/indices] Create library for fractional indices code
This PR:
- adds the checkbox to the toolbar
- removes the embed button from the toolbar
### Change Type
- [x] `minor` — New Feature
### Release Notes
- Adds missing checkbox to toolbar.
This PR makes it so that horizontal alignment in geo and sticky note
shapes also effects the position of the text within the shape.
<img width="1169" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/96b28a7d-0f13-46ba-9ea1-82d02b4f870b">
<img width="1274" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/fa768c71-4e9e-4cfe-ad8a-94d7700c445d">
This PR also places the shape's label at the center when there is no
text and the shape is not editing.
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Create shapes with labels
2. Confirm that their labels are positioned correctly
3. Export the shapes and verify the export
### Release Notes
- Geo shapes and sticky notes now position their labels based on their
alignment.
This PR adds a laser pointer. It's also available in readonly rooms.
![Kapture 2023-05-18 at 17 00
18](https://github.com/tldraw/tldraw/assets/23072548/4f638dff-8c17-4f9d-8177-4a63a524b7fd)
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Select the laser pointer tool
2. Draw some lasers.
### Release Notes
- Adds the laser pointer tool.
This PR fixes a bug in firefox where the pointer can get stuck down
while pressing the control key.
It achieves this by taking a previous fix (specifically for
`useShapeEvents`), and it applies the fix at a deeper level (within
`app.dispatch`).
## Before
![2023-05-16 at 15 33 02 - Crimson
Coyote](https://github.com/tldraw/tldraw/assets/15892272/7d4b5bb1-a2e5-400c-9935-fddcc9645e52)
## After
![2023-05-16 at 15 34 03 - Purple
Panda](https://github.com/tldraw/tldraw/assets/15892272/34a598b2-bf6d-4847-8ce9-a3d52c418174)
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Use firefox.
2. On the canvas... pointer down (to start a selection box).
3. Control key down.
4. Pointer up.
5. Make sure that that the selection box is gone.
^ Repeat the above for:
Pointer down on a shape.
Pointer down on a handle.
### Release Notes
- [Firefox] Fixed a bug where the pointer could get stuck down when the
control key is held down.