Porównaj commity

...

100 Commity

Autor SHA1 Wiadomość Data
Kesavaraja Krishnan 10f5c6902b
Merge branch 'main' into custom-ui-more-tools 2024-04-23 10:03:48 +05:30
Mitja Bezenšek 4245fd55b2
Fix deploy script (#3550)
Seems like `tar` is moving to `ts` in version 7 and this caused some
issues with imports.

Saw this issue on [readonly
PR](https://github.com/tldraw/tldraw/actions/runs/8783569356/job/24099998235?pr=3192#step:6:684),
looks like a result of a [dependabot
PR](https://github.com/tldraw/tldraw/pull/3505).

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [x] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-22 15:33:25 +00:00
alex cce794e04b
Expose `usePreloadAssets` (#3545)
Expose `usePreloadAssets` and make sure the exploded/sublibraries
examples uses it. Before this change, fonts weren't loaded correctly for
the exploded example.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `docs` — Changes to the documentation, examples, or templates.
- [x] `bugfix` — Bug fix
2024-04-22 10:32:22 +00:00
dependabot[bot] 4507ce6378
Bump the npm_and_yarn group across 1 directory with 2 updates (#3505)
Bumps the npm_and_yarn group with 2 updates in the / directory:
[vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and
[tar](https://github.com/isaacs/node-tar).

Updates `vite` from 5.2.8 to 5.2.9
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted -->5.2.9 (2024-04-15)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: <code>fsp.rm</code> removing files does not take effect (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16032">#16032</a>)
(<a href="https://github.com/vitejs/vite/commit/b05c405">b05c405</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16032">#16032</a></li>
<li>fix: fix accumulated stacks in error overlay (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16393">#16393</a>)
(<a href="https://github.com/vitejs/vite/commit/102c2fd">102c2fd</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16393">#16393</a></li>
<li>fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16376">#16376</a>)
(<a href="https://github.com/vitejs/vite/commit/58a2938">58a2938</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16376">#16376</a></li>
<li>chore: update region comment (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16380">#16380</a>)
(<a href="https://github.com/vitejs/vite/commit/77562c3">77562c3</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16380">#16380</a></li>
<li>perf: reduce size of injected __vite__mapDeps code (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16184">#16184</a>)
(<a href="https://github.com/vitejs/vite/commit/c0ec6be">c0ec6be</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16184">#16184</a></li>
<li>perf(css): only replace empty chunk if imported (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16349">#16349</a>)
(<a href="https://github.com/vitejs/vite/commit/e2658ad">e2658ad</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16349">#16349</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a77707d69c"><code>a77707d</code></a>
release: v5.2.9</li>
<li><a
href="102c2fd5ad"><code>102c2fd</code></a>
fix: fix accumulated stacks in error overlay (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16393">#16393</a>)</li>
<li><a
href="58a2938a97"><code>58a2938</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16376">#16376</a>)</li>
<li><a
href="77562c3ff2"><code>77562c3</code></a>
chore: update region comment (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16380">#16380</a>)</li>
<li><a
href="b05c405f68"><code>b05c405</code></a>
fix: <code>fsp.rm</code> removing files does not take effect (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16032">#16032</a>)</li>
<li><a
href="e2658ad6fe"><code>e2658ad</code></a>
perf(css): only replace empty chunk if imported (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16349">#16349</a>)</li>
<li><a
href="c0ec6bea69"><code>c0ec6be</code></a>
perf: reduce size of injected __vite__mapDeps code (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16184">#16184</a>)</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite/commits/v5.2.9/packages/vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `tar` from 6.2.1 to 7.0.1
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md">tar's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>7.0</h2>
<ul>
<li>Rewrite in TypeScript, provide ESM and CommonJS hybrid
interface</li>
<li>Add tree-shake friendly exports, like
<code>import('tar/create')</code>
and <code>import('tar/read-entry')</code> to get individual functions or
classes.</li>
<li>Add <code>chmod</code> option that defaults to false, and deprecate
<code>noChmod</code>. That is, reverse the default option regarding
explicitly setting file system modes to match tar entry
settings.</li>
<li>Add <code>processUmask</code> option to avoid having to call
<code>process.umask()</code> when <code>chmod: true</code> (or
<code>noChmod: false</code>) is
set.</li>
</ul>
<h2>6.2</h2>
<ul>
<li>Add support for brotli compression</li>
<li>Add <code>maxDepth</code> option to prevent extraction into
excessively
deep folders.</li>
</ul>
<h2>6.1</h2>
<ul>
<li>remove dead link to benchmarks (<a
href="https://redirect.github.com/isaacs/node-tar/issues/313">#313</a>)
(<a href="https://github.com/yetzt"><code>@​yetzt</code></a>)</li>
<li>add examples/explanation of using tar.t (<a
href="https://github.com/isaacs"><code>@​isaacs</code></a>)</li>
<li>ensure close event is emited after stream has ended (<a
href="https://github.com/webark"><code>@​webark</code></a>)</li>
<li>replace deprecated String.prototype.substr() (<a
href="https://github.com/CommanderRoot"><code>@​CommanderRoot</code></a>,
<a
href="https://github.com/lukekarrys"><code>@​lukekarrys</code></a>)</li>
</ul>
<h2>6.0</h2>
<ul>
<li>Drop support for node 6 and 8</li>
<li>fix symlinks and hardlinks on windows being packed with
<code>\</code>-style path targets</li>
</ul>
<h2>5.0</h2>
<ul>
<li>Address unpack race conditions using path reservations</li>
<li>Change large-numbers errors from TypeError to Error</li>
<li>Add <code>TAR_*</code> error codes</li>
<li>Raise <code>TAR_BAD_ARCHIVE</code> warning/error when there are no
valid
entries found in an archive</li>
<li>do not treat ignored entries as an invalid archive</li>
<li>drop support for node v4</li>
<li>unpack: conditionally use a file mapping to write files on
Windows</li>
<li>Set more portable 'mode' value in portable mode</li>
<li>Set <code>portable</code> gzip option in portable mode</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="d99fce38eb"><code>d99fce3</code></a>
7.0.1</li>
<li><a
href="af043922c0"><code>af04392</code></a>
Do not apply linkpath,global from global pax header</li>
<li><a
href="b0fbdea463"><code>b0fbdea</code></a>
7.0.0</li>
<li><a
href="957da7506c"><code>957da75</code></a>
remove old lib folder</li>
<li><a
href="9a260c2dba"><code>9a260c2</code></a>
test verifying <a
href="https://redirect.github.com/isaacs/node-tar/issues/398">#398</a>
is fixed</li>
<li><a
href="2d89a4edc3"><code>2d89a4e</code></a>
Properly handle long linkpath in PaxHeader</li>
<li><a
href="314ec7e642"><code>314ec7e</code></a>
list: close file even if no error thrown</li>
<li><a
href="b3afdbb264"><code>b3afdbb</code></a>
unpack test: use modern tap features</li>
<li><a
href="2330416081"><code>2330416</code></a>
test: code style, prefer () to _ for empty fns</li>
<li><a
href="ae9ce7ec2a"><code>ae9ce7e</code></a>
test: fix normalize-unicode coverage on linux</li>
<li>Additional commits viewable in <a
href="https://github.com/isaacs/node-tar/compare/v6.2.1...v7.0.1">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/tldraw/tldraw/network/alerts).

</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com>
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-21 12:39:38 +00:00
Steve Ruiz a6d2ab05d2
Perf: minor drawing speedup (#3464)
Tiny changes as I walk through freehand code. These would only really
make a difference on pages with many freehand shapes.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Release Notes

- Improve performance of draw shapes.
2024-04-21 11:46:35 +00:00
Steve Ruiz b5fab15c6d
Prevent default on native clipboard events (#3536)
This PR calls prevent default on native clipboard events. This prevents
the error sound on Safari.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix

### Test Plan

1. Use the cut, copy, and paste events on Safari.
2. Everything should still work, but no sounds should play.

### Release Notes

- Fix copy sound on clipboard events.
2024-04-21 11:45:55 +00:00
David Sheldrick b5dfd81540
WebGL Minimap (#3510)
This PR replaces our current minimap implementation with one that uses
WebGL

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Add a brief release note for your PR here.

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-19 13:56:55 +00:00
Steve Ruiz f6a2e352de
Improve back to content (#3532)
This PR improves the "back to content" behavior. Rather than using an
interval, we now add a "camera-stopped" event that triggers the check.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` 

### Test Plan

1. Create some shapes, then move the camera to an empty part of the
canvas.
2. Check that the back to content button appears.
3. Ensure that the back to content button does not appear when the
canvas is empty.
2024-04-19 12:07:33 +00:00
Mitja Bezenšek 1fc68975e2
Fix version (#3521)
We were using react's version instead of the version of our packages.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [x] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-18 13:38:57 +00:00
Mitja Bezenšek 47070ec109
Use computed cache for getting the parent child relationships (#3508)
Use the existing computed cache for parent child relationships instead
of creating it.

Tiny bit faster, less memory, and simpler.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-18 08:01:46 +00:00
David Sheldrick 741ed00bda
[signia] Smart dirty checking of active computeds (#3516)
This is a huge perf win, and it came to me while procrastinating on
making dinner.

The idea is that we can skip checking the parents of a computed value if

- it is being dereferenced during a reaction cycle
- the computed value was not traversed during the current reaction cycle

This more than doubles the speed of the webgl minimap render on my
machine (from 2ms down to like 0.8ms).

This will make the biggest difference for anything that derives a value
from a large collection of other computed values where typically only a
small amount of them change at one time (e.g. iterating over all the
shape page bounds to compile an RBush)

Most code paths where we see a big chunk of `haveParentsChanged` in
flame graphs should be much faster after this.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features
2024-04-18 07:57:37 +00:00
Mitja Bezenšek dd0b7b882d
VS Code 2.0.30 (#3519)
Version bump for the hotfix.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [x] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 20:16:40 +00:00
David Sheldrick 625f4abc3b
[fix] allow loading files (#3517)
I messed up the schema validator for loading files.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 19:38:31 +00:00
Mitja Bezenšek f70fd2729d
VS Code 2.0.29 (#3515)
Version bump.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [x] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 15:31:40 +00:00
Mime Čuvalo d247b5dc53
arrows: fix bound arrow labels going over text shape (#3512)
Fixes https://github.com/tldraw/tldraw/issues/3433

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Release Notes

- Arrows: fix label positioning when bound.
2024-04-17 14:35:25 +00:00
Mime Čuvalo f9bafb2f8a
textfields: fix Safari cursor rendering bug, take 2 (#3513)
Take 2 on what this PR was trying to do:
https://github.com/tldraw/tldraw/pull/3373
Fixes https://github.com/tldraw/tldraw/issues/3398 hopefully this time
without the infinite recursion 🙃

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 14:31:35 +00:00
Mime Čuvalo f754bebc32
geo: fix double unique id on DOM (#3514)
Minor thing, but there's two nodes with the same ID. I got rid of the
one on the HTMLContainer, either one seems fine to remove though
¯\\_(ツ)_/¯

<img width="546" alt="Screenshot 2024-04-17 at 14 53 32"
src="https://github.com/tldraw/tldraw/assets/469604/5c4acdef-842c-4c4a-b9fd-504e23837efe">


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 14:01:12 +00:00
Mime Čuvalo f44ea90da6
arrows: still use Dist instead of Dist2 (#3511)
A little regression from https://github.com/tldraw/tldraw/pull/3454. We
still need the exact distance here.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know

### Release Notes

- Fix arrow label positioning
2024-04-17 13:16:22 +00:00
Mitja Bezenšek 0b44a8b47a
Fix culling. (#3504)
Fixes culling for cases when another user would drag shapes inside your
viewport. We weren't correctly calculating the culling status for arrows
that might be bound to those shapes and also for shapes within dragged
in groups / frames.


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Open the same room in two browsers / tabs.
2. Have some shapes that are visible in one browser, but not the other.
3. Drag these shapes so that they are visible in the other browser as
well.
4. They should correctly get unculled.
5. Do this by dragging shapes that have arrows bound to them (arrows
should uncull), groups (shapes within them should uncull), frames.

- [x] Unit Tests
- [ ] End to end tests

### Release Notes

- Fix culling.
2024-04-17 11:39:09 +00:00
Mime Čuvalo 34ad856873
textfields: nix disableTab option; make TextShapes have custom Tab behavior as intended (#3506)
We shouldn't be making this something you have to negate everytime you
use `useEditableText`. The TextShape can just have its custom behavior
since that's the intended usecase. (although I think that Tab there
doesn't do much anyway, but whatevs)

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 11:11:08 +00:00
Steve Ruiz 1450454873
"Soft preload" icons (#3507)
This PR includes a "soft preload" feature for icons, where icons will be
loaded when the canvas first mounts. The component will not wait for
icons to finish loading before showing the editor, but this should help
with "pop in" on menu icons.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Test Plan

1. Load the component
2. After load, open a menu for the first time
3. The icons should immediately be visible

### Release Notes

- Improve icon preloading
2024-04-17 10:57:08 +00:00
Mime Čuvalo a253af95d9
textfields: on mobile edit->edit, allow going to empty geo (#3469)
(this is a PR redo of https://github.com/tldraw/tldraw/pull/3424 which
got messed up a bit)

It doesn't quite feel like this is the right fix but it does solve the
issue. I was trying to see if `getShapeAtPoint` needed more work but the
further I went in that rabbit hole it seemed like I shouldn't touch that
code without causing a bunch of disruption at the moment.

Specifically, the code that does `Check labels first` in Editor.ts is a
little obscure (lines 4384-4397). It only checks a couple specifics
shapes (with certain combinations, i.e. a geo with "none" fill) _and_ it
doesn't check `hitLabels` which also maybe feels wrong? I tried
unraveling it but there's a lot of code relying on it at the moment to
mess with it in the stickies work.
(I was looking at https://github.com/tldraw/tldraw/pull/1910 and
https://github.com/tldraw/tldraw/pull/1806 for historical context fwiw)

Before:


https://github.com/tldraw/tldraw/assets/469604/b263a192-2085-4ffb-9e47-6e9c32abe1f9



After:


https://github.com/tldraw/tldraw/assets/469604/5b0b422b-dd5c-4593-9ac5-dec595923ea6



### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-17 09:34:23 +00:00
Steve Ruiz 7732e99811
Color tweaks (light and dark mode) (#3486)
This PR makes some changes to the appearance of colors in light and dark
mode. In general colors should be very slightly darker and less
saturated in light mode, creating greater contrast against the canvas,
fill, and note colors.

Before:

![image](https://github.com/tldraw/tldraw/assets/23072548/aa9a0c64-bf7a-4cde-a611-92fa6d78eabb)

After:

![image](https://github.com/tldraw/tldraw/assets/23072548/352bc688-aa68-4b50-b990-fab643cb0bef)

There are still some balancing to do on dark mode.

Before:
<img width="1393" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/d87114a1-c96e-4b77-bd29-7b44f4faa54f">

After:
<img width="1504" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/c8818afe-b961-4a1d-8852-914ff599a7f3">

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix

### Release Notes

- Adjusts colors

---------

Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-17 09:31:55 +00:00
Steve Ruiz 6282f65519
Stickies: fix sticky note clipping (#3503)
This PR restores masking for sticky notes that are the child of frames.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-17 09:31:36 +00:00
Lu Wilson 413838cd3d
Add slides example (#3467)
This PR adds a slides use-case example.


https://github.com/tldraw/tldraw/assets/15892272/89fdcb56-167d-4046-bfec-f93b18a83da2


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [x] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [x] `dunno` — I don't know


### Test Plan

1. Try out the slideshow example! (scroll to the bottom to see it).

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Docs: Added a slideshow example

---------

Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com>
2024-04-17 09:27:37 +00:00
Mime Čuvalo 7104515c9c
textfields: wait a tick before selecting all to fix iOS (#3501)
fixes https://github.com/tldraw/tldraw/issues/3500

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-16 16:15:13 +00:00
Mime Čuvalo fa3464ca8c
textfields: fix dragging selected shape behind another (#3498)
The fix here was that we need to check if we're editing before
dispatching the pointer down event. This is some leftover DNA from code
when we had textareas always present and when
tl-svg-container/tl-html-container wasn't around. The
`setPointerCapture` was originally fixing a bug where dragging a shape
using the textlabel as the origin would start to breakdown when you got
to UI toolbar/panel.

Also, turns out we don't need the `setPointerCapture` anymore because of
the same reason.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-16 15:54:03 +00:00
Mime Čuvalo 2c4266c574
css more shapes that need transparent behavior (#3497)
Couple more shapes need the z-index rule enabled, basically the 'draw'-y
shapes.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-16 15:19:30 +00:00
Mime Čuvalo 1f09a6e262
stickies: a bit of fuzziness when calculating certain text (#3493)
Fixes
https://linear.app/tldraw/issue/TLD-2402/long-words-in-stickies-sometimes-wrap-before-the-font-size-shrinks


https://github.com/tldraw/tldraw/assets/15892272/0b6f6d3c-d21d-430b-97d0-7c9b5abefa0b

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-16 14:37:20 +00:00
Lu Wilson 8778629f62
Only show cursor chat button in select mode (#3485)
This PR hides the cursor chat context menu button when not in select
tool.

fixes
https://github.com/orgs/tldraw/projects/41/views/1?pane=issue&itemId=59908615

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [x] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Fix cursor chat button appearing when not in select tool.
2024-04-16 12:42:26 +00:00
Lu Wilson c7cb91d7d4
Fix alt-duplicating shapes sometimes not working (#3488)
This PR fixes alt-duplicating shapes not working if you pointer-down'd
on their text label.

fixes
https://github.com/orgs/tldraw/projects/41/views/1?pane=issue&itemId=59901721

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [x] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Add a brief release note for your PR here.
2024-04-16 12:40:01 +00:00
David Sheldrick 9a4087efe1
[perf] faster signia capture (again) (#3487)
Describe what your pull request does. If appropriate, add GIFs or images
showing the before and after.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Add a brief release note for your PR here.
2024-04-16 11:12:01 +00:00
Mime Čuvalo c39e437793
stickies: dont remove selection ranges when edit->edit (#3484)
This was necessary before but with latest refactors it doesn't help
anything. Also, it causes a minor issue with document title:
https://linear.app/tldraw/issue/TLD-2398/double-clicking-board-title-when-editing-text-doesnt-auto-select-the

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-16 10:58:12 +00:00
Mime Čuvalo 98598fa7d6
stickies: hide clone handles on mobile (#3478)
### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-16 10:56:54 +00:00
Mitja Bezenšek 88ee4e9993
Revert "RBush again? (#3439)" (#3481)
This reverts commit 45dffd1af6.

Revert rbush. There's issues with shapes that have computed bounds
(arrows, groups).

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


- Add a brief release note for your PR here.
2024-04-16 10:56:35 +00:00
David Sheldrick cb118ef712
Revert "[perf] faster signia capture (#3471)" (#3480)
This reverts commit 8a5741c283.

Introduced a fuzz error
https://github.com/tldraw/tldraw/actions/runs/8703994315/job/23871324407


- [x] `internal` — Does not affect user-facing stuff
2024-04-16 10:41:43 +00:00
David Sheldrick 6f05a9b756
[fix] use page point for pointer (#3476)
fixes #3475

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-16 10:19:54 +00:00
David Sheldrick 8a5741c283
[perf] faster signia capture (#3471)
This PR uses an additional ArraySet to make capturing parent
relationships faster for computeds with more than a handful of parents.
Seems to result in an overall ~20% speedup of the `maybeCaptureParent`
function in normal usage.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Slight performance improvement to reactivity bookkeeping.
2024-04-16 08:21:27 +00:00
Mime Čuvalo 273ba62e0e
perf: calculate hypoteneuse manually instead of using hypot (#3468)
Something was bothering me a bit with the discussion around sqrt's being
slow. Looks like `Math.hypot` has a performance cost associated with it.

Looking at the Chromium source code:
https://chromium.googlesource.com/v8/v8/+/4.3.21/src/math.js?autodive=0%2F%2F#19
and

https://source.chromium.org/chromium/chromium/src/+/main:v8/src/builtins/math.tq;l=36?q=math&sq=&ss=chromium%2Fchromium%2Fsrc:v8%2Fsrc%2F

it looks like maybe we'd be avoiding the multiple arguments that can be
passed into Math.hypot which is maybe the source of the perf hit.

Also, interestingly in `math.tq` you can see it doing this funky sqrt
calculation: `Float64Sqrt((a / max) * (a / max) + (b / max) * (b / max))
* max` - I think that possibly is trying to avoid some overflow in some
cases with bigger numbers, but also possibly with a perf hit.

[edit]: OK, actually on Firefox, doing sqrt seems slower - but digging
more into this, it looks like doing `** 0.5` instead of `sqrt` is much
faster.

More related articles:
- https://stackoverflow.com/questions/71898044/why-is-math-hypot-so-slow
-
https://stackoverflow.com/questions/3764978/why-hypot-function-is-so-slow
-
https://www.reddit.com/r/javascript/comments/wk3e57/askjs_why_mathsqrt_is_so_slow_in_firefox/

[edit again!] looks like this is being fixed in the latest Chrome!
https://blog.seokho.dev/development/2024/03/18/V8-optimize-MathHypot.html

```
 ┌─────────┬───────┬─────────┬─────────┬─────────┬────────┐
    │ (index) │ Cold  │ Slowest │ Fastest │ Average │ Total  │
    ├─────────┼───────┼─────────┼─────────┼─────────┼────────┤
    │   old   │ 13.39 │  10.07  │  9.69   │  9.98   │ 998.57 │
    │  sqrt   │ 8.19  │  6.66   │  6.61   │  6.67   │ 667.6  │
    │ pow 0.5 │ 1.89  │  0.28   │  0.28   │   0.3   │ 29.79  │
    │   new   │ 1.64  │  0.28   │  0.28   │  0.29   │ 28.95  │
    └─────────┴───────┴─────────┴─────────┴─────────┴────────┘
```

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-15 18:45:30 +00:00
Mitja Bezenšek 45dffd1af6
RBush again? (#3439)
Adds RBush to handle spatial querying. We use it for:
- Culling. Helps a lot with panning as we don't have to compute the
culled shapes from scratch. Instead we just query rbush again. It makes
culling quite granular: spatial index updates when shapes change
(additions, removals, changes to bounds), visible shapes depends on
that, but also updates when the viewport page bound change, culled
shapes then depend on that but also change with selections changes. The
api stayed the same, which is great since the fuzz tests can stay as
they are.
- Brushing 
- Erasing
- Scribble brushing
- Getting shapes at point (for example, when updating the hover id)

This improves performance of all of those operations. I might have
missed some places where this might also be useful.

### Erasing before (Test on my old ipad)


https://github.com/tldraw/tldraw/assets/2523721/edb9c004-a44a-4779-b2d0-98617b057314

### Erasing after


https://github.com/tldraw/tldraw/assets/2523721/8f8367fd-fa8e-4963-ba13-720c5f0c2da5

### Creating an arrow before


https://github.com/tldraw/tldraw/assets/2523721/4068f8b7-f7b8-4826-83f2-083b1f3783bc

### After (much better, but still bad)


https://github.com/tldraw/tldraw/assets/2523721/11af6be6-01d8-4740-bf15-896e2dd31dd6



### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-15 16:28:18 +00:00
David Sheldrick 4f70a4f4e8
New migrations again (#3220)
Describe what your pull request does. If appropriate, add GIFs or images
showing the before and after.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `galaxy brain` — Architectural changes



### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

#### BREAKING CHANGES

- The `Migrations` type is now called `LegacyMigrations`.
- The serialized schema format (e.g. returned by
`StoreSchema.serialize()` and `Store.getSnapshot()`) has changed. You
don't need to do anything about it unless you were reading data directly
from the schema for some reason. In which case it'd be best to avoid
that in the future! We have no plans to change the schema format again
(this time was traumatic enough) but you never know.
- `compareRecordVersions` and the `RecordVersion` type have both
disappeared. There is no replacement. These were public by mistake
anyway, so hopefully nobody had been using it.
- `compareSchemas` is a bit less useful now. Our migrations system has
become a little fuzzy to allow for simpler UX when adding/removing
custom extensions and 3rd party dependencies, and as a result we can no
longer compare serialized schemas in any rigorous manner. You can rely
on this function to return `0` if the schemas are the same. Otherwise it
will return `-1` if the schema on the right _seems_ to be newer than the
schema on the left, but it cannot guarantee that in situations where
migration sequences have been removed over time (e.g. if you remove one
of the builtin tldraw shapes).

Generally speaking, the best way to check schema compatibility now is to
call `store.schema.getMigrationsSince(persistedSchema)`. This will throw
an error if there is no upgrade path from the `persistedSchema` to the
current version.

- `defineMigrations` has been deprecated and will be removed in a future
release. For upgrade instructions see
https://tldraw.dev/docs/persistence#Updating-legacy-shape-migrations-defineMigrations

- `migrate` has been removed. Nobody should have been using this but if
you were you'll need to find an alternative. For migrating tldraw data,
you should stick to using `schema.migrateStoreSnapshot` and, if you are
building a nuanced sync engine that supports some amount of backwards
compatibility, also feel free to use `schema.migratePersistedRecord`.
- the `Migration` type has changed. If you need the old one for some
reason it has been renamed to `LegacyMigration`. It will be removed in a
future release.
- the `Migrations` type has been renamed to `LegacyMigrations` and will
be removed in a future release.
- the `SerializedSchema` type has been augmented. If you need the old
version specifically you can use `SerializedSchemaV1`

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-15 12:53:42 +00:00
Mime Čuvalo 63f20d1834
undo devFreeze unintentional commit (#3466)
Undo the accidental commit.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-15 11:40:48 +00:00
dependabot[bot] 8c02dab5fb
Bump the npm_and_yarn group across 1 directory with 2 updates (#3443)
Bumps the npm_and_yarn group with 2 updates in the / directory:
[tar](https://github.com/isaacs/node-tar) and
[undici](https://github.com/nodejs/undici).

Updates `tar` from 6.2.0 to 6.2.1
<details>
<summary>Commits</summary>
<ul>
<li><a
href="bef7b1e4ff"><code>bef7b1e</code></a>
6.2.1</li>
<li><a
href="fe8cd57da5"><code>fe8cd57</code></a>
prevent extraction in excessively deep subfolders</li>
<li><a
href="fe7ebfdced"><code>fe7ebfd</code></a>
remove security.md</li>
<li>See full diff in <a
href="https://github.com/isaacs/node-tar/compare/v6.2.0...v6.2.1">compare
view</a></li>
</ul>
</details>
<br />

Updates `undici` from 5.28.3 to 5.28.4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/nodejs/undici/releases">undici's
releases</a>.</em></p>
<blockquote>
<h2>v5.28.4</h2>
<h2>⚠️ Security Release ⚠️</h2>
<ul>
<li>Fixes <a
href="https://github.com/nodejs/undici/security/advisories/GHSA-m4v8-wqvr-p9f7">https://github.com/nodejs/undici/security/advisories/GHSA-m4v8-wqvr-p9f7</a>
CVE-2024-30260</li>
<li>Fixes <a
href="https://github.com/nodejs/undici/security/advisories/GHSA-9qxr-qj54-h672">https://github.com/nodejs/undici/security/advisories/GHSA-9qxr-qj54-h672</a>
CVE-2024-30261</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/nodejs/undici/compare/v5.28.3...v5.28.4">https://github.com/nodejs/undici/compare/v5.28.3...v5.28.4</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fb98306907"><code>fb98306</code></a>
Bumped v5.28.4</li>
<li><a
href="2b39440bd9"><code>2b39440</code></a>
Merge pull request from GHSA-9qxr-qj54-h672</li>
<li><a
href="64e3402da4"><code>64e3402</code></a>
Merge pull request from GHSA-m4v8-wqvr-p9f7</li>
<li><a
href="723c4e7280"><code>723c4e7</code></a>
Revert &quot;build(deps-dev): bump formdata-node from 4.4.1 to 6.0.3 (<a
href="https://redirect.github.com/nodejs/undici/issues/2389">#2389</a>)&quot;</li>
<li><a
href="0e9d54b2c2"><code>0e9d54b</code></a>
skip failing test due to Node.js changes</li>
<li>See full diff in <a
href="https://github.com/nodejs/undici/compare/v5.28.3...v5.28.4">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/tldraw/tldraw/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-15 11:37:33 +00:00
Steve Ruiz 41601ac61e
Stickies: release candidate (#3249)
This PR is the target for the stickies PRs that are moving forward. It
should collect changes.

- [x] New icon
- [x] Improved shadows
- [x] Shadow LOD
- [x] New colors / theme options
- [x] Shrink text size to avoid word breaks on the x axis
- [x] Hide indicator whilst typing (reverted)
- [x] Adjacent note positions
  - [x] buttons / clone handles
  - [x] position helpers for creating / translating (pits)
- [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter,
Shift+Cmd+enter)
  - [x] multiple shape translating 
- [x] Text editing
  - [x] Edit on type (feature flagged)
  - [x] click goes in correct place
- [x] Notes as parents (reverted)
- [x] Update colors
- [x] Update SVG appearance

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `feature` — New feature

### Test Plan

Todo: fold in test plans for child PRs

### Unit tests:

- [ ] Shrink text size to avoid word breaks on the x axis
- [x] Adjacent notes
  - [x] buttons (clone handles)
  - [x] position helpers (pits)
- [x] keyboard shortcuts: (Tab, Shift+tab (RTL aware), Cmd-Enter,
Shift+Cmd+enter)
- [ ] Text editing
  - [ ] Edit on type
  - [ ] click goes in correct place

### Release Notes

- Improves sticky notes (see list)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Mime Čuvalo <mimecuvalo@gmail.com>
Co-authored-by: alex <alex@dytry.ch>
Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Lu[ke] Wilson <l2wilson94@gmail.com>
Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2024-04-14 18:40:02 +00:00
Steve Ruiz 8c6a9ff47e
Cancel pointer velocity while pinching (#3462)
There was a bug that could occur if you pinched while using the hand
tool, where on pinch end the hand tool would slide the camera based on
the pinching velocity. The fix is to cancel out any velocity while
pinching.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix

### Test Plan

On mobile...

1. Select the hand tool.
2. Begin a pinch
3. Stop the pinch
4. The camera should stay where it is

### Release Notes

- Fixed a bug that could occur while pinching with the hand tool
selected.
2024-04-14 13:22:26 +00:00
Sunny Zanchi 1752977bf6
conditionally use star-history dark theme (#3461)
This PR makes the "github star history" image on the readme use a dark
image if the user's preference is for dark mode.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [x] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

updates the star-history image in the README to conditionally show a
dark theme image based on the user's `prefers-color-scheme`
2024-04-14 07:45:22 +00:00
Mitja Bezenšek 7e61e448ab
Perf: Improve perf of `getCurrentPageShapesSorted` (#3453)
This significantly improves performance. Here's a comparison with 2k
shapes. Top is the new logic, bottom the old one.


![image](https://github.com/tldraw/tldraw/assets/2523721/e17b3733-dfd1-4aec-a427-31537bb9d159)

One place where this does make a significant difference is when you have
a lot of shapes on the page and you start [creating a new
arrow](https://github.com/orgs/tldraw/projects/40?pane=issue&itemId=59296136):

Before:

![image](https://github.com/tldraw/tldraw/assets/2523721/e4550197-c2be-480e-8f9a-090cebe1c8e4)

![image](https://github.com/tldraw/tldraw/assets/2523721/7559fe14-ad08-4ee0-9c9e-de0b60d401b2)


After:

![image](https://github.com/tldraw/tldraw/assets/2523721/4c6a1df6-732f-48b4-a7ea-6ce0894cf46e)

![image](https://github.com/tldraw/tldraw/assets/2523721/1cd5f2aa-919c-4271-af9a-227e8babf458)


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-13 21:04:19 +00:00
Steve Ruiz 87f70b7de5
Perf: Use a computed cache for masked shape page bounds (#3460)
This PR adds a computed cache for masked shape page bounds, which speeds
up visibility checks (a lot!).

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features
2024-04-13 20:07:10 +00:00
Mitja Bezenšek 143755fda0
Allow users to edit the document title by double clicking it even when editing a shape. (#3459)
Fixes [#3437](https://github.com/tldraw/tldraw/issues/3437)

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [x] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Create a shared document
2. Add a text note and start editing it
3. Double click document name. You should be now editing the document
name.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Allow users to editing document name by double clicking even when
previously editing text.
2024-04-13 19:47:37 +00:00
Mitja Bezenšek edf3627229
Only run when shapes change. (#3456)
Before we were running this on any change, even mouse position changes.
Now we only run it when shapes change.

Results wouldn't change in any case, so there's not a huge improvement.
Still, why run it if it is not necessary.

Before:


https://github.com/tldraw/tldraw/assets/2523721/b4111494-488a-42d0-9dfe-7fbc2ed88315

After:


https://github.com/tldraw/tldraw/assets/2523721/d96de329-235b-4dcb-93ea-fe297062985d



### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-13 19:47:16 +00:00
Mitja Bezenšek b979bba37a
Don't show edit link for locked shapes. (#3457)
Hides the edit link option in the context menu for locked shapes.

Fixes [#3308](https://github.com/tldraw/tldraw/issues/3308)

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1.  Add a link to a shape.
2. Lock it
3. Right click it to open the context menu.
4. You should not see the `Edit link` option

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Hide edit link context menu option for locked shapes.
2024-04-13 19:46:50 +00:00
Steve Ruiz 3ceebc82f8
Faster selection / erasing (#3454)
This PR makes a small improvement to the way we measure distances.
(Often we measure distances multiple times per frame per shape on the
screen). In many cases, we compare a minimum distance. This makes those
checks faster by avoiding a square root.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Release Notes

- Improve performance of minimum distance checks.
2024-04-13 13:30:30 +00:00
Mitja Bezenšek 152b915704
[hotfix] Panning fix for VS Code (#3452)
After the panning hotfix got merged I created a branch from that, then
bumped the vscode version and created a new version of the extension so
that the extension also gets the hotfix.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [x] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know

---------

Co-authored-by: SomeHats <huppy+SomeHats@tldraw.com>
Co-authored-by: ds300 <huppy+ds300@tldraw.com>
Co-authored-by: alex <alex@dytry.ch>
Co-authored-by: GitHub <noreply@github.com>
Co-authored-by: mimecuvalo <huppy+mimecuvalo@tldraw.com>
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
Co-authored-by: steveruizok <huppy+steveruizok@tldraw.com>
2024-04-12 05:34:24 +00:00
Steve Ruiz 6cd498a1ed
Remove docs for Editor.batch (#3451)
Remove misleading docs for `Editor.batch`.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-11 16:57:14 +00:00
Mitja Bezenšek 6d5ec149fa
Fix panning. (#3445)
We also need to clear the timeout when panning.


https://github.com/tldraw/tldraw/assets/2523721/f32fd4d0-332c-4a80-bed0-9ce49a68e1ab


https://github.com/tldraw/tldraw/assets/2523721/e97f5fac-083f-4f77-ab72-40701790f039

Had an [alternative
approach](https://github.com/tldraw/tldraw/pull/3444) of setting
timeouts and clearing them in dispatch, but since the timeout is 500ms I
think this should work as well.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-11 16:00:56 +00:00
Steve Ruiz b5c87ab876
Performance measurement tool (for unit tests) (#3447)
This PR adds a micro benchmarking utility. We can use it in our jest
tests or in random scripts, though given the other requirements of our
library, benchmarking.

<img width="750" alt="Screenshot 2024-04-11 at 2 44 23 PM"
src="https://github.com/tldraw/tldraw/assets/23072548/6bba07eb-65fd-45a2-abd8-ddd0e206b9fa">


## What this isn't

This is not benchmarking. The speeds etc are based on your machine.

## What this is

This is a tool for measuring / comparing different implementations etc.
Some things run much faster than others.

### Change Type

- [x] `sdk`
- [x] `internal`
2024-04-11 15:31:21 +00:00
alex a18525ea78
Fix SVG exports in Next.js (#3446)
Next.js bans the use of react-dom/server APIs on the client. React's
docs recommend against using these too:
https://react.dev/reference/react-dom/server/renderToString#removing-rendertostring-from-the-client-code

In this diff, we switch from using `ReactDOMServer.renderToStaticMarkup`
to `ReactDOMClient.createRoot`, fixing SVG exports in next.js apps.
`getSvg` remains deprecated, but we've introduced a new `getSvgElement`
method with a similar API to `getSvgString` - it returns an `{svg,
width, height}` object.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-11 14:02:05 +00:00
Mitja Bezenšek 84dbf2df20
VS Code 2.0.27 (#3442)
Version bump.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [x] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-11 09:42:16 +00:00
Steve Ruiz b3a1db90ec
Remove minimap throttling (#3438)
Our throttling isn't right for the minimap. Yanking this back.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-10 14:12:08 +00:00
Steve Ruiz 2cc8f44f83
Make minimap display sharp rectangles. (#3434)
The minimap now uses faster sharp rectangles for shapes.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Release Notes

- Improve
2024-04-10 12:53:11 +00:00
Steve Ruiz ae6ecf35b1
Fix cursor chat in context menu. (#3435)
This PR fixes flipped boolean logic for displaying the cursor chat
option on coarse pointer devices.

### Change Type

- [x] `dotcom` — Changes the tldraw.com web app
- [x] `bugfix` — Bug fix
2024-04-10 12:51:59 +00:00
Taha f40099e04e
Update font import URL in quick-start.mdx (#3430)
Fixes font import link in quickstart guide

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [x] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Fixes font import link in tldraw.dev quickstart guide
2024-04-10 12:46:55 +00:00
Mitja Bezenšek de951dee59
Reorder dom elements. (#3431)
We reorded the dom a bit when we added the web gl rendered culled
shapes. We can now revert that.

Also noticed we weren't positioning the wrapper, so the z-index didn't
not apply.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-10 12:03:09 +00:00
Steve Ruiz 180cb67250
Improve hand dragging with long press (#3432)
This PR makes a small improvement to the hand tool to address a "long
press"-related issues.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-10 12:02:50 +00:00
Mitja Bezenšek 987b1ac0b9
Perf: Incremental culled shapes calculation. (#3411)
Reworks our culling logic:
- No longer show the gray rectangles for culled shapes. 
- Don't use `renderingBoundExpanded`, instead we now use
`viewportPageBounds`. I've removed `renderingBoundsExpanded`, but we
might want to deprecate it?
- There's now a incremental computation of non visible shapes, which are
shapes outside of `viewportPageBounds` and shapes that outside of their
parents' clipping bounds.
- There's also a new `getCulledShapes` function in `Editor`, which uses
the non visible shapes computation as a part of the culled shape
computation.
- Also moved some of the `getRenderingShapes` tests to newly created
`getCullingShapes` tests.

Feels much better on my old, 2017 ipad (first tab is this PR, second is
current prod, third is staging).


https://github.com/tldraw/tldraw/assets/2523721/327a7313-9273-4350-89a0-617a30fc01a2

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Regular culling shapes tests. Pan / zoom around. Use minimap. Change
pages.

- [x] Unit Tests
- [ ] End to end tests

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-10 10:29:11 +00:00
Steve Ruiz 2bbab1a790
Perf: Improve text outline performance (#3429)
We use text shadows to create "outlines" around text shapes. These
shadows are rendered on the GPU. In Chrome (and on computers with a
capable GPU) text shadows work pretty well, however on Safari—and in
particular on iOS—they cause massive frame drops.


https://github.com/tldraw/tldraw/assets/23072548/b65cbcaa-6cc3-46f3-b54d-1f9cc07fc499

This PR:
- adds an LOD to text shadows, removing them at < 35% zoom
- removes text shadows entirely on Safari

If we had a "high performance" or "low-end device" mode, then shadows /
text shadows would be the first to go.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Test Plan

1. Use text shapes on iOS.
2. Use text shapes on Safari.
3. Use text shapes on Chrome.

### Release Notes

- Improves performance of text shapes on iOS / Safari.
2024-04-10 10:20:16 +00:00
Steve Ruiz 6305e83830
Fix some tests (#3403)
This PR fixes some jest test.

- We skip the culling shapes in test environments.
- We skip rendering patterns in test environments.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `tests` — Changes to any test code
2024-04-09 15:42:54 +00:00
Steve Ruiz 3b98e36914
Perf: throttle `updateHoveredId` (#3419)
This PR throttles the `updateHoveredId` call so that it happens ever
30ms.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Release Notes

- Improves canvas performance by throttling the update to the editor's
hovered id.
2024-04-09 15:33:07 +00:00
Steve Ruiz 988dbbde28
Fix text bug on iOS (#3423)
In this PR, we no longer buffer pointer down/ups. We now batch only
`pointer_move`, `wheel`, and `pinch` events.

Batched inputs were causing text not to work on iOS. On iOS, the
keyboard is only shown if we call `focus` during the same event loop as
a user input.

### Change Type
- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix

### Test Plan

1. Use text on iOS.
2024-04-09 15:30:33 +00:00
Steve Ruiz dadb57edcd
Perf: block hit tests while moving camera (#3418)
This PR uses an element that prevents hit tests on shapes while the
camera is moving.


https://github.com/tldraw/tldraw/assets/23072548/9905f3d4-ba64-4e4d-ae99-194f513eaac8

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features


### Test Plan

1. Move the camera.
2. Interact with the canvas.
3. Zoom in and out.

### Release Notes

- Improves performance of canvas while the camera is moving.
2024-04-09 14:34:24 +00:00
Steve Ruiz 3f64bf8c5b
Perf: slightly faster `getShapeAtPoint` (#3416)
This PR makes a small improvement to the speed of `getShapeAtPoint`. It
removes `Editor.getCurrentPageRenderingShapesSorted`.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features
2024-04-09 12:57:46 +00:00
Mitja Bezenšek 5347c5f30e
Add two simple perf helpers. (#3399)
Can be useful for ad-hoc measure of performance. One is a method
decorator, which can be use on methods like so:

```typescript
  @measureDuration
  someLongRunningProccess() {
  // ....
  }
```

And the other offer more granular control. It also returns what the
callback returns, so it can be use in assignments / return statements.

```typescript
return measureCbDuration('sorting took', () =>  renderingShapes.sort(sortById))
```


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [x] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-08 13:41:09 +00:00
Steve Ruiz fb2d3b4372
Perf: (slightly) faster min dist checks (#3401)
This PR improves a bunch of places where we do "minimum distance
checks". Previously, we were using `Vec.Dist`, which uses `Math.hypot`
to find the actual distance, but we can just as well use the squared
distance. So this PR makes a small improvement to `Vec.Dist2` and then
switches to that method when checking minimum distances.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features


### Test Plan

- [x] Unit Tests

### Release Notes

- Performance: small improvements to hit testing.
2024-04-08 13:31:05 +00:00
Mitja Bezenšek 947f7b1d76
[culling] Improve setting of display none. (#3376)
Small improvement for culling shapes. We now use reactor to do it. .

Before:

![image](https://github.com/tldraw/tldraw/assets/2523721/7f791cdd-c0e2-4b92-84d1-8b071540de10)

After:

![image](https://github.com/tldraw/tldraw/assets/2523721/ca2e2a9e-f9f6-48a8-936f-05a402c1e7a2)


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-08 11:36:12 +00:00
Orion Reed 86403c1b0d
Fix typo in Store.ts (#3385)
An immense contribution, I know.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ x ] `docs` — Changes to the documentation, examples, or templates.

<!--  Please select a 'Type' label ️ -->

- [ x ] `chore` — Updating dependencies, other boring stuff
2024-04-08 08:06:24 +00:00
Mitja Bezenšek d01a2223be
Fix an issue with layers when moving shapes. (#3380)
https://github.com/tldraw/tldraw/assets/2523721/d35b5e41-5270-4fad-8f9e-f8d7ac46558c



https://github.com/tldraw/tldraw/assets/2523721/2e1d1f54-f980-437d-aa51-f598b59d56b9



### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-05 19:09:07 +00:00
Steve Ruiz 97b5e4093a
[culling] minimal culled diff with webgl (#3377)
This PR extracts the #3344 changes to a smaller diff against main. It
does not include the changes to how / where culled shapes are
calculated, though I understand this could be much more efficiently
done!

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

---------

Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com>
2024-04-05 18:03:22 +00:00
Steve Ruiz 4d32a38cf8
put `getCurrentPageId` into a computed (#3378)
This PR makes the `getCurrentPageId` method use a computed. Previously,
anything that referenced the current page id would pick up any change to
instance state. This will help a bunch of interactions like brushing
that would update the instance state on every frame.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features
2024-04-05 16:02:11 +00:00
Mitja Bezenšek f1e0af7631
Display none for culled shapes (#3291)
Comparing different culling optimizations:


https://github.com/tldraw/tldraw/assets/2523721/0b3b8b42-ed70-45b7-bf83-41023c36a563

I think we should go with the `display: none` + showing the skeleteon.
The way it works is:
- We now add a sibling to the shape wrapper div which serves as the
skeleton for the culled shapes.
- Only one of the two divs (shape wrapper and skeleton div) is
displayed. The other one is using `display: none` to improve
performance.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


- Improve performance of culled shapes by using `display: none`.

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-05 13:23:02 +00:00
Steve Ruiz 4a494a2eaf
Update useFileSystem.tsx (#3371)
This PR makes a small change to how useFileSystem reports errors, so
that legitimate errors may be caught.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `feature` — New feature
2024-04-05 11:40:28 +00:00
Taha e8de70ec85
Examples: update kbd shortcuts, add actions overrides example (#3330)
I think the keyboard shortcuts example already teaches the concept that
the actions overrides example does. I've updated the keyboard shortcuts
example and included an action override example in case we want that
too.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [x] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
2.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Add action overrides example, update keyboard shortcuts example

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-05 10:04:38 +00:00
Steve Ruiz 58286db90c
Add long press event (#3275)
This PR adds a "long press" event that fires when pointing for more than
500ms. This event is used in the same way that dragging is used (e.g. to
transition to from pointing_selection to translating) but only on
desktop. On mobile, long presses are used to open the context menu.

![Kapture 2024-03-26 at 18 57
15](https://github.com/tldraw/tldraw/assets/23072548/34a7ee2b-bde6-443b-93e0-082453a1cb61)

## Background

This idea came out of @TodePond's #3208 PR. We use a "dead zone" to
avoid accidentally moving / rotating things when clicking on them, which
is especially common on mobile if a dead zone feature isn't implemented.
However, this makes it difficult to make "fine adjustments" because you
need to drag out of the dead zone (to start translating) and then drag
back to where you want to go.

![Kapture 2024-03-26 at 19 00
38](https://github.com/tldraw/tldraw/assets/23072548/9a15852d-03d0-4b88-b594-27dbd3b68780)

With this change, you can long press on desktop to get to that
translating state. It's a micro UX optimization but especially nice if
apps want to display different UI for "dragging" shapes before the user
leaves the dead zone.

![Kapture 2024-03-26 at 19 02
59](https://github.com/tldraw/tldraw/assets/23072548/f0ff337e-2cbd-4b73-9ef5-9b7deaf0ae91)

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [x] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Long press shapes, selections, resize handles, rotate handles, crop
handles.
2. You should enter the corresponding states, just as you would have
with a drag.

- [ ] Unit Tests TODO

### Release Notes

- Add support for long pressing on desktop.
2024-04-04 21:50:01 +00:00
Steve Ruiz 43edeb09b5
Add white migration (#3334)
This PR adds a down migration for #3321.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `dunno` — I don't know
2024-04-04 18:16:17 +00:00
dependabot[bot] 0161ec796e
Bump the npm_and_yarn group across 1 directory with 1 update (#3348)
Bumps the npm_and_yarn group with 1 update in the / directory:
[vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).

Updates `vite` from 5.2.7 to 5.2.8
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted -->5.2.8 (2024-04-03)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: csp nonce injection when no closing tag (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16281">#16281</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16282">#16282</a>)
(<a href="https://github.com/vitejs/vite/commit/3c85c6b">3c85c6b</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16281">#16281</a>
<a
href="https://redirect.github.com/vitejs/vite/issues/16282">#16282</a></li>
<li>fix: do not access document in <code>/@vite/client</code> when not
defined (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16318">#16318</a>)
(<a href="https://github.com/vitejs/vite/commit/646319c">646319c</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16318">#16318</a></li>
<li>fix: fix sourcemap when using object as <code>define</code> value
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15805">#15805</a>)
(<a href="https://github.com/vitejs/vite/commit/445c4f2">445c4f2</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/15805">#15805</a></li>
<li>fix(css): unknown file error happened with lightningcss (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16306">#16306</a>)
(<a href="https://github.com/vitejs/vite/commit/01af308">01af308</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16306">#16306</a></li>
<li>fix(hmr): multiple updates happened when invalidate is called while
multiple tabs open (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16307">#16307</a>)
(<a href="https://github.com/vitejs/vite/commit/21cc10b">21cc10b</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16307">#16307</a></li>
<li>fix(scanner): duplicate modules for same id if glob is used in
html-like types (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16305">#16305</a>)
(<a href="https://github.com/vitejs/vite/commit/eca68fa">eca68fa</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16305">#16305</a></li>
<li>chore(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16325">#16325</a>)
(<a href="https://github.com/vitejs/vite/commit/a78e265">a78e265</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16325">#16325</a></li>
<li>refactor: use types from sass instead of <code>@​types/sass</code>
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16340">#16340</a>)
(<a href="https://github.com/vitejs/vite/commit/4581e83">4581e83</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16340">#16340</a></li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="8b8d4024fb"><code>8b8d402</code></a>
release: v5.2.8</li>
<li><a
href="646319cc84"><code>646319c</code></a>
fix: do not access document in <code>/@vite/client</code> when not
defined (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16318">#16318</a>)</li>
<li><a
href="445c4f2158"><code>445c4f2</code></a>
fix: fix sourcemap when using object as <code>define</code> value (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/15805">#15805</a>)</li>
<li><a
href="a78e265822"><code>a78e265</code></a>
chore(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16325">#16325</a>)</li>
<li><a
href="4581e8371d"><code>4581e83</code></a>
refactor: use types from sass instead of <code>@​types/sass</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16340">#16340</a>)</li>
<li><a
href="3c85c6b52e"><code>3c85c6b</code></a>
fix: csp nonce injection when no closing tag (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16281">#16281</a>)
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16282">#16282</a>)</li>
<li><a
href="21cc10bfda"><code>21cc10b</code></a>
fix(hmr): multiple updates happened when invalidate is called while
multiple ...</li>
<li><a
href="01af308dfd"><code>01af308</code></a>
fix(css): unknown file error happened with lightningcss (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16306">#16306</a>)</li>
<li><a
href="eca68fa942"><code>eca68fa</code></a>
fix(scanner): duplicate modules for same id if glob is used in html-like
type...</li>
<li>See full diff in <a
href="https://github.com/vitejs/vite/commits/v5.2.8/packages/vite">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=vite&package-manager=npm_and_yarn&previous-version=5.2.7&new-version=5.2.8)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/tldraw/tldraw/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-04-04 07:34:07 +00:00
Steve Ruiz 1ba9cbfa2a
only buffer pointer events (#3337)
This PR changes our input buffering to only buffer pointer events. We
were already moving in this direction with the complete / cancel
flushes, now it's just more explicit. If we want to add other events
into here, then we can.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-04-03 15:42:52 +00:00
Steve Ruiz 3f4a170968
Fix blur bug in editable text (#3343)
This PR fixes a bug that was introduced by #3223. There was a code path
that normally used to never run (a blur event running when the shape was
no longer editing) but which was being run now that shapes aren't
immediately removed on pointer down.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix

### Test Plan

1. Create a sticky note
2. Begin editing the note
3. click on the canvas
4. You should be in pointing_canvas
2024-04-03 15:41:56 +00:00
Taha 4f2cf3dee0
Tool with child states (#3074)
Adds an example of a tool with child states. I'm going over the
annotations at the moment, just wanted to validate the idea in the
meantime.
Closes tld-2114
- [x] `documentation` — Changes to the documentation only[^2]

### Release Notes

- Add an example of a tool with child states

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-03 11:25:07 +00:00
Mime Čuvalo 03e4c8575c
textfields: fix regression with Text shape and resizing (#3333)
The refactor of the textfields in this PR
https://github.com/tldraw/tldraw/pull/3050 caused a regression in
resizing Text shapes. (as demonstrated in this PR's video:
https://github.com/tldraw/tldraw/pull/3327)
We reverted that PR and now this PR updates the CSS to fix the gap that
was introduced when it was refactored.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-03 10:01:04 +00:00
Mime Čuvalo 843347bde1
Revert "Fix text resizing bug (#3327)" (#3332)
This reverts commit 0e912fe0f2.

(The fix is more to do with a CSS regression instead of a JS fix.)


### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-04-03 09:59:11 +00:00
David Sheldrick 5557f6be5b
Revert "squish sync data events before sending them out" (#3331)
Reverts tldraw/tldraw#3118
2024-04-03 10:31:28 +01:00
Taha 0e912fe0f2
Fix text resizing bug (#3327)
Fixes a bug with text resizing on text shapes, now the transform origin
is set depending on the alignment.

![2024-04-02 at 16 50 49 - Aqua
Snail](https://github.com/tldraw/tldraw/assets/98838967/86b59691-e950-4367-8632-03ae6dfef7f6)

![2024-04-02 at 16 49 37 - Teal
Tuna](https://github.com/tldraw/tldraw/assets/98838967/6b6c97a8-fc53-45a0-8282-6bd63e77507b)

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [x] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Make a text shape
2. resize it
3. It should stay within the bounds

### Release Notes

- Fixes an issue with text shapes overflowing their bounds when resized.
2024-04-02 16:22:58 +00:00
Mitja Bezenšek 584380ba8b
Input buffering (#3223)
This PR buffs input events.

## The story so far

In the olde days, we throttled events from the canvas events hook so
that a pointer event would only be sent every 1/60th of a second. This
was fine but made drawing on the iPad / 120FPS displays a little sad.

Then we removed this throttle. It seemed fine! Drawing at 120FPS was
great. We improved some rendering speeds and tightened some loops so
that the engine could keep up with 2x the number of points in a line.

Then we started noticing that iPads and other screens could start
choking on events as it received new inputs and tried to process and
render inputs while still recovering from a previous dropped frame. Even
worse, on iPad the work of rendering at 120FPS was causing the browser
to throttle the app after some sustained drawing. Yikes!

### Batching

I did an experimental PR (#3180) to bring back batching but do it in the
editor instead. What we would do is: rather than immediately processing
an event when we get it, we would instead put the event into a buffer.
On the next 60FPS tick, we would flush the buffer and process all of the
events. We'd have them all in the same transaction so that the app would
only render once.

### Render batching?

We then tried batching the renders, so that the app would only ever
render once per (next) frame. This added a bunch of complexity around
events that needed to happen synchronously, such as writing text in a
text field. Some inputs could "lag" in a way familiar to anyone who's
tried to update an input's state asynchronously. So we backed out of
this.

### Coalescing?

Another idea from @ds300 was to "coalesce" the events. This would be
useful because, while some interactions like drawing would require the
in-between frames in order to avoid data loss, most interactions (like
resizing) didn't actually need the in-between frames, they could just
use the last input of a given type.

Coalescing turned out to be trickier than we thought, though. Often a
state node required information from elsewhere in the app when
processing an event (such as camera position or page point, which is
derived from the camera position), and so the coalesced events would
need to also include this information or else the handlers wouldn't work
the way they should when processing the "final" event during a tick.

So we backed out of the coalescing strategy for now. Here's the [PR that
removes](937469d69d)
it.

### Let's just buffer the fuckers

So this PR now should only include input buffering.

I think there are ways to achieve the same coalescing-like results
through the state nodes, which could gather information during the
`onPointerMove` handler and then actually make changes during the
`onTick` handler, so that the changes are only done as many time as
necessary. This should help with e.g. resizing lots of shapes at once.

But first let's land the buffering!

---

Mitja's original text:

This PR builds on top of Steve's [experiment
PR](https://github.com/tldraw/tldraw/pull/3180) here. It also adds event
coalescing for [`pointerMove`
events](https://github.com/tldraw/tldraw/blob/mitja/input-buffering/packages/editor/src/lib/editor/Editor.ts#L8364-L8368).
The API is [somewhat similar
](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/getCoalescedEvents)
to `getCoalescedEvent`. In `StateNodes` we register an `onPointerMove`
handler. When the event happens it gets called with the event `info`.
There's now an additional field on `TLMovePointerEvent` called
`coalescedInfo` which includes all the events. It's then on the user to
process all of these.

I decided on this API since it allows us to only expose one event
handler, but it still gives the users access to all events if they need
them.

We would otherwise either need to:

- Expose two events (coalesced and non-coalesced one and complicate the
api) so that state nodes like Resizing would not be triggered for each
pointer move.
- Offer some methods on the editor that would allow use to get the
coalesced information. Then the nodes that need that info could request
it. I [tried
this](9ad973da3a (diff-32f1de9a5a9ec72aa49a8d18a237fbfff301610f4689a4af6b37f47af435aafcR67)),
but it didn't feel good.

This also complicated the editor inputs. The events need to store
information about the event (like the mouse position when the event
happened for `onPointerMove`). But we cannot immediately update inputs
when the event happens. To make this work for `pointerMove` events I've
added `pagePoint`. It's
[calculated](https://github.com/tldraw/tldraw/pull/3223/files#diff-980beb0aa0ee9aa6d1cd386cef3dc05a500c030638ffb58d45fd11b79126103fR71)
when the event triggers and then consumers can get it straight from the
event (like
[Drawing](https://github.com/tldraw/tldraw/pull/3223/files#diff-32f1de9a5a9ec72aa49a8d18a237fbfff301610f4689a4af6b37f47af435aafcR104)).

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [x] `improvement` — Improving existing features
- [ ] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know


### Test Plan

1. Add a step-by-step description of how to test your PR here.
4.

- [ ] Unit Tests
- [ ] End to end tests

### Release Notes

- Add a brief release note for your PR here.

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2024-04-02 14:29:14 +00:00
Dan Groshev b42a222c88
squish sync data events before sending them out (#3118)
Recently (https://github.com/tldraw/tldraw/pull/3012), we started
aggregating data messages before sending them out. However, local
testing shows that we generate *many* redundant messages (see the test
file for an example of a real buffer captured during local testing with
just two users). This PR adds a function to squish those updates
together, reducing the amount of data we need to transfer and load on
the client that won't need to process those redundant messages.

The function is checked with [fast-check](https://fast-check.dev/), a JS
property test framework, to make sure that squished deltas result in
exactly the same state as the original ones.

### Change Type

- [x] `minor` — New feature

### Test Plan

1. Needs a group smoke test

- [x] End to end tests
2024-04-02 08:57:58 +00:00
Steve Ruiz 8db84b33b2
Add white (#3321)
This PR adds white. It's available with Alt+T.
![Kapture 2024-04-01 at 18 32
22](https://github.com/tldraw/tldraw/assets/23072548/932c9621-ee09-403f-aacc-0226e7b03967)



### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `feature` — New feature

### Release Notes

- Adds secret white color.
2024-04-01 18:48:56 +00:00
Steve Ruiz 3df866a86f
[internal] Add license report scripts (#2751)
This PR adds scripts that allow us to generate reports on our
dependencies.

### Change Type

- [x] `internal` — Any other changes that don't affect the published
package[^2]
2024-04-01 13:36:40 +00:00
Steve Ruiz fba2b0d076
Fix count shapes and nodes (#3318)
This PR simplifies the debug count for debugging number of elements on
the page. It fixes a bug where note shapes and other shapes without
shapeid ids were not correctly counted.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `bugfix` — Bug fix
2024-03-31 12:03:58 +00:00
dependabot[bot] 1db0c271a6
Bump the npm_and_yarn group across 1 directory with 2 updates (#3304)
Bumps the npm_and_yarn group with 2 updates in the / directory:
[vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and
[express](https://github.com/expressjs/express).

Updates `vite` from 5.1.6 to 5.2.7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/releases">vite's
releases</a>.</em></p>
<blockquote>
<h2>create-vite@5.2.3</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/create-vite@5.2.3/packages/create-vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>create-vite@5.2.2</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/create-vite@5.2.2/packages/create-vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>create-vite@5.2.1</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/create-vite@5.2.1/packages/create-vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
<h2>create-vite@5.2.0</h2>
<p>Please refer to <a
href="https://github.com/vitejs/vite/blob/create-vite@5.2.0/packages/create-vite/CHANGELOG.md">CHANGELOG.md</a>
for details.</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's
changelog</a>.</em></p>
<blockquote>
<h2><!-- raw HTML omitted -->5.2.7 (2024-03-29)<!-- raw HTML omitted
--></h2>
<ul>
<li>chore: deprecate splitVendorChunkPlugin (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16274">#16274</a>)
(<a href="https://github.com/vitejs/vite/commit/45a06da">45a06da</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16274">#16274</a></li>
<li>fix: skip injecting <code>__vite__mapDeps</code> when it's not used
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16271">#16271</a>)
(<a href="https://github.com/vitejs/vite/commit/890538a">890538a</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16271">#16271</a></li>
<li>fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16258">#16258</a>)
(<a href="https://github.com/vitejs/vite/commit/7caef42">7caef42</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16258">#16258</a></li>
<li>fix(hmr): don't mutate module graph when collecting modules (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16302">#16302</a>)
(<a href="https://github.com/vitejs/vite/commit/dfffea1">dfffea1</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16302">#16302</a></li>
<li>fix(hmr): trigger hmr for missing file import errored module after
file creation (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16303">#16303</a>)
(<a href="https://github.com/vitejs/vite/commit/ffedc06">ffedc06</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16303">#16303</a></li>
<li>fix(sourcemap): don't warn even if the sourcesContent is an empty
string (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16273">#16273</a>)
(<a href="https://github.com/vitejs/vite/commit/24e376a">24e376a</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16273">#16273</a></li>
<li>feat(hmr): reload when HTML file is created/deleted (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16288">#16288</a>)
(<a href="https://github.com/vitejs/vite/commit/1f53796">1f53796</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16288">#16288</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.2.6 (2024-03-24)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: <code>fs.deny</code> with globs with directories (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16250">#16250</a>)
(<a href="https://github.com/vitejs/vite/commit/ba5269c">ba5269c</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16250">#16250</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.2.5 (2024-03-24)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: avoid SSR requests in waitForRequestIdle (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16246">#16246</a>)
(<a href="https://github.com/vitejs/vite/commit/7093f77">7093f77</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16246">#16246</a></li>
<li>docs: clarify enforce vs hook.order (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16226">#16226</a>)
(<a href="https://github.com/vitejs/vite/commit/3a73e48">3a73e48</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16226">#16226</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.2.4 (2024-03-23)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: dont resolve imports with malformed URI (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16244">#16244</a>)
(<a href="https://github.com/vitejs/vite/commit/fbf69d5">fbf69d5</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16244">#16244</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.2.3 (2024-03-22)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: handle warmup request error correctly (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16223">#16223</a>)
(<a href="https://github.com/vitejs/vite/commit/d7c5256">d7c5256</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16223">#16223</a></li>
<li>fix: skip encode if is data uri (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16233">#16233</a>)
(<a href="https://github.com/vitejs/vite/commit/8617e76">8617e76</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16233">#16233</a></li>
<li>fix(optimizer): fix <code>optimizeDeps.include</code> glob syntax
for <code>./*</code> exports (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16230">#16230</a>)
(<a href="https://github.com/vitejs/vite/commit/f184c80">f184c80</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16230">#16230</a></li>
<li>fix(runtime): fix sourcemap with <code>prepareStackTrace</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16220">#16220</a>)
(<a href="https://github.com/vitejs/vite/commit/dad7f4f">dad7f4f</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16220">#16220</a></li>
<li>chore: <code>utf8</code> replaced with <code>utf-8</code> (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16232">#16232</a>)
(<a href="https://github.com/vitejs/vite/commit/9800c73">9800c73</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16232">#16232</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.2.2 (2024-03-20)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix(importAnalysis): skip encode in ssr (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16213">#16213</a>)
(<a href="https://github.com/vitejs/vite/commit/e4d2d60">e4d2d60</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16213">#16213</a></li>
</ul>
<h2><!-- raw HTML omitted -->5.2.1 (2024-03-20)<!-- raw HTML omitted
--></h2>
<ul>
<li>fix: encode path uri only (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16212">#16212</a>)
(<a href="https://github.com/vitejs/vite/commit/0b2e40b">0b2e40b</a>),
closes <a
href="https://redirect.github.com/vitejs/vite/issues/16212">#16212</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="ad246da989"><code>ad246da</code></a>
release: v5.2.7</li>
<li><a
href="45a06daac8"><code>45a06da</code></a>
chore: deprecate splitVendorChunkPlugin (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16274">#16274</a>)</li>
<li><a
href="ffedc06cab"><code>ffedc06</code></a>
fix(hmr): trigger hmr for missing file import errored module after file
creat...</li>
<li><a
href="dfffea1f43"><code>dfffea1</code></a>
fix(hmr): don't mutate module graph when collecting modules (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16302">#16302</a>)</li>
<li><a
href="1f5379601e"><code>1f53796</code></a>
feat(hmr): reload when HTML file is created/deleted (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16288">#16288</a>)</li>
<li><a
href="24e376ad86"><code>24e376a</code></a>
fix(sourcemap): don't warn even if the sourcesContent is an empty string
(<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16">#16</a>...</li>
<li><a
href="7caef4216e"><code>7caef42</code></a>
fix(deps): update all non-major dependencies (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16258">#16258</a>)</li>
<li><a
href="890538a694"><code>890538a</code></a>
fix: skip injecting <code>__vite__mapDeps</code> when it's not used (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16271">#16271</a>)</li>
<li><a
href="7369016d8a"><code>7369016</code></a>
release: v5.2.6</li>
<li><a
href="ba5269cca8"><code>ba5269c</code></a>
fix: <code>fs.deny</code> with globs with directories (<a
href="https://github.com/vitejs/vite/tree/HEAD/packages/vite/issues/16250">#16250</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/vitejs/vite/commits/v5.2.7/packages/vite">compare
view</a></li>
</ul>
</details>
<br />

Updates `express` from 4.18.2 to 4.19.2
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/express/releases">express's
releases</a>.</em></p>
<blockquote>
<h2>4.19.2</h2>
<h2>What's Changed</h2>
<ul>
<li><a
href="0b746953c4">Improved
fix for open redirect allow list bypass</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/expressjs/express/compare/4.19.1...4.19.2">https://github.com/expressjs/express/compare/4.19.1...4.19.2</a></p>
<h2>4.19.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Fix ci after location patch by <a
href="https://github.com/wesleytodd"><code>@​wesleytodd</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5552">expressjs/express#5552</a></li>
<li>fixed un-edited version in history.md for 4.19.0 by <a
href="https://github.com/wesleytodd"><code>@​wesleytodd</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5556">expressjs/express#5556</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/expressjs/express/compare/4.19.0...4.19.1">https://github.com/expressjs/express/compare/4.19.0...4.19.1</a></p>
<h2>4.19.0</h2>
<h2>What's Changed</h2>
<ul>
<li>fix typo in release date by <a
href="https://github.com/UlisesGascon"><code>@​UlisesGascon</code></a>
in <a
href="https://redirect.github.com/expressjs/express/pull/5527">expressjs/express#5527</a></li>
<li>docs: nominating <a
href="https://github.com/wesleytodd"><code>@​wesleytodd</code></a> to be
project captian by <a
href="https://github.com/wesleytodd"><code>@​wesleytodd</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5511">expressjs/express#5511</a></li>
<li>docs: loosen TC activity rules by <a
href="https://github.com/wesleytodd"><code>@​wesleytodd</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5510">expressjs/express#5510</a></li>
<li>Add note on how to update docs for new release by <a
href="https://github.com/crandmck"><code>@​crandmck</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5541">expressjs/express#5541</a></li>
<li><a
href="660ccf5fa3">Prevent
open redirect allow list bypass due to encodeurl</a></li>
<li>Release 4.19.0 by <a
href="https://github.com/wesleytodd"><code>@​wesleytodd</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5551">expressjs/express#5551</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/crandmck"><code>@​crandmck</code></a>
made their first contribution in <a
href="https://redirect.github.com/expressjs/express/pull/5541">expressjs/express#5541</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/expressjs/express/compare/4.18.3...4.19.0">https://github.com/expressjs/express/compare/4.18.3...4.19.0</a></p>
<h2>4.18.3</h2>
<h2>Main Changes</h2>
<ul>
<li>Fix routing requests without method</li>
<li>deps: body-parser@1.20.2
<ul>
<li>Fix strict json error message on Node.js 19+</li>
<li>deps: content-type@~1.0.5</li>
<li>deps: raw-body@2.5.2</li>
</ul>
</li>
</ul>
<h2>Other Changes</h2>
<ul>
<li>Use https: protocol instead of deprecated git: protocol by <a
href="https://github.com/vcsjones"><code>@​vcsjones</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5032">expressjs/express#5032</a></li>
<li>build: Node.js@16.18 and Node.js@18.12 by <a
href="https://github.com/abenhamdine"><code>@​abenhamdine</code></a> in
<a
href="https://redirect.github.com/expressjs/express/pull/5034">expressjs/express#5034</a></li>
<li>ci: update actions/checkout to v3 by <a
href="https://github.com/armujahid"><code>@​armujahid</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5027">expressjs/express#5027</a></li>
<li>test: remove unused function arguments in params by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5124">expressjs/express#5124</a></li>
<li>Remove unused originalIndex from acceptParams by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5119">expressjs/express#5119</a></li>
<li>Fixed typos by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5117">expressjs/express#5117</a></li>
<li>examples: remove unused params by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5113">expressjs/express#5113</a></li>
<li>fix: parameter str is not described in JSDoc by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5130">expressjs/express#5130</a></li>
<li>fix: typos in History.md by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5131">expressjs/express#5131</a></li>
<li>build : add Node.js@19.7 by <a
href="https://github.com/abenhamdine"><code>@​abenhamdine</code></a> in
<a
href="https://redirect.github.com/expressjs/express/pull/5028">expressjs/express#5028</a></li>
<li>test: remove unused function arguments in params by <a
href="https://github.com/raksbisht"><code>@​raksbisht</code></a> in <a
href="https://redirect.github.com/expressjs/express/pull/5137">expressjs/express#5137</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/expressjs/express/blob/master/History.md">express's
changelog</a>.</em></p>
<blockquote>
<h1>4.19.2 / 2024-03-25</h1>
<ul>
<li>Improved fix for open redirect allow list bypass</li>
</ul>
<h1>4.19.1 / 2024-03-20</h1>
<ul>
<li>Allow passing non-strings to res.location with new encoding handling
checks</li>
</ul>
<h1>4.19.0 / 2024-03-20</h1>
<ul>
<li>Prevent open redirect allow list bypass due to encodeurl</li>
<li>deps: cookie@0.6.0</li>
</ul>
<h1>4.18.3 / 2024-02-29</h1>
<ul>
<li>Fix routing requests without method</li>
<li>deps: body-parser@1.20.2
<ul>
<li>Fix strict json error message on Node.js 19+</li>
<li>deps: content-type@~1.0.5</li>
<li>deps: raw-body@2.5.2</li>
</ul>
</li>
<li>deps: cookie@0.6.0
<ul>
<li>Add <code>partitioned</code> option</li>
</ul>
</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="04bc62787b"><code>04bc627</code></a>
4.19.2</li>
<li><a
href="da4d763ff6"><code>da4d763</code></a>
Improved fix for open redirect allow list bypass</li>
<li><a
href="4f0f6cc67d"><code>4f0f6cc</code></a>
4.19.1</li>
<li><a
href="a003cfab03"><code>a003cfa</code></a>
Allow passing non-strings to res.location with new encoding handling
checks f...</li>
<li><a
href="a1fa90fcea"><code>a1fa90f</code></a>
fixed un-edited version in history.md for 4.19.0</li>
<li><a
href="11f2b1db22"><code>11f2b1d</code></a>
build: fix build due to inconsistent supertest behavior in older
versions</li>
<li><a
href="084e36506a"><code>084e365</code></a>
4.19.0</li>
<li><a
href="0867302ddb"><code>0867302</code></a>
Prevent open redirect allow list bypass due to encodeurl</li>
<li><a
href="567c9c665d"><code>567c9c6</code></a>
Add note on how to update docs for new release (<a
href="https://redirect.github.com/expressjs/express/issues/5541">#5541</a>)</li>
<li><a
href="69a4cf2819"><code>69a4cf2</code></a>
deps: cookie@0.6.0</li>
<li>Additional commits viewable in <a
href="https://github.com/expressjs/express/compare/4.18.2...4.19.2">compare
view</a></li>
</ul>
</details>
<details>
<summary>Maintainer changes</summary>
<p>This version was pushed to npm by <a
href="https://www.npmjs.com/~wesleytodd">wesleytodd</a>, a new releaser
for express since your current version.</p>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/tldraw/tldraw/network/alerts).

</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com>
2024-03-29 16:23:34 +00:00
Steve Ruiz 379094ddfb
Don't trigger pointer move on zoom (#3305)
In this PR, when the camera changes, we check whether the pointer's page
position has actually changed before triggering a pointer move event.
This means that the pointer move will not fire while zooming in and out.

### Change Type

- [x] `sdk` — Changes the tldraw SDK
- [x] `improvement` — Improving existing features

### Test Plan

1. Zoom in and out.
2. The performance tab should not see any calls to `updateHoveredShape`
or other pointer move related events.

### Release Notes

- Improve performance of zooming.
2024-03-29 15:29:28 +00:00
Mitja Bezenšek 27e961be99
Fix typo. (#3306)
Typo.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [x] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [ ] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-03-29 12:32:25 +00:00
Steve Ruiz 1fe74ecaa4
[chore] Bump browser-fs-access. (#3277)
This PR bumps browser-fs-access to the latest version.

### Change Type

<!--  Please select a 'Scope' label ️ -->

- [ ] `sdk` — Changes the tldraw SDK
- [ ] `dotcom` — Changes the tldraw.com web app
- [ ] `docs` — Changes to the documentation, examples, or templates.
- [ ] `vs code` — Changes to the vscode plugin
- [x] `internal` — Does not affect user-facing stuff

<!--  Please select a 'Type' label ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `chore` — Updating dependencies, other boring stuff
- [ ] `galaxy brain` — Architectural changes
- [ ] `tests` — Changes to any test code
- [ ] `tools` — Changes to infrastructure, CI, internal scripts,
debugging tools, etc.
- [ ] `dunno` — I don't know
2024-03-29 10:56:30 +00:00
336 zmienionych plików z 119984 dodań i 109612 usunięć

Wyświetl plik

@ -19,7 +19,7 @@ body:
id: reproduction
attributes:
label: How can we reproduce the bug?
description: If you can make the bug happen again, please share the steps involved.
description: If you can make the bug happen again, please share the steps involved. You can [fork this CodeSandbox](https://codesandbox.io/p/sandbox/tldraw-example-n539u) to make a reproduction.
validations:
required: false
- type: dropdown

6
.gitignore vendored
Wyświetl plik

@ -7,6 +7,8 @@ yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
.rooms
node_modules
dist
dist-cjs
@ -92,4 +94,6 @@ apps/docs/content/gen
.env*
.wrangler
/vercel.json
/vercel.json
license-report-prod.html
license-report.html

Wyświetl plik

@ -77,7 +77,17 @@ Please see our [contributing guide](https://github.com/tldraw/tldraw/blob/main/C
## Star History
<a href="https://star-history.com/#tldraw/tldraw">
<img src="https://api.star-history.com/svg?repos=tldraw/tldraw&type=Date" alt="Star History Chart" width="100%" />
<picture>
<source
media="(prefers-color-scheme: dark)"
srcset="https://api.star-history.com/svg?repos=tldraw/tldraw&type=Date&theme=dark"
/>
<source
media="(prefers-color-scheme: light)"
srcset="https://api.star-history.com/svg?repos=tldraw/tldraw&type=Date"
/>
<img src="https://api.star-history.com/svg?repos=tldraw/tldraw&type=Date" alt="Star History Chart" width="100%" />
</picture>
</a>
## Contact

Wyświetl plik

@ -8,7 +8,6 @@
- Minor version bumps are released on a regular cadence. At the time of writing that cadence is monthly. **They may contain breaking changes**. We aim to make breaking changes as minimally disruptive as possible by providing warnings several releases in advance, and by providing tooling to help you migrate your code. We recommend updating tldraw at a similar pace to our release cadence, and be sure to check the release notes.
- Patch version bumps are for bugfixes and hotfixes that can't wait for the next cadence release.
## How to publish a new major or minor release
New cadence releases are published from `main`. You trigger a release manually by running the workflow defined in `publish-new.yml`.

Plik diff jest za duży Load Diff

Plik diff jest za duży Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -1,9 +1,75 @@
---
title: Collaboration
status: published
author: steveruizok
author: ds300
date: 3/22/2023
order: 8
---
See the [tldraw-yjs example](https://github.com/tldraw/tldraw-yjs-example) for an example of how to use yjs with the `tldraw` library.
We've designed the tldraw SDK to work with any collaboration backend. Depending on which backend you choose, you will need an interface that pipes changes coming from the editor to the backend and then merge changes from the backend back to the editor.
The best way to get started is by adapting one of our examples.
### Yjs sync example
We created a [tldraw-yjs example](https://github.com/tldraw/tldraw-yjs-example) to illustrate a way of using the [yjs](https://yjs.dev) library with the tldraw SDK. If you need a "drop in solution" for prototyping multiplayer experiences with tldraw, start here.
### Sockets example
We have a [sockets example](https://github.com/tldraw/tldraw-sockets-example) that uses [PartyKit](https://www.partykit.io/) as a backend. Unlike the yjs example, this example does not use any special data structures to handle conflicts. It should be a good starting point if you needed to write your own conflict-resolution logic.
### Our own sync engine
We developed our own sync engine for use on tldraw.com based on a push/pull/rebase-style algorithm. It powers our "shared projects", such as [this one](https://tldraw.com/r). The engine's source code can be found [here](https://github.com/tldraw/tldraw/tree/main/packages/tlsync). It was designed to be hosted on Cloudflare workers with [DurableObjects](https://developers.cloudflare.com/durable-objects/).
We don't suggest using this code directly. However, like our other examples, it may serve as a good reference for your own sync engine.
## Store data
For information about how to synchronize the store with other processes, i.e. how to get data out and put data in, including from remote sources, see the (Persistence)[/docs/persistence] page.
## User presence
Tldraw has support for displaying the 'presence' of other users. Presence information consists of:
- The user's pointer position
- The user's set of selected shapes
- The user's viewport bounds (the part of the canvas they are currently viewing)
- The user's name, id, and a color to represent them
This information will usually come from two sources:
- The tldraw editor state (e.g. pointer position, selected shapes)
- The data layer of whichever app tldraw has been embedded in (e.g. user name, user id)
Tldraw is agnostic about how this data is shared among users. However, in order for tldraw to use the presence data it needs to be put into the editor's store as `instance_presence` records.
We provide a helper for constructing a reactive signal for an `instance_presence` record locally, which can then be sent to other clients somehow. It is called [createPresenceStateDerivation](?).
```ts
import { createPresenceStateDerivation, react, atom } from 'tldraw'
// First you need to create a Signal containing the basic user details: id, name, and color
const user = atom<{ id: string; color: string; name: string }>('user', {
id: myUser.id,
color: myUser.color,
name: myUser.name,
})
// if you don't have your own user data backend, you can use our localStorage-only user preferences store
// import { getUserPreferences, computed } from 'tldraw'
// const user = computed('user', getUserPreferences)
// Then, with access to your store instance, you can create a presence signal
const userPresence = createPresenceStateDerivation(user)(store)
// Then you can listen for changes to the presence signal and send them to other clients
const unsub = react('update presence', () => {
const presence = userPresence.get()
broadcastPresence(presence)
})
```
The other clients would then call `store.put([presence])` to add the presence information to their store.
Any such `instance_presence` records tldraw finds in the store that have a different user `id` than the editor's configured user id will cause the presence information to be rendered on the canvas.

Wyświetl plik

@ -50,21 +50,9 @@ editor.getSelectedShapeIds() // [myShapeId, myOtherShapeId]
Each change to the state happens within a transaction. You can batch changes into a single transaction using the [Editor#batch](?) method. It's a good idea to batch wherever possible, as this reduces the overhead for persisting or distributing those changes.
### Listening for changes
### Listening for changes, and merging changes from other sources
You can subscribe to changes using the [Store#listen](?) method on [Editor#store](?). Each time a transaction completes, the editor will call the callback with a history entry. This entry contains information about the records that were added, changed, or deleted, as well as whether the change was caused by the user or from a remote change.
```ts
editor.store.listen((entry) => {
entry // { changes, source }
})
```
### Remote changes
By default, changes to the editor's store are assumed to have come from the editor itself. You can use the [Store#mergeRemoteChanges](?) method of the editor's [Editor#store](?) to make changes in the store that will be emitted via [Store#listen](?) with the `source` property as `'remote'`.
If you're setting up some kind of multiplayer backend, you would want to send only the `'user'` changes to the server and merge the changes from the server using [Store#mergeRemoteChanges](?) (`editor.store.mergeRemoteChanges`).
For information about how to synchronize the store with other processes, i.e. how to get data out and put data in, see the (Persistence)[/docs/persistence] page.
### Undo and redo

Wyświetl plik

@ -17,7 +17,7 @@ Persistence in tldraw means storing information about the editor's state to a da
## The `"persistenceKey"` prop
Both the `<Tldraw>` or `<TldrawEditor>` components support local persitence and cross-tab synchronization via the `persistenceKey` prop. Passing a value to this prop will persist the contents of the editor locally to the browser's IndexedDb.
Both the `<Tldraw>` or `<TldrawEditor>` components support local persistence and cross-tab synchronization via the `persistenceKey` prop. Passing a value to this prop will persist the contents of the editor locally to the browser's IndexedDb.
```tsx
import { Tldraw } from 'tldraw'
@ -54,7 +54,7 @@ export default function () {
In the example above, both editors would synchronize their document locally. They would still have two independent instance states (e.g. selections) but the document would be kept in sync and persisted under the same key.
## Snapshots
## Document Snapshots
You can get a JSON snapshot of the editor's content using the [Editor#store](?)'s [Store#getSnapshot](?) method.
@ -96,7 +96,7 @@ function LoadButton() {
A [snapshot](/reference/store/StoreSnapshot) includes both the store's [serialized records](/reference/store/SerializedStore) and its [serialized schema](/reference/store/SerializedSchema), which is used for migrations.
> By default, the `getSnapshot` method returns only the editor's document data. If you want to get records from a different scope, You can pass in `session`, `document`, `presence`, or else `all` for all scopes.
> By default, the `getSnapshot` method returns only the editor's document data. If you want to get records from a different scope, you can pass in `session`, `document`, `presence`, or else `all` for all scopes.
Note that loading a snapshot does not reset the editor's in memory state or UI state. For example, loading a snapshot during a resizing operation may lead to a crash. This is because the resizing state maintains its own cache of information about which shapes it is resizing, and its possible that those shapes may no longer exist!
@ -170,3 +170,242 @@ export default function () {
```
For a good example of this pattern, see the [yjs-example](https://github.com/tldraw/tldraw-yjs-example).
## Listening for changes
You can listen for incremental updates to the document state by calling `editor.store.listen`, e.g.
```ts
const unlisten = editor.store.listen(
(update) => {
console.log('update', update)
},
{ scope: 'document', source: 'user' }
)
```
These updates contain information about which records were added, removed, and updated. See [HistoryEntry](?)
The `scope` filter can be used to listen for changes to a specific record scope, e.g. `document`, `session`, `presence`, or `all`.
The `source` filter can be used to listen for changes from a specific source, e.g. `user`, `remote`, or `all`. (See [Store#mergeRemoteChanges](?) for more information on remote changes.)
Note that these incremental updates do not include the schema version. You should make sure that you keep a record of the latest schema version for your snapshots.
You can get the schema version by calling `editor.store.schema.serialize()` and the returned value can replace the `schema` property in the snapshot next time you need to load a snapshot. The schema does not change at runtime so you only need to do this once per session.
## Handling remote changes
If you need to synchronize changes from a remote source, e.g. a multiplayer backend, you can use the `editor.store.mergeRemoteChanges` method. This will 'tag' the changes with the `source` property as `'remote'` so you can filter them out when listening for changes.
```ts
myRemoteSource.on('change', (changes) => {
editor.store.mergeRemoteChanges(() => {
changes.forEach((change) => {
// Apply the changes to the store
editor.store.put(/* ... */)
})
})
})
```
## Migrations
Tldraw uses migrations to bring data from old snapshots up to date. These run automatically when calling `editor.store.loadSnapshot`.
### Running migrations manually
If you need to run migrations on a snapshot without loading it into the store, you can call [StoreSchema#migrateStoreSnapshot](?) directly.
```ts
import { createTLSchema } from 'tldraw'
const snapshot = await getSnapshotFromSomewhere()
const migrationResult = createTLSchema().migrateStoreSnapshot(snapshot)
if (migrationResult.type === 'success') {
console.log('Migrated snapshot', migrationResult.value)
} else {
console.error('Migration failed', migrationResult.reason)
}
```
### Custom migrations
Tldraw supports a couple of ways of adding custom data types to the tldraw store:
- [Custom shape types](/docs/shapes#Custom-shapes-1)
- [`meta` properties](/docs/shapes#Meta-information) on all of our built-in record types.
You might wish to migrate your custom data types over time as you make changes to them.
To enable this, tldraw provides two ways to add custom migrations:
1. **Shape props migrations**, specifically for migrating the shape.props objects on your custom shape types.
2. **The `migrations` config option**, which is more general purpose but much less commonly needed. This will allow you to migrate any data in the store.
#### Shape props migrations
If you have a custom shape type, you can define a `migrations` property on the shape util class. Use the `createShapePropsMigrationSequence` helper to define this property.
```ts
import { createShapePropsMigrationSequence, createShapePropsMigrationIds, ShapeUtil } from 'tldraw'
// Migrations must start a 1 and be sequential integers.
const Versions = createShapePropMigrationIds('custom-shape', {
AddColor: 1,
})
class MyCustomShapeUtil extends ShapeUtil {
static type = 'custom-shape'
static migrations = createShapePropsMigrationSequence({
sequence: [
{
id: Versions.AddColor,
up(props) {
// set the default color
props.color = 'black'
},
},
],
})
// ...
}
```
#### The `migrations` config option
First create a set of migration ids.
```ts
import { createMigrationIds } from 'tldraw'
// The first argument is a unique namespace for your migration sequence.
// We recommend using a reverse domain name, e.g. we use 'com.tldraw.foo.bar'
const SEQUENCE_ID = 'com.example.my-app'
const Versions = createMigrationIds(SEQUENCE_ID, {
// Migrations must start at 1 and be sequential integers.
AddColor: 1,
})
```
Then create a migration sequence.
```ts
import { createMigrationSequence, isShape } from 'tldraw'
const myMigrations = createMigrationSequence({
sequenceId: SEQUENCE_ID,
sequence: [
{
id: Versions.AddColor,
// Scope can be one of
// - 'store' to have the up function called on the whole snapshot at once
// - 'record' to have the up function called on each record individually
scope: 'record',
// if scope is 'record', you can filter which records the migration runs on
filter: (record) => isShape(record) && record.type === 'custom-shape',
up(record) {
record.props.color = 'black'
},
},
],
})
```
And finally pass your migrations in to tldraw via the `migrations` config option. There are a few places where you might need to do this, depending on how specialized your usage of Tldraw is:
```tsx
// When rendering the Tldraw component
<Tldraw
...
migrations={[myMigrations]}
/>
// or when creating the store
store = createTLStore({
...
migrations: [myMigrations],
})
// or when creating the schema
schema = createTLSchema({
...
migrations: [myMigrations],
})
```
### Updating legacy shape migrations (defineMigrations)
You can convert your legacy migrations to the new migrations format by the following process:
1. Wrap your version numbers in `createShapePropsMigrationIds`
```diff
- const Versions = {
+ const Versions = createShapePropMigrationIds('custom-shape', {
AddColor: 1
- }
+ })
```
2. Replace your `defineMigrations` call with `createShapePropsMigrationSequence`
```ts
const migrations = defineMigrations({
currentVersion: Versions.AddColor,
migrators: {
[Versions.AddColor]: {
up: (shape: any) => ({ ...shape, props: { ...shape.props, color: 'black' } }),
down: ({ props: { color, ...props }, ...shape }: any) => ({ ...shape, props }),
},
},
})
```
Becomes
```ts
const migrations = createShapePropsMigrationSequence({
sequence: [
{
id: Versions.AddColor,
// [!!!] You no longer have access to the top-level shape object.
// Only the shape.props object is passed in to the migrator function.
up(props) {
// [!!!] You no longer need to return a new copy of the shape object.
// Instead, you can modify the props object in place.
props.color = 'black'
},
// [!!!] You no longer need to specify a down migration.
},
],
})
```
## Examples
### Local persistence
Tldraw ships with a local-only sync engine based on `IndexedDb` and `BroadcastChannel` called [`TLLocalSyncClient`](https://github.com/tldraw/tldraw/blob/main/packages/editor/src/lib/utils/sync/TLLocalSyncClient.ts).
### Tldraw.com sync engine
[tldraw.com/r](https://tldraw.com/r) currently uses a simple custom sync engine based on a push/pull/rebase-style algorithm.
It can be found [here](https://github.com/tldraw/tldraw/tree/main/packages/tlsync).
It was optimized for Cloudflare workers with [DurableObjects](https://developers.cloudflare.com/durable-objects/)
We don't suggest using our code directly yet, but it may serve as a good reference for your own sync engine.
### Yjs sync example
We created a [tldraw-yjs example](https://github.com/tldraw/tldraw-yjs-example) to illustrate a way of using yjs with the tldraw SDK.
### Shape props migrations example
Our [custom-config example](/examples/shapes/tools/custom-config) shows how to add custom shape props migrations to the tldraw store.
### Meta properties migrations example
Our [custom-config example](/examples/shapes/tools/custom-config) shows how to add custom migrations to the tldraw store.

Wyświetl plik

@ -239,4 +239,6 @@ You can turn on `pointer-events` to allow users to interact inside of the shape.
You can make shapes "editable" to help decide when they're interactive or not.
...and more!
### Migrations
You can add migrations for your shape props by adding a `migrations` property to your shape's util class. See [the persistence docs](/docs/persistence#Shape-props-migrations) for more information.

Wyświetl plik

@ -31,7 +31,7 @@ To import fonts and CSS for tldraw:
- Copy and paste this into the file:
```CSS
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@500;700;&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Inter:wght@500;700&display=swap");
@import url("tldraw/tldraw.css");
body {

Wyświetl plik

@ -26,7 +26,7 @@
"@tldraw/tlsync": "workspace:*",
"@tldraw/utils": "workspace:*",
"@vercel/analytics": "^1.1.1",
"browser-fs-access": "^0.33.0",
"browser-fs-access": "^0.35.0",
"idb": "^7.1.1",
"nanoid": "4.0.2",
"qrcode": "^1.5.1",

Wyświetl plik

@ -304,7 +304,10 @@ const DocumentNameEditor = track(function DocumentNameEditor({
) : (
<div
className="tlui-document-name__text"
onDoubleClick={() => setState((prev) => ({ ...prev, isEditing: true }))}
onDoubleClick={() => {
editor.setEditingShape(null)
setState((prev) => ({ ...prev, isEditing: true }))
}}
>
{addRealSpaceForWhitespace(name)}
</div>

Wyświetl plik

@ -1,5 +1,6 @@
import { ReactNode, useEffect, useState, version } from 'react'
import { ReactNode, useEffect, useState } from 'react'
import { LoadingScreen } from 'tldraw'
import { version } from '../../version'
import { useUrl } from '../hooks/useUrl'
import { trackAnalyticsEvent } from '../utils/trackAnalyticsEvent'
@ -113,7 +114,7 @@ export function IFrameProtector({
<div className="tldraw__editor tl-container">
<div className="iframe-warning__container">
<a className="iframe-warning__link" href={url} target="_blank">
{'Visit this page on tldraw.com '}
{'Visit this page on tldraw.com'}
<svg
width="15"
height="15"

Wyświetl plik

@ -6,9 +6,7 @@ export function CursorChatMenuItem() {
const actions = useActions()
const shouldShow = useValue(
'show cursor chat',
() => {
return editor.getInstanceState().isCoarsePointer && !editor.getSelectedShapes().length
},
() => editor.getCurrentToolId() === 'select' && !editor.getInstanceState().isCoarsePointer,
[editor]
)

Wyświetl plik

@ -6,13 +6,6 @@ const RELEASE_INFO = `${env} ${process.env.NEXT_PUBLIC_TLDRAW_RELEASE_INFO ?? 'u
export function DebugMenuItems() {
return (
<TldrawUiMenuGroup id="release">
<TldrawUiMenuItem
id="release-info"
label={`Version ${RELEASE_INFO}`}
onSelect={() => {
window.alert(`${RELEASE_INFO}`)
}}
/>
<TldrawUiMenuItem
id="v1"
label="Test v1 content"
@ -22,6 +15,13 @@ export function DebugMenuItems() {
window.location.reload()
}}
/>
<TldrawUiMenuItem
id="release-info"
label={'Release info'}
onSelect={() => {
window.alert(`${RELEASE_INFO}`)
}}
/>
</TldrawUiMenuGroup>
)
}

Wyświetl plik

@ -140,7 +140,7 @@ describe(ClientWebSocketAdapter, () => {
const message: TLSocketClientSentEvent<TLRecord> = {
type: 'connect',
connectRequestId: 'test',
schema: { schemaVersion: 0, storeVersion: 0, recordVersions: {} },
schema: { schemaVersion: 1, storeVersion: 0, recordVersions: {} },
protocolVersion: TLSYNC_PROTOCOL_VERSION,
lastServerClock: 0,
}

Wyświetl plik

@ -41,9 +41,9 @@ export async function setupPageWithShapes(page: PlaywrightTestArgs['page']) {
await page.mouse.click(200, 250)
await page.keyboard.press('r')
await page.mouse.click(250, 300)
// deselect everything
await page.evaluate(() => editor.selectNone())
await page.keyboard.press('Escape')
await page.keyboard.press('Escape')
}
export async function cleanupPage(page: PlaywrightTestArgs['page']) {

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 5.2 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 5.2 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 5.2 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.0 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 5.2 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 5.0 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.3 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.2 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.3 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.2 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.4 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 4.4 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 4.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.6 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.6 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 3.4 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.1 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 3.1 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.9 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.8 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.8 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.4 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.8 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.4 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.8 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 2.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.7 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.7 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.7 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.7 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.6 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.6 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.6 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.6 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Plik binarny nie jest wyświetlany.

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 1.5 KiB

Wyświetl plik

@ -21,6 +21,7 @@ test.describe('Canvas events', () => {
await page.mouse.move(200, 200) // to kill any double clicks
await page.mouse.move(100, 100)
await page.mouse.down()
await page.waitForTimeout(20)
expect(await page.evaluate(() => __tldraw_editor_events.at(-1))).toMatchObject({
target: 'canvas',
type: 'pointer',
@ -46,6 +47,7 @@ test.describe('Canvas events', () => {
await page.mouse.down()
await page.mouse.move(101, 101)
await page.mouse.up()
await page.waitForTimeout(20)
expect(await page.evaluate(() => __tldraw_editor_events.at(-1))).toMatchObject({
target: 'canvas',
type: 'pointer',
@ -118,6 +120,7 @@ test.describe('Shape events', () => {
test('pointer down', async () => {
await page.mouse.move(51, 51)
await page.mouse.down()
await page.waitForTimeout(20)
expect(await page.evaluate(() => __tldraw_editor_events.at(-1))).toMatchObject({
target: 'canvas',
type: 'pointer',
@ -128,6 +131,7 @@ test.describe('Shape events', () => {
test('pointer move', async () => {
await page.mouse.move(51, 51)
await page.mouse.move(52, 52)
await page.waitForTimeout(20)
expect(await page.evaluate(() => __tldraw_editor_events.at(-1))).toMatchObject({
target: 'canvas',
type: 'pointer',
@ -139,6 +143,7 @@ test.describe('Shape events', () => {
await page.mouse.move(51, 51)
await page.mouse.down()
await page.mouse.up()
await page.waitForTimeout(20)
expect(await page.evaluate(() => __tldraw_editor_events.at(-1))).toMatchObject({
target: 'canvas',
type: 'pointer',

Wyświetl plik

@ -112,6 +112,7 @@ test.describe('Shape Tools', () => {
// Click on the page
await page.mouse.click(200, 200)
await page.waitForTimeout(20)
// We should have a corresponding shape in the page
expect(await getAllShapeTypes(page)).toEqual([shape])
@ -119,6 +120,7 @@ test.describe('Shape Tools', () => {
// Reset for next time
await page.mouse.click(50, 50) // to ensure we're not focused
await page.keyboard.press('v') // go to the select tool
await page.waitForTimeout(20)
await page.keyboard.press('Control+a')
await page.keyboard.press('Backspace')
}
@ -156,6 +158,7 @@ test.describe('Shape Tools', () => {
// Reset for next time
await page.mouse.click(50, 50) // to ensure we're not focused
await page.keyboard.press('v')
await page.waitForTimeout(20)
await page.keyboard.press('Control+a')
await page.keyboard.press('Backspace')
}

Wyświetl plik

@ -1,5 +1,5 @@
import test, { Page, expect } from '@playwright/test'
import { BoxModel, Editor } from 'tldraw'
import { BoxModel, Editor, TLNoteShape, TLShapeId } from 'tldraw'
import { setupPage } from '../shared-e2e'
export function sleep(ms: number) {
@ -242,4 +242,92 @@ test.describe('text measurement', () => {
expect(formatLines(spans)).toEqual([[' \n'], [' \n'], [' \n'], [' ']])
})
test('for auto-font-sizing shapes, should do normal font size for text that does not have long words', async () => {
const shape = await page.evaluate(() => {
const id = 'shape:testShape' as TLShapeId
editor.createShapes([
{
id,
type: 'note',
x: 0,
y: 0,
props: {
text: 'this is just some regular text',
size: 'xl',
},
},
])
return editor.getShape(id) as TLNoteShape
})
expect(shape.props.fontSizeAdjustment).toEqual(32)
})
test('for auto-font-sizing shapes, should auto-size text that have slightly long words', async () => {
const shape = await page.evaluate(() => {
const id = 'shape:testShape' as TLShapeId
editor.createShapes([
{
id,
type: 'note',
x: 0,
y: 0,
props: {
text: 'Amsterdam',
size: 'xl',
},
},
])
return editor.getShape(id) as TLNoteShape
})
expect(shape.props.fontSizeAdjustment).toEqual(27)
})
test('for auto-font-sizing shapes, should auto-size text that have long words', async () => {
const shape = await page.evaluate(() => {
const id = 'shape:testShape' as TLShapeId
editor.createShapes([
{
id,
type: 'note',
x: 0,
y: 0,
props: {
text: 'this is a tentoonstelling',
size: 'xl',
},
},
])
return editor.getShape(id) as TLNoteShape
})
expect(shape.props.fontSizeAdjustment).toEqual(20)
})
test('for auto-font-sizing shapes, should wrap text that has words that are way too long', async () => {
const shape = await page.evaluate(() => {
const id = 'shape:testShape' as TLShapeId
editor.createShapes([
{
id,
type: 'note',
x: 0,
y: 0,
props: {
text: 'a very long dutch word like ziekenhuisinrichtingsmaatschappij',
size: 'xl',
},
},
])
return editor.getShape(id) as TLNoteShape
})
expect(shape.props.fontSizeAdjustment).toEqual(14)
})
})

Wyświetl plik

@ -0,0 +1,27 @@
import { Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
export default function BasicExample() {
return (
<div className="tldraw__editor">
<Tldraw
overrides={{
actions: (_editor, actions, _helpers) => {
const newActions = {
...actions,
delete: { ...actions['delete'], kbd: 'x' },
}
return newActions
},
}}
/>
</div>
)
}
/*
This example shows how you can override tldraw's actions object to change the keyboard shortcuts.
In this case we're changing the delete action's shortcut to 'x'. To customize the actions menu
please see the custom actions menu example. For more information on keyboard shortcuts see the
keyboard shortcuts example.
*/

Wyświetl plik

@ -0,0 +1,12 @@
---
title: Action overrides
component: ./ActionOverridesExample.tsx
category: ui
priority: 2
---
Override tldraw's actions
---
This example shows how you can override tldraw's actions object to change the keyboard shortcuts. In this case we're changing the delete action's shortcut to 'x'. To customize the actions menu please see the custom actions menu example. For more information on keyboard shortcuts see the keyboard shortcuts example.

Wyświetl plik

@ -1,4 +1,4 @@
import { Editor, Tldraw } from 'tldraw'
import { Editor, TLStoreSnapshot, Tldraw } from 'tldraw'
import { PlayingCardTool } from './PlayingCardShape/playing-card-tool'
import { PlayingCardUtil } from './PlayingCardShape/playing-card-util'
import snapshot from './snapshot.json'
@ -27,7 +27,7 @@ export default function BoundsSnappingShapeExample() {
// [c]
onMount={handleMount}
// [d]
snapshot={snapshot}
snapshot={snapshot as TLStoreSnapshot}
/>
</div>
)

Wyświetl plik

@ -1,21 +1,26 @@
import { defineMigrations } from 'tldraw'
import { createShapePropsMigrationIds } from '@tldraw/tlschema/src/records/TLShape'
import { createShapePropsMigrationSequence } from 'tldraw'
const versions = createShapePropsMigrationIds(
// this must match the shape type in the shape definition
'card',
{
AddSomeProperty: 1,
}
)
// Migrations for the custom card shape (optional but very helpful)
export const cardShapeMigrations = defineMigrations({
currentVersion: 1,
migrators: {
1: {
// for example, removing a property from the shape
up(shape) {
const migratedUpShape = { ...shape }
delete migratedUpShape._somePropertyToRemove
return migratedUpShape
export const cardShapeMigrations = createShapePropsMigrationSequence({
sequence: [
{
id: versions.AddSomeProperty,
up(props) {
// it is safe to mutate the props object here
props.someProperty = 'some value'
},
down(shape) {
const migratedDownShape = { ...shape }
migratedDownShape._somePropertyToRemove = 'some value'
return migratedDownShape
down(props) {
delete props.someProperty
},
},
},
],
})

Wyświetl plik

@ -36,7 +36,8 @@ export function CustomRenderer() {
const theme = getDefaultColorTheme({ isDarkMode: editor.user.getIsDarkMode() })
const currentPageId = editor.getCurrentPageId()
for (const { shape, maskedPageBounds, opacity } of renderingShapes) {
for (const { shape, opacity } of renderingShapes) {
const maskedPageBounds = editor.getShapeMaskedPageBounds(shape)
if (!maskedPageBounds) continue
ctx.save()

Wyświetl plik

@ -0,0 +1,151 @@
import {
Circle2d,
Geometry2d,
HTMLContainer,
Rectangle2d,
ShapeUtil,
TLBaseShape,
TLShape,
Tldraw,
} from 'tldraw'
import 'tldraw/tldraw.css'
// There's a guide at the bottom of this file!
// [1]
type MyGridShape = TLBaseShape<'my-grid-shape', Record<string, never>>
type MyCounterShape = TLBaseShape<'my-counter-shape', Record<string, never>>
// [2]
const SLOT_SIZE = 100
class MyCounterShapeUtil extends ShapeUtil<MyCounterShape> {
static override type = 'my-counter-shape' as const
override canResize = () => false
override hideResizeHandles = () => true
getDefaultProps(): MyCounterShape['props'] {
return {}
}
getGeometry(): Geometry2d {
return new Circle2d({ radius: SLOT_SIZE / 2 - 10, isFilled: true })
}
component() {
return (
<HTMLContainer
style={{
backgroundColor: '#e03131',
border: '1px solid #ff8787',
borderRadius: '50%',
}}
/>
)
}
indicator() {
return <circle r={SLOT_SIZE / 2 - 10} cx={SLOT_SIZE / 2 - 10} cy={SLOT_SIZE / 2 - 10} />
}
}
// [3]
class MyGridShapeUtil extends ShapeUtil<MyGridShape> {
static override type = 'my-grid-shape' as const
getDefaultProps(): MyGridShape['props'] {
return {}
}
getGeometry(): Geometry2d {
return new Rectangle2d({
width: SLOT_SIZE * 5,
height: SLOT_SIZE * 2,
isFilled: true,
})
}
override canResize = () => false
override hideResizeHandles = () => true
// [a]
override canDropShapes = (shape: MyGridShape, shapes: TLShape[]) => {
if (shapes.every((s) => s.type === 'my-counter-shape')) {
return true
}
return false
}
// [b]
override onDragShapesOver = (shape: MyGridShape, shapes: TLShape[]) => {
if (!shapes.every((child) => child.parentId === shape.id)) {
this.editor.reparentShapes(shapes, shape.id)
}
}
// [c]
override onDragShapesOut = (shape: MyGridShape, shapes: TLShape[]) => {
this.editor.reparentShapes(shapes, this.editor.getCurrentPageId())
}
component() {
return (
<HTMLContainer
style={{
backgroundColor: '#efefef',
borderRight: '1px solid #ccc',
borderBottom: '1px solid #ccc',
backgroundSize: `${SLOT_SIZE}px ${SLOT_SIZE}px`,
backgroundImage: `
linear-gradient(to right, #ccc 1px, transparent 1px),
linear-gradient(to bottom, #ccc 1px, transparent 1px)
`,
}}
/>
)
}
indicator() {
return <rect width={SLOT_SIZE * 5} height={SLOT_SIZE * 2} />
}
}
export default function DragAndDropExample() {
return (
<div className="tldraw__editor">
<Tldraw
shapeUtils={[MyGridShapeUtil, MyCounterShapeUtil]}
onMount={(editor) => {
editor.createShape({ type: 'my-grid-shape', x: 100, y: 100 })
editor.createShape({ type: 'my-counter-shape', x: 700, y: 100 })
editor.createShape({ type: 'my-counter-shape', x: 750, y: 200 })
editor.createShape({ type: 'my-counter-shape', x: 770, y: 300 })
}}
/>
</div>
)
}
/*
This example demonstrates how to use the drag-and-drop system.
[1] Define some shape types. For the purposes of this example, we'll define two
shapes: a grid and a counter.
[2] Make a shape util for the first shape. For this example, we'll make a simple
red circle that you drag and drop onto the other shape.
[3] Make the other shape util. In this example, we'll make a grid that you can
place the the circle counters onto.
[a] Use the `canDropShapes` method to specify which shapes can be dropped onto
the grid shape.
[b] Use the `onDragShapesOver` method to reparent counters to the grid shape
when they are dragged on top.
[c] Use the `onDragShapesOut` method to reparent counters back to the page
when they are dragged off.
*/

Wyświetl plik

@ -0,0 +1,12 @@
---
title: Drag and drop
component: ./DragAndDropExample.tsx
category: shapes/tools
priority: 1
---
Shapes that can be dragged and dropped onto each other.
---
You can create custom shapes that can be dragged and dropped onto each other.

Wyświetl plik

@ -1,9 +1,10 @@
import {
ContextMenu,
DefaultContextMenuContent,
ErrorScreen,
LoadingScreen,
TldrawEditor,
TldrawHandles,
TldrawHoveredShapeIndicator,
TldrawScribble,
TldrawSelectionBackground,
TldrawSelectionForeground,
@ -11,7 +12,9 @@ import {
defaultShapeTools,
defaultShapeUtils,
defaultTools,
usePreloadAssets,
} from 'tldraw'
import { defaultEditorAssetUrls } from 'tldraw/src/lib/utils/static-assets/assetUrls'
import 'tldraw/tldraw.css'
// There's a guide at the bottom of this file!
@ -23,11 +26,20 @@ const defaultComponents = {
SelectionForeground: TldrawSelectionForeground,
SelectionBackground: TldrawSelectionBackground,
Handles: TldrawHandles,
HoveredShapeIndicator: TldrawHoveredShapeIndicator,
}
//[2]
export default function ExplodedExample() {
const assetLoading = usePreloadAssets(defaultEditorAssetUrls)
if (assetLoading.error) {
return <ErrorScreen>Could not load assets.</ErrorScreen>
}
if (!assetLoading.done) {
return <LoadingScreen>Loading assets...</LoadingScreen>
}
return (
<div className="tldraw__editor">
<TldrawEditor

Wyświetl plik

@ -1,5 +1,14 @@
import { useState } from 'react'
import { Box, Editor, StoreSnapshot, TLPageId, TLRecord, Tldraw, TldrawImage } from 'tldraw'
import {
Box,
Editor,
StoreSnapshot,
TLPageId,
TLRecord,
TLStoreSnapshot,
Tldraw,
TldrawImage,
} from 'tldraw'
import 'tldraw/tldraw.css'
import initialSnapshot from './snapshot.json'
@ -7,7 +16,9 @@ import initialSnapshot from './snapshot.json'
export default function TldrawImageExample() {
const [editor, setEditor] = useState<Editor>()
const [snapshot, setSnapshot] = useState<StoreSnapshot<TLRecord>>(initialSnapshot)
const [snapshot, setSnapshot] = useState<StoreSnapshot<TLRecord>>(
initialSnapshot as TLStoreSnapshot
)
const [currentPageId, setCurrentPageId] = useState<TLPageId | undefined>()
const [showBackground, setShowBackground] = useState(true)
const [isDarkMode, setIsDarkMode] = useState(false)

Wyświetl plik

@ -1,6 +1,5 @@
import { TLUiActionsContextType, TLUiOverrides, TLUiToolsContextType, Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
import jsonSnapshot from './snapshot.json'
// There's a guide at the bottom of this file!
@ -8,13 +7,18 @@ import jsonSnapshot from './snapshot.json'
const overrides: TLUiOverrides = {
//[a]
actions(_editor, actions): TLUiActionsContextType {
actions['toggle-grid'].kbd = 'x'
return actions
const newActions = {
...actions,
'toggle-grid': { ...actions['toggle-grid'], kbd: 'x' },
'copy-as-png': { ...actions['copy-as-png'], kbd: '$1' },
}
return newActions
},
//[b]
tools(_editor, tools): TLUiToolsContextType {
tools['draw'].kbd = 'p'
return tools
const newTools = { ...tools, draw: { ...tools.draw, kbd: 'p' } }
return newTools
},
}
@ -22,7 +26,7 @@ const overrides: TLUiOverrides = {
export default function KeyboardShortcuts() {
return (
<div className="tldraw__editor">
<Tldraw persistenceKey="tldraw_kbd_shortcuts" overrides={overrides} snapshot={jsonSnapshot} />
<Tldraw overrides={overrides} />
</div>
)
}

Wyświetl plik

@ -5,8 +5,14 @@ category: ui
priority: 2
---
Override default keyboard shortcuts.
How to replace tldraw's default keyboard shortcuts with your own.
---
How to replace tldraw's default keyboard shortcuts with your own.
This example shows how you can replace tldraw's default keyboard shortcuts with your own,
or add a shortcut for an action that doesn't have one. An example of how to add shortcuts
for custom tools can be found in the custom-config example.
- Toggle show grid by pressing 'x'
- Select the Draw tool by pressing 'p'
- Copy as png by pressing 'ctrl/cmd + 1'

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -0,0 +1,74 @@
import { Tldraw, createMigrationIds, createMigrationSequence } from 'tldraw'
import 'tldraw/tldraw.css'
import { snapshot } from './snapshot'
import { components } from './ui-overrides'
/**
* This example demonstrates how to add custom migrations for `meta` properties, or any other
* data in your store snapshots.
*
* If you have a custom shape type and you want to add migrations for its `props` object,
* there is a simpler dedicated API for that. Check out [the docs](https://tldraw.dev/docs/persistence#Shape-props-migrations) for more info.
*/
/**
* Let's say you added some page metadata, e.g. to allow setting the background color of a page independently.
*/
interface _PageMetaV1 {
backgroundTheme?: 'red' | 'blue' | 'green' | 'purple'
}
/**
* And then perhaps later on you decided to remove support for 'purple' because it's an ugly color.
* So all purple pages will become blue.
*/
export interface PageMetaV2 {
backgroundTheme?: 'red' | 'blue' | 'green'
}
/**
* You would then create a migration to update the metadata from v1 to v2.
*/
// First pick a 'sequence id' that is unique to your app
const sequenceId = 'com.example.my-app'
// Then create a 'migration id' for each version of your metadata
const versions = createMigrationIds(sequenceId, {
// the numbers must start at 1 and increment by 1
RemovePurple: 1,
})
const migrations = createMigrationSequence({
sequenceId,
sequence: [
{
id: versions.RemovePurple,
// `scope: 'record` tells the schema to call this migration on individual records.
// `scope: 'store'` would call it on the entire snapshot, to allow for actions like deleting/creating records.
scope: 'record',
// When `scope` is 'record', you can specify a filter function to only apply the migration to records that match the filter.
filter: (record) => record.typeName === 'page',
// This up function will be called on all records that match the filter
up(page: any) {
if (page.meta.backgroundTheme === 'purple') {
page.meta.backgroundTheme = 'blue'
page.name += ' (was purple)'
}
},
},
],
})
export default function MetaMigrationsExample() {
return (
<div className="tldraw__editor">
<Tldraw
// Pass in the custom migrations
migrations={[migrations]}
// When you load a snapshot from a previous version, the migrations will be applied automatically
snapshot={snapshot}
// This adds a dropdown to the canvas for changing the backgroundTheme property
components={components}
/>
</div>
)
}

Wyświetl plik

@ -0,0 +1,12 @@
---
title: Meta Migrations
component: ./MetaMigrations.tsx
category: data/assets
priority: 6
---
Create custom migrations for `meta` properties.
---
You can add arbitrary data migrations for tldraw snapshot data. This is mainly useful for updating the `meta` property of a record as your data types evolve.

Wyświetl plik

@ -0,0 +1,57 @@
import { TLStoreSnapshot } from 'tldraw'
export const snapshot = {
store: {
'document:document': {
gridSize: 10,
name: '',
meta: {},
id: 'document:document',
typeName: 'document',
},
'page:red': {
meta: {
backgroundTheme: 'red',
},
id: 'page:red',
name: 'Red',
index: 'a1',
typeName: 'page',
},
'page:green': {
meta: {
backgroundTheme: 'green',
},
id: 'page:green',
name: 'Green',
index: 'a2',
typeName: 'page',
},
'page:blue': {
meta: {
backgroundTheme: 'blue',
},
id: 'page:blue',
name: 'Blue',
index: 'a3',
typeName: 'page',
},
'page:purple': {
meta: {
backgroundTheme: 'purple',
},
id: 'page:purple',
name: 'Purple',
index: 'a0',
typeName: 'page',
},
},
schema: {
schemaVersion: 2,
sequences: {
'com.tldraw.store': 4,
'com.tldraw.document': 2,
'com.tldraw.page': 1,
},
},
} as TLStoreSnapshot

Wyświetl plik

@ -0,0 +1,41 @@
import { useLayoutEffect } from 'react'
import { TLComponents, track, useEditor } from 'tldraw'
import { PageMetaV2 } from './MetaMigrations'
export const components: TLComponents = {
TopPanel: track(() => {
const editor = useEditor()
const currentPage = editor.getCurrentPage()
const meta: PageMetaV2 = currentPage.meta
useLayoutEffect(() => {
const elem = document.querySelector('.tl-background') as HTMLElement
if (!elem) return
elem.style.backgroundColor = meta.backgroundTheme ?? 'unset'
}, [meta.backgroundTheme])
return (
<span style={{ pointerEvents: 'all', padding: '5px 15px', margin: 10, fontSize: 18 }}>
bg: &nbsp;
<select
value={meta.backgroundTheme ?? 'none'}
onChange={(e) => {
if (e.currentTarget.value === 'none') {
editor.updatePage({ ...currentPage, meta: {} })
} else {
editor.updatePage({
...currentPage,
meta: { backgroundTheme: e.currentTarget.value },
})
}
}}
>
<option value="none">None</option>
<option value="red">Red</option>
<option value="blue">Blue</option>
<option value="green">Green</option>
</select>
</span>
)
}),
}

Wyświetl plik

@ -84,7 +84,7 @@ deletes that shape.
[1]
This is where we define our state node by extending the StateNode class. Since
there are no children states We can simply give it an id and define methods we
there are no children states We can give it an id and define methods we
want to override to handle events.

Wyświetl plik

@ -5,26 +5,34 @@ export function useChangedShapesReactor(
cb: (info: { culled: TLShape[]; restored: TLShape[] }) => void
) {
const editor = useEditor()
const rPrevShapes = useRef(editor.getRenderingShapes())
const rPrevShapes = useRef({
renderingShapes: editor.getRenderingShapes(),
culledShapes: editor.getCulledShapes(),
})
useEffect(() => {
return react('when rendering shapes change', () => {
const after = editor.getRenderingShapes()
const after = {
culledShapes: editor.getCulledShapes(),
renderingShapes: editor.getRenderingShapes(),
}
const before = rPrevShapes.current
const culled: TLShape[] = []
const restored: TLShape[] = []
const beforeToVisit = new Set(before)
const beforeToVisit = new Set(before.renderingShapes)
for (const afterInfo of after) {
const beforeInfo = before.find((s) => s.id === afterInfo.id)
for (const afterInfo of after.renderingShapes) {
const beforeInfo = before.renderingShapes.find((s) => s.id === afterInfo.id)
if (!beforeInfo) {
continue
} else {
if (afterInfo.isCulled && !beforeInfo.isCulled) {
const isAfterCulled = after.culledShapes.has(afterInfo.id)
const isBeforeCulled = before.culledShapes.has(beforeInfo.id)
if (isAfterCulled && !isBeforeCulled) {
culled.push(afterInfo.shape)
} else if (!afterInfo.isCulled && beforeInfo.isCulled) {
} else if (!isAfterCulled && isBeforeCulled) {
restored.push(afterInfo.shape)
}
beforeToVisit.delete(beforeInfo)

Wyświetl plik

@ -4,6 +4,7 @@ import {
T,
TLBaseShape,
TLOnResizeHandler,
TLStoreSnapshot,
Tldraw,
resizeBox,
} from 'tldraw'
@ -94,7 +95,7 @@ export default function ShapeWithMigrationsExample() {
// Pass in the array of custom shape classes
shapeUtils={customShapeUtils}
// Use a snapshot to load an old version of the shape
snapshot={snapshot}
snapshot={snapshot as TLStoreSnapshot}
/>
</div>
)

Wyświetl plik

@ -0,0 +1,12 @@
---
title: Slideshow
component: ./SlidesExample.tsx
category: use-cases
priority: 1
---
Slideshow example.
---
Make slides for a presentation.

Wyświetl plik

@ -0,0 +1,7 @@
import { BaseBoxShapeTool } from 'tldraw'
export class SlideShapeTool extends BaseBoxShapeTool {
static override id = 'slide'
static override initial = 'idle'
override shapeType = 'slide'
}

Wyświetl plik

@ -0,0 +1,127 @@
import { useCallback } from 'react'
import {
Geometry2d,
Rectangle2d,
SVGContainer,
ShapeProps,
ShapeUtil,
T,
TLBaseShape,
TLOnResizeHandler,
resizeBox,
useValue,
} from 'tldraw'
import { getPerfectDashProps } from 'tldraw/src/lib/shapes/shared/getPerfectDashProps'
import { moveToSlide, useSlides } from './useSlides'
export type SlideShape = TLBaseShape<
'slide',
{
w: number
h: number
}
>
export class SlideShapeUtil extends ShapeUtil<SlideShape> {
static override type = 'slide' as const
static override props: ShapeProps<SlideShape> = {
w: T.number,
h: T.number,
}
override canBind = () => false
override hideRotateHandle = () => true
getDefaultProps(): SlideShape['props'] {
return {
w: 720,
h: 480,
}
}
getGeometry(shape: SlideShape): Geometry2d {
return new Rectangle2d({
width: shape.props.w,
height: shape.props.h,
isFilled: false,
})
}
override onRotate = (initial: SlideShape) => initial
override onResize: TLOnResizeHandler<SlideShape> = (shape, info) => {
return resizeBox(shape, info)
}
override onDoubleClick = (shape: SlideShape) => {
moveToSlide(this.editor, shape)
this.editor.selectNone()
}
override onDoubleClickEdge = (shape: SlideShape) => {
moveToSlide(this.editor, shape)
this.editor.selectNone()
}
component(shape: SlideShape) {
const bounds = this.editor.getShapeGeometry(shape).bounds
// eslint-disable-next-line react-hooks/rules-of-hooks
const zoomLevel = useValue('zoom level', () => this.editor.getZoomLevel(), [this.editor])
// eslint-disable-next-line react-hooks/rules-of-hooks
const slides = useSlides()
const index = slides.findIndex((s) => s.id === shape.id)
// eslint-disable-next-line react-hooks/rules-of-hooks
const handleLabelPointerDown = useCallback(() => this.editor.select(shape.id), [shape.id])
if (!bounds) return null
return (
<>
<div onPointerDown={handleLabelPointerDown} className="slide-shape-label">
{`Slide ${index + 1}`}
</div>
<SVGContainer>
<g
style={{
stroke: 'var(--color-text)',
strokeWidth: 'calc(1px * var(--tl-scale))',
opacity: 0.25,
}}
pointerEvents="none"
strokeLinecap="round"
strokeLinejoin="round"
>
{bounds.sides.map((side, i) => {
const { strokeDasharray, strokeDashoffset } = getPerfectDashProps(
side[0].dist(side[1]),
1 / zoomLevel,
{
style: 'dashed',
lengthRatio: 6,
}
)
return (
<line
key={i}
x1={side[0].x}
y1={side[0].y}
x2={side[1].x}
y2={side[1].y}
strokeDasharray={strokeDasharray}
strokeDashoffset={strokeDashoffset}
/>
)
})}
</g>
</SVGContainer>
</>
)
}
indicator(shape: SlideShape) {
return <rect width={shape.props.w} height={shape.props.h} />
}
}

Wyświetl plik

@ -0,0 +1,109 @@
import {
DefaultKeyboardShortcutsDialog,
DefaultKeyboardShortcutsDialogContent,
DefaultToolbar,
DefaultToolbarContent,
TLComponents,
TLUiOverrides,
Tldraw,
TldrawUiMenuItem,
computed,
track,
useIsToolSelected,
useTools,
} from 'tldraw'
import 'tldraw/tldraw.css'
import { SlideShapeTool } from './SlideShapeTool'
import { SlideShapeUtil } from './SlideShapeUtil'
import { SlidesPanel } from './SlidesPanel'
import './slides.css'
import { $currentSlide, getSlides, moveToSlide } from './useSlides'
const components: TLComponents = {
HelperButtons: SlidesPanel,
Minimap: null,
Toolbar: (props) => {
const tools = useTools()
const isSlideSelected = useIsToolSelected(tools['slide'])
return (
<DefaultToolbar {...props}>
<TldrawUiMenuItem {...tools['slide']} isSelected={isSlideSelected} />
<DefaultToolbarContent />
</DefaultToolbar>
)
},
KeyboardShortcutsDialog: (props) => {
const tools = useTools()
return (
<DefaultKeyboardShortcutsDialog {...props}>
<TldrawUiMenuItem {...tools['slide']} />
<DefaultKeyboardShortcutsDialogContent />
</DefaultKeyboardShortcutsDialog>
)
},
}
const overrides: TLUiOverrides = {
actions(editor, actions) {
const $slides = computed('slides', () => getSlides(editor))
return {
...actions,
'next-slide': {
id: 'next-slide',
label: 'Next slide',
kbd: 'right',
onSelect() {
const slides = $slides.get()
const currentSlide = $currentSlide.get()
const index = slides.findIndex((s) => s.id === currentSlide?.id)
const nextSlide = slides[index + 1] ?? currentSlide ?? slides[0]
if (nextSlide) {
editor.stopCameraAnimation()
moveToSlide(editor, nextSlide)
}
},
},
'previous-slide': {
id: 'previous-slide',
label: 'Previous slide',
kbd: 'left',
onSelect() {
const slides = $slides.get()
const currentSlide = $currentSlide.get()
const index = slides.findIndex((s) => s.id === currentSlide?.id)
const previousSlide = slides[index - 1] ?? currentSlide ?? slides[slides.length - 1]
if (previousSlide) {
editor.stopCameraAnimation()
moveToSlide(editor, previousSlide)
}
},
},
}
},
tools(editor, tools) {
tools.slide = {
id: 'slide',
icon: 'group',
label: 'Slide',
kbd: 's',
onSelect: () => editor.setCurrentTool('slide'),
}
return tools
},
}
const SlidesExample = track(() => {
return (
<div className="tldraw__editor">
<Tldraw
persistenceKey="slideshow_example"
shapeUtils={[SlideShapeUtil]}
tools={[SlideShapeTool]}
components={components}
overrides={overrides}
/>
</div>
)
})
export default SlidesExample

Wyświetl plik

@ -0,0 +1,32 @@
import { TldrawUiButton, stopEventPropagation, track, useEditor, useValue } from 'tldraw'
import { moveToSlide, useCurrentSlide, useSlides } from './useSlides'
export const SlidesPanel = track(() => {
const editor = useEditor()
const slides = useSlides()
const currentSlide = useCurrentSlide()
const selectedShapes = useValue('selected shapes', () => editor.getSelectedShapes(), [editor])
if (slides.length === 0) return null
return (
<div className="slides-panel scroll-light" onPointerDown={(e) => stopEventPropagation(e)}>
{slides.map((slide, i) => {
const isSelected = selectedShapes.includes(slide)
return (
<TldrawUiButton
key={'slides-panel-button:' + slide.id}
type="normal"
className="slides-panel-button"
onClick={() => moveToSlide(editor, slide)}
style={{
background: currentSlide?.id === slide.id ? 'var(--color-background)' : 'transparent',
outline: isSelected ? 'var(--color-selection-stroke) solid 1.5px' : 'none',
}}
>
{`Slide ${i + 1}`}
</TldrawUiButton>
)
})}
</div>
)
})

Wyświetl plik

@ -0,0 +1,32 @@
.slides-panel {
display: flex;
flex-direction: column;
gap: 4px;
max-height: calc(100% - 110px);
margin: 50px 0px;
padding: 4px;
background-color: var(--color-low);
pointer-events: all;
border-top-right-radius: var(--radius-4);
border-bottom-right-radius: var(--radius-4);
overflow: auto;
border-right: 2px solid var(--color-background);
border-bottom: 2px solid var(--color-background);
border-top: 2px solid var(--color-background);
}
.slides-panel-button {
border-radius: var(--radius-4);
outline-offset: -1px;
}
.slide-shape-label {
pointer-events: all;
position: absolute;
background: var(--color-low);
padding: calc(12px * var(--tl-scale));
border-bottom-right-radius: calc(var(--radius-4) * var(--tl-scale));
font-size: calc(12px * var(--tl-scale));
color: var(--color-text);
white-space: nowrap;
}

Wyświetl plik

@ -0,0 +1,28 @@
import { EASINGS, Editor, atom, useEditor, useValue } from 'tldraw'
import { SlideShape } from './SlideShapeUtil'
export const $currentSlide = atom<SlideShape | null>('current slide', null)
export function moveToSlide(editor: Editor, slide: SlideShape) {
const bounds = editor.getShapePageBounds(slide.id)
if (!bounds) return
$currentSlide.set(slide)
editor.selectNone()
editor.zoomToBounds(bounds, { duration: 500, easing: EASINGS.easeInOutCubic, inset: 0 })
}
export function useSlides() {
const editor = useEditor()
return useValue<SlideShape[]>('slide shapes', () => getSlides(editor), [editor])
}
export function useCurrentSlide() {
return useValue($currentSlide)
}
export function getSlides(editor: Editor) {
return editor
.getSortedChildIdsForParent(editor.getCurrentPageId())
.map((id) => editor.getShape(id))
.filter((s) => s?.type === 'slide') as SlideShape[]
}

Wyświetl plik

@ -1,6 +1,8 @@
import { Tldraw } from 'tldraw'
import { TLStoreSnapshot, Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
import jsonSnapshot from './snapshot.json'
import _jsonSnapshot from './snapshot.json'
const jsonSnapshot = _jsonSnapshot as TLStoreSnapshot
// There's a guide at the bottom of this file!

Wyświetl plik

@ -1,4 +1,3 @@
import { ShapePropsType } from '@tldraw/tlschema/src/shapes/TLBaseShape'
import {
DefaultColorStyle,
DefaultFontStyle,
@ -9,6 +8,7 @@ import {
Geometry2d,
LABEL_FONT_SIZES,
Polygon2d,
ShapePropsType,
ShapeUtil,
T,
TEXT_PROPS,
@ -20,11 +20,11 @@ import {
TextLabel,
Vec,
ZERO_INDEX_KEY,
getDefaultColorTheme,
resizeBox,
structuredClone,
vecModelValidator,
} from 'tldraw'
import { useDefaultColorTheme } from 'tldraw/src/lib/shapes/shared/ShapeFill'
import { getSpeechBubbleVertices, getTailIntersectionPoint } from './helpers'
// Copied from tldraw/tldraw
@ -176,11 +176,11 @@ export class SpeechBubbleUtil extends ShapeUtil<SpeechBubbleShape> {
type,
props: { color, font, size, align, text },
} = shape
const theme = getDefaultColorTheme({
isDarkMode: this.editor.user.getIsDarkMode(),
})
const vertices = getSpeechBubbleVertices(shape)
const pathData = 'M' + vertices[0] + 'L' + vertices.slice(1) + 'Z'
const isSelected = shape.id === this.editor.getOnlySelectedShapeId()
// eslint-disable-next-line react-hooks/rules-of-hooks
const theme = useDefaultColorTheme()
return (
<>
@ -192,7 +192,6 @@ export class SpeechBubbleUtil extends ShapeUtil<SpeechBubbleShape> {
fill={'none'}
/>
</svg>
<TextLabel
id={id}
type={type}
@ -202,7 +201,8 @@ export class SpeechBubbleUtil extends ShapeUtil<SpeechBubbleShape> {
align={align}
verticalAlign="start"
text={text}
labelColor={color}
labelColor={theme[color].solid}
isSelected={isSelected}
wrap
/>
</>

Wyświetl plik

@ -0,0 +1,12 @@
---
title: Tool with child states
component: ./ToolWithChildStatesExample.tsx
category: shapes/tools
priority: 2
---
You can implement more complex behaviour in a custom tool by using child states
---
Tools are nodes in tldraw's state machine. They are responsible for handling user input. You can create custom tools by extending the StateNode class and overriding its methods. In this example we expand on the sticker tool from the custom tool example to show how to create a tool that can handle more complex interactions by using child states.

Wyświetl plik

@ -0,0 +1,258 @@
import {
StateNode,
TLEventHandlers,
TLShapePartial,
TLTextShape,
Tldraw,
createShapeId,
} from 'tldraw'
import 'tldraw/tldraw.css'
// There's a guide at the bottom of this file!
const OFFSET = -12
// [1]
class StickerTool extends StateNode {
static override id = 'sticker'
static override initial = 'idle'
static override children = () => [Idle, Pointing, Dragging]
}
// [2]
class Idle extends StateNode {
static override id = 'idle'
//[a]
override onEnter = () => {
this.editor.setCursor({ type: 'cross' })
}
//[b]
override onPointerDown: TLEventHandlers['onPointerDown'] = (info) => {
const { editor } = this
switch (info.target) {
case 'canvas': {
const hitShape = editor.getShapeAtPoint(editor.inputs.currentPagePoint)
if (hitShape) {
this.onPointerDown({
...info,
shape: hitShape,
target: 'shape',
})
return
}
this.parent.transition('pointing', { shape: null })
break
}
case 'shape': {
if (editor.inputs.shiftKey) {
editor.updateShape({
id: info.shape.id,
type: 'text',
props: { text: '👻 boo!' },
})
} else {
this.parent.transition('pointing', { shape: info.shape })
}
break
}
}
}
//[c]
override onDoubleClick: TLEventHandlers['onDoubleClick'] = (info) => {
const { editor } = this
if (info.phase !== 'up') return
switch (info.target) {
case 'canvas': {
const hitShape = editor.getShapeAtPoint(editor.inputs.currentPagePoint)
if (hitShape) {
this.onDoubleClick({
...info,
shape: hitShape,
target: 'shape',
})
return
}
const { currentPagePoint } = editor.inputs
editor.createShape({
type: 'text',
x: currentPagePoint.x + OFFSET,
y: currentPagePoint.y + OFFSET,
props: { text: '❤️' },
})
break
}
case 'shape': {
editor.deleteShapes([info.shape.id])
break
}
}
}
}
// [3]
class Pointing extends StateNode {
static override id = 'pointing'
private shape: TLTextShape | null = null
override onEnter = (info: { shape: TLTextShape | null }) => {
this.shape = info.shape
}
override onPointerUp: TLEventHandlers['onPointerUp'] = () => {
this.parent.transition('idle')
}
override onPointerMove: TLEventHandlers['onPointerMove'] = () => {
if (this.editor.inputs.isDragging) {
this.parent.transition('dragging', { shape: this.shape })
}
}
}
// [4]
class Dragging extends StateNode {
static override id = 'dragging'
// [a]
private shape: TLShapePartial | null = null
private emojiArray = ['❤️', '🔥', '👍', '👎', '😭', '🤣']
// [b]
override onEnter = (info: { shape: TLShapePartial }) => {
const { currentPagePoint } = this.editor.inputs
const newShape = {
id: createShapeId(),
type: 'text',
x: currentPagePoint.x + OFFSET,
y: currentPagePoint.y + OFFSET,
props: { text: '❤️' },
}
if (info.shape) {
this.shape = info.shape
} else {
this.editor.createShape(newShape)
this.shape = { ...newShape }
}
}
//[c]
override onPointerUp: TLEventHandlers['onPointerUp'] = () => {
this.parent.transition('idle')
}
//[d]
override onPointerMove: TLEventHandlers['onPointerUp'] = () => {
const { shape } = this
const { originPagePoint, currentPagePoint } = this.editor.inputs
const distance = originPagePoint.dist(currentPagePoint)
if (shape) {
this.editor.updateShape({
id: shape.id,
type: 'text',
props: {
text: this.emojiArray[Math.floor(distance / 20) % this.emojiArray.length],
},
})
}
}
}
// [5]
const customTools = [StickerTool]
export default function ToolWithChildStatesExample() {
return (
<div className="tldraw__editor">
<Tldraw
// Pass in the array of custom tool classes
tools={customTools}
// Set the initial state to the sticker tool
initialState="sticker"
// hide the ui
hideUi
// Put some helpful text on the canvas
onMount={(editor) => {
editor.createShape({
type: 'text',
x: 50,
y: 50,
props: {
text: '-Double click the canvas to add a sticker\n-Double click a sticker to delete it\n-Click and drag on a sticker to change it\n-Click and drag on the canvas to create a sticker\n-Shift click a sticker for a surprise!',
size: 's',
align: 'start',
},
})
}}
/>
</div>
)
}
/*
Introduction:
Tools are nodes in tldraw's state machine. They are responsible for handling user input.
You can create custom tools by extending the `StateNode` class and overriding its
methods. In this example we expand on the sticker tool from the custom tool example to
show how to create a tool that can handle more complex interactions by using child states.
[1]
This is our custom tool. It has three child states: `Idle`, `Pointing`, and `Dragging`.
We need to define the `id` and `initial` properties, the id is a unique string that
identifies the tool to the editor, and the initial property is the initial state of the
tool. We also need to define a `children` method that returns an array of the tool's
child states.
[2]
This is our Idle state. It is the initial state of the tool. It's job is to figure out
what the user is trying to do and transition to the appropriate state. When transitioning
between states we can use the second argument to pass data to the new state. It has three
methods:
[a] `onEnter`
When entering any state, the `onEnter` method is called. In this case, we set the cursor to
a crosshair.
[b] `onPointerDown`
This method is called when the user presses the mouse button. The target parameter is always
the canvas, so we can use an editor method to check if we're over a shape, and call the
method again with the shape as the target. If we are over a shape, we transition to the
`pointing` state with the shape in the info object. If we're over a shape and holding the
shift key, we update the shape's text. If we're over the canvas, we transition to the
`pointing` state with a null shape in the info object.
[c] `onDoubleClick`
This method is called when the user double clicks the mouse button. We're using some similar
logic here to check if we're over a shape, and if we are, we delete it. If we're over the canvas,
we create a new shape.
[3]
This is our `Pointing` state. It's a transitionary state, we use it to store the shape we're pointing
at, and transition to the dragging state if the user starts dragging. It has three methods:
[a] `onEnter`
When entering this state, we store the shape we're pointing at by getting it from the info object.
[b] `onPointerUp`
This method is called when the user releases the mouse button. We transition to the `idle` state.
[c] `onPointerMove`
This method is called when the user moves the mouse. If the user starts dragging, we transition to
the `dragging` state and pass the shape we're pointing at.
[4]
This is our `Dragging` state. It's responsible for creating and updating the shape that the user is
dragging.
[a] `onEnter`
When entering this state, we create a new shape if we're not dragging an existing one. If we are,
we store the shape we're dragging.
[b] `onPointerUp`
This method is called when the user releases the mouse button. We transition to the `idle` state.
[c] `onPointerMove`
This method is called when the user moves the mouse. We use the distance between the origin and
current mouse position to cycle through an array of emojis and update the shape's text.
[5]
We pass our custom tool to the `Tldraw` component as an array. We also set the initial state to our
custom tool. For the purposes of this demo, we're also hiding the UI and adding some helpful text to
the canvas.
*/

Wyświetl plik

@ -21,7 +21,7 @@ setDefaultEditorAssetUrls(assetUrls)
setDefaultUiAssetUrls(assetUrls)
const gettingStartedExamples = examples.find((e) => e.id === 'Getting started')
if (!gettingStartedExamples) throw new Error('Could not find getting started exmaples')
const basicExample = gettingStartedExamples.value.find((e) => e.title === 'Persistence key')
const basicExample = gettingStartedExamples.value.find((e) => e.title === 'Tldraw component')
if (!basicExample) throw new Error('Could not find initial example')
const router = createBrowserRouter([

Wyświetl plik

@ -1,3 +1,21 @@
## 2.0.30
- Fixes a bug that prevented opening some files.
## 2.0.29
- Improved note shapes.
- Color improvements for both light and dark mode.
- Bug fixes and performance improvements.
## 2.0.28
- Fix an issue with panning the canvas.
## 2.0.27
- Bug fixes and performance improvements.
## 2.0.26
- Bug fixes and performance improvements.

Wyświetl plik

@ -1,7 +1,7 @@
{
"name": "tldraw-vscode",
"description": "The tldraw extension for VS Code.",
"version": "2.0.26",
"version": "2.0.30",
"private": true,
"author": {
"name": "tldraw Inc.",

Wyświetl plik

@ -1,3 +1,4 @@
<svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.8539 0.315423C24.2744 -0.105141 24.9563 -0.105141 25.3769 0.315423L29.6846 4.62312C30.1051 5.04368 30.1051 5.72555 29.6846 6.14612L21.1928 14.6379C21.0291 14.8016 20.84 14.9379 20.633 15.0414L12.1739 19.2709C11.7593 19.4782 11.2585 19.397 10.9308 19.0692C10.603 18.7414 10.5217 18.2407 10.729 17.8261L14.9586 9.367C15.0621 9.15995 15.1984 8.97093 15.362 8.80723L23.8539 0.315423ZM24.6154 2.59992L16.8851 10.3302L14.6488 14.8027L15.1973 15.3511L19.6697 13.1149L27.4001 5.38462L24.6154 2.59992ZM19.2308 2.15384L17.0769 4.30769H8.24617C7.32369 4.30769 6.69661 4.30853 6.2119 4.34813C5.73976 4.38671 5.4983 4.45663 5.32987 4.54245C4.9246 4.74894 4.5951 5.07844 4.38861 5.48371C4.30279 5.65214 4.23287 5.89359 4.19429 6.36573C4.15469 6.85044 4.15385 7.47753 4.15385 8.4V21.7538C4.15385 22.6763 4.15469 23.3034 4.19429 23.7881C4.23287 24.2603 4.30279 24.5017 4.38861 24.6701C4.5951 25.0754 4.9246 25.4049 5.32987 25.6114C5.4983 25.6972 5.73976 25.7671 6.2119 25.8057C6.69661 25.8453 7.32369 25.8462 8.24617 25.8462H21.6C22.5225 25.8462 23.1496 25.8453 23.6343 25.8057C24.1064 25.7671 24.3479 25.6972 24.5163 25.6114C24.9216 25.4049 25.2511 25.0754 25.4576 24.6701C25.5434 24.5017 25.6133 24.2603 25.6519 23.7881C25.6915 23.3034 25.6923 22.6763 25.6923 21.7538V12.923L27.8462 10.7692V21.7538V21.7983C27.8462 22.6652 27.8462 23.3807 27.7986 23.9635C27.7491 24.5688 27.643 25.1253 27.3767 25.648C26.9637 26.4585 26.3047 27.1175 25.4941 27.5305C24.9715 27.7968 24.415 27.9029 23.8097 27.9524C23.2269 28 22.5114 28 21.6445 28H21.6H8.24617H8.20166C7.33478 28 6.61932 28 6.0365 27.9524C5.43117 27.9029 4.87472 27.7968 4.35205 27.5305C3.5415 27.1175 2.88251 26.4585 2.46951 25.648C2.2032 25.1253 2.09705 24.5688 2.0476 23.9635C1.99998 23.3807 1.99999 22.6652 2 21.7984V21.7983V21.7538V8.4V8.35552V8.35546V8.35545C1.99999 7.48859 1.99998 6.77315 2.0476 6.19034C2.09705 5.585 2.2032 5.02855 2.46951 4.50589C2.88251 3.69534 3.5415 3.03635 4.35205 2.62336C4.87472 2.35704 5.43117 2.2509 6.0365 2.20144C6.61932 2.15382 7.33476 2.15383 8.20163 2.15384H8.20169H8.24617H19.2308Z" fill="black"/>
<path d="M17 27V19C17 17.8954 17.8954 17 19 17H27" stroke="black" stroke-width="2"/>
<path d="M17.5789 26.45L26.3775 18.0914C26.775 17.7138 27 17.1896 27 16.6414V5C27 3.89543 26.1046 3 25 3H5C3.89543 3 3 3.89543 3 5V25C3 26.1046 3.89543 27 5 27H16.2014C16.7141 27 17.2072 26.8031 17.5789 26.45Z" stroke="black" stroke-width="2"/>
</svg>

Przed

Szerokość:  |  Wysokość:  |  Rozmiar: 2.2 KiB

Po

Szerokość:  |  Wysokość:  |  Rozmiar: 433 B

Wyświetl plik

@ -111,6 +111,7 @@
"action.zoom-to-selection": "Zoom to selection",
"assets.files.upload-failed": "Upload failed",
"assets.url.failed": "Couldn't load URL preview",
"color-style.white": "White",
"color-style.black": "Black",
"color-style.blue": "Blue",
"color-style.green": "Green",

Wyświetl plik

@ -21,7 +21,7 @@ module.exports = {
},
],
},
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$',
testRegex: '.+\\.(test|spec)\\.(jsx?|tsx?)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
modulePathIgnorePatterns: [
'<rootDir>/test/__fixtures__',

Wyświetl plik

@ -11,6 +11,10 @@ import { TextDecoder, TextEncoder } from 'util'
global.TextEncoder = TextEncoder
global.TextDecoder = TextDecoder
Image.prototype.decode = async function () {
return true
}
function convertNumbersInObject(obj: any, roundToNearest: number) {
if (!obj) return obj
if (Array.isArray(obj)) {

Wyświetl plik

@ -71,7 +71,7 @@
]
},
"devDependencies": {
"@microsoft/api-extractor": "^7.41.0",
"@microsoft/api-extractor": "^7.43.1",
"@next/eslint-plugin-next": "^13.3.0",
"@swc/core": "^1.3.55",
"@swc/jest": "^0.2.34",
@ -96,6 +96,7 @@
"jest": "30.0.0-alpha.2",
"json5": "^2.2.3",
"lazyrepo": "0.0.0-alpha.27",
"license-report": "^6.5.0",
"lint-staged": ">=10",
"prettier": "^3.0.3",
"prettier-plugin-organize-imports": "^3.2.3",

Some files were not shown because too many files have changed in this diff Show More