tldraw/packages
David Sheldrick 48fa9018f4
[bindings] beforeUnbind/afterUnbind to replace beforeDelete/afterDelete (#3761)
Before this PR the interface for doing cleanup when shapes/bindings were
deleted was quite footgunny and inexpressive.

We were abusing the shape beforeDelete callbacks to implement
copy+paste, which doesn't work in situations where cascading deletes are
required. This caused bugs in both our pin and sticker examples, where
copy+paste was broken. I noticed the same bug in my experiment with text
labels, and I think the fact that it took us a while to notice these
bugs indicates other users are gonna fall prey to the same bugs unless
we help them out.

One suggestion to fix this was to add `onAfterDelete(From|To)Shape`
callbacks. The cascading deletes could happen in those, while keeping
the 'commit changes' kinds of updates in the `before` callbacks and
theoretically that would fix the issues with copy+paste. However,
expecting people to figure this out on their own is asking a heckuva lot
IMO, and it's a heavy bit of nuance to try to convey in the docs. It's
hard enough to convey it here. Plus I could imagine for some users it
might easily even leave the store in an inconsistent state to allow a
bound shape to exist for any length of time after the shape it was bound
to was already deleted.

It also just makes an already large and muddy API surface area even
larger and muddier and if that can be avoided let's avoid it.

This PR clears things up by making it so that there's only one callback
for when a binding is removed. The callback is given a `reason` for why
it is being called

The `reason` is one of the following:

- The 'from' is being deleted
- The 'to' shape is being deleted
- The binding is being deleted on it's own.

Technically a binding might end up being deleted when both the `from`
and `to` shapes are being deleted, but it's very hard to know for
certain when that is happening, so I decided to just ignore it for now.
I think it would only matter for perf reasons, to avoid doing useless
work.

So this PR replaces the `onBeforeDelete`, `onAfterDelete`,
`onBeforeFromShapeDelete` and `onBeforeToShapeDelete` (and the
prospective `onAfterFromShapeDelete` and `onAfterToShapeDelete`) with
just two callbacks:

- `onBeforeUnbind({binding, reason})` - called before any shapes or the
binding have been deleted.
- `onAfterUnbind({binding, reason})` - called after the binding and any
shapes have been deleted.

This still allows all the same behaviour as before, without having to
spread the logic between multiple callbacks. It's also just clearer IMO
since you only get one callback invocation per unbinding rather than
potentially two. It also fixes our copy+paste footgun since we can now
implement that by just deleting the bindings rather than invoking the
`onBeforeDelete(From|To)Shape` callbacks.

I'm not worried about losing the explicit before/after delete callbacks
for the binding record or shape records because sdk users still have the
ability to detect all those situations with full nuance in obvious ways.
The one thing that would even require extra bookkeeping is getting
access to a shape record after the shape was deleted, but that's
probably not a thing anybody would want to do 🤷🏼

### 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-05-16 13:48:36 +00:00
..
assets Update READMEs, add form link (#3741) 2024-05-12 20:48:07 +00:00
dotcom-shared Move storing of snapshots to R2 (#3693) 2024-05-08 09:06:02 +00:00
editor [bindings] beforeUnbind/afterUnbind to replace beforeDelete/afterDelete (#3761) 2024-05-16 13:48:36 +00:00
namespaced-tldraw Don't check api.json files into git (#3565) 2024-04-24 15:58:26 +00:00
state [signia] perf thing again (#3645) 2024-04-30 13:44:52 +00:00
store Store-level "operation end" event (#3748) 2024-05-14 09:42:41 +00:00
tldraw [bindings] beforeUnbind/afterUnbind to replace beforeDelete/afterDelete (#3761) 2024-05-16 13:48:36 +00:00
tlschema Update READMEs, add form link (#3741) 2024-05-12 20:48:07 +00:00
tlsync Bindings (#3326) 2024-05-08 12:37:31 +00:00
utils assets: rework mime-type detection to be consistent/centralized; add support for webp/webm, apng, avif (#3730) 2024-05-13 08:29:43 +00:00
validate Update READMEs, add form link (#3741) 2024-05-12 20:48:07 +00:00