Repository navigation
fix(app-shell): the console toaster steps clear of an open right-edge drawer (objectui#11685) - #11722
Merged
objectstack-fleet[bot] merged 1 commit intoOct 6, 2026
Conversation
… drawer (objectui#11685) The toaster keeps its top-right corner (objectui#7482). While a right-edge drawer is open it is offset instead: into the strip of page left of the drawer when a toast fits there, otherwise below the drawer's header, so a success toast no longer lands on the drawer's expand and close buttons or its title. The drawer is read off the DOM (an open Radix dialog laid out fixed to the top, right and bottom edges); nothing is added to the package entry. Claude-Session: https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7z Co-authored-by: Claude <noreply@anthropic.com>
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
This was referenced Oct 6, 2026
objectstack-fleet
Bot
deleted the
claude/issue-11685-toast-clears-drawer-chrome
branch
October 6, 2026 15:44
This was referenced Oct 6, 2026
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.
Fixes #11685
Clause-②: no — nothing is added to the package entry: no export, prop, type member or language-pack key.
ConsoleToasterkeeps its one export and its props type. The change stays insidepackages/app-shell/src/chrome/ConsoleToaster.tsx.What changed
The toaster keeps
position="top-right". objectui#7482 chose that corner because bottom-right belongs to the ChatDock composer and its FAB, and sonner pauses dismiss while the pointer is inside its region. That pin,ConsoleToaster anchor (objectui#7482), is untouched and green. While a right-edge drawer is open,ConsoleToasternow hands sonner anoffset/mobileOffsetinstead of moving the anchor:--offset-right= drawer width + 24px. The strip is under the drawer's modal overlay, so no control sits there, and no part of the drawer is covered.--offset-top= header bottom + 24px, and--mobile-offset-top= header bottom + 16px (sonner's own phone gap).offsetisundefined, which is sonner's default and today's behaviour. A caller's ownoffsetprop still wins through the existing{...props}spread.The signal adds no export. A right-edge drawer is read off the DOM: an open Radix dialog (
role="dialog",data-state="open") whose computed style isposition: fixedwithtop,rightandbottomall zero. Everyside="right"sheet matches: the record drawer thatObjectViewopens throughNavigationOverlay, and the metadata-admin, activity, build-debug and draft-changes sheets. None of these match:role="dialog", but it is not itself fixed);The header is the dialog's top-level child that holds its
aria-labelledbytitle. Sizes are layout sizes (offsetWidth,offsetTop+offsetHeight), so the drawer's slide-in transform does not skew them. These observers re-measure on the next animation frame:MutationObservers onbody, one for portal mount and unmount and one fordata-stateflips;ResizeObserveron each open drawer and its header, for drag-resize;windowresize.State updates only when the value changes.
The landing site is the one triage named. The overlap comes from the toaster's placement, so no drawer code changed.
Measurement (one-off, real layout, Chromium)
happy-dom has no layout, so the geometry was measured in headless Chromium 1194 (
/opt/pw-browsers/chromium) against the console's own Vite dev server, with the workspacesrcaliases and real Tailwind. A throwaway entry page, not committed, mounted three real components:ConsoleToaster;NavigationOverlayin drawer mode, with the propsObjectViewpasses it: title,onExpand,expandLabel,storageKey, andwidthfromoverlayWidthFor('auto', ...)with 3 / 8 / 15 / 20 fields, which gives the sm / md / lg / xl buckets;RecordDetailView, with tworecord_headeractions (Approve, Reject).Clicking the page's New button opened the drawer and raised
toast.success('Product created'), the shape of the create flow. 900ms later the page raised a secondtoast.success('Approved').objectstackcheckout in this container has no built CLI (packages/cli/distis absent), so the showcase backend could not start without building a shared checkout. The components, the CSS and the toaster are the real ones; only the toast's trigger is scripted.Boxes are
getBoundingClientRect()in CSS px. The drawer header's bottom edge is at 45px. At 1440 the expand button spans x 1366–1394 and the close button x 1396–1424, both at y 8–36.Before (base
c910630). The first toast sits attop: 24px; right: 24pxin every configuration; at 1440 that is x 1060–1416, y 24–77.5, and the second toast is at y 91.5–145. In all 16 configurations (4 viewports, 4 drawer sizes) the toast intersects the drawer header, the expand button, the close button and the chrome title. In all 12 desktop configurations the second toast also covers the Approve action.After (this branch):
The card's pin holds in all 16 configurations: the toast's box does not intersect the drawer's header controls. Where the strip beside the drawer is too narrow, the toast still sits over the drawer's first content row (the record header and its actions). That is the cost of the card's "below the drawer header" route, listed under Acceptance notes.
Dynamic checks (same harness, drawer size sm):
--offset-right: 888px.638px(drawer at 410–1024).--offset-top: 69px.888px.587px. The toast follows the drawer's edge.24px/24px.Tests
The new pin is
ConsoleToaster.drawerClearance-11685.test.tsx(ConsoleToaster clears an open right-edge drawer (objectui#11685)). Its six cases:data-state="closed"and on unmount, and forward again on re-open;offsetstill wins.happy-dom has no layout, so the test assigns the Chromium-measured values to the drawer's
offsetWidthand the header'soffsetTop/offsetHeight. The file says so in its header.Ablation, run from the committed fix and restored from
HEAD. Removing theoffset/mobileOffsetwiring takes the two anchors from 1/1 to 0/0 (marker 0 to 1) and turns 4 of 6 red, withexpected '24px' to be '888px'andexpected '24px' to be '69px'. The four are the beside, below-header and close/unmount cases and the ignore case's non-vacuity tail. The control and the caller-wins case stay green, as designed. After the restore,git diff HEADis 0 bytes and the file's blobade5562728efequals theHEADblob.Gates (local; the union ran on
bd2663d)pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' buildVERDICT command-exit 0(29 packages)pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/chrome/plus the 5 files named belowTest Files 14 passed (14),Tests 68 passed (68)pnpm --filter @object-ui/app-shell type-checkVERDICT command-exit 0;tsc -p tsconfig.test.json --listFilesreads 5039 files, the new test among thempnpm check:control-bytesOK (scanned 7664 tracked text file(s); skipped 85 binary)pnpm check:new-line-citations0 new citation(s)pnpm check:changeset-claimsNo pending changeset names a file this change touches.pnpm check:pending-changeset-literalsNo test source names a pending changeset.check:test-path-roots,check:unreferenced-sources,check:phantom-deps, andscripts/check-changeset-presence/-no-major/-fixed/-overwriteDeclared narrowing. I started the full
pnpm --filter @object-ui/app-shell test(1033 test files) and stopped it after it had held the shared verify lock for 32 minutes while other seats timed out behind it. It ended inVERDICT command-exit 143, so the full suite is NOT MEASURED locally; CI runs it.The narrowed run covered the whole
chrome/directory, plus every test file outside it that namesConsoleToaster(git grep -l ConsoleToasterover test files). Those are the four consoleApptests, which mock it to a null component, andWizardForm.outcomeToastSupersede, which names it in a comment. Why that is enough:ConsoleToaster.tsxhas no import-time side effect, and its export and props type are byte-unchanged. Only a test that renders the real component can observe the change, and the only tests that do are the chrome pins.The repo-wide
pnpm lintbelongs to CI. eslint on the two touched files ran with--no-inline-config --format json: 2 files, 0 errors, 0 warnings. The lint is not type-aware (eslint.config.jssets noparserOptions.project).Acceptance notes
pointer-events: noneonbodywhile a modal is open, and sonner sets nothing on its toaster. So with a drawer open the toaster computespointer-events: none(measured in every configuration above). A toast's close button and its action buttons cannot be clicked; the click lands on whatever is beneath.Undoaction hits the drawer's overlay (elementFromPointreturns the overlaydiv).Undodoes not fire, and the drawer closes.RecordDetailViewanduseConsoleActionRuntimeraise success toasts with anUndoaction.content/docs/guide/notifications.mdnamesConsoleToasteronly as where toasts go, so no doc changed.Session:
https://claude.ai/code/session_01DrKzdPdyLLBW3qpZ4vtk7zGenerated by Claude Code