Optional Mount Parameters (#123)

* adding optional parameters

* updating bodyText mount prop to default

* updating snapshot for new props

* adding parent element for mounting

* adding null default for parentElement

* adding dist to gitignore

* adding test case for mounting to element

* adding div to document in test

* unmount after test

* updating test to pass

* updating eslint to handle certain rules as warning and fix others
This commit is contained in:
Gavin Foster 2019-06-20 12:26:02 -05:00 committed by Benjamin Boudreau
parent d00d6af82a
commit 309bfd6a5b
12 changed files with 77 additions and 24 deletions

View File

@ -7,7 +7,10 @@
"extends": "airbnb", "extends": "airbnb",
"rules": { "rules": {
"no-underscore-dangle": 0, "no-underscore-dangle": 0,
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }] "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"import/prefer-default-export": 1,
"import/no-extraneous-dependencies": 1,
"no-await-in-loop": 1
}, },
"plugins": ["react"], "plugins": ["react"],
"settings": { "settings": {

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
node_modules node_modules
coverage coverage
/dist/*

View File

@ -1,8 +1,8 @@
module.exports = { module.exports = {
process() { process() {
return 'module.exports = {};' return 'module.exports = {};';
}, },
getCacheKey() { getCacheKey() {
return 'cssTransform' return 'cssTransform';
}, },
} };

View File

@ -1,7 +1,7 @@
const path = require('path') const path = require('path');
module.exports = { module.exports = {
process(src, filename) { process(src, filename) {
return `module.exports = ${JSON.stringify(path.basename(filename))};` return `module.exports = ${JSON.stringify(path.basename(filename))};`;
}, },
} };

View File

@ -8,7 +8,8 @@
"start": "webpack-dev-server", "start": "webpack-dev-server",
"test": "jest", "test": "jest",
"test-update-snapshots": "jest --updateSnapshot", "test-update-snapshots": "jest --updateSnapshot",
"deploy": "npm run build && gh-pages -d dist" "deploy": "npm run build && gh-pages -d dist",
"lint": "./node_modules/.bin/eslint ."
}, },
"babel": { "babel": {
"presets": [ "presets": [

View File

@ -8,7 +8,9 @@
<script src="./widget.js"></script> <script src="./widget.js"></script>
<script> <script>
EmbeddableWidget.mount(); EmbeddableWidget.mount({
bodyText: 'Body'
});
</script> </script>
</body> </body>
</html> </html>

View File

@ -1,7 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<Widget /> open/close 1`] = ` exports[`<Widget /> open/close 1`] = `
<Widget> <Widget
bodyText="Body"
footerText="Footer"
headerText="Header"
>
<div <div
className="docked-widget" className="docked-widget"
> >
@ -65,7 +69,11 @@ exports[`<Widget /> open/close 1`] = `
`; `;
exports[`<Widget /> open/close 2`] = ` exports[`<Widget /> open/close 2`] = `
<Widget> <Widget
bodyText="Body"
footerText="Footer"
headerText="Header"
>
<div <div
className="docked-widget" className="docked-widget"
> >
@ -121,7 +129,11 @@ exports[`<Widget /> open/close 2`] = `
`; `;
exports[`<Widget /> open/close 3`] = ` exports[`<Widget /> open/close 3`] = `
<Widget> <Widget
bodyText="Body"
footerText="Footer"
headerText="Header"
>
<div <div
className="docked-widget" className="docked-widget"
> >

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Transition } from 'react-transition-group'; import { Transition } from 'react-transition-group';
import './widget.scss'; import './widget.scss';
@ -47,6 +48,7 @@ class Widget extends Component {
render() { render() {
const { opened } = this.state; const { opened } = this.state;
const body = this.renderBody(); const body = this.renderBody();
const { bodyText, headerText, footerText } = this.props;
return ( return (
<div className="docked-widget"> <div className="docked-widget">
@ -55,7 +57,7 @@ class Widget extends Component {
<div className={`widget widget-${status}`}> <div className={`widget widget-${status}`}>
<div className="widget-header"> <div className="widget-header">
<div className="widget-header-title"> <div className="widget-header-title">
Header {headerText}
</div> </div>
<button <button
type="button" type="button"
@ -67,10 +69,10 @@ class Widget extends Component {
</button> </button>
</div> </div>
<div className="widget-body"> <div className="widget-body">
Body {bodyText}
</div> </div>
<div className="widget-footer"> <div className="widget-footer">
Footer {footerText}
</div> </div>
</div> </div>
)} )}
@ -81,4 +83,16 @@ class Widget extends Component {
} }
} }
Widget.propTypes = {
headerText: PropTypes.string,
bodyText: PropTypes.string,
footerText: PropTypes.string,
};
Widget.defaultProps = {
headerText: 'Header',
bodyText: 'Body',
footerText: 'Footer',
};
export default Widget; export default Widget;

View File

@ -28,10 +28,9 @@ describe('<Widget />', () => {
{ {
const dockAnchorEl = await waitForSelection(widgetDom, 'button.dock'); const dockAnchorEl = await waitForSelection(widgetDom, 'button.dock');
expect(dockAnchorEl).toHaveLength(1); expect(dockAnchorEl).toHaveLength(1);
} }
expect(widgetDom).toMatchSnapshot(); expect(widgetDom).toMatchSnapshot();
}); });
}); });

View File

@ -6,8 +6,8 @@ import '../../vendor/cleanslate.css';
export default class EmbeddableWidget { export default class EmbeddableWidget {
static el; static el;
static mount() { static mount({ parentElement = null, ...props } = {}) {
const component = <Widget />; const component = <Widget {...props} />;
function doRender() { function doRender() {
if (EmbeddableWidget.el) { if (EmbeddableWidget.el) {
@ -15,7 +15,12 @@ export default class EmbeddableWidget {
} }
const el = document.createElement('div'); const el = document.createElement('div');
el.setAttribute('class', 'cleanslate'); el.setAttribute('class', 'cleanslate');
document.body.appendChild(el);
if (parentElement) {
document.querySelector(parentElement).appendChild(el);
} else {
document.body.appendChild(el);
}
ReactDOM.render( ReactDOM.render(
component, component,
el, el,

View File

@ -21,6 +21,20 @@ describe('EmbeddableWidget', () => {
await waitForSelection(document, 'div'); await waitForSelection(document, 'div');
}); });
test('#mount to document element', async () => {
const newElement = document.createElement('span');
newElement.setAttribute('id', 'widget-mount');
document.body.appendChild(newElement);
EmbeddableWidget.mount({
parentElement: '#widget-mount',
});
await waitForSelection(document, 'div');
expect(document.querySelectorAll('#widget-mount')).toHaveLength(1);
});
test('#mount twice', async () => { test('#mount twice', async () => {
EmbeddableWidget.mount(); EmbeddableWidget.mount();
expect(() => EmbeddableWidget.mount()).toThrow('already mounted'); expect(() => EmbeddableWidget.mount()).toThrow('already mounted');

View File

@ -1,5 +1,4 @@
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const increaseSpecificity = require('postcss-increase-specificity'); const increaseSpecificity = require('postcss-increase-specificity');
const JavaScriptObfuscator = require('webpack-obfuscator'); const JavaScriptObfuscator = require('webpack-obfuscator');
const CopyPlugin = require('copy-webpack-plugin'); const CopyPlugin = require('copy-webpack-plugin');
@ -14,7 +13,7 @@ const defaultConfig = {
mode: process.env.NODE_ENV || 'development', mode: process.env.NODE_ENV || 'development',
devServer: { devServer: {
contentBase: publicDir, contentBase: publicDir,
port: 9000 port: 9000,
}, },
plugins: [ plugins: [
// new CleanWebpackPlugin({protectWebpackAssets: false}), // new CleanWebpackPlugin({protectWebpackAssets: false}),
@ -39,8 +38,11 @@ const defaultConfig = {
{ {
test: /\.js$/, test: /\.js$/,
exclude: /node_modules/, exclude: /node_modules/,
use: ['eslint-loader'] loader: 'eslint-loader',
}, options: {
emitWarning: true,
},
},
{ {
test: /\.(scss|css)$/, test: /\.(scss|css)$/,
use: [ use: [