-
Notifications
You must be signed in to change notification settings - Fork 19
Fix #1652 - Listbox popover does not move when page scrolls #1747
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix #1652 - Listbox popover does not move when page scrolls #1747
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Thank you! I’ll check this out later today but it looks great. |
|
Looks like the higher z-index on the topbar now puts it on top of the side modal. I think setting a higher z-index on Unfortunately my images in #1652 are broken, or you probably would have seen that the original spot I noticed this was in a scrolling side modal. (My guess is something went wrong when we made the repo public.)
|
|
Thanks for the analysis, that all seems right. There is at least one listbox in a side modal. If you stop the instance here and click add network interface you can see it. It would be nice if there was a way to avoid putting a special z-index on that listbox manually but we can do that if we have to. |
|
This is maybe uncharacteristic for me, but here I prefer a more magic solution because it doesn't rely on us to remember to pass the prop correctly. I'm not that worried about the solution breaking because I bet there's a way we could test with Playwright that it's working in one spot, and we wouldn't have to remember to test every spot either (which is good, because otherwise it's no better than having to remember to pass the prop). I like your idea about detecting the floating-ui portals, though I wonder — is it just detecting that there is both a listbox and a side modal at the same time? I wonder if you could get into a weird situation where you have a listbox open in the main content and then you open a side modal and somehow the listbox wrongly gets the z-index that it would from being inside the side modal. Opening a side modal probably closes any open listboxes anyway, so this is pretty unlikely. Another magic approach would be to use context to let const ModalContext = createContext(false);
function SideModal({ children }) {
return <ModalContext.Provider value={true}>{children}</ModalContext.Provider>
}
function Listbox({ children }) {
const isInsideModal = useContext(ModalContext);
return <div className={isInsideModal ? "z-50" : "z-20"}>{children}</div>
}This would not be sensitive to floating-ui changing. Coincidentally, we already have a context like this defined for the regular non-side modal, though we're not using it anywhere. console/libs/ui/lib/modal/Modal.tsx Lines 17 to 21 in bfb680e
|
|
Ah, yeah, can see useContext as being a good approach. Will play around with it when I'm back early next week and make sure there aren't edge cases we're not thinking about, but on first glance it seems like it could be a pretty elegant solution for this situation. |
|
The useContext approach was really solid. Great call. I added some tests (one unit test for a new function, some Playwright tests as well), and also moved the Tailwind classes into a I discovered that there was a flaw in my earlier ordering suggestion: there's at least one occasion (upload an image) where both a SideModal and a regular Modal need to be open at the same time, with the Modal floating above the SideModal. I adjusted the layers in the One curious aspect to Playwright: there were a few tests where content we expect to be obscured is still "see-able" by Playwright. Manual testing, and watching Playwright run through the test, confirms that the layers work as they should. It could be that my tests are missing something, or that Playwright has a funny relationship with grid-positioned content, or something else. Open to any thoughts you have on the tests I called out in lines 54–71 of z-index.e2e.ts. This PR's getting a little rangey, but I think it's close. As always, happy to incorporate any feedback. |
|
Fantastic, thank you. I'll have to think about the Playwright bits tomorrow. I love the centralized list of z-indexes, I agree it's better to see them together. Here's a cute idea — if you put them directly in the tailwind config zIndex: {
toast: '50',
modalDropdown: '50',
modal: '40',
sideModalDropdown: '40',
sideModal: '30',
topBar: '20',
popover: '10',
contentDropdown: '10',
content: '0',
},you can avoid the syntactic sadness of string interpolation - className={`${zIndex.modalDropdown} m-4`}
+ className="z-modalDropdown m-4" |
So clean! |
|
Ok, I manually tested and it looks pretty great. Also the diff with whitespace changes hidden ( I found one last tiny issue in both
|
|
FYI you'll have to |
|
It's not very well documented and I could not find anyone actually doing this, but before Playwright will click something it checks a bunch of stuff, like that it's attached to the DOM, stable, blah blah blah. Most importantly, it checks that it can receive events, i.e., there is nothing above it stealing its clicks. So one way to check whether something is obscured is to assert that it is "visible" (doesn't actually mean in Playwright what the word means) and in viewport, but an attempt to click it still fails. There's a In any case, the tests seem to work — when I change the z-indexes to make them fail, they do in fact fail. |
david-crespo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work, and thanks for going along with all the back and forth!
|
Hey, awesome! Great job on the new tests / thanks for explaining the situation there. Thank you for being up for the back and forth as well! 😄 This was fun, and I'm glad we got the bug fixed! |
|
And let me know if you'd like some company merch for your trouble! |
oxidecomputer/console@bfb680e...af6536d * [af6536d5](oxidecomputer/console@af6536d5) skip one flaky test in safari ugh * [84b5177b](oxidecomputer/console@84b5177b) Add full commit range to omicron PR body (oxidecomputer/console#1759) * [26737fd8](oxidecomputer/console@26737fd8) bump pinned omicron to latest * [81e38209](oxidecomputer/console@81e38209) Tweak playwright config (oxidecomputer/console#1758) * [6582b247](oxidecomputer/console@6582b247) increase timeout for image upload error check * [e2147840](oxidecomputer/console@e2147840) Revert mistake commit "curious what it does when we don't say anything" * [7530c3da](oxidecomputer/console@7530c3da) curious what it does when we don't say anything * [bb436357](oxidecomputer/console@bb436357) Fix image upload modal cancel loop (oxidecomputer/console#1755) * [e1558785](oxidecomputer/console@e1558785) add lint-fast npm script * [4614fe6f](oxidecomputer/console@4614fe6f) Fix oxidecomputer/console#1652 - Listbox popover does not move when page scrolls (oxidecomputer/console#1747) * [14685b11](oxidecomputer/console@14685b11) Upgrade playwright eslint plugin to get new rules (oxidecomputer/console#1752) * [2b3d519d](oxidecomputer/console@2b3d519d) Add loading state to ok button in confirm delete modal (oxidecomputer/console#1750) * [0895081b](oxidecomputer/console@0895081b) update readme to reflect RFDs now public * [be687595](oxidecomputer/console@be687595) Bump TS 5.2, Zod, and other deps (oxidecomputer/console#1749)
UI changes: * [bb436357](oxidecomputer/console@bb436357) oxidecomputer/console#1755 * [4614fe6f](oxidecomputer/console@4614fe6f) oxidecomputer/console#1747 * [2b3d519d](oxidecomputer/console@2b3d519d) oxidecomputer/console#1750 All changes: oxidecomputer/console@bfb680e...af6536d * [af6536d5](oxidecomputer/console@af6536d5) skip one flaky test in safari ugh * [84b5177b](oxidecomputer/console@84b5177b) oxidecomputer/console#1759 * [26737fd8](oxidecomputer/console@26737fd8) bump pinned omicron to latest * [81e38209](oxidecomputer/console@81e38209) oxidecomputer/console#1758 * [6582b247](oxidecomputer/console@6582b247) increase timeout for image upload error check * [e2147840](oxidecomputer/console@e2147840) Revert mistake commit "curious what it does when we don't say anything" * [7530c3da](oxidecomputer/console@7530c3da) curious what it does when we don't say anything * [bb436357](oxidecomputer/console@bb436357) oxidecomputer/console#1755 * [e1558785](oxidecomputer/console@e1558785) add lint-fast npm script * [4614fe6f](oxidecomputer/console@4614fe6f) oxidecomputer/console#1747 * [14685b11](oxidecomputer/console@14685b11) oxidecomputer/console#1752 * [2b3d519d](oxidecomputer/console@2b3d519d) oxidecomputer/console#1750 * [0895081b](oxidecomputer/console@0895081b) update readme to reflect RFDs now public * [be687595](oxidecomputer/console@be687595) oxidecomputer/console#1749












Preamble: I know, per the contributing guidelines, you might not get to this PR. No worries! I hope it helps, though!
Currently, when a user opens up a Listbox component, the popover is frozen in place. Although the coordinates for the Listbox's positioning are created relative to where the target is on the page, the coordinates don't update as the user scrolls around on the page:

BEFORE:
Floating UI, the library used in console to create dropdowns, has an optional
autoUpdateutility. (More on autoUpdate in their docs.)This PR passes in the

whileElementsMounted: autoUpdate,attribute, anchoring the Listboxes to the on-screen element that summoned them. Note how the dropdown now scrolls up and off the top of the screen:AFTER:
Getting this to work correctly required two other changes I'll mention:
z-50and Listbox getting dropped fromz-50toz-40.ResizeObserverpreviously, but with the additional attribute getting passed in, it required a polyfill. I added a dev dependency to package.json. This is the same dev dependency the Floating UI library uses (here).