Repository navigation
fix(feed): make widget content inert in customize mode - #7016
Conversation
pointer-events-none on the widget surface still let card buttons that opt back in with pointer-events-auto (bookmark, upvote, author stack) take pointer input, kept links in the tab order, and the pinned ad slot was never covered at all, so a click in customize mode could navigate away. inert removes the content from hit-testing and focus; drag, resize, the remove badge and the widget menu live outside it and keep working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
| expect( | ||
| screen | ||
| .getByRole('button', { name: 'Remove Top story' }) | ||
| .closest('[inert]'), |
There was a problem hiding this comment.
This assertion always passes. The test env runs jsdom 20.0.3, which doesn't implement HTMLElement.prototype.inert. So node.inert = true only sets a plain JS property and never adds the inert attribute. .closest('[inert]') then returns null for every element, including ones inside the inert surface. I checked this with a standalone jsdom 20.0.3: after a.inert = true, getAttribute('inert') is null and child.closest('[inert]') is null.
The content?.inert checks above it do work, since they read the same property back. Only the claim that the menu isn't inert is untested.
Either of these would fix it:
- assert the structure directly:
expect(content?.contains(screen.getByRole('button', { name: 'Remove Top story' }))).toBe(false), or - reuse the reflecting
inertpolyfill fromcomponents/drawers/Drawer.spec.tsxso that[inert]selectors mean something here.
Non-blocking, but right now the test doesn't cover the regression it describes (the controls ending up inside the inert node).
Reviewed by AI.
| * does not carry the attribute. | ||
| */ | ||
| export const useInertRef = <T extends HTMLElement>( | ||
| isInert: boolean, |
There was a problem hiding this comment.
Non-blocking: this is now the fourth hand-written copy of setting inert from an effect. The others are SidebarDesktopV2 (~L1308, the same effect including the false cleanup), ShellCluster and PostOptionsSheet. It's also a general hook exported from a component file, and FeedWidgetAdSlot imports it from there.
Could it move to hooks/ (e.g. hooks/useInertRef.ts), with SidebarDesktopV2 switched over to it in a follow-up? If you'd rather keep this PR small, it's fine to leave it where it is.
Reviewed by AI.
Problem
In customize mode a click inside a widget could still navigate away:
pointer-events-auto(bookmark, upvote/comment, author/source stack) still took pointer input in the Top story widgetFix
useInertRef(inFeedWidgetFrame.tsx) setsnode.inertwhile editing (React 18 doesn't carry the attribute, same pattern asSidebarDesktopV2). Applied to the widget surface (replacingpointer-events-none) and to the ad slot's content. The remove badge, widget menu and resize corners sit outside that content, so they keep working; inert hit-tests likepointer-events: none, so dragging from the widget body still lands on the cell.Test plan
🤖 Generated with Claude Code
Preview domain
https://fix-feed-widget-edit-inert.preview.app.daily.dev