adding bookmarklet
This commit is contained in:
175
src/components/__snapshots__/widget.test.js.snap
Normal file
175
src/components/__snapshots__/widget.test.js.snap
Normal file
@@ -0,0 +1,175 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<Widget /> open/close 1`] = `
|
||||
<Widget>
|
||||
<div
|
||||
className="docked-widget"
|
||||
>
|
||||
<Transition
|
||||
appear={false}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={false}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={250}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="widget widget-exited"
|
||||
>
|
||||
<div
|
||||
className="widget-header"
|
||||
>
|
||||
<div
|
||||
className="widget-header-title"
|
||||
>
|
||||
Header
|
||||
</div>
|
||||
<a
|
||||
className="widget-header-icon"
|
||||
onClick={[Function]}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className="widget-body"
|
||||
>
|
||||
Body
|
||||
</div>
|
||||
<div
|
||||
className="widget-footer"
|
||||
>
|
||||
Footer
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<a
|
||||
className="dock"
|
||||
onClick={[Function]}
|
||||
>
|
||||
^ OPEN ^
|
||||
</a>
|
||||
</div>
|
||||
</Widget>
|
||||
`;
|
||||
|
||||
exports[`<Widget /> open/close 2`] = `
|
||||
<Widget>
|
||||
<div
|
||||
className="docked-widget"
|
||||
>
|
||||
<Transition
|
||||
appear={false}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={true}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={250}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="widget widget-entering"
|
||||
>
|
||||
<div
|
||||
className="widget-header"
|
||||
>
|
||||
<div
|
||||
className="widget-header-title"
|
||||
>
|
||||
Header
|
||||
</div>
|
||||
<a
|
||||
className="widget-header-icon"
|
||||
onClick={[Function]}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className="widget-body"
|
||||
>
|
||||
Body
|
||||
</div>
|
||||
<div
|
||||
className="widget-footer"
|
||||
>
|
||||
Footer
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</Widget>
|
||||
`;
|
||||
|
||||
exports[`<Widget /> open/close 3`] = `
|
||||
<Widget>
|
||||
<div
|
||||
className="docked-widget"
|
||||
>
|
||||
<Transition
|
||||
appear={false}
|
||||
enter={true}
|
||||
exit={true}
|
||||
in={false}
|
||||
mountOnEnter={false}
|
||||
onEnter={[Function]}
|
||||
onEntered={[Function]}
|
||||
onEntering={[Function]}
|
||||
onExit={[Function]}
|
||||
onExited={[Function]}
|
||||
onExiting={[Function]}
|
||||
timeout={250}
|
||||
unmountOnExit={false}
|
||||
>
|
||||
<div
|
||||
className="widget widget-exited"
|
||||
>
|
||||
<div
|
||||
className="widget-header"
|
||||
>
|
||||
<div
|
||||
className="widget-header-title"
|
||||
>
|
||||
Header
|
||||
</div>
|
||||
<a
|
||||
className="widget-header-icon"
|
||||
onClick={[Function]}
|
||||
>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<div
|
||||
className="widget-body"
|
||||
>
|
||||
Body
|
||||
</div>
|
||||
<div
|
||||
className="widget-footer"
|
||||
>
|
||||
Footer
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<a
|
||||
className="dock"
|
||||
onClick={[Function]}
|
||||
>
|
||||
^ OPEN ^
|
||||
</a>
|
||||
</div>
|
||||
</Widget>
|
||||
`;
|
||||
75
src/components/widget.js
Normal file
75
src/components/widget.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Transition } from 'react-transition-group';
|
||||
import './widget.scss';
|
||||
|
||||
class Widget extends Component {
|
||||
state = {
|
||||
opened: false,
|
||||
showDock: true,
|
||||
}
|
||||
|
||||
handleToggleOpen = () => {
|
||||
this.setState((prev) => {
|
||||
let { showDock } = prev;
|
||||
if (!prev.opened) {
|
||||
showDock = false;
|
||||
}
|
||||
return {
|
||||
showDock,
|
||||
opened: !prev.opened,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
handleWidgetExit = () => {
|
||||
this.setState({
|
||||
showDock: true,
|
||||
});
|
||||
}
|
||||
|
||||
renderBody = () => {
|
||||
if (this.state.showDock) {
|
||||
return (
|
||||
<a className="dock" onClick={this.handleToggleOpen}>
|
||||
^ OPEN ^
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
render() {
|
||||
const body = this.renderBody();
|
||||
|
||||
return (
|
||||
<div className="docked-widget">
|
||||
<Transition in={this.state.opened} timeout={250} onExited={this.handleWidgetExit}>
|
||||
{status => (
|
||||
<div className={`widget widget-${status}`}>
|
||||
<div className="widget-header">
|
||||
<div className="widget-header-title">
|
||||
Header
|
||||
</div>
|
||||
<a className="widget-header-icon" onClick={this.handleToggleOpen}>
|
||||
X
|
||||
</a>
|
||||
</div>
|
||||
<div className="widget-body">
|
||||
Body
|
||||
</div>
|
||||
<div className="widget-footer">
|
||||
Footer
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
{body}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Widget.propTypes = {};
|
||||
|
||||
export default Widget;
|
||||
94
src/components/widget.scss
Normal file
94
src/components/widget.scss
Normal file
@@ -0,0 +1,94 @@
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutDown {
|
||||
from {
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
||||
|
||||
to {
|
||||
visibility: hidden;
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.docked-widget {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
right: 10px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.dock {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
width: 180px;
|
||||
border: 1px solid grey;
|
||||
}
|
||||
|
||||
|
||||
.widget {
|
||||
width: 200px;
|
||||
border: 1px solid grey;
|
||||
border-bottom: none;
|
||||
animation-duration: 0.2s;
|
||||
animation-fill-mode: forwards;
|
||||
|
||||
&-entering {
|
||||
animation-name: slideInUp;
|
||||
}
|
||||
&-entered {
|
||||
visibility: visible;
|
||||
}
|
||||
&-exiting {
|
||||
animation-name: slideOutDown;
|
||||
}
|
||||
&-exited {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
&-header {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
background: lightgrey;
|
||||
color: grey;
|
||||
padding-left: 10px;
|
||||
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: .75rem;
|
||||
}
|
||||
}
|
||||
&-body {
|
||||
background: white;
|
||||
padding: 10px;
|
||||
height: 150px;
|
||||
}
|
||||
&-footer {
|
||||
background: green;
|
||||
line-height: 30px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
37
src/components/widget.test.js
Normal file
37
src/components/widget.test.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import Widget from './widget';
|
||||
import { waitForSelection } from '../test-helpers';
|
||||
|
||||
describe('<Widget />', () => {
|
||||
test('open/close', async () => {
|
||||
const widgetDom = mount(<Widget />);
|
||||
expect(widgetDom).toMatchSnapshot();
|
||||
|
||||
{
|
||||
const dockAnchorEl = widgetDom.find('a.dock');
|
||||
expect(dockAnchorEl).toHaveLength(1);
|
||||
// open widget
|
||||
dockAnchorEl.simulate('click');
|
||||
}
|
||||
|
||||
expect(widgetDom).toMatchSnapshot();
|
||||
|
||||
// dock does not exist anymore
|
||||
expect(widgetDom.find('a.dock')).toHaveLength(0);
|
||||
|
||||
const closeAnchorEl = await waitForSelection(widgetDom, 'a.widget-header-icon');
|
||||
|
||||
expect(closeAnchorEl).toHaveLength(1);
|
||||
// close widget
|
||||
closeAnchorEl.simulate('click');
|
||||
|
||||
{
|
||||
const dockAnchorEl = await waitForSelection(widgetDom, 'a.dock');
|
||||
expect(dockAnchorEl).toHaveLength(1);
|
||||
}
|
||||
|
||||
expect(widgetDom).toMatchSnapshot();
|
||||
});
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user