Commit graph

108 commits

Author SHA1 Message Date
David Sheldrick
d683cc0943
No impure getters pt9 (#2222)
follow up to #2189 

### Change Type

- [x] `patch` — Bug fix
2023-11-14 17:07:35 +00:00
David Sheldrick
dc0f6ae0f2
No impure getters pt8 (#2221)
follow up to #2189 
### Change Type

- [x] `patch` — Bug fix
2023-11-14 16:32:27 +00:00
Steve Ruiz
7186368f0d
StateNode atoms (#2213)
This PR extracts some improvements from #2198 into a separate PR.

### Release Notes
- adds computed `StateNode.getPath`
- adds computed StateNode.getCurrent`
- adds computed StateNode.getIsActive`
- adds computed `Editor.getPath()`
- makes transition's second property optional

### Change Type

- [x] `minor` — New feature

### Test Plan

- [x] Unit Tests
- [x] End to end tests
2023-11-14 13:02:50 +00:00
David Sheldrick
9d783f65cb
No impure getters pt5 (#2208)
Follow up to #2189 

### Change Type

- [x] `patch` — Bug fix
2023-11-14 10:23:03 +00:00
David Sheldrick
daf729d45c
No impure getters pt4 (#2206)
follow up to #2189 and #2203 

### Change Type

- [x] `patch` — Bug fix
2023-11-13 16:02:50 +00:00
David Sheldrick
7ffda2335c
No impure getters pt3 (#2203)
Follow up to #2189 and #2202 

### Change Type

- [x] `patch` — Bug fix

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version
2023-11-13 14:31:27 +00:00
David Sheldrick
2ca2f81f2a
No impure getters pt2 (#2202)
follow up to #2189
2023-11-13 12:42:07 +00:00
Steve Ruiz
5db3c1553e
Replace Atom.value with Atom.get() (#2189)
This PR replaces the `.value` getter for the atom with `.get()`

### Change Type

- [x] `major` — Breaking change

---------

Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
2023-11-13 11:51:22 +00:00
Gabriel Lee
260a31db81
feat: add new prop to force mobile mode layout (#1734)
Adds a new prop to force mobile mode layout, similar to how the
?layout=mobile query param works.

An alternative of having the prop accept a breakpoint number was
considered, but while that provides more flexibility, it's best if
usages of tldraw don't need to know about the internal workings of
tldraw. (e.g. someone might use breakpoint 7 to get the "desktop" mode,
but that won't be reliable when in the future more breakpoints are
added)


![licecap-output-1](https://github.com/tldraw/tldraw/assets/5616556/b08fa239-be4f-46c2-9a78-c53b453e4d1a)

![licecap-output-2](https://github.com/tldraw/tldraw/assets/5616556/9be55807-adc7-4253-8b20-757a07a8b157)

Closes #1709 

### 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. `<Tldraw persistenceKey="tldraw_example" autoFocus
forceMobileModeLayout />`
2. notice that the layout stays in mobile mode no matter the width of
the screen

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

### Release Notes

- add new prop to force mobile mode layout

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-11-11 14:11:59 +00:00
Steve Ruiz
1367e4c500
[feature] Things on the canvas (#2150)
This PR adds two new component overrides to the editor's `components`
slot. They are:

- `<OnTheCanvas/>`, which renders inside of the html layer that scales
and translates with the camera
- `<InFrontOfTheCanvas/>`, which renders in front of the canvas but
behind any UI elements, and which does not scale / pan with the camera.

![Kapture 2023-11-06 at 12 19
15](https://github.com/tldraw/tldraw/assets/23072548/51c0421d-8b39-48b5-9b8a-c717253c3423)

### Change Type

- [x] `minor` — New feature

### Test Plan

1. See the "on the canvas" example.

### Release Notes

- [editor] Adds two new components, `OnTheCanvas` and
`InFrontOfTheCanvas`.
2023-11-07 09:27:20 +00:00
Steve Ruiz
ddb73cb6cf
Tighten up editor ui (#2102)
This PR tightens up the editor UI. It removes padding around the editor.

![Kapture 2023-10-28 at 18 27
15](https://github.com/tldraw/tldraw/assets/23072548/18075308-7b62-43a1-8c80-ff4e4136197b)

<img width="1196" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/a8205ef1-b142-4fdc-9745-e400c0c4939a">

<img width="1196" alt="image"
src="https://github.com/tldraw/tldraw/assets/23072548/87e9dcd1-39f5-466a-a256-9cbd2ff2cf7e">

### Change Type

- [x] `minor` — New feature

### Release Notes

- Small adjustment to editor ui.
2023-10-28 21:58:32 +00:00
Steve Ruiz
d757e5a32a
Add meta example (#2122)
This PR adds a meta example, showing how to add meta properties to
shapes.

### Change Type

- [x] `documentation` — Changes to the documentation only[^2]
2023-10-27 17:36:19 +00:00
Steve Ruiz
aaf810b015
Add offline indicator (also to top zone example) (#2083)
This PR adds an offline indicator to the UI package. It's not used in
the default app but we'll use it on tldraw.com, and it makes sense to
include it here as it's generally useful.

### Change Type

- [x] `minor` — New feature

### Test Plan

1. See the zones example.

### Release Notes

- [@tldraw/tldraw] add offline indicator to ui components
2023-10-17 08:32:41 +00:00
alex
22955bb0ec
Only upload playwright to S3 if we have the right credentials (#2074)
These credentials aren't available to non-tldraw contributors which was
breaking uploads.

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-10-13 13:42:41 +00:00
antonio moura
981ef61810
Fix ExplodedExample.tsx (#2068)
Previous implementation was incorrect, causing the following bug:


![image](https://github.com/tldraw/tldraw/assets/26308297/03f2a996-dd58-4864-8f89-8e7af2ecca69)


### 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

---------

Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-10-13 08:28:59 +00:00
Steve Ruiz
8a8b718e53
Move example into examples folder (#2064)
This PR moves an example into the examples folder.

### Change Type

- [x] `internal` — Any other changes that don't affect the published
package[^2]
2023-10-11 09:54:26 +00:00
alex
421102282d
Fix newlines in text geo shapes (#2059)
Previously, entering a geo shape and adding a bunch of newlines wouldn't
correctly update the shape's height. This fixes that.

### Change Type

- [x] `patch` — Bug fix


### Test Plan

1. Create a geo shape
2. Enter text editing mode
3. Spam the enter key
4. See that the shape grows appropriately
5. Exit editing and check that the trailing newlines have been deleted.

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

---------

Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
Co-authored-by: Steve Ruiz <steveruizok@gmail.com>
2023-10-10 12:58:28 +00:00
alex
4ccb6d8a50
re-enable visual regression tests (#2056)
Re-enable visual regression tests

### Change Type
- [x] `tests` — Changes to any test code only[^2]

---------

Co-authored-by: huppy-bot[bot] <128400622+huppy-bot[bot]@users.noreply.github.com>
2023-10-10 12:33:16 +00:00
Steve Ruiz
8892176b1a
[improvement] Scope getShapeAtPoint to rendering shapes only (#2043)
This PR:

1. Adds a `renderingOnly` option to the `Editor.getShapeAtPoint` method.
When true, the method will only hit test against rendering shapes
(shapes that are inside of the current `renderingBounds`) rather than
all shapes on the canvas.
2. Includes some low level improvements to the way that edges find their
nearest point.
3. Includes a fix to circle geometry that could produce NaN values
 
### Change Type

- [x] `minor` — New feature

### Test Plan

1. Check whether hovering shapes still works as you would expect.

- [x] Unit Tests

### Release Notes

- Improve perf for hovering shapes / shape hit tests
2023-10-09 14:18:42 +00:00
alex
37f8a7a491
Remove topBar prop from <TldrawUi /> (#2018)
This diff removes the UI top center bar from the public API and tweaks
some of the styling around the top bar as a whole. Now, the left and
right bars shrink to fit their content, and the center bar is unstyled
by us. It's also marked `@internal`.

This also exposes `<Spinner />` for internal use.

### Change Type

- [x] `minor` — New feature

### Test Plan

-

### Release Notes

- [BREAKING] removed topBar prop
2023-10-09 06:02:43 +00:00
Steve Ruiz
53a8fd6c69
Update readme (#2027)
This PR updates the tldraw readme.

### Change Type

- [x] `patch` — Bug fix
2023-10-06 12:10:33 +00:00
Steve Ruiz
fa32173409
[fix] Multiple example (#2026)
This PR fixes the multiple example.

### Change Type

- [x] `patch` — Bug fix
2023-10-06 09:02:39 +00:00
Steve Ruiz
9c1dc00740
Debugging cleanup / misc cleanup (#2025)
This PR:
- removes feature flags for people menu, highlighter shape
- removes debugging for cursors
- adds a debug flag for hiding shapes
- changes Canvas to use `useValue` rather than `track`
- removes the default background color on `tl-background`
- in the editor components, makes `Background` null by default

### Change Type

- [x] `minor` — New feature
2023-10-06 08:57:46 +00:00
Steve Ruiz
d715fa3a2e
[fix] Focus events (actually) (#2015)
This PR restores the controlled nature of focus. Focus allows keyboard
shortcuts and other interactions to occur. The editor's focus should
always / entirely be controlled via the autoFocus prop or by manually
setting `editor.instanceState.isFocused`.

Design note: I'm starting to think that focus is the wrong abstraction,
and that we should instead use a kind of "disabled" state for editors
that the user isn't interacting with directly. In a page where multiple
editors exit (e.g. a notion page), a developer could switch from
disabled to enabled using a first interaction.

### Change Type

- [x] `patch` — Bug fix

### Test Plan

- [x] End to end tests
2023-10-04 09:01:48 +00:00
alex
92886e1f40
fix text in geo shapes not causing its container to grow (#2003)
We got things sliggghhhtly wrong in #1980. That diff was attempting to
fix a bug where the text measurement element would refuse to go above
the viewport size in safari. This was most obvious in the case where
there was no fixed width on a text shape, and that diff fixed that case,
but it was also happening when a fixed width text shape was wider than
viewport - which wasn't covered by that fix. It turned out that that fix
also introduced a bug where shapes would no longer grow along the y-axis
- in part because the relationship between `width`, `maxWidth`, and
`minWidth` is very confusing.

The one-liner fix is to just use `max-content` instead of `fit-content`
- that way, the div ignores the size of its container. But I also
cleared up the API for text measurement to remove the `width` property
entirely in favour of `maxWidth`. I think this makes things much clearer
and as far as I can tell doesn't affect anything.

Closes #1998 

### Change Type

- [x] `patch` — Bug fix

### Test Plan

1. Create an arrow & geo shape with labels, plus a note and text shape
2. Try to break text measurement - overflow the bounds, make very wide
text, experiment with fixed/auto-size text, etc.
2023-10-03 14:26:13 +00:00
Steve Ruiz
fb2f515b74
[improvement] prevent editing in readonly (#1990)
This PR prevents certain shapes from being edited while in readonly
mode. It adds `ShapeUtil.canEditInReadOnly` to allow developers to opt
in to editing shapes. It's currently applied only to embed shapes.

### Change Type

- [x] `major`

### Test Plan

1. In a readonly mode, try to edit text / sticky notes / arrow labels
via double click / enter. You should not be able to edit them.
2. Try to edit an embed. You should be able to edit it.

### Release Notes

- Prevent editing text shapes in readonly mode.
2023-10-03 11:03:01 +00:00
Taha
f73bf9a7fe
Fix text-wrapping on Safari (#1980)
Co-authored-by: Alex Alex@dytry.ch

closes [#1978](https://github.com/tldraw/tldraw/issues/1978)

Text was wrapping on Safari because the measure text div was rendered
differently on different browsers. Interestingly, when forcing the
text-measure div to be visible and on-screen in Chrome, the same
text-wrapping behaviour was apparent. By setting white-space to 'pre'
when width hasn't been set by the user, we can ensure that only line
breaks the user has inputted are rendered by default on all browsers.

### 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

[^1]: publishes a `patch` release, for devDependencies use `internal`
[^2]: will not publish a new version

### Test Plan

1. On Safari
2. Make a new text shape and start typing
3. At a certain point the text starts to wrap without the width having
been set


### Release Notes

- Fix text wrapping differently on Safari and Chrome/Firefox

Before/After

<image width="350"
src="https://github.com/tldraw/tldraw/assets/98838967/320171b4-61e0-4a41-b8d3-830bd90bea65">
<image width="350"
src="https://github.com/tldraw/tldraw/assets/98838967/b42d7156-0ce9-4894-9692-9338dc931b79">
2023-10-02 11:30:53 +00:00
Steve Ruiz
da33179a31
Remove focus management (#1953)
This PR removes the automatic focus events from the editor.

The `autoFocus` prop is now true by default. When true, the editor will
begin in a focused state (`editor.instanceState.isFocused` will be
`true`) and the component will respond to keyboard shortcuts and other
interactions. When false, the editor will begin in an unfocused state
and not respond to keyboard interactions.

**It's now up to the developer** using the component to update
`isFocused` themselves. There's no predictable way to do that on our
side, so we leave it to the developer to decide when to turn on or off
focus for a container (for example, using an intersection observer to
"unfocus" components that are off screen).

### Change Type

- [x] `major` — Breaking change

### Test Plan

1. Open the multiple editors example.
2. Click to focus each editor.
3. Use the keyboard shortcuts to check that the correct editor is
focused.
4. Start editing a shape, then select the other editor. The first
editing shape should complete.

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

### Release Notes

- [editor] Make autofocus default, remove automatic blur / focus events.

---------

Co-authored-by: David Sheldrick <d.j.sheldrick@gmail.com>
2023-10-02 11:29:54 +00:00
Steve Ruiz
5cd74f4bd6
[feature] Include sources in TLExternalContent (#1925)
This PR adds the source items from a paste event to the data shared with
external content handlers. This allows developers to customize the way
certain content is handled.

For example, pasting text sometimes incudes additional clipboard items,
such as the HTML representation of that text. We wouldn't want to create
two shapes—one for the text and one for the HTML—so we still treat this
as a single text paste. The `registerExternalContentHandler` API allows
a developer to change how that text is handled, and the new `sources`
API will now allow the developer to take into consideration all of the
items that were on the clipboard.
 
![Kapture 2023-09-19 at 12 25
52](https://github.com/tldraw/tldraw/assets/23072548/fa976320-cfec-4921-b481-10cae0d4043e)

### Change Type

- [x] `minor` — New feature

### Test Plan

1. Try the external content source example.
2. Paste text that includes HTML (e.g. from VS Code)

### Release Notes

- [editor / tldraw] add `sources` to `TLExternalContent`
2023-09-19 15:33:54 +00:00
Steve Ruiz
b6ebe1e274
[improvement] quick actions (#1922)
This PR:

- improves the quick actions bar, enabling undo / redo actions when the
eraser is selected.
- for actions that effect selected shapes, calling the action when the
select tool is not selected will select the select tool and run the
action
- actions that effect selected shapes are hidden from the menu when the
select tool is not selected

### Change Type

- [x] `major`

### Test Plan

1. Select the eraser tool, the undo / redo buttons should still be
there.

1. Select two shapes
2. Select the draw tool
3. The menu should not display most options, e.g. cut or paste, but
should display undo / redo
4. Press Shift+H
5. The shapes should not move, but the select tool should be selected
again

### Release Notes

- Improve the menu / kbds behavior when select tool is not active
2023-09-19 15:33:39 +00:00
David Sheldrick
d9ce936ed0
Fix pinch start with toolbar open (#1895)
closes #1893 

Normally when you start a pinch it does the following within a few
frames:

- first finger goes down, begins a drawing gesture, adds a mark to the
undo stack
- second finger goes down, cancels the drawing gesture, bails to the
mark

but when the toolbar is open, it follows the same process without adding
a mark to the undo stack, so that when it bails it bails to the previous
mark.

This PR updates the logic to create a mark ID when setting the mark, and
only bail if the mark id was set on enter.

### 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

[^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.
2.

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

### Release Notes

- Fixes a bug that could trigger undo by accident when closing the style
toolbar via a pinch gesture on mobile.
2023-09-18 10:50:15 +00:00
Steve Ruiz
0b3e83be52
Add snapshot prop, examples (#1856)
This PR:
- adds a `snapshot` prop to the <Tldraw> component. It does basically
the same thing as calling `loadSnapshot` after creating the store, but
happens before the editor actually loads.
- adds a largeish example (including a JSON snapshot) to the examples

We have some very complex ways of juggling serialized data between
multiplayer, file formats, and the snapshot APIs. I'd like to see these
simplified, or at least for our documentation to reflect a narrow subset
of all the options available.

The most common questions seem to be:

Q: How do I serialize data?
A: Via the `Editor.getSnapshot()` method

Q: How do I restore serialized data?
A: Via the `Editor.loadSnapshot()` method OR via the `<Tldraw>`
component's `snapshot` prop

The store has an `initialData` constructor prop, however this is quite
complex as the store also requires a schema class instance with which to
migrate the data. In our components (<Tldraw> and <TldrawEditor>) we
were also accepting `initialData`, however we weren't accepting a
schema, and either way I think it's unrealistic to also expect users to
create schemas themselves and pass those in.

AFAIK the `initialData` prop is only used in the file loading, which is
a good example of how complex it looks like to create a schema and
migrate data outside of the components.

### Change Type

- [x] `minor` — New feature
2023-09-08 14:48:55 +00:00
Steve Ruiz
81b8e65741
export asset stuff (#1829)
This PR adds several new exports related to assets.

### Change Type

- [x] `minor` — New feature
2023-08-26 08:30:29 +00:00
Steve Ruiz
57fcb3d07b
[feature] Asset props (#1824)
This PR adds additional props to the <Tldraw> component for setting the
maximum asset size, maximum image dimensions, accepted image types, and
accepted video types. It adds an example for using these properties and
for uploading image assets.

### Change Type

- [x] `minor` — New feature

### Test Plan

1. Try (and fail) to upload image types other than the default types.
2. Try (and fail) to upload images / videos larger than 10mb.
3. Use the example to customize the properties.

### Release Notes

- [@tldraw/tldraw] add asset props
2023-08-25 17:30:09 +00:00
Steve Ruiz
2c7c97af9c
[fix] style changes (#1814)
This PR updates the way that styles are changed. It splits `setStyle`
and `setOpacity` into `setStyleForNext Shape` and
`setOpacityForNextShape` and `setStyleForSelectedShapes` and
`setOpacityForSelectedShapes`. It fixes the issue with setting one style
re-setting other styles.

### Change Type

- [x] `major` — Breaking change

### Test Plan

1. Set styles when shapes are not selected.
2. Set styles when shapes are selected.
3. Set styles when shapes are selected and the selected tool is not
select.

- [x] Unit Tests
2023-08-23 10:14:49 +00:00
Steve Ruiz
22329c51fc
[improvement] More selection logic (#1806)
This PR includes further UX improvements to selection.

- clicking inside of a hollow shape will no longer select it on pointer
up
- clicking a shape's filled label will select it on pointer down
- clicking a shape's empty label will select it on pointer up
- clicking and dragging a selected arrow is now better limited to its
body, not its bounds
- arrows will no longer bind to labels

### Text labels

A big change here relates to text labels. Previously, we had listeners
set on the text label elements; I've removed these and we now check the
actual label bounds geometry for a hit. For geo shapes, this geometry is
now placed correctly based on the alignment / vertical alignment of the
label.

- Clicking on a label with text in it will select the shape on pointer
down.
- Clicking on an empty text label will select the shape on pointer up.

## Hollow shapes

Previously, shapes with `fill: none` were also being selected on pointer
up. I've removed that logic because it was producing wrong-feeling
selections too often. We now select these shapes only when clicking on
the label (as mentioned above) or when clicking on the edges of the
shape. This is in line with the original behavior (currently on
tldraw.com, prior to the earlier PR that updated selection logic).

## Arrows

Arrows still hit the inside of hollow shapes, using the "smallest
hovered" logic previously used for pointer-up selection on hollow
shapes. They also now correctly do so while ignoring text labels.

### Change Type

- [x] `minor` — New feature

### Test Plan

1. try selecting geo shapes, nested geo shapes, arrows and shapes with
labels or without labels

- [x] Unit Tests
2023-08-13 15:55:24 +00:00
Steve Ruiz
8991468446
history options / markId / createPage (#1796)
This PR:

- adds history options to several commands in order to allow them to
support squashing and ephemeral data (previously, these commands had
boolean values for squashing / ephemeral)

It also:
- changes `markId` to return the editor instance rather than the mark id
passed into the command
- removes `focus` and `blur` commands
- changes `createPage` parameters
- unifies `animateShape` / `animateShapes` options

### Change Type

- [x] `major` — Breaking change

### Test Plan

- [x] Unit Tests
2023-08-05 11:21:07 +00:00
Steve Ruiz
ae56d975e0
remove yjs example (#1795)
This PR moves the yjs example into its own repository here:
https://github.com/tldraw/tldraw-yjs-example

### Change Type

- [x] `internal`
2023-08-04 16:23:38 +00:00
Steve Ruiz
bf27743595
Rename shapes apis (#1787)
This PR updates APIs related to shapes in the Editor.

- removes the requirement for an `id` when creating shapes
- `shapesOnCurrentPage` -> `currentPageShapes`
- `findAncestor` -> `findShapeAncestor`
- `findCommonAncestor` -> `findCommonShapeAncestor`
- Adds `getCurrentPageShapeIds`
- `getAncestors` -> `getShapeAncestors`
- `getClipPath` -> `getShapeClipPath`
- `getGeometry` -> `getShapeGeometry`
- `getHandles` -> `getShapeHandles`
- `getTransform` -> `getShapeLocalTransform`
- `getPageTransform` -> `getShapePageTransform`
- `getOutlineSegments` -> `getShapeOutlineSegments`
- `getPageBounds` -> `getShapePageBounds`
- `getPageTransform` -> `getShapePageTransform`
- `getParentTransform` -> `getShapeParentTransform`
- `selectionBounds` -> `selectionRotatedPageBounds`

### Change Type

- [x] `major` — Breaking change

### Test Plan

- [x] Unit Tests
2023-08-02 18:12:25 +00:00
Steve Ruiz
79fae186e4
Revert "Editor commands API / effects" (#1783)
Reverts tldraw/tldraw#1778.

Fuzz testing picked up errors related to deleting pages and undo/redo
which may doom this PR.

### Change Type

- [x] `major` — Breaking change
2023-08-01 17:03:31 +00:00
Steve Ruiz
e17074a8b3
Editor commands API / effects (#1778)
This PR shrinks the commands API surface and adds a manager
(`CleanupManager`) for side effects.

### Change Type

- [x] `major` — Breaking change

### Test Plan

Use the app! Especially undo and redo. Our tests are passing but I've
found more cases where our coverage fails to catch issues.

### Release Notes

- tbd
2023-08-01 13:21:14 +00:00
Steve Ruiz
d750da8f40
ShapeUtil.getGeometry, selection rewrite (#1751)
This PR is a significant rewrite of our selection / hit testing logic.

It
- replaces our current geometric helpers (`getBounds`, `getOutline`,
`hitTestPoint`, and `hitTestLineSegment`) with a new geometry API
- moves our hit testing entirely to JS using geometry
- improves selection logic, especially around editing shapes, groups and
frames
- fixes many minor selection bugs (e.g. shapes behind frames)
- removes hit-testing DOM elements from ShapeFill etc.
- adds many new tests around selection
- adds new tests around selection
- makes several superficial changes to surface editor APIs

This PR is hard to evaluate. The `selection-omnibus` test suite is
intended to describe all of the selection behavior, however all existing
tests are also either here preserved and passing or (in a few cases
around editing shapes) are modified to reflect the new behavior.

## Geometry

All `ShapeUtils` implement `getGeometry`, which returns a single
geometry primitive (`Geometry2d`). For example:

```ts
class BoxyShapeUtil {
  getGeometry(shape: BoxyShape) {
    return new Rectangle2d({
        width: shape.props.width, 
        height: shape.props.height, 
        isFilled: true,
        margin: shape.props.strokeWidth
      })
    }
}
```

This geometric primitive is used for all bounds calculation, hit
testing, intersection with arrows, etc.

There are several geometric primitives that extend `Geometry2d`:
- `Arc2d`
- `Circle2d`
- `CubicBezier2d`
- `CubicSpline2d`
- `Edge2d`
- `Ellipse2d`
- `Group2d`
- `Polygon2d`
- `Rectangle2d`
- `Stadium2d`

For shapes that have more complicated geometric representations, such as
an arrow with a label, the `Group2d` can accept other primitives as its
children.

## Hit testing

Previously, we did all hit testing via events set on shapes and other
elements. In this PR, I've replaced those hit tests with our own
calculation for hit tests in JavaScript. This removed the need for many
DOM elements, such as hit test area borders and fills which only existed
to trigger pointer events.

## Selection

We now support selecting "hollow" shapes by clicking inside of them.
This involves a lot of new logic but it should work intuitively. See
`Editor.getShapeAtPoint` for the (thoroughly commented) implementation.

![Kapture 2023-07-23 at 23 27
27](https://github.com/tldraw/tldraw/assets/23072548/a743275c-acdb-42d9-a3fe-b3e20dce86b6)

every sunset is actually the sun hiding in fear and respect of tldraw's
quality of interactions

This PR also fixes several bugs with scribble selection, in particular
around the shift key modifier.

![Kapture 2023-07-24 at 23 34
07](https://github.com/tldraw/tldraw/assets/23072548/871d67d0-8d06-42ae-a2b2-021effba37c5)

...as well as issues with labels and editing.

There are **over 100 new tests** for selection covering groups, frames,
brushing, scribbling, hovering, and editing. I'll add a few more before
I feel comfortable merging this PR.

## Arrow binding

Using the same "hollow shape" logic as selection, arrow binding is
significantly improved.

![Kapture 2023-07-22 at 07 46
25](https://github.com/tldraw/tldraw/assets/23072548/5aa724b3-b57d-4fb7-92d0-80e34246753c)

a thousand wise men could not improve on this

## Moving focus between editing shapes

Previously, this was handled in the `editing_shapes` state. This is
moved to `useEditableText`, and should generally be considered an
advanced implementation detail on a shape-by-shape basis. This addresses
a bug that I'd never noticed before, but which can be reproduced by
selecting an shape—but not focusing its input—while editing a different
shape. Previously, the new shape became the editing shape but its input
did not focus.

![Kapture 2023-07-23 at 23 19
09](https://github.com/tldraw/tldraw/assets/23072548/a5e157fb-24a8-42bd-a692-04ce769b1a9c)

In this PR, you can select a shape by clicking on its edge or body, or
select its input to transfer editing / focus.

![Kapture 2023-07-23 at 23 22
21](https://github.com/tldraw/tldraw/assets/23072548/7384e7ea-9777-4e1a-8f63-15de2166a53a)

tldraw, glorious tldraw

### Change Type

- [x] `major` — Breaking change

### Test Plan

1. Erase shapes
2. Select shapes
3. Calculate their bounding boxes

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

### Release Notes

- [editor] Remove `ShapeUtil.getBounds`, `ShapeUtil.getOutline`,
`ShapeUtil.hitTestPoint`, `ShapeUtil.hitTestLineSegment`
- [editor] Add `ShapeUtil.getGeometry`
- [editor] Add `Editor.getShapeGeometry`
2023-07-25 16:10:15 +00:00
Steve Ruiz
0323ee1f6b
[fix] dark mode (#1754)
This PR fixes a bug where dark mode would not immediately cause shapes
to update their colors. Previously, we got the current theme during
render but not in a way that hooked into the change. In this update, we
hook into the change. We also pass the change down to shape fills as
props rather than getting the theme from deeper down.

### Change Type

- [x] `patch`

### Test Plan

1. Use dark mode.
2. Switch colors

### Release Notes

- [fix] dark mode colors not updating
2023-07-20 11:38:55 +00:00
Steve Ruiz
b22ea7cd4e
More cleanup, focus bug fixes (#1749)
This PR is another grab bag:
- renames `readOnly` to `readonly` throughout editor
- fixes a regression related to focus and keyboard shortcuts
- adds a small outline for focused editors

### Change Type

- [x] `major`

### Test Plan

- [x] End to end tests
2023-07-19 10:52:21 +00:00
Steve Ruiz
789b1d1ac6
Fix e2e test (#1748)
This PR fixes a failing end to end test that snuck in.

### Change Type

- [x] `tests` — Changes to any test code only[^2]

### Test Plan

- [x] End to end tests
2023-07-18 22:13:11 +00:00
Steve Ruiz
3e31ef2a7d
Remove helpers / extraneous API methods. (#1745)
This PR removes several extraneous computed values from the editor. It
adds some silly instance state onto the instance state record and
unifies a few methods which were inconsistent. This is fit and finish
work 🧽

## Computed Values

In general, where once we had a getter and setter for `isBlahMode`,
which really masked either an `_isBlahMode` atom on the editor or
`instanceState.isBlahMode`, these are merged into `instanceState`; they
can be accessed / updated via `editor.instanceState` /
`editor.updateInstanceState`.

## tldraw select tool specific things

This PR also removes some tldraw specific state checks and creates new
component overrides to allow us to include them in tldraw/tldraw.

### Change Type

- [x] `major` — Breaking change

### Test Plan

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

### Release Notes

- [tldraw] rename `useReadonly` to `useReadOnly`
- [editor] remove `Editor.isDarkMode`
- [editor] remove `Editor.isChangingStyle`
- [editor] remove `Editor.isCoarsePointer`
- [editor] remove `Editor.isDarkMode`
- [editor] remove `Editor.isFocused`
- [editor] remove `Editor.isGridMode`
- [editor] remove `Editor.isPenMode`
- [editor] remove `Editor.isReadOnly`
- [editor] remove `Editor.isSnapMode`
- [editor] remove `Editor.isToolLocked`
- [editor] remove `Editor.locale`
- [editor] rename `Editor.pageState` to `Editor.currentPageState`
- [editor] add `Editor.pageStates`
- [editor] add `Editor.setErasingIds`
- [editor] add `Editor.setEditingId`
- [editor] add several new component overrides
2023-07-18 21:50:23 +00:00
Steve Ruiz
b7d9c8684c
tldraw zero - package shuffle (#1710)
This PR moves code between our packages so that:
- @tldraw/editor is a “core” library with the engine and canvas but no
shapes, tools, or other things
- @tldraw/tldraw contains everything particular to the experience we’ve
built for tldraw

At first look, this might seem like a step away from customization and
configuration, however I believe it greatly increases the configuration
potential of the @tldraw/editor while also providing a more accurate
reflection of what configuration options actually exist for
@tldraw/tldraw.

## Library changes

@tldraw/editor re-exports its dependencies and @tldraw/tldraw re-exports
@tldraw/editor.

- users of @tldraw/editor WITHOUT @tldraw/tldraw should almost always
only import things from @tldraw/editor.
- users of @tldraw/tldraw should almost always only import things from
@tldraw/tldraw.

- @tldraw/polyfills is merged into @tldraw/editor
- @tldraw/indices is merged into @tldraw/editor
- @tldraw/primitives is merged mostly into @tldraw/editor, partially
into @tldraw/tldraw
- @tldraw/file-format is merged into @tldraw/tldraw
- @tldraw/ui is merged into @tldraw/tldraw

Many (many) utils and other code is moved from the editor to tldraw. For
example, embeds now are entirely an feature of @tldraw/tldraw. The only
big chunk of code left in core is related to arrow handling.

## API Changes

The editor can now be used without tldraw's assets. We load them in
@tldraw/tldraw instead, so feel free to use whatever fonts or images or
whatever that you like with the editor.

All tools and shapes (except for the `Group` shape) are moved to
@tldraw/tldraw. This includes the `select` tool.

You should use the editor with at least one tool, however, so you now
also need to send in an `initialState` prop to the Editor /
<TldrawEditor> component indicating which state the editor should begin
in.

The `components` prop now also accepts `SelectionForeground`.

The complex selection component that we use for tldraw is moved to
@tldraw/tldraw. The default component is quite basic but can easily be
replaced via the `components` prop. We pass down our tldraw-flavored
SelectionFg via `components`.

Likewise with the `Scribble` component: the `DefaultScribble` no longer
uses our freehand tech and is a simple path instead. We pass down the
tldraw-flavored scribble via `components`.

The `ExternalContentManager` (`Editor.externalContentManager`) is
removed and replaced with a mapping of types to handlers.

- Register new content handlers with
`Editor.registerExternalContentHandler`.
- Register new asset creation handlers (for files and URLs) with
`Editor.registerExternalAssetHandler`

### Change Type

- [x] `major` — Breaking change

### Test Plan

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

### Release Notes

- [@tldraw/editor] lots, wip
- [@tldraw/ui] gone, merged to tldraw/tldraw
- [@tldraw/polyfills] gone, merged to tldraw/editor
- [@tldraw/primitives] gone, merged to tldraw/editor / tldraw/tldraw
- [@tldraw/indices] gone, merged to tldraw/editor
- [@tldraw/file-format] gone, merged to tldraw/tldraw

---------

Co-authored-by: alex <alex@dytry.ch>
2023-07-17 21:22:34 +00:00
Steve Ruiz
43a0dd83f8
support custom shapes in yjs example (#1737)
This PR adds support for custom shapes (`shapes`) to the y.js example. A
user should pass the same data to the `useYjsStore` hook as they pass to
the `<Tldraw>` component.

### Change Type

- [x] `internal`
2023-07-14 20:33:57 +00:00
David Sheldrick
83a391b46b
Add cloud shape (#1708)
![Kapture 2023-07-04 at 16 36
31](https://github.com/tldraw/tldraw/assets/1242537/bcb19959-ac66-46fa-92ea-50fe4692a96c)


### 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. Make some cloud shapes, try different sizes, colors, fills.
2. Export cloud shapes to images.

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

### Release Notes

- Adds a cloud shape.
2023-07-07 15:32:08 +00:00
Steve Ruiz
910be6073f
[refactor] reduce dependencies on shape utils in editor (#1693)
We'd like to make the @tldraw/editor layer more independent of specific
shapes. Unfortunately there are many places where shape types and
certain shape behavior is deeply embedded in the Editor. This PR begins
to refactor out dependencies between the editor library and shape utils.

It does this in two ways:
- removing shape utils from the arguments of `isShapeOfType`, replacing
with a generic
- removing shape utils from the arguments of `getShapeUtil`, replacing
with a generic
- moving custom arrow info cache out of the util and into the editor
class
- changing the a tool's `shapeType` to be a string instead of a shape
util

We're here trading type safety based on inferred types—"hey editor, give
me your instance of this shape util class"—for knowledge at the point of
call—"hey editor, give me a shape util class of this type; and trust me
it'll be an instance this shape util class". Likewise for shapes.

### A note on style 

We haven't really established our conventions or style when it comes to
types, but I'm increasingly of the opinion that we should defer to the
point of call to narrow a type based on generics (keeping the types in
typescript land) rather than using arguments, which blur into JavaScript
land.

### Change Type

- [x] `major` — Breaking change

### Test Plan

- [x] Unit Tests

### Release Notes

- removes shape utils from the arguments of `isShapeOfType`, replacing
with a generic
- removes shape utils from the arguments of `getShapeUtil`, replacing
with a generic
- moves custom arrow info cache out of the util and into the editor
class
- changes the a tool's `shapeType` to be a string instead of a shape
util
2023-07-07 13:56:31 +00:00