Skip to content

feat(editor): pass shapes to ShapeUtil.canBind()#7821

Merged
MitjaBezensek merged 2 commits intomainfrom
mitja/can-bind-shape-improvements
Feb 11, 2026
Merged

feat(editor): pass shapes to ShapeUtil.canBind()#7821
MitjaBezensek merged 2 commits intomainfrom
mitja/can-bind-shape-improvements

Conversation

@MitjaBezensek
Copy link
Copy Markdown
Contributor

@MitjaBezensek MitjaBezensek commented Feb 4, 2026

Closes #7748

ShapeUtil.canBind() previously only received shape type strings via fromShapeType/toShapeType, making it impossible to make binding decisions based on shape props. This PR replaces those with fromShape/toShape as TLShape | { type } unions — matching the pattern already used by Editor.canBindShapes().

When the full shape exists, it's passed directly. When it doesn't (e.g. during arrow creation before the arrow is committed to the store), a { type } stub is passed instead. Consumers can use 'id' in shape to narrow to TLShape when they need prop access.

Change type

  • api

Test plan

  1. Create arrows and verify they still bind to shapes correctly
  2. Verify group shapes still reject bindings
  3. Check pin-bindings, layout-bindings, and sticker-bindings examples still work
  • Unit tests
  • End to end tests

API changes

  • Breaking! Removed fromShapeType and toShapeType from TLShapeUtilCanBindOpts
  • Added fromShape: TLShape | { type: TLShape['type'] } to TLShapeUtilCanBindOpts
  • Added toShape: TLShape | { type: TLShape['type'] } to TLShapeUtilCanBindOpts

Release notes

  • Pass full shapes (when possible) to ShapeUtil.canBind() so binding decisions can be based on shape props, not just types.

Note

Medium Risk
Touches a core editor API used by all binding checks and introduces a signature/typing change that may break downstream canBind implementations or edge cases where only type stubs are available.

Overview
ShapeUtil.canBind() now receives fromShape/toShape (either full TLShape objects or { type } stubs) via an expanded TLShapeUtilCanBindOpts, enabling binding decisions based on actual shape data when available.

Editor.canBindShapes() constructs and passes these new fields while keeping fromShapeType/toShapeType as deprecated compatibility fields, and example utils (layout bindings, pin bindings) plus ArrowShapeUtil are updated to use fromShape.type/toShape.type.

Written by Cursor Bugbot for commit b971312. This will update automatically on new commits. Configure here.

canBind now receives fromShape/toShape as TLShape | { type } unions
instead of just type strings.
@huppy-bot huppy-bot bot added the api API change label Feb 4, 2026
@vercel
Copy link
Copy Markdown

vercel bot commented Feb 4, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
examples Ready Ready Preview Feb 5, 2026 0:37am
5 Skipped Deployments
Project Deployment Actions Updated (UTC)
analytics Ignored Ignored Preview Feb 5, 2026 0:37am
chat-template Ignored Ignored Preview Feb 5, 2026 0:37am
tldraw-docs Ignored Ignored Preview Feb 5, 2026 0:37am
tldraw-shader Ignored Ignored Preview Feb 5, 2026 0:37am
workflow-template Ignored Ignored Preview Feb 5, 2026 0:37am

Request Review

/** The type of shape referenced by the `toId` of the binding. */
toShapeType: TLShape['type']
/** The shape referenced by the `fromId` of the binding, or a `{ type }` stub if unavailable. */
fromShape: TLShape | { type: TLShape['type'] }
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we avoid making this a breaking change? we're getting feedback that we're causing a lot of downstream thrash for customers.
possible to make the previous options deprecated, for now? 🙏

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good shout! Done.

Copy link
Copy Markdown
Member

@mimecuvalo mimecuvalo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pre-approving modulo last comment

override canBind({ toShape }: TLShapeUtilCanBindOpts<TLArrowShape>): boolean {
// bindings can go from arrows to shapes, but not from shapes to arrows
return toShapeType !== 'arrow'
return toShape.type !== 'arrow'
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be: (toShape.type ?? toShapeType)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, don't think we need that. We pass the same thing in both of them.

@steveruizok steveruizok added this pull request to the merge queue Feb 11, 2026
github-merge-queue bot pushed a commit that referenced this pull request Feb 11, 2026
Closes #7748

`ShapeUtil.canBind()` previously only received shape type strings via
`fromShapeType`/`toShapeType`, making it impossible to make binding
decisions based on shape props. This PR replaces those with
`fromShape`/`toShape` as `TLShape | { type }` unions — matching the
pattern already used by `Editor.canBindShapes()`.

When the full shape exists, it's passed directly. When it doesn't (e.g.
during arrow creation before the arrow is committed to the store), a `{
type }` stub is passed instead. Consumers can use `'id' in shape` to
narrow to `TLShape` when they need prop access.

### Change type

- [x] `api`

### Test plan

1. Create arrows and verify they still bind to shapes correctly
2. Verify group shapes still reject bindings
3. Check pin-bindings, layout-bindings, and sticker-bindings examples
still work

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

### API changes

- Breaking! Removed `fromShapeType` and `toShapeType` from
`TLShapeUtilCanBindOpts`
- Added `fromShape: TLShape | { type: TLShape['type'] }` to
`TLShapeUtilCanBindOpts`
- Added `toShape: TLShape | { type: TLShape['type'] }` to
`TLShapeUtilCanBindOpts`

### Release notes

- Pass full shapes (when possible) to `ShapeUtil.canBind()` so binding
decisions can be based on shape props, not just types.


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches a core editor API used by all binding checks and introduces a
signature/typing change that may break downstream `canBind`
implementations or edge cases where only type stubs are available.
> 
> **Overview**
> `ShapeUtil.canBind()` now receives `fromShape`/`toShape` (either full
`TLShape` objects or `{ type }` stubs) via an expanded
`TLShapeUtilCanBindOpts`, enabling binding decisions based on actual
shape data when available.
> 
> `Editor.canBindShapes()` constructs and passes these new fields while
keeping `fromShapeType`/`toShapeType` as *deprecated* compatibility
fields, and example utils (layout bindings, pin bindings) plus
`ArrowShapeUtil` are updated to use `fromShape.type`/`toShape.type`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
b971312. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
@MitjaBezensek MitjaBezensek removed this pull request from the merge queue due to a manual request Feb 11, 2026
@MitjaBezensek MitjaBezensek added this pull request to the merge queue Feb 11, 2026
Merged via the queue into main with commit e744008 Feb 11, 2026
22 checks passed
@MitjaBezensek MitjaBezensek deleted the mitja/can-bind-shape-improvements branch February 11, 2026 11:42
@Valley-15 Valley-15 mentioned this pull request Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api API change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow ShapeUtil.canBind to receive full shape objects, not just types

2 participants