-
Notifications
You must be signed in to change notification settings - Fork 46.4k
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
[Gatsby Docs Update] Fixed iOS overscroll issues, and redesigned mobile sidebar button to … #10761
Changes from all commits
e197968
87cc5c5
cdddfdb
8c0555c
9cb25bf
d221b42
9beb61f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,12 +25,80 @@ class StickyResponsiveSidebar extends Component { | |
open: false, | ||
}; | ||
this.toggleOpen = this._toggleOpen.bind(this); | ||
this.handleDocumentTouchMove = this._handleDocumentTouchMove.bind(this); | ||
this.handleSidebarTouchStart = this._handleSidebarTouchStart.bind(this); | ||
} | ||
|
||
componentDidMount() { | ||
document.addEventListener('touchmove', this.handleDocumentTouchMove); | ||
document | ||
.querySelector('.scrollable') | ||
.addEventListener('touchstart', this.handleSidebarTouchStart); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Strong initial dislike to all of the global handlers/selectors here. If we have to do this, I think we should wrap it up in a separate component rather than mix it into the sticky component. Ideally we could do this in a more "React" way (with props/refs) but I'd have to think about that a bit more. Might be harder to do. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Edit: It might be possible to make it a bit more 'React' ish. For now we could start by adding a comment and linking to the blog post that describes this fix for the iOS overscroll bug. (http://blog.christoffer.online/2015-06-10-six-things-i-learnt-about-ios-rubberband-overflow-scrolling/) |
||
} | ||
|
||
componentWillUnmount() { | ||
document.removeEventListener('touchmove', this.handleDocumentTouchMove); | ||
document | ||
.querySelector('.scrollable') | ||
.removeEventListener('touchstart', this.handleSidebarTouchStart); | ||
document.documentElement.classList.remove('is-menu-open'); | ||
} | ||
|
||
_toggleOpen() { | ||
document.documentElement.classList[this.state.open ? 'remove' : 'add']( | ||
'is-menu-open', | ||
); | ||
this.setState({open: !this.state.open}); | ||
} | ||
|
||
isMenuOpen() { | ||
return ( | ||
this.state.open && | ||
window.matchMedia(media.greaterThan('small').replace('@media ', '')) | ||
); | ||
} | ||
|
||
// Prevent background scroll | ||
// http://blog.christoffer.online/2015-06-10-six-things-i-learnt-about-ios-rubberband-overflow-scrolling/ | ||
_handleDocumentTouchMove(evt) { | ||
if (!this.isMenuOpen()) { | ||
return; | ||
} | ||
|
||
let isTouchMoveAllowed = true; | ||
let target = evt.target; | ||
|
||
while (target !== null) { | ||
if (target.classList && target.classList.contains('disable-scrolling')) { | ||
isTouchMoveAllowed = false; | ||
break; | ||
} | ||
target = target.parentNode; | ||
} | ||
|
||
if (!isTouchMoveAllowed) { | ||
evt.preventDefault(); | ||
} | ||
} | ||
|
||
// Remove iOS Rubber Effect | ||
// http://blog.christoffer.online/2015-06-10-six-things-i-learnt-about-ios-rubberband-overflow-scrolling/ | ||
_handleSidebarTouchStart(evt) { | ||
if (!this.isMenuOpen()) { | ||
return; | ||
} | ||
|
||
const top = evt.currentTarget.scrollTop; | ||
const totalScroll = evt.currentTarget.scrollHeight; | ||
const currentScroll = top + evt.currentTarget.offsetHeight; | ||
|
||
if (top === 0) { | ||
evt.currentTarget.scrollTop = 1; | ||
} else if (currentScroll === totalScroll) { | ||
evt.currentTarget.scrollTop = top - 1; | ||
} | ||
} | ||
|
||
render() { | ||
const {title} = this.props; | ||
const {open} = this.state; | ||
|
@@ -60,9 +128,10 @@ class StickyResponsiveSidebar extends Component { | |
return ( | ||
<div> | ||
<div | ||
className="scrollable" | ||
style={{ | ||
opacity: menuOpacity, | ||
transition: 'opacity 0.5s ease', | ||
transition: 'opacity 0.2s ease', | ||
}} | ||
css={{ | ||
[media.lessThan('small')]: smallScreenSidebarStyles, | ||
|
@@ -106,7 +175,7 @@ class StickyResponsiveSidebar extends Component { | |
<div | ||
style={{ | ||
transform: `translate(0px, ${menuOffset}px)`, | ||
transition: 'transform 0.5s ease', | ||
transition: 'transform 0.2s 0.05s ease', | ||
}} | ||
css={{ | ||
marginTop: 60, | ||
|
@@ -124,24 +193,35 @@ class StickyResponsiveSidebar extends Component { | |
}, | ||
|
||
[media.greaterThan('small')]: { | ||
tranform: 'none !important', | ||
transform: 'none !important', | ||
}, | ||
}}> | ||
<Sidebar {...this.props} /> | ||
<div | ||
css={{ | ||
[media.lessThan('small')]: { | ||
// Extra scrolling space for iOS Safari | ||
paddingBottom: this.state.open ? 150 : 0, | ||
}, | ||
}}> | ||
<Sidebar {...this.props} /> | ||
</div> | ||
</div> | ||
</div> | ||
<div | ||
css={{ | ||
backgroundColor: colors.darker, | ||
bottom: 0, | ||
bottom: 44, // iOS Safari's inert "bottom 44px" | ||
color: colors.brand, | ||
display: 'none', // gets overriden at small screen sizes | ||
left: 0, | ||
left: 20, | ||
cursor: 'pointer', | ||
position: 'fixed', | ||
right: 0, | ||
width: '100%', | ||
right: 20, | ||
zIndex: 3, | ||
maxWidth: 150, | ||
marginLeft: 'auto', | ||
borderRadius: 100, | ||
border: '1px solid rgba(255, 255, 255, 0.1)', | ||
[media.lessThan('small')]: smallScreenBottomBarStyles, | ||
}} | ||
onClick={this.toggleOpen}> | ||
|
@@ -168,17 +248,18 @@ class StickyResponsiveSidebar extends Component { | |
alignSelf: 'center', | ||
display: 'flex', | ||
flexDirection: 'column', | ||
color: colors.white, | ||
}}> | ||
<ChevronSvg | ||
cssProps={{ | ||
transform: `translate(0, ${iconOffset}px) rotate(180deg)`, | ||
transition: 'transform 0.5s ease', | ||
transition: 'transform 0.2s 0.05s ease', | ||
}} | ||
/> | ||
<ChevronSvg | ||
cssProps={{ | ||
transform: `translate(0, ${0 - iconOffset}px)`, | ||
transition: 'transform 0.5s ease', | ||
transition: 'transform 0.2s 0.05s ease', | ||
}} | ||
/> | ||
</div> | ||
|
@@ -189,14 +270,23 @@ class StickyResponsiveSidebar extends Component { | |
<div | ||
style={{ | ||
transform: `translate(0, ${labelOffset}px)`, | ||
transition: 'transform 0.5s ease', | ||
transition: 'transform 0.2s 0.05s ease', | ||
}}> | ||
<div | ||
css={{ | ||
height: 40, | ||
lineHeight: '40px', | ||
}}> | ||
{title} | ||
<span | ||
css={{ | ||
whiteSpace: 'nowrap', | ||
textOverflow: 'ellipsis', | ||
maxWidth: 90, | ||
display: 'inline-block', | ||
overflow: 'hidden', | ||
}}> | ||
{title} | ||
</span> | ||
</div> | ||
<div | ||
css={{ | ||
|
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.
It would be nice to avoid global styles for this. I suggest we pass an
isOpen
prop do this component instead and (probably) expose a toggle function to the sticky sidebar via context. (I'll be happy to help implement this change.)