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 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 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)
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]
- 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.
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`.
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 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 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.
Vertical text alignment for geo shapes.
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Add a step-by-step description of how to test your PR here.
2.
- [ ] Unit Tests
- [ ] Webdriver tests
### Release Notes
- This adds vertical text alignment property to geo shapes.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Followup to https://github.com/tldraw/brivate/pull/1584
- Removes the old collaborators component, replacing with the new one.
- Removes the associated debug flag
### 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
Check that multiplayer presence UI renders correctly
- cursors
- cursor hints (when a peer's cursor goes off the screen)
- selection brush box
- selection/erasing brush
- selected shape(s) outline
### Release Notes
- [Breaking] Removes the old version of LiveCollaborators, replacing it
with the new one based on `TLInstancePresence`
This PR refactors our clipboard handlers. It should simplify the way
that things work and better handle the difference between how the native
API events are handled vs. the browser's clipboard API events.
![Kapture 2023-05-17 at 13 26
34](https://github.com/tldraw/tldraw/assets/23072548/5dedcc25-a1d2-423f-8bc2-415f761b643b)
Everything that used to be supported now also still works.
In addition, we now have several useful features:
### Multiline text can be pasted into the app
When pasting text that contains more than one line, the text is pasted
correctly; even if the clipboard also includes HTML data. Previously, we
would try to paste HTML data if we found it, because that data might
contain tldraw's own content as a comment; but if that failed, we would
paste the data as text instead. This led to pasting text that lost lots
of information from that text, such as line breaks and indentations.
### Multiline text shapes are aligned correctly
When pasting raw text that has more than one line, the text will be left
aligned—or right aligned if the text is likely from a RTL language.
![Kapture 2023-05-17 at 13 42
54](https://github.com/tldraw/tldraw/assets/23072548/f705acd5-136c-4144-80da-6e97ff766a58)
### Common minimum indentation is removed from each line
![Kapture 2023-05-17 at 13 56
28](https://github.com/tldraw/tldraw/assets/23072548/d45c95f6-6d28-4c9f-8cd3-8078700ce928)
This is something that absolutely every app should implement, but here
we go. When multiline text has "common indentation" on each line, which
is often the case when pasting text from code, then that indentation is
removed from each line.
### Auto wrapping for big pastes
When a line has no text breaks but a lot of text, we now set the width
of the text shape.
![Kapture 2023-05-17 at 14 00
04](https://github.com/tldraw/tldraw/assets/23072548/0b7f69c3-bcf9-42e9-a1ed-df026f868793)
## How it works
A `ClipboardThing` is the common interface for things that we found on
the clipboard, native or otherwise. Both `handlePasteFromClipboardApi`
and `handlePasteFromEventClipboardData` parse out `ClipboardThing`s and
pass them to `handleClipboardThings`.
<img width="905" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/fd087539-edbb-4527-b5ff-ca7d7c1726b2">
A `ClipboardResult` is the result of processing a `ClipboardThing`, and
usually contains text and other information about that text. We make
decisions on what to create based on which `ClipboardResult`s we find.
When pasting text, we check to see whether the result would be bigger
than the viewport, or if the text is multiline, or if the text is of an
RTL language by testing certain common RTL characters. We make some
adjustments based on those factors, ensuring that the top-left corner of
the text is on screen and reasonably positioned within the viewport if
possible.
### Change Type
- [x] `minor` — New Feature
### Test Plan
1. Copy and paste shapes
2. Copy and paste text from elsewhere into the app
3. Copy and paste images from elsewhere into the app
4. Try on different browsers
### Release Notes
- Improves clipboard logic when pasting text
- Adds support for pasting multi-line text
- Adds maximum widths when pasting single-line text
- Adds support for RTL languages when pasting multi-line or wrapped text
- Strips leading indentation when pasting text
We were storing the state of whether or not a document is read-only in
the store. It does not need to be stored there, and it was creating
consistency problems for us, so let's not store it in there.
fixes https://github.com/tldraw/brivate/issues/1864
### 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. Create a multiplayer room
2. Create a read-only link for the room
3. Paste the link into a new browser tab (not incognito, needs to have
the same session state)
4. Check the room is read-only in the new tab
5. Check the room is still writable in the previous tab.
### Release Notes
- Removes the isReadOnly value from the `user_document_settings` record
type.
Expand the selection outline on draw shapes according to pen thickness
when only one shape is selected.
![Kapture 2023-05-15 at 16 20
01](https://github.com/tldraw/tldraw/assets/1489520/373f0ec1-f43d-46c9-9729-0c84aaf2564b)
Right now the outline of many of our shapes don't take stroke thickness
into account. This is a pretty hard thing to get right, so in the short
term here's a fix for one of the most common places this is an issue:
selecting a single horizontal/vertical draw shape. This fix isn't
perfect: resizing gets slightly janky when you completely flip the shape
- see how the handle leaves the cursor behind in the gif when that
happens. We can revisit with a more comprehensive solution later.
This is pulled out from the highlighter work! The highlighter shape will
use the shape APIs added here.
### Change Type
- [x] `patch` — Bug Fix
### Test Plan
1. Create a draw shape
2. Select it
3. Selection bounds should include the stroke width
4. Add another shape to the selection
5. Selection bounds should no longer include the stroke width
### Release Notes
- Improve selection outlines around horizontal or vertical draw shapes
I need to mock nanoid for the ephemeral state fuzz tests, to create
repeatable test runs. In order to do that properly it needs to have a
consistent version among all our packages.
At the same time I'm removing some old unused params in AppOptions
### 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)
### Release Notes
- Remove unused userId and instanceId props from AppOptions
This PR adds a `check-box` geo shape.
![Kapture 2023-05-08 at 15 31
49](https://user-images.githubusercontent.com/23072548/236853749-99ba786f-73a4-4b65-86ca-f2cdac61a903.gif)
It also improves some logic around the `onClick` shape util handler and
some surprisingly related fixes to point hit testing.
### Test Plan
1. Create a geo shape
2. Set it as a checkbox style
3. *easter egg* double click while holding alt to toggle between
check-box and rectangle
- [x] Unit Tests
### Release Note
- Adds checkbox geo shape.
This PR adds docs for the methods in the TLShapeUtil class.
I think that it's a good page to have docs on, as it shows people what's
possible with the custom shape API.
Currently, our docs are not showing `@param` info for lots of methods,
including the ones added in this PR.
I'll do fix for that in a follow-up PR, so that it's easier to review.
---
Note: Moving forward, we probably want to consider **_where_** these
docs are shown, and how we achieve that.
For example, do we put the docs for these methods in:
* The docs page for the `TLShapeUtil` class?
* The docs pages for the handler types, eg:
[`OnResizeHandler`](http://localhost:3000/gen/editor/OnResizeHandler-type)?
* Both?
Right now, I opted for putting them in the the TLShapeUtil class, as it
keeps them all in one place, and it's what we already do for some
others.
We should consider both - what works best for the docs? and what works
best for code editors?
---
This PR also includes a fix to our pre-commit step that @SomeHats did.
Right now this examples app looks exactly the same as our old examples
app, but there are a couple of tiny differences:
- We use `vite` instead of our own esbuild setup for development and
bundling
- We use `@tldraw/assets` for smart asset hashing instead of copying the
assets to a public folder
You can use `@tldraw/assets` with vite with a bunch of extra config, but
it (plus a bunch of other bundlers) also support a special syntax for
specifying asset urls: `new URL('./my/asset.svg',
import.meta.url).href`. This approach is more standards-complient, but
doesn't work with every bundler just yet. This diff also adds a
url-based version of `@tldraw/assets`, although I'd like to tweak the
entry point - right now you need to import from
`@tldraw/assets/lib/urls`, but i'd like to find a way to get this to
`@tldraw/assets/urls` or something at some point.
There are a couple other extra fixes in here:
- vscode builds were broken, they're fixed now!
- there's also a little tweak to the `getBundlerAssetUrls` API to allow
passing in a function instead of an object for URL formatting
- there are new internal-only functions for injecting asset urls
globally instead of passing them in via react props. this means we can
get the benefits of cacheable URLs without having to clutter our
examples by passing them in
In this PR I'm adding new versions of the `LiveCollaborators` and
`Collaborators` components for the ephemeral state work. They are behind
a feature flag for now.
This PR adds
- A new `TLInstancePresence` record type, to collect info about the
presence state in a particular instance of the editor. This will
eventually be used to sync presence data instead of sending
instance-only state across the wire.
- **Record Scopes**
`RecordType` now has a `scope` property which can be one of three
things:
- `document`: the record belongs to the document and should be synced
and persisted freely. Currently: `TLDocument`, `TLPage`, `TLShape`, and
`TLAsset`
- `instance`: the record belongs to a single instance of the store and
should not be synced at all. It should not be persisted directly in most
cases, but rather compiled into a kind of 'instance configuration' to
store alongside the local document data so that when reopening the
associated document it can remember some of the previous instance state.
Currently: `TLInstance`, `TLInstancePageState`, `TLCamera`, `TLUser`,
`TLUserDocument`, `TLUserPresence`
- `presence`: the record belongs to a single instance of the store and
should not be persisted, but may be synced using the special presence
sync protocol. Currently just `TLInstancePresence`
This sets us up for the following changes, which are gonna be pretty
high-impact in terms of integrating tldraw into existing systems:
- Removing `instanceId` as a config option. Each instance gets a
randomly generated ID.
- We'd replace it with an `instanceConfig` option that has stuff like
selectedIds, camera positions, and so on. Then it's up to library users
to get and reinstate the instance config at persistence boundaries.
- Removing `userId` as config option, and removing the `TLUser` type
altogether.
- We might need to revisit when doing auth-enabled features like locking
shapes, but I suspect that will be separate.