feat(editor): add resizeToBounds method#8120
Conversation
Add a method to resize and reposition a set of shapes so their combined page bounds match a target bounding box. Handles shape clusters connected by arrow bindings, parent transforms, and aspect ratio locking. Also adds 'resize_to_bounds' to the canBeLaidOut opts type union so shapes can opt out of this layout operation.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
5 Skipped Deployments
|
The resizeToBounds feature is independent of the display values work and has been moved to its own PR (#8120).
Fix localOffset mutation bug in stretchShapes where the shared localOffset was rotated instead of the per-shape clone. Add zero-dimension guard to resizeToBounds to prevent NaN/Infinity scales. Remove this.run() wrapper so callers control undo batching. Add tests for read-only mode, rotated shapes, framed shapes, and arrow-bound clusters.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
…rs helper Six layout methods (stackShapes, packShapes, alignShapes, distributeShapes, stretchShapes, resizeToBounds) each repeated ~35 lines of identical clustering boilerplate. Extract this into a private getShapeClusters helper that handles shape resolution, axis-aligned filtering, canBeLaidOut checks, and arrow-bound cluster collection.
|
For additional context: I was watching an agent try to use our Editor methods to move a group of shapes from one place / size to another. (IIRC, something like "make the man bigger and put him next to the tree"). It was very difficult / inefficient because of how many intermediate calculations it needed to make in order to update each of the shapes. As a user, I would have used the selection to operate on the shapes as if they were a single rectangle: select the shapes to create the selection box, then move the selection box, resize the selection box, etc. This method allows the same sort of abstraction at the level of our API. |
| export interface TLShapeUtilCanBeLaidOutOpts { | ||
| /** The type of action causing the layout. */ | ||
| type?: 'align' | 'distribute' | 'pack' | 'stack' | 'flip' | 'stretch' | ||
| type?: 'align' | 'distribute' | 'pack' | 'stack' | 'flip' | 'stretch' | 'resize_to_bounds' |
There was a problem hiding this comment.
hm, could be collidey with other scale stuff. I'd like to reserve scale for when/if scale becomes a first class property
Update `next.mdx` release notes to cover all SDK-relevant PRs merged to main since v4.4.0. Highlights: - Display values system (#8121) with breaking changes and migration guide - Click-through on transparent image pixels (#7942) - `Editor.resizeToBounds()` (#8120) - SVG sanitization (#7896) - TypeScript enum-to-const refactoring (#8084) - 14 bug fixes and 4 improvements ### Change type - [x] `other` ### Test plan 1. Verify the release notes render correctly on the docs site ### Release notes - Update next release notes with changes since v4.4.0. <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Low Risk** > Low risk: documentation-only changes updating release notes content and date, with no runtime/code behavior impact. > > **Overview** > Updates `apps/docs/content/releases/next.mdx` for the upcoming release by refreshing the date and replacing the brief blurb with expanded release notes. > > Documents new SDK surface area (`Geometry2d.ignoreHit`, `Editor.resizeToBounds`, `sanitizeSvg`), highlights click-through on transparent image pixels, and adds a list of recent improvements and bug fixes (paste parenting, link/alt-text persistence, SVG sanitization behavior, circular-dependency cleanup, and several crash/export/sync fixes). > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 5f7dc0a. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
In order to support resizing a set of shapes to fit a target bounding box (e.g. for layout operations), this PR adds
Editor.resizeToBounds().The method takes an array of shapes (or shape IDs) and a target
BoxLike, then scales and repositions the shapes so their combined page bounds match the target. It handles arrow-bound shape clusters, parent transforms, and aspect ratio locking.This PR also:
stretchShapeswhere the sharedlocalOffsetvector was being mutated instead of the per-shape clone when applying parent rotationresizeToBoundsto avoidNaN/InfinityscalesstackShapes,packShapes,alignShapes,distributeShapes,stretchShapes,resizeToBounds) into a privategetShapeClustershelper, removing ~230 lines of duplicated coderesizeToBoundsinteractive examplecanBeLaidOuttype commentChange type
featureTest plan
editor.resizeToBounds([shape1, shape2], { x: 0, y: 0, w: 500, h: 500 })resize-to-boundsexample and verify buttons resize shapes correctlyAPI changes
Editor.resizeToBounds(shapes, bounds)method'resize_to_bounds'toTLShapeUtilCanBeLaidOutOpts.typeRelease notes
Editor.resizeToBounds()method for resizing shapes to fit target boundslocalOffsetmutation bug instretchShapeswhen shapes have parent transforms