[BNE-107] Documents: size menu on wp link closes automatically when tapped on ios safari#192
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses iOS Safari touch interaction bugs around the Work Package options popover (especially the size menu), including preventing premature popover closing and suppressing BlockNote’s formatting toolbar from reappearing while the options popover is open.
Changes:
- Added a shared
supportsHover()utility and used it to branch scroll/close behavior for anchored popovers and preview behavior. - Introduced
useSuppressFormattingToolbarto keep BlockNote’s formatting toolbar closed while WP popovers are active (inline + block). - Adjusted WP popover event handling and block card interactivity/styling; added integration tests for the new behaviors.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| test/lib/components/integration/wpOptionsPopover.browser.test.tsx | Adds regression coverage for formatting toolbar suppression + scroll close behavior. |
| test/lib/components/integration/editor.blockWorkPackage.browser.test.tsx | Adds assertions for block wrapper user-select and role semantics. |
| lib/utils/device.ts | Adds supportsHover() helper used to differentiate touch vs hover-capable devices. |
| lib/hooks/useWorkPackagePreview.ts | Uses supportsHover() for consistent hover/touch behavior detection. |
| lib/hooks/useSuppressFormattingToolbar.ts | New hook to suppress BlockNote formatting toolbar while popovers are active. |
| lib/components/WorkPackage/OptionsPopover.tsx | Adjusts popover event handling and sets closeOnScroll based on hover capability. |
| lib/components/WorkPackage/anchoredPopover.tsx | Adds closeOnScroll option; touch mode repositions on scroll instead of closing. |
| lib/components/InlineWorkPackage/InlineWorkPackageChip.tsx | Uses formatting-toolbar suppression hook while options popover is open. |
| lib/components/BlockWorkPackage/BlockWorkPackage.tsx | Disables text selection on wrapper, suppresses formatting toolbar when popover open, adds role for iOS tap behavior. |
| lib/components/BlockWorkPackage/BlockCards.tsx | Adds role="button" for clickable cards so iOS fires click on first tap. |
Comments suppressed due to low confidence (1)
lib/components/BlockWorkPackage/BlockWorkPackage.tsx:189
- UnavailableCardWrapper is given role="button" and an onClick handler, but it is not focusable and cannot be activated via keyboard (Enter/Space). This makes the block popover inaccessible to keyboard users when the work package is unavailable.
<UnavailableCardWrapper
ref={cardRef}
role="button"
onClick={(e) => {
e.stopPropagation();
setIsOptionsOpen((prev) => !prev);
}}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <CardBase | ||
| ref={cardRef} | ||
| className="op-bn-work-package op-bn-work-package--m" | ||
| $inDropdown={inDropdown} | ||
| onClick={onClick} | ||
| // role=button so iOS treats the card as interactive and fires the click on | ||
| // the first tap (a plain div inside the contenteditable needs two). Interim: | ||
| // mirrors the inline chip; | ||
| role={onClick ? 'button' : undefined} | ||
| data-testid="block-card" | ||
| style={onClick ? { cursor: 'pointer' } : undefined} |
There was a problem hiding this comment.
Intentional interim choice: role="button" is what makes iOS fire the click on the first tap, and it mirrors the existing inline chip. Full menu-button a11y semantics - focusability (tabIndex), Enter/Space activation, aria-haspopup/aria-expanded - are deliberately deferred and tracked in COMMS-892, which will bring the inline chip and block card to a consistent, keyboard-operable pattern.
ac05ee3 to
c66dcbb
Compare
judithroth
left a comment
There was a problem hiding this comment.
I was not able to test with iOS Safari, but on my Android this (still) works. Since you tested with a real iPhone and Ivana will as well, I think it is okay 🙂
Ticket
https://community.openproject.org/wp/BNE-107
What are you trying to accomplish?
Fix on iOS Safari the size menu inside a work package link's options popover closed the moment it was tapped, so the size couldn't be changed. Reproducing it with real touch surfaced a cluster of related bugs in the same
popover, all addressed here:
What approach did you choose and why?
The root cause was a chain of touch-specific behaviours around the popover, which is portaled out of the chip/block and anchored to it.
Popover closing on tap. The container used
preventDefaulton mousedown to keep the editor focused, but on iOS that suppresses the first tap's click on every popover button (each needed a "priming" tap). Removed it, keeping onlystopPropagation. The tap now blurs the editor, which hides the keyboard and fires a viewport scroll that used to close the popover - souseAnchoredPopovergained acloseOnScrolloption: touch repositions instead of closing, desktop still closes on scroll (sharedsupportsHover()helper).Second (BlockNote) toolbar. BlockNote re-opens its formatting toolbar on any pointerup over a focused editor with a non-empty selection, and the chip/block holds a NodeSelection the whole time its popover is open. Added a small
useSuppressFormattingToolbarhook that keeps the toolbar shut while the popover is open, reused by both inline and block.Block popover needing two taps. iOS only fires the click on the first tap for elements it treats as interactive. The inline chip already had
role="button"; the block card was a plain<div>. Addedrole="button"to the clickable card - interim, mirroring the inline chip; full menu-button a11y semantics (aria-haspopup/expanded, keyboard) are tracked in COMMS-892.Text selection on the block card. Replaced a vestigial
user-select: allwithuser-select: none.Merge checklist