feat(studio): fit-to-children button for automatic element sizing#1224
Merged
Conversation
9 tasks
Collaborator
Author
This was referenced Jun 5, 2026
11f6cd5 to
42ac88c
Compare
1e4d380 to
1bbb5f0
Compare
42ac88c to
632b897
Compare
1bbb5f0 to
31dab4f
Compare
This was referenced Jun 5, 2026
james-russo-rames-d-jusso
left a comment
There was a problem hiding this comment.
Summary: "fit to children" icon button next to W/H in the property panel's Layout section. Click → computes the BCR union of element's nodeType === 1 children and calls onSetManualSize(element, { width, height }) with the rounded extents.
Small, focused PR with a thoughtful PR body (the "why BCR instead of fit-content" preamble is exactly the right archaeology context for the next reader). No blockers — a couple of concerns about coordinate-space handling and one UX gap, plus standard nits.
Concerns
- BCR is viewport-relative, not composition-pixel-relative.
getBoundingClientRect()returns post-transform coordinates. If the studio's iframe document is rendered with any transform / zoom (andstudioUiPreferences.previewZoomexists, so zoom is at least a stored concept), the union'smaxX - minXis in overlay pixels, whileonSetManualSize's{ width, height }is presumably interpreted in composition pixels — those diverge whenever the user is not at 100% zoom.snapTargetCollection.collectSnapContextin #1228 handles the same divergence by dividing byrootScaleX = iframeRect.width / rootWidth; mirroring that pattern here is the safe bet. Worth confirming the studio's rendering model first — if the scale is applied outside the iframe (host-page CSS transform on the iframe element), then iframe-internal BCRs already land in composition pixels and you're fine. - No parent reposition. If a child has its top-left at
(-50, -50)relative to the parent's current top-left,minX/minYcapture the child's outside-the-parent bound, and the resultingwidth / heightare correct — butonSetManualSizeonly sets width/height, not position, so the parent stays at its current(left, top)and the child still hangs off the top-left corner. Figma's "Resize to Fit" + AE's "Fit Comp to Layer" both reposition. The PR title ("encompass all children") suggests reposition was the intent; the implementation only resizes. Either scope the PR to "grow-only fit" (and rename to make that explicit) or thread a position commit through too. - No visibility filter.
snapTargetCollection.collectVisibleElementsin #1228 callsisElementVisibleForOverlay(child)sovisibility: hiddenand zero-area-via-CSS children are skipped. Here, only zero-BCR children are skipped (which catchesdisplay: nonebecause BCR is0×0, but notvisibility: hidden, which still lays out and has a non-zero BCR). The PR body says "all visible children" — worth matching that with the same visibility predicate.
Nits
- Button is rendered whenever
canApplyManualSizeis true, but does nothing whenchildren.length === 0. Better UX: render the button disabled with a tooltip ("No children to fit to") so the user gets feedback instead of a silent no-op. (nit) title="Fit to children"carries the label, but screen readers' handling oftitleis inconsistent. Addaria-label="Fit to children"for AT users; keeptitlefor hover. (nit)- Type predicate
(c): c is HTMLElement => c.nodeType === 1over-narrows —nodeType === 1is theElementcheck;SVGElementis alsonodeType 1. Compositions can contain SVG (icons, vector marks). BCR works onElementregardless, so no functional bug; the cast is just a small lie to the type checker. Either widen the predicate toElementor filter toinstanceof HTMLElementif SVG is intentionally excluded. (nit) - Inline
onClickis ~20 lines of click logic — extract tohandleFitToChildren = useCallback(...)(or a plain handler in the parent's hooks layer) for readability and so the logic is exercisable by a future test. (nit) - The Test plan's "Works on elements with absolute-positioned children" item is the load-bearing one — that's the case where
fit-contentwould fail (per PR body) and where the BCR-union approach earns its complexity. Avitestsmoke test of the click handler (mocked element with three positioned children, assertonSetManualSizecalled with the computed extents) would catch most of the concerns above cheaply. (nit)
Questions
- Is the studio's iframe ever rendered with an internal transform (zoom-via-iframe-document-transform) rather than via host-page CSS transform on the iframe element? Determines whether the BCR coordinate-space concern is real or theoretical.
- Reposition intent (concern #2) — grow-only fit, or full-fit-with-position?
onSetManualSize— does it emit a single undo entry, or one per axis? (Affects the Test plan's "Cmd+Z reverts" item.)
What I didn't verify
- The studio's iframe rendering model / where the zoom transform lives.
onSetManualSize's signature + side effects (undo behaviour, validation, async commit).- Whether
element.elementis always an iframe-internal node (vs. occasionally a host-page node) — assumed iframe-internal per the rest of the stack. - Cross-realm BCR behaviour for SVG-in-HTML children in compositions.
- Live behaviour at non-100% preview zoom (no setup).
— Rames D Jusso
632b897 to
8e55340
Compare
69dc0a1 to
930761b
Compare
8e55340 to
f817e37
Compare
930761b to
adf28b7
Compare
f817e37 to
4187b3d
Compare
adf28b7 to
f712f9b
Compare
4187b3d to
e69d6c1
Compare
f712f9b to
40569ef
Compare
e69d6c1 to
22ad321
Compare
Adds an icon button next to W/H fields that computes the bounding box union of all visible children and resizes the element to fit. Uses BCR union scaled to composition pixels, filters visibility:hidden.
22ad321 to
be2816f
Compare
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Adds a fit-to-children icon button next to the W/H fields in the property panel's Layout section. Clicking it computes the bounding box union of all visible children and resizes the parent element to fit — like Figma's "Resize to Fit" or After Effects' "Fit Comp to Layer".
Why BCR union instead of CSS fit-content
CSS `fit-content` collapses to the intrinsic content size (text width, image dimensions), which is wrong for composition elements. In a video composition, children are typically absolute-positioned divs with explicit dimensions — `fit-content` on the parent collapses to zero because absolute children don't contribute to the parent's intrinsic size.
The BCR (bounding client rect) union approach measures the actual rendered bounds of all visible children via `getBoundingClientRect()` and sets the parent's width/height to encompass them. This works correctly regardless of positioning mode, transforms, or CSS layout.
Implementation
Test plan
Stack: 4/4 — depends on #1223