Skip to content

Commit 5b4f239

Browse files
hyochanclaude
andcommitted
fix(docs): close mobile sidebar pointer-events and slide it off-screen
The mobile drawer was only `visibility: hidden; opacity: 0` while closed but stayed pinned at `top: 56px; left: 0; width: 280px`. iOS Safari still delivered taps to the drawer's child links in that state, so menu items inside the closed drawer fired even though the drawer looked closed. Belt-and-braces fix: translateX(-100%) moves the geometry off-screen and pointer-events: none turns off hit-testing on the entire subtree. Also unmounts the portaled toggle while the drawer is open so the fixed button at top: 70px doesn't absorb taps meant for the drawer's "APIs" / open child rows underneath, and bumps baseline-browser-mapping to ^2.10.22 to silence the "data is over two months old" warning from browserslist. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e24297e commit 5b4f239

4 files changed

Lines changed: 54 additions & 35 deletions

File tree

bun.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/docs/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"@typescript-eslint/parser": "^8.39.1",
3737
"@vitejs/plugin-react": "^4.3.1",
3838
"babel-plugin-react-compiler": "^19.1.0-rc.2",
39+
"baseline-browser-mapping": "^2.10.22",
3940
"eslint": "^9.21.0",
4041
"eslint-plugin-react-hooks": "^5.1.0",
4142
"eslint-plugin-react-refresh": "^0.4.7",

packages/docs/src/pages/docs/index.tsx

Lines changed: 38 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -153,40 +153,44 @@ function Docs() {
153153
}, []);
154154

155155
// Portal the sidebar toggle to document.body so it sits OUTSIDE any
156-
// ancestor's stacking context. Several earlier rounds of "z-index 9001
157-
// should beat the top nav's 100" still left the docs Menu button
158-
// un-tappable on mobile WebKit because some ancestor of
159-
// `.docs-container` (.main-content / .layout) was apparently painting
160-
// its own stacking layer below the navigation. Rendering at body root
161-
// makes the toggle a true top-level fixed element, immune to that.
162-
const sidebarToggle = createPortal(
163-
<button
164-
type="button"
165-
className={`docs-sidebar-toggle ${isSidebarOpen ? 'hidden' : ''} ${isScrolled ? 'scrolled' : ''}`}
166-
onClick={(event) => {
167-
event.stopPropagation();
168-
setIsSidebarOpen((open) => !open);
169-
}}
170-
aria-label="Toggle sidebar"
171-
>
172-
<svg
173-
width="20"
174-
height="20"
175-
viewBox="0 0 20 20"
176-
fill="none"
177-
xmlns="http://www.w3.org/2000/svg"
178-
>
179-
<path
180-
d="M3 5h14M3 10h14M3 15h14"
181-
stroke="currentColor"
182-
strokeWidth="2"
183-
strokeLinecap="round"
184-
/>
185-
</svg>
186-
<span>Menu</span>
187-
</button>,
188-
document.body
189-
);
156+
// ancestor's stacking context, AND fully unmount it while the drawer
157+
// is open. Earlier rounds left the toggle in the DOM with
158+
// `.hidden { opacity: 0; pointer-events: none }` while the drawer was
159+
// open, which on iOS Safari still let the toggle absorb taps that
160+
// landed on the drawer's first menu item ("APIs" header sits at
161+
// y≈88-120px, exactly where the fixed toggle at top: 70px lives).
162+
// Removing the element from the DOM entirely guarantees the drawer
163+
// items underneath get every tap they should.
164+
const sidebarToggle = isSidebarOpen
165+
? null
166+
: createPortal(
167+
<button
168+
type="button"
169+
className={`docs-sidebar-toggle ${isScrolled ? 'scrolled' : ''}`}
170+
onClick={(event) => {
171+
event.stopPropagation();
172+
setIsSidebarOpen(true);
173+
}}
174+
aria-label="Toggle sidebar"
175+
>
176+
<svg
177+
width="20"
178+
height="20"
179+
viewBox="0 0 20 20"
180+
fill="none"
181+
xmlns="http://www.w3.org/2000/svg"
182+
>
183+
<path
184+
d="M3 5h14M3 10h14M3 15h14"
185+
stroke="currentColor"
186+
strokeWidth="2"
187+
strokeLinecap="round"
188+
/>
189+
</svg>
190+
<span>Menu</span>
191+
</button>,
192+
document.body
193+
);
190194

191195
return (
192196
<div className="docs-container">

packages/docs/src/styles/documentation.css

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,13 +982,22 @@
982982
background: var(--bg-secondary);
983983
z-index: 9000;
984984
transition:
985+
transform 0.25s ease,
985986
opacity 0.2s ease,
986987
visibility 0.2s ease;
987988
border-right: 1px solid var(--border-color);
988989
padding: var(--spacing-xl) 0;
989990
box-shadow: 4px 0 24px rgba(0, 0, 0, 0.15);
991+
/* Closed state: slide fully off-screen, hide visually, AND disable
992+
pointer events. iOS Safari has been observed to still deliver taps
993+
to children of a `visibility: hidden; opacity: 0` fixed element,
994+
so we belt-and-braces it: translateX moves the geometry out of the
995+
hit-test area, and pointer-events: none turns off hit-testing for
996+
this entire subtree even if the transform isn't honored. */
997+
transform: translateX(-100%);
990998
opacity: 0;
991999
visibility: hidden;
1000+
pointer-events: none;
9921001
overflow-y: auto;
9931002
box-sizing: border-box;
9941003
}
@@ -1000,8 +1009,10 @@
10001009
}
10011010

10021011
.docs-sidebar.open {
1012+
transform: translateX(0);
10031013
opacity: 1;
10041014
visibility: visible;
1015+
pointer-events: auto;
10051016
}
10061017

10071018
.docs-content {

0 commit comments

Comments
 (0)