-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
46b7484
commit e976448
Showing
6 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
$sheet-desktop-width: rem(380px); | ||
|
||
.Sheet { | ||
position: fixed; | ||
bottom: 0; | ||
width: 100vw; | ||
height: 100vh; | ||
background: color('white'); | ||
box-shadow: shadow('layer'); | ||
|
||
&.desktop { | ||
right: 0; | ||
width: $sheet-desktop-width; | ||
} | ||
|
||
&:focus { | ||
outline: 0; | ||
} | ||
} | ||
|
||
.Container { | ||
position: fixed; | ||
z-index: z-index('modal', $fixed-element-stacking-order); | ||
top: 0; | ||
right: 0; | ||
bottom: 0; | ||
left: 0; | ||
|
||
&.desktop { | ||
left: auto; | ||
width: $sheet-desktop-width; | ||
} | ||
} | ||
|
||
// Bottom | ||
.Bottom { | ||
will-change: transform; | ||
transition: transform duration('slow') easing('base'); | ||
transform-origin: bottom; | ||
} | ||
.enterBottom { | ||
transform: translateY(100%); | ||
} | ||
.enterBottomActive { | ||
transform: translateY(0%); | ||
} | ||
.exitBottom { | ||
transform: translateY(0%); | ||
} | ||
.exitBottomActive { | ||
transform: translateY(100%); | ||
} | ||
|
||
// Right | ||
.Right { | ||
will-change: transform; | ||
transition: transform duration('slow') easing('base'); | ||
transform-origin: right; | ||
} | ||
.enterRight { | ||
transform: translateX(100%); | ||
} | ||
.enterRightActive { | ||
transform: translateX(0%); | ||
} | ||
.exitRight { | ||
transform: translateX(0%); | ||
} | ||
.exitRightActive { | ||
transform: translateX(100%); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import * as React from 'react'; | ||
|
||
import {CSSTransition} from 'react-transition-group'; | ||
import debounce from 'lodash/debounce'; | ||
import {classNames} from '@shopify/react-utilities/styles'; | ||
|
||
import {navigationBarCollapsed} from '../../utilities/breakpoints'; | ||
import {Key} from '../../types'; | ||
import {layer, overlay, Duration} from '../shared'; | ||
|
||
import TrapFocus from '../TrapFocus'; | ||
import Portal from '../Portal'; | ||
import KeypressListener from '../KeypressListener'; | ||
import EventListener from '../EventListener'; | ||
|
||
import styles from './Sheet.scss'; | ||
|
||
export interface Props { | ||
open: boolean; | ||
children: React.ReactNode; | ||
onClose(): void; | ||
} | ||
|
||
export interface State { | ||
mobile: boolean; | ||
} | ||
|
||
export default class Sheet extends React.PureComponent<Props, State> { | ||
state: State = { | ||
mobile: false, | ||
}; | ||
|
||
private handleResize = debounce( | ||
() => { | ||
const {mobile} = this.state; | ||
if (mobile !== isMobile()) { | ||
this.setState({mobile: !mobile}); | ||
} | ||
}, | ||
40, | ||
{leading: true, trailing: true, maxWait: 40}, | ||
); | ||
|
||
componentDidMount() { | ||
const {mobile} = this.state; | ||
if (mobile !== isMobile()) { | ||
this.setState({mobile: !mobile}); | ||
} | ||
} | ||
|
||
render() { | ||
const {children, open, onClose} = this.props; | ||
const {mobile} = this.state; | ||
|
||
const sheetClassName = classNames(styles.Sheet, !mobile && styles.desktop); | ||
|
||
const containerClassName = classNames( | ||
styles.Container, | ||
!mobile && styles.desktop, | ||
); | ||
|
||
function Container() { | ||
return ( | ||
<div className={containerClassName} {...layer.props} {...overlay.props}> | ||
<TrapFocus trapping={open}> | ||
<div role="dialog" tabIndex={-1} className={sheetClassName}> | ||
{children} | ||
</div> | ||
</TrapFocus> | ||
</div> | ||
); | ||
} | ||
|
||
const sharedTransitionProps = { | ||
timeout: Duration.Slow, | ||
in: open, | ||
mountOnEnter: true, | ||
unmountOnExit: true, | ||
}; | ||
|
||
const bottomClassNames = { | ||
enter: classNames(styles.Bottom, styles.enterBottom), | ||
enterActive: classNames(styles.Bottom, styles.enterBottomActive), | ||
exit: classNames(styles.Bottom, styles.exitBottom), | ||
exitActive: classNames(styles.Bottom, styles.exitBottomActive), | ||
}; | ||
|
||
const rightClassNames = { | ||
enter: classNames(styles.Right, styles.enterRight), | ||
enterActive: classNames(styles.Right, styles.enterRightActive), | ||
exit: classNames(styles.Right, styles.exitRight), | ||
exitActive: classNames(styles.Right, styles.exitRightActive), | ||
}; | ||
|
||
const finalTransitionProps = { | ||
classNames: mobile ? bottomClassNames : rightClassNames, | ||
...sharedTransitionProps, | ||
}; | ||
|
||
return ( | ||
<Portal idPrefix="sheet"> | ||
<CSSTransition {...finalTransitionProps}> | ||
<Container /> | ||
</CSSTransition> | ||
<KeypressListener keyCode={Key.Escape} handler={onClose} /> | ||
<EventListener event="resize" handler={this.handleResize} /> | ||
</Portal> | ||
); | ||
} | ||
} | ||
|
||
export function isMobile(): boolean { | ||
return navigationBarCollapsed().matches; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
import Sheet from './Sheet'; | ||
|
||
export {Props, isMobile} from './Sheet'; | ||
export default Sheet; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import * as React from 'react'; | ||
import {noop} from '@shopify/javascript-utilities/other'; | ||
import {mountWithAppProvider} from 'test-utilities'; | ||
import Sheet from '../Sheet'; | ||
|
||
window.matchMedia = | ||
window.matchMedia || | ||
function() { | ||
return { | ||
matches: false, | ||
addListener() {}, | ||
removeListener() {}, | ||
}; | ||
}; | ||
|
||
describe('<Sheet />', () => { | ||
const mockProps = { | ||
open: true, | ||
onClose: noop, | ||
}; | ||
|
||
it('renders its children', () => { | ||
const children = <div>Content</div>; | ||
|
||
const drawer = mountWithAppProvider( | ||
<Sheet {...mockProps}>{children}</Sheet>, | ||
); | ||
|
||
expect(drawer.find(children)).not.toBeNull(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters