[EuiFlyout] Preserve pixel width on container resize when size is numeric - #9976
Open
clintandrewhall wants to merge 3 commits into
Open
[EuiFlyout] Preserve pixel width on container resize when size is numeric#9976clintandrewhall wants to merge 3 commits into
size is numeric#9976clintandrewhall wants to merge 3 commits into
Conversation
|
💚 CLA has been signed |
|
👋 Since this is a community submitted pull request, a Buildkite build has not been started automatically. Would an Elastic organization member please verify the contents of this pull request and kick off a build manually? |
clintandrewhall
pushed a commit
that referenced
this pull request
Aug 31, 2026
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ETTN39EVo6iTDT7cztt7T
clintandrewhall
marked this pull request as ready for review
August 31, 2026 19:12
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
The callback reset can still allow container-driven onResize calls when the callback identity changes concurrently.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Updates resizable flyouts to preserve numeric pixel widths during container resizing.
Changes:
- Re-clamps numeric sizes while retaining proportional scaling for named sizes.
- Prevents most container-driven
onResizecallbacks. - Adds regression tests and changelog entries.
File summaries
| File | Description |
|---|---|
use_flyout_resizable.ts |
Implements conditional resize behavior. |
use_flyout_resizable.test.ts |
Tests resizing, clamping, and callbacks. |
9976.md |
Documents both fixes. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…`size` A resizable flyout given a numeric `size` did not keep the width the user dragged it to. When the flyout container's width changed, the current pixel width was multiplied by the reference-width ratio to preserve the flyout's *percentage* of the container. That is correct for named sizes — EUI defines `s`/`m`/`l` as 25%/50%/75% in `flyout.styles.ts` — but a numeric `size` is a pixel contract: the consumer measured, persisted, and re-supplied a pixel value, and scaling discards exactly the information they are trying to preserve. Branch on the `size` type in the constraint-change path: numeric sizes are re-clamped only, named sizes keep scaling. Also reset `callOnResize` when the reference width changes. It is set to `true` on `onMouseUp`/`onKeyDown` and was never reset on this path, so container resizes fired `onResize` with a machine-generated width and consumers that persist that value had the user's stored width overwritten. The reset is gated on the reference width actually changing so it cannot suppress the legitimate `onResize` at the end of a drag. Closes #9969 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ETTN39EVo6iTDT7cztt7T
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ETTN39EVo6iTDT7cztt7T
…ring Resetting `callOnResize` state was not sufficient on its own. The `onResize` effect can re-run in the same render the container resize arrives in — for example when a parent rerender also hands down a new inline `onResize` — and it then reads the render's pre-update `callOnResize === true`, calling the consumer back with the pre-clamp width before the state reset lands. Track the container-driven resize in a ref instead. It is written synchronously by the constraint effect, which is declared before the `onResize` effect and so always runs first within a commit, making the signal visible to the callback effect in the same pass. The ref is cleared by `onMouseUp`/`onKeyDown` — the only callers that set `callOnResize` back to `true` — so a user resize following a container resize is still reported. Reported by the Copilot reviewer on PR #9976. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ETTN39EVo6iTDT7cztt7T
clintandrewhall
force-pushed
the
claude/eui-flyout-numeric-clamp-0g0fw8
branch
from
August 31, 2026 19:35
4cf430f to
40cfb8c
Compare
💚 Build Succeeded
History
|
💚 Build Succeeded
History
|
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
Closes #9969
What: A resizable
EuiFlyoutgiven a numericsizeno longer rescales when the flyout container's width changes. It keeps the user's pixel width and is only re-clamped. Container-driven resizes also no longer fireonResize.Why: When the container width changed,
useEuiFlyoutResizablemultiplied the current pixel width by the reference-width ratio to preserve the flyout's percentage of the container. For atype="push"flyout this moves both panes on a single container resize — the flyout rescales and the pushed content reflows to match.Separately,
callOnResizeis set totrueononMouseUp/onKeyDownand was never reset on the constraint-change path, so these machine-generated rescales calledonResize. Consumers that persist the callback value had the user's stored width permanently overwritten by a window resize.How: Branch on the
sizetype in the constraint-change path ofuse_flyout_resizable.ts, and resetcallOnResizewhen the reference width actually changed.Why the fix is conditional, and why it does not conflict with #9683
#9683 fires on the same trigger — the flyout container's width changing — but asks for the opposite outcome: a manually-resized main+child pair should revert to its coded
s/msize when it goes stacked. Both asks are valid because they describe different consumer contracts, andtypeof size === 'number'is the discriminator:sizeprop's'/'m'/'l'/'fill'544)Scaling is correct for named sizes because EUI literally defines them as percentages in
packages/eui/src/components/flyout/flyout.styles.ts:An
mflyout that stays at 50% through a container resize is behaving as designed, and the pre-existing code comment said so explicitly ("preserves the flyout's percentage position in both directions"). Removing the scale factor unconditionally would be a silent semantic change for every resizable named-size flyout, and would pre-empt #9683's design space. This PR therefore changes the numeric branch only.The test
preserves the percentage for a named "size"inuse_flyout_resizable.test.tsis the regression guard for that: it asserts anmflyout still holds 50% across a reference-width change. It passes both with and without this diff, which is exactly what a guard should do.Notes for reviewers
resizeModeprop deliberately not added. The issue floats an explicitresizeMode: 'pixel' | 'percent'prop as the more discoverable API. This PR implements the inferred (typeof size === 'number') version, which needs no consumer changes and keeps the diff reviewable. Happy to switch to the explicit prop if the team prefers it.callOnResizereset is gated on the reference width having changed (if (_referenceWidth !== prevRefWidth)) rather than firing unconditionally. An unconditional reset in this branch would risk suppressing the legitimateonResizeat the end of a drag when a sibling width or other clamp input changes around the same tick. There is a test covering that a drag-then-release still firesonResizeexactly once with the final width.%round-trip is lossless on this path.referenceWidthcomes fromuseResizeObserver(container, 'width')(which reportsborderBoxSize.inlineSize) andflyout.component.tsxconverts back withcontainerRect.widthfromgetBoundingClientRect()— both border-box. This PR does not change the%output mechanism.container.clientWidthfallback inflyout.component.tsx:365(used when the ResizeObserver hasn't reported yet) is content-box where the rest of the path is border-box, so it is off by the container's padding on the first frame — including the push padding this component applies itself. That's a real but distinct bug and is intentionally not folded in here.Reporting consumer
Kibana's Discover document details flyout. Kibana scopes flyouts to the app workspace container (
#app-main-scroll), so a window resize, a sidebar resize, or opening the AI Assistant all changereferenceWidth; Discover persists theonResizewidth tolocalStorage, which is the user-visible half of the bug. Kibana tracks its own consumer-side fixes (the ones that do not need this change) at elastic/kibana#287943.API Changes
size(numeric)sizeis now treated as a pixel contract: on container resize the flyout is re-clamped rather than rescaled proportionallyonResizeScreenshots
No visual change for named sizes. For numeric sizes the change is that the flyout stops moving on container resize; see the screenshot in #9969 for the reported behavior.
Impact Assessment
size.sizeduring a container resize, and in the direction the issue asks for. Named sizes (s/m/l/fill) are untouched.use_flyout_resizable.test.tshad no coverage of scaling onreferenceWidthchange (every prior test uses a staticreferenceWidth), so nothing was weakened to get green.Impact level: 🟢 Low
Release Readiness
Documentation:no doc-visible API changeFigma:n/aMigration guide:n/aAdoption plan (new features):bug fix; the reporting consumer is DiscoverQA instructions for reviewer
EuiFlyoutwithtype="push", a numericsize(e.g.544), and acontainerelement narrower than the viewport.maxWidth), and that only the pushed content resizes.onResizedoes not fire for the container resize.size="m".mflyout still scales proportionally, holding 50% of the container across the resize (pre-existing behavior, deliberately preserved for [Flyout System] Resizable Flyout Issues #9683).onResizestill fires exactly once with the final width.Checklist before marking Ready for Review
QA: Tested light/dark modes, high contrast, mobile, Chrome/Safari/Edge/Firefox, keyboard-only, screen reader— no rendering or styling changeQA: Tested docs changes— no docs changesflyout_resizable.spec.tsxnever passes acontainerand never changes the container width mid-test, so it does not exercise the branch this PR touches and is unaffected. A Cypress case that resizes a real container would be worthwhile, but I could not validate one in my environment (the Cypress binary host is unreachable there), so I left it out rather than push an unverified spec. Happy to add it on request.Breaking changes: Added— not a breaking changebreaking changelabelGenerated by Claude Code