When we went from overrides-based to component based UI customisation
APIs, we didn't do the toolbar because it had some significant extra
complexity around overflowing the contents of the menu into the
dropdown. This is really hard to do at render-time with react - you
can't introspect what a component will return to move some of it into an
overflow.
Instead, this diff runs that logic in a `useLayoutEffect` - we render
all the items into both the main toolbar and the overflow menu, then in
the effect (or if the rendered components change) we use CSS to remove
the items we don't need, check which was last active, etc. Originally, I
wasn't really into this approach - but i've actually found it to work
super well and be very reliable.
### Change Type
- [x] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Test the toolbar at many different sizes with many different 'active
tools'
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Use the Readme and bg color of elements to make it clearer which menu is
being customised.
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- Add a brief release note for your PR here.
This PR:
- adds the export all menu items to the main menu
- removes the export all menu items from the dotcom menus
- removes the shape menu and reverts several changes from
https://github.com/tldraw/tldraw/pull/2782. This was not properly
reviewed (I thought it was a PR about hiding / showing menu items).
- fixes a bug with exporting (exporting JSON was not working when the
user had no selected shapes)
- fixes a bug that would prevent "flip shapes" from appearing in the
menu
- prevents export / copy actions from running if there are no shapes on
the page
- allows export / copy actions to default to all shapes on the page if
no shapes are selected
These changes have not been released in the dotcom yet. There's will be
some thrash in the APIs.
# Menu philosophy
In the menu, the **edit** submenu relates to undo/redo, plus the user's
current selection.
Menu items that relate to specific to certain shapes are hidden when not
available.
Menu items that relate to all shapes are disabled when not available.
<img width="640" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/e467e6bb-d958-4a9a-ac19-1dada52dcfa6">
### Change Type
- [x] `major` — Bug fix
### Test
- Select no shapes (arrange / flip should not be visible)
- Select one geo shape (arrange / flip should not be visible)
- Select two geo shapes (arrange / flip should be visible)
- Select one draw shape (arrange / flip should not be visible)
### Release Notes
- Revert some changes in the menu.
Before this PR all .md files were targeted by the `.ignore` file, which
has bitten me on a number of occasions since .md files often contain
valuable information (e.g. the vscode extensions docs). This PR
unignores .md files while still ignoring _generated_ .md files like our
changelogs, the api-report files, and the generated docs sections.
Additionally, the `yarn format` and `yarn lint` commands were configured
slightly differently, which was confusing, so I've unified those and
simplified the lint.ts script at the same time.
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [x] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
This PR does a few things to help with performance:
1. Instead of doing changes on raf we now do them 60 times per second.
This limits the number of updates on high refresh rate screens like the
iPad. With the current code this only applied to the history updates (so
when you subscribed to the updates), but the next point takes this a bit
futher.
2. We now trigger react updates 60 times per second. This is a change in
`useValue` and `useStateTracking` hooks.
3. We now throttle the inputs (like the `pointerMove`) in state nodes.
This means we batch multiple inputs and only apply them at most 60 times
per second.
We had to adjust our own tests to pass after this change so I marked
this as major as it might require the users of the library to do the
same.
Few observations:
- The browser calls the raf callbacks when it can. If it gets
overwhelmed it will call them further and further apart. As things call
down it will start calling them more frequently again. You can clearly
see this in the drawing example. When fps gets to a certain level we
start to get fewer updates, then fps can recover a bit. This makes the
experience quite janky. The updates can be kinda ok one second (dropping
frames, but consistently) and then they can completely stop and you have
to let go of the mouse to make them happen again. With the new logic it
seems everything is a lot more consistent.
- We might look into variable refresh rates to prevent this overtaxing
of the browser. Like when we see that the times between our updates are
getting higher we could make the updates less frequent. If we then see
that they are happening more often we could ramp them back up. I had an
[experiment for this
here](4834863966 (diff-318e71563d7c47173f89ec084ca44417cf70fc72faac85b96f48b856a8aec466L30-L35)).
Few tests below. Used 6x slowdown for these.
# Resizing
### Before
https://github.com/tldraw/tldraw/assets/2523721/798a033f-5dfa-419e-9a2d-fd8908272ba0
### After
https://github.com/tldraw/tldraw/assets/2523721/45870a0c-c310-4be0-b63c-6c92c20ca037
# Drawing
Comparison is not 100% fair, we don't store the intermediate inputs
right now. That said, tick should still only produce once update so I do
think we can get a sense of the differences.
### Before
https://github.com/tldraw/tldraw/assets/2523721/2e8ac8c5-bbdf-484b-bb0c-70c967f4541c
### After
https://github.com/tldraw/tldraw/assets/2523721/8f54b7a8-9a0e-4a39-b168-482caceb0149
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [x] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Release Notes
- Improves the performance of rendering.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Adds an example of how to add migrations for a custom shape.
closes tld-2246
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- Adds a shape with migrations example
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Describe what your pull request does. If appropriate, add GIFs or images
showing the before and after.
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [x] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
Look at the revised documentation
### Release Notes
N/A
Two examples:
One in the UI section that shows how to add a tool to the toolbar along
with an icon
One in the shapes and tools section that shows a simple sticker tool
with no child states
I'll go over the copy again before it's merged, but don't want to spend
too long on it right now in case the feeling is that these should both
be a single example.
Next: The [minimal
example](https://tldraw.dev/examples/editor-api/only-editor) is
currently the best example we have of a tool with child states. I think
this should be adapted and copied/moved over to the custom shapes and
tools category.
closes tld-2266
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- Adds a simple custom tool example
This PR provides some safe wrappers for local storage calls. Local
storage is not available in all environments (for example, a React
Native web view). The PR also adds an eslint rule preventing direct
calls to local / session storage.
### Change Type
- [x] `patch` — Bug fix
### Release Notes
- Fixes a bug that could cause crashes in React Native webviews.
This PR:
- adds a simple custom shape example
- adds an interactive shape example
- updates editable shape example
closes TLD-2118
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- adds a simple custom shape example
- adds an interactive shape example
- updates editable shape example
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Adds an example of how to use tldraw styles in a custom shape
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- shape with tldraw styles example
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR updates our end to end tests so that they check every route in
our examples to ensure that it loads (skipping any routes that don't
features a canvas).
### Change Type
- [x] `tests` — Changes to any test code only[^2]
### Test Plan
- [x] End to end tests
This PR adds a custom selection UI example.
![Kapture 2024-03-01 at 14 02
25](https://github.com/tldraw/tldraw/assets/23072548/039cc6ab-17b9-4bc3-8c05-ad3ce788a5d3)
It also fixes a bug with pageToScreen and adds a
`getSelectionRotatedScreenBounds` method.
### Change Type
- [ ] `patch` — Bug fix
- [x] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Release Notes
- Adds selection UI example.
- Adds `Editor.getSelectionRotatedScreenBounds` method
- Fixes a bug with `pageToScreen`.
Rename `@tldraw/tldraw` to just `tldraw`! `@tldraw/tldraw` still exists
as an alias to `tldraw` for folks who are still using that.
### Test Plan
- [x] Unit Tests
- [ ] End to end tests
### Release Notes
- The `@tldraw/tldraw` package has been renamed to `tldraw`. You can
keep using the old version if you want though!
This PR removes code that would add a reference to the editor to the
window. This is a feature that we added very early on during testing,
but which we should have moved out of the library earlier. Adding it
here as one of our last PRs before release.
If you've relied on this, you'll need to update your use of the library
to do it manually:
```ts
<Tldraw onMount={(editor) => {
;(window as any).app = editor
;(window as any).editor = editor
}}/>
```
### Change Type
- [x] `major` — Breaking change
### Release Notes
- Remove `window.editor` and `window.app` references to editor.
A basic test for each of the menu areas
fixes TLD-2251
- [x] `tests` — Changes to any test code only[^2]
### Release Notes
- Add a brief release note for your PR here.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR adds an example that shows you how to make your dialogs pop
outside of the Tldraw component and go fullscreen.
Closes TLD-2191
### Change Type
- [x] `documentation` — Changes to the documentation only[^2]
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Try out the "External dialog" example.
2. Open the keyboard shortcuts dialog (or any dialog).
3. The dialog should be centered in the browser window, not just the
tldraw component.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Dev: Added an example for dialogs that go outside the component.
Handle's days are numbered, and in the line shape we've moved away from
storing `TLHandle` directly. This diff updates the speech bubble shape
to rename the 'handle' prop to 'tail' and make it just be the
coordinates. The handle props are derived at runtime.
### Change Type
- [x] `documentation` — Changes to the documentation only[^2]
The log statements in this were confusing me when I was inspecting style
changes the other day because when you changed some value from A
(before) to B (after) it only logged out the A value. I tried
experimenting with logging both A and B but it didn't feel necessary,
switching to only B feels fine.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package[^2]
This PR adds an example for how to add external UI components.
It's something that I've been asked for help with in the past, and it's
something I wish more consumers would do when using tldraw inline - it
would help the editor feel less cramped. Therefore, I'd like to have it
is as an example we can point people to.
![2024-02-19 at 11 53 18 - Maroon
Boar](https://github.com/tldraw/tldraw/assets/15892272/f043bb77-3181-4a7d-b736-2b6a5012e208)
> Some other context:
> We've talked about giving this sorta thing more first-class support in
the future, eg: with a `useEditorInstance` hook or something.
Closes TLD-2128
### Change Type
- [x] `documentation` — Changes to the documentation only[^2]
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Try out the External UI example.
2. Make sure you can change tool by pressing the toolbar buttons.
3. Make sure you can change tool by pressing keys (eg: d, e)
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Docs: Added external UI example.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR moves the focus
### Change Type
- [x] `minor`
### Test Plan
1. Select an element.
2. Press the delete quick action menu button.
3. Undo the delete with a keyboard shortcut.
1. Create a geo shape
2. Use the style panel to change the geo type
3. Undo so that it deletes
4. Try to redo
### Release Notes
- [Fix] Keyboard shortcut focus bug
---------
Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
This PR adds E2E tests for the style panel.
It checks that:
- the style panel opens and closes as expected on mobile
- the style panel button is disabled for the eraser tool on mobile
- selecting a style hints the button
- changing a style changes the appearance of the shape
- It also moves a test from the toolbar tests that checks the correct
styles are exposed for the right tools
fixes tld-2222
- [x] `tests` — Changes to any test code only[^2]
### Release Notes
- Add style panel E2E tests
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
This PR adds a custom static assets example.
It also:
- extracts preloadFont into a async function to make custom preloading
easier
- accounts for file-based formats
### Change Type
- [x] `minor` — New feature
### Test Plan
1. Test the example.
### Release Notes
- Docs, added custom static assets example.
This PR adds an example of how to use the new getBoundsSnapGeometry
method to get custom snapping behaviour on your shapes.
![2024-02-21 at 15 58 23 - Purple
Bovid](https://github.com/tldraw/tldraw/assets/98838967/8d7e73bb-ea29-45f6-98ed-141a8ce17065)
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- Adds a custom bounds snapping shape
This PR fixes and improves the appearance on dialogs on small tldraw
components, eg: Inline components.
Fixes TLD-2232
![image](https://github.com/tldraw/tldraw/assets/15892272/0fae3be9-4a52-45f3-a107-529e101aa4bd)
![image](https://github.com/tldraw/tldraw/assets/15892272/eb0ad67f-b390-4738-885a-65c968d7c989)
![image](https://github.com/tldraw/tldraw/assets/15892272/24946c06-4762-4e51-8113-797be2203f79)
![image](https://github.com/tldraw/tldraw/assets/15892272/0d646044-c8a5-4b05-9530-5f3758767d0d)
Marking as minor instead of patch because it adds a new prop to
`TldrawUiKbd`.
### Change Type
- [ ] `patch` — Bug fix
- [x] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Open the "Inset editor" example.
2. Open the keyboard shortcuts dialog.
3. Shrink the window down.
4. Make sure the dialog remains visible at all window sizes.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Dev: Made default dialogs work better when used in small components.
Closes#2800
This PR makes it so that `check-scripts` will error out if you forget to
add a "references" entry to a tsconfig file when adding an internal
dependency in our monorepo.
If these project references are missed it can prevent TS from
building/rebuilding things when they need to be built/rebuilt.
### Change Type
- [x] `internal` — Any other changes that don't affect the published
package[^2]
This PR fixes the custom keyboard shortcut dialog example.
Previously, the custom menu item wasn't appearing in the menu because it
didn't have a shortcut associated with it. (we filter out any actions
without one).
I fixed it by adding a smiley face. I tried adding a real shortcut, but
I think it made the example too complicated. So I decided on a fake
smiley face instead! After all, the example is demonstrating how to
customise the UI, not how to add an action.
![image](https://github.com/tldraw/tldraw/assets/15892272/e521c603-9978-439b-8f51-684c2e2d3f97)
### Change Type
- [x] `documentation` — Changes to the documentation only[^2]
- [x] `internal` — Any other changes that don't affect the published
package[^2]
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Open the custom keyboard shortcuts dialog example.
2. Open the keyboard shortcuts menu.
3. Check that it says "Like my posts" in the dialog.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Docs: Fixed custom keyboard shortcut dialog example.
This PR converts all example titles and categories to sentence case, to
make them consistent with our UI and the other examples.
### Change Type
- [x] `documentation` — Changes to the documentation only[^2]
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Look at the examples app.
2. Check that all the titles of examples make you feel calm and good
inside.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Docs: Made the examples titles sentence case.
This PR adds a validation mode whereby previous known-to-be-valid values
can be used to speed up the validation process itself. At the same time
it enables us to do fine-grained equality checking on records much more
quickly than by using something like lodash isEqual, and using that we
can prevent triggering effects for record updates that don't actually
alter any values in the store.
Here's some preliminary perf testing of average time spent in
`store.put()` during some common interactions
| task | before (ms) | after (ms) |
| ---- | ---- | ---- |
| drawing lines | 0.0403 | 0.0214 |
| drawing boxes | 0.0408 | 0.0348 |
| translating lines | 0.0352 | 0.0042 |
| translating boxes | 0.0051 | 0.0032 |
| rotating lines | 0.0312 | 0.0065 |
| rotating boxes | 0.0053 | 0.0035 |
| brush selecting boxes | 0.0200 | 0.0232 |
| traversal with shapes | 0.0130 | 0.0108 |
| traversal without shapes | 0.0201 | 0.0173 |
**traversal** means moving the camera and pointer around the canvas
#### Discussion
At the scale of hundredths of a millisecond these .put operations are so
fast that even if they became literally instantaneous the change would
not be human perceptible. That said, there is an overall marked
improvement here. Especially for dealing with draw shapes.
These figures are also mostly in line with expectations, aside from a
couple of things:
- I don't understand why the `brush selecting boxes` task got slower
after the change.
- I don't understand why the `traversal` tasks are slower than the
`translating boxes` task, both before and after. I would expect that
.putting shape records would be much slower than .putting pointer/camera
records (since the latter have fewer and simpler properties)
### Change Type
- [x] `patch` — Bug fix
### 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.
This PR adds an example for an editable shape. I wanted to show the
onEditEnd method so I just made the shape do a little wiggle.
Closes#2592
### Change Type
- [x] `documentation` — Changes to the documentation only[^2]
### Release Notes
- Adds an editable shape example
This one is a roundup of superficial changes, apologies for having them
in a single PR.
This PR:
- does some chair re-arranging for one of our hotter paths related to
updating shapes
- changes our type exports for editor components
- adds shape indicator to editor components
- moves canvas to be an editor component
- fixes a CSS bug with hinted buttons
- fixes CSS bugs with the menus
- fixes bad imports in examples
### Change Type
- [x] `major`
Adds the ability to change document names in the top center part of the
UI. This mostly brings back the functionality we already had in the
past.
This is basically a port of what @SomeHats did a while back. I changed
the dropdown options and removed some of the things (we are not dealing
with network requests directly so some of that logic did not apply any
longer). We did have autosave back then, not sure if we want to bring
that back?
Changes the `exportAs` api, thus braking.
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [x] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Top center should now show a new UI element. It has a dropdown with a
few actions.
2. Double clicking the name should also start editing it.
3. The name should also be respected when exporting things. Not if you
select some shapes or a frame. In that case we still use the old names.
But if you don't have anything selected and then export / save a project
it should have the document name.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Allow users to name their documents.
fix typo in examples
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [x] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Release Notes
- fix typo in examples
This PR adds some e2e tests for the toolbar.
Fixtures have been set up for the toolbar and style panel, and are
fairly barebones at the moment. Eventually each menu should have a
fixture associated with it, and all tests will use the class defined in
the fixtures file.
### Change Type
- [x] `tests` — Changes to any test code only[^2]
### Release Notes
- Add e2e tests for the toolbar
This PR adds the `TldrawImage` component that displays a tldraw snapshot
as an SVG image.
![2024-02-15 at 12 29 52 - Coral
Cod](https://github.com/tldraw/tldraw/assets/15892272/14140e9e-7d6d-4dd3-88a3-86a6786325c5)
## Why
We've seen requests for this kind of thing from users. eg: GitBook, and
on discord:
<img width="710" alt="image"
src="https://github.com/tldraw/tldraw/assets/15892272/3d3a3e9d-66b9-42e7-81de-a70aa7165bdc">
The component provides a way to do that.
This PR also untangles various bits of editor state from image
exporting, which makes it easier for library users to export images more
agnostically. (ie: they can now export any shapes on any page in any
theme. previously, they had to change the user's state to do that).
## What else
- This PR also adds an **Image snapshot** example to demonstrate the new
component.
- We now pass an `isDarkMode` property to the `toSvg` method (inside the
`ctx` argument). This means that `toSvg` doesn't have to rely on editor
state anymore. I updated all our `toSvg` methods to use it.
- See code comments for more info.
## Any issues?
When you toggle to editing mode in the new example, text measurements
are initially wrong (until you edit the size of a text shape). Click on
the text shape to see how its indicator is wrong. Not sure why this is,
or if it's even related. Does it ring a bell with anyone? If not, I'll
take a closer look. (fixed, see comments --steve)
## Future work
Now that we've untangled image exporting from editor state, we could
expose some more helpful helpers for making this easier.
Fixes tld-2122
### Change Type
- [x] `minor` — New feature
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Open the **Image snapshot** example.
2. Try editing the image, saving the image, and making sure the image
updates.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Dev: Added the `TldrawImage` component.
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [x] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
no tests
### Release Notes
- Fixed a typo in the description in the hosted-images example.
This PR:
- replaces the `shareZone` prop with `SharePanel` component
- replaces the `topZone` prop with `TopPanel` components
- replaces the `Button` component with `TldrawUiButton` and
subcomponents
- adds `TldrawUi` prefix to our primitives
- fixes a couple of bugs with the components
### Change Type
- [x] `major` — Breaking change
This PR refactors our menu systems and provides an interface to hide or
replace individual user interface elements.
# Background
Previously, we've had two types of overrides:
- "schema" overrides that would allow insertion or replacement of items
in the different menus
- "component" overrides that would replace components in the editor's
user interface
This PR is an attempt to unify the two and to provide for additional
cases where the "schema-based" user interface had begun to break down.
# Approach
This PR makes no attempt to change the `actions` or `tools`
overrides—the current system seems to be correct for those because they
are not reactive. The challenge with the other ui schemas is that they
_are_ reactive, and thus the overrides both need to a) be fed in from
outside of the editor as props, and b) react to changes from the editor,
which is an impossible situation.
The new approach is to use React to declare menu items. (Surprise!)
```tsx
function CustomHelpMenuContent() {
return (
<>
<DefaultHelpMenuContent />
<TldrawUiMenuGroup id="custom stuff">
<TldrawUiMenuItem
id="about"
label="Like my posts"
icon="external-link"
readonlyOk
onSelect={() => {
window.open('https://x.com/tldraw', '_blank')
}}
/>
</TldrawUiMenuGroup>
</>
)
}
const components: TLComponents = {
HelpMenuContent: CustomHelpMenuContent,
}
export default function CustomHelpMenuContentExample() {
return (
<div className="tldraw__editor">
<Tldraw components={components} />
</div>
)
}
```
We use a `components` prop with the combined editor and ui components.
- [ ] Create a "layout" component?
- [ ] Make UI components more isolated? If possible, they shouldn't
depend on styles outside of themselves, so that they can be used in
other layouts. Maybe we wait on this because I'm feeling a slippery
slope toward presumptions about configurability.
- [ ] OTOH maybe we go hard and consider these things as separate
components, even packages, with their own interfaces for customizability
/ configurability, just go all the way with it, and see what that looks
like.
# Pros
Top line: you can customize tldraw's user interface in a MUCH more
granular / powerful way than before.
It solves a case where menu items could not be made stateful from
outside of the editor context, and provides the option to do things in
the menus that we couldn't allow previously with the "schema-based"
approach.
It also may (who knows) be more performant because we can locate the
state inside of the components for individual buttons and groups,
instead of all at the top level above the "schema". Because items /
groups decide their own state, we don't have to have big checks on how
many items are selected, or whether we have a flippable state. Items and
groups themselves are allowed to re-build as part of the regular React
lifecycle. Menus aren't constantly being rebuilt, if that were ever an
issue.
Menu items can be shared between different menu types. We'll are
sometimes able to re-use items between, for example, the menu and the
context menu and the actions menu.
Our overrides no longer mutate anything, so there's less weird searching
and finding.
# Cons
This approach can make customization menu contents significantly more
complex, as an end user would need to re-declare most of a menu in order
to make any change to it. Luckily a user can add things to the top or
bottom of the context menu fairly easily. (And who knows, folks may
actually want to do deep customization, and this allows for it.)
It's more code. We are shipping more react components, basically one for
each menu item / group.
Currently this PR does not export the subcomponents, i.e. menu items. If
we do want to export these, then heaven help us, it's going to be a
_lot_ of exports.
# Progress
- [x] Context menu
- [x] Main menu
- [x] Zoom menu
- [x] Help menu
- [x] Actions menu
- [x] Keyboard shortcuts menu
- [x] Quick actions in main menu? (new)
- [x] Helper buttons? (new)
- [x] Debug Menu
And potentially
- [x] Toolbar
- [x] Style menu
- [ ] Share zone
- [x] Navigation zone
- [ ] Other zones
### Change Type
- [x] `major` — Breaking change
### Test Plan
1. use the context menu
2. use the custom context menu example
3. use cursor chat in the context menu
- [x] Unit Tests
- [ ] End to end tests
### Release Notes
- Add a brief release note for your PR here.
(pending landing on: "Going to wait to land this one until the Google
SEO 'soft 404' validation finishes. I want to make sure we're testing
separate things.")
- removes Loading text
- adds sitemap to try to get Google to play nice
### Change Type
- [x] `patch` — Bug fix
---------
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
Currently, we type our fractional index keys as `string` and don't have
any validation for them. I'm touching some of this code for my work on
line handles and wanted to change that:
- fractional indexes are now `IndexKey`s, not `string`s. `IndexKey`s
have a brand property so can't be used interchangeably with strings
(like our IDs)
- There's a new `T.indexKey` validator which we can use in our
validations to make sure we don't end up with nonsense keys.
This PR is part of a series - please don't merge it until the things
before it have landed!
1. #2827 (you are here)
2. #2831
3. #2793
4. #2841
5. #2845
### Change Type
- [x] `patch` — Bug fix
### Test Plan
1. Mostly relying on unit & end to end tests here - no user facing
changes.
- [x] Unit Tests
Fixes#2826, extracted from #2680
The problem is that we had two different articles whose ids were being
derived as `persistence`, the `persistence.mdx` file and the
`persistence/` example.
I've
1. Made it an error for two articles to have the same id
2. Renamed the `persistence/` article to `local-storage` since that's
the API it's using.
### Change Type
- [ ] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [x] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
### Test Plan
1. Add a step-by-step description of how to test your PR here.
3.
- [ ] Unit Tests
- [ ] End to end tests
### Release Notes
- Add a brief release note for your PR here.
This PR fixes the overlays / custom brush example
### Change Type
- [x] `patch` — Bug fix
- [ ] `minor` — New feature
- [ ] `major` — Breaking change
- [ ] `dependencies` — Changes to package dependencies[^1]
- [ ] `documentation` — Changes to the documentation only[^2]
- [ ] `tests` — Changes to any test code only[^2]
- [ ] `internal` — Any other changes that don't affect the published
package[^2]
- [ ] I don't know
This PR changes the way that viewport bounds are calculated by using the
canvas element as the source of truth, rather than the container. This
allows for cases where the canvas is not the same dimensions as the
component. (Given the way our UI and context works, there are cases
where this is desired, i.e. toolbars and other items overlaid on top of
the canvas area).
The editor's `getContainer` is now only used for the text measurement.
It would be good to get that out somehow.
# Pros
We can inset the canvas
# Cons
We can no longer imperatively call `updateScreenBounds`, as we need to
provide those bounds externally.
### Change Type
- [x] `major` — Breaking change
### Test Plan
1. Use the examples, including the new inset canvas example.
- [x] Unit Tests
### Release Notes
- Changes the source of truth for the viewport page bounds to be the
canvas instead.