diff --git a/frontend/playwright/ui/pages/WasmWorkspacePage.js b/frontend/playwright/ui/pages/WasmWorkspacePage.js index a29f741612..405f3eb55e 100644 --- a/frontend/playwright/ui/pages/WasmWorkspacePage.js +++ b/frontend/playwright/ui/pages/WasmWorkspacePage.js @@ -54,6 +54,19 @@ export class WasmWorkspacePage extends WorkspacePage { await this.hideUI(); } + async getRenderCount() { + return this.page.evaluate(() => window.wasmRenderCount || 0); + } + + async waitForNextRender(previousCount = null) { + const baseCount = + previousCount === null ? await this.getRenderCount() : previousCount; + await this.page.waitForFunction( + (count) => (window.wasmRenderCount || 0) > count, + baseCount, + ); + } + async hideUI() { await this.page.keyboard.press("\\"); await expect(this.pageName).not.toBeVisible(); diff --git a/frontend/playwright/ui/render-wasm-specs/shapes.spec.js b/frontend/playwright/ui/render-wasm-specs/shapes.spec.js index 67eccff5b9..11253425c6 100644 --- a/frontend/playwright/ui/render-wasm-specs/shapes.spec.js +++ b/frontend/playwright/ui/render-wasm-specs/shapes.spec.js @@ -356,3 +356,39 @@ test("Renders shapes with multiple fills and blur", async ({ await expect(workspace.canvas).toHaveScreenshot(); }); + +test("Keeps component visible when focusing after creating it", async ({ + page, +}) => { + const workspace = new WasmWorkspacePage(page); + await workspace.setupEmptyFile(); + await workspace.mockRPC(/get\-file\?/, "workspace/get-file-not-empty.json"); + await workspace.mockRPC( + "update-file?id=*", + "workspace/update-file-create-rect.json", + ); + + await workspace.goToWorkspace({ + fileId: "6191cd35-bb1f-81f7-8004-7cc63d087374", + pageId: "6191cd35-bb1f-81f7-8004-7cc63d087375", + }); + await workspace.waitForFirstRender(); + + await workspace.clickLayers(); + await workspace.clickLeafLayer("Rectangle"); + await page.keyboard.press("ControlOrMeta+k"); + + const componentLayer = workspace.layers + .getByTestId("layer-row") + .filter({ has: page.getByTestId("icon-component") }) + .first(); + await expect(componentLayer).toBeVisible(); + await componentLayer.click(); + + const previousRenderCount = await workspace.getRenderCount(); + await page.keyboard.press("f"); + await workspace.waitForNextRender(previousRenderCount); + + await workspace.hideUI(); + await expect(workspace.canvas).toHaveScreenshot(); +}); diff --git a/frontend/playwright/ui/render-wasm-specs/shapes.spec.js-snapshots/Keeps-component-visible-when-focusing-after-creating-it-1.png b/frontend/playwright/ui/render-wasm-specs/shapes.spec.js-snapshots/Keeps-component-visible-when-focusing-after-creating-it-1.png new file mode 100644 index 0000000000..ebdf07ab64 Binary files /dev/null and b/frontend/playwright/ui/render-wasm-specs/shapes.spec.js-snapshots/Keeps-component-visible-when-focusing-after-creating-it-1.png differ diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index b0de9c6211..b8ef18fda1 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -1896,10 +1896,12 @@ impl RenderState { } } + let can_flatten = element.can_flatten() && !self.focus_mode.should_focus(&element.id); + // Skip render_shape_enter/exit for flattened containers // If a container was flattened, it doesn't affect children visually, so we skip // the expensive enter/exit operations and process children directly - if !element.can_flatten() { + if !can_flatten { // Enter focus early so shadow_before_layer can run (it needs focus_mode.is_active()) self.focus_mode.enter(&element.id); @@ -1978,7 +1980,7 @@ impl RenderState { // Skip nested state updates for flattened containers // Flattened containers don't affect children, so we don't need to track their state - if !element.can_flatten() { + if !can_flatten { match element.shape_type { Type::Frame(_) if Self::frame_clip_layer_blur(element).is_some() => { self.nested_blurs.push(None); @@ -2003,7 +2005,7 @@ impl RenderState { let children_clip_bounds = node_render_state.get_children_clip_bounds(element, None); - let children_ids: Vec<_> = if element.can_flatten() { + let children_ids: Vec<_> = if can_flatten { // Container was flattened: get simplified children (which skip this level) get_simplified_children(tree, element) } else {