-
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.
initial move of Sheet as subcomponent of Frame
- Loading branch information
1 parent
dcc6c55
commit 2cecc10
Showing
8 changed files
with
292 additions
and
1 deletion.
There are no files selected for viewing
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
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: 100%; | ||
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,110 @@ | ||
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 {SheetProps as Props} from '../../types'; | ||
|
||
import styles from './Sheet.scss'; | ||
|
||
export const BOTTOM_CLASS_NAMES = { | ||
enter: classNames(styles.Bottom, styles.enterBottom), | ||
enterActive: classNames(styles.Bottom, styles.enterBottomActive), | ||
exit: classNames(styles.Bottom, styles.exitBottom), | ||
exitActive: classNames(styles.Bottom, styles.exitBottomActive), | ||
}; | ||
|
||
export const RIGHT_CLASS_NAMES = { | ||
enter: classNames(styles.Right, styles.enterRight), | ||
enterActive: classNames(styles.Right, styles.enterRightActive), | ||
exit: classNames(styles.Right, styles.exitRight), | ||
exitActive: classNames(styles.Right, styles.exitRightActive), | ||
}; | ||
|
||
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 finalTransitionProps = { | ||
classNames: mobile ? BOTTOM_CLASS_NAMES : RIGHT_CLASS_NAMES, | ||
...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; |
70 changes: 70 additions & 0 deletions
70
src/components/Frame/components/Sheet/tests/Sheet.test.tsx
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,70 @@ | ||
import * as React from 'react'; | ||
|
||
import {CSSTransition} from 'react-transition-group'; | ||
import {noop} from '@shopify/javascript-utilities/other'; | ||
import {matchMedia} from '@shopify/jest-dom-mocks'; | ||
import {mountWithAppProvider} from 'test-utilities'; | ||
|
||
import Sheet, {isMobile, BOTTOM_CLASS_NAMES, RIGHT_CLASS_NAMES} from '../Sheet'; | ||
|
||
describe('<Sheet />', () => { | ||
beforeEach(() => { | ||
matchMedia.mock(); | ||
}); | ||
|
||
afterEach(() => { | ||
matchMedia.restore(); | ||
}); | ||
|
||
const mockProps = { | ||
open: true, | ||
onClose: noop, | ||
}; | ||
|
||
it('renders its children', () => { | ||
const children = <div>Content</div>; | ||
|
||
const sheet = mountWithAppProvider( | ||
<Sheet {...mockProps}>{children}</Sheet>, | ||
); | ||
|
||
expect(sheet.find(children)).not.toBeNull(); | ||
}); | ||
|
||
it('renders a css transition component with bottom class names at mobile sizes', () => { | ||
matchMedia.setMedia(() => ({matches: true})); | ||
|
||
const sheet = mountWithAppProvider( | ||
<Sheet {...mockProps}> | ||
<div>Content</div> | ||
</Sheet>, | ||
); | ||
|
||
expect(sheet.find(CSSTransition).props().classNames).toEqual( | ||
BOTTOM_CLASS_NAMES, | ||
); | ||
}); | ||
|
||
it('renders a css transition component with right class names at desktop sizes', () => { | ||
const sheet = mountWithAppProvider( | ||
<Sheet {...mockProps}> | ||
<div>Content</div> | ||
</Sheet>, | ||
); | ||
|
||
expect(sheet.find(CSSTransition).props().classNames).toEqual( | ||
RIGHT_CLASS_NAMES, | ||
); | ||
}); | ||
|
||
describe('isMobile', () => { | ||
it('returns false by default', () => { | ||
expect(isMobile()).toBe(false); | ||
}); | ||
|
||
it('returns true at mobile sizes', () => { | ||
matchMedia.setMedia(() => ({matches: true})); | ||
expect(isMobile()).toBe(true); | ||
}); | ||
}); | ||
}); |
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
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