diff --git a/packages/component-modal/package.json b/packages/component-modal/package.json new file mode 100644 index 0000000000000000000000000000000000000000..d24ae2f4121b221bb1d2d651ad610152aff2d73c --- /dev/null +++ b/packages/component-modal/package.json @@ -0,0 +1,11 @@ +{ + "name": "pubsweet-component-modal", + "version": "0.0.1", + "main": "src", + "license": "MIT", + "dependencies": { + "react": "^16.2.0", + "react-dom": "^16.2.0", + "react-redux": "^5.0.7" + } +} diff --git a/packages/component-modal/src/components/Modal.js b/packages/component-modal/src/components/Modal.js new file mode 100644 index 0000000000000000000000000000000000000000..55ff87b6073db5df11b6ed5e6349971d44079df9 --- /dev/null +++ b/packages/component-modal/src/components/Modal.js @@ -0,0 +1,40 @@ +import React from 'react' +import ReactDOM from 'react-dom' +import styled from 'styled-components' + +const createModalRootElement = () => { + const modalDiv = document.createElement('div') + modalDiv.setAttribute('id', 'ps-modal-root') + document.body.insertAdjacentElement('beforeend', modalDiv) + + return modalDiv +} + +const modalRoot = createModalRootElement() + +class Modal extends React.Component { + render() { + const { component: Component, overlayColor, ...rest } = this.props + return ReactDOM.createPortal( + <ModalRoot overlayColor={overlayColor}> + <Component {...rest} /> + </ModalRoot>, + modalRoot, + ) + } +} + +export default Modal + +const ModalRoot = styled.div` + position: fixed; + top: 0; + left: 0; + bottom: 0; + right: 0; + display: flex; + justify-content: center; + align-items: center; + background-color: ${({ overlayColor }) => + overlayColor || 'rgba(0, 0, 0, 0.8)'}; +` diff --git a/packages/component-modal/src/components/index.js b/packages/component-modal/src/components/index.js new file mode 100644 index 0000000000000000000000000000000000000000..fca40a67dd2ff42c9d986d2f83fcdb8a369b3dca --- /dev/null +++ b/packages/component-modal/src/components/index.js @@ -0,0 +1 @@ +export { default as withModal } from './withModal' diff --git a/packages/component-modal/src/components/withModal.js b/packages/component-modal/src/components/withModal.js new file mode 100644 index 0000000000000000000000000000000000000000..4506ade0c82e85282718745d07cc7e1fed6b589a --- /dev/null +++ b/packages/component-modal/src/components/withModal.js @@ -0,0 +1,38 @@ +import React from 'react' +import { connect } from 'react-redux' + +import Modal from './Modal' +import { setModalVisibility } from '../redux/modal' + +const mapState = state => ({ + modalVisible: state.modal.visible, + modalProps: state.modal.props, +}) + +const mapDispatch = dispatch => ({ + hideModal: () => dispatch(setModalVisibility(false)), + showModal: (modalProps = {}) => + dispatch(setModalVisibility(true, modalProps)), +}) + +const withModal = ({ + modalComponent: Component, + overlayColor, +}) => WrappedComponent => + connect(mapState, mapDispatch)( + ({ modalVisible, modalProps, hideModal, ...rest }) => ( + <div> + {modalVisible && ( + <Modal + {...modalProps} + component={Component} + hideModal={hideModal} + overlayColor={overlayColor} + /> + )} + <WrappedComponent {...rest} /> + </div> + ), + ) + +export default withModal diff --git a/packages/component-modal/src/index.js b/packages/component-modal/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..142a4ac157a7fbc6729478a20150421853b8c7ba --- /dev/null +++ b/packages/component-modal/src/index.js @@ -0,0 +1,8 @@ +module.exports = { + client: { + components: [() => require('./components')], + reducers: { + modal: () => require('./redux/modal').default, + }, + }, +} diff --git a/packages/component-modal/src/redux/modal.js b/packages/component-modal/src/redux/modal.js new file mode 100644 index 0000000000000000000000000000000000000000..8730d759836c52c0d062c0ba9cdd735cdb6e2e6a --- /dev/null +++ b/packages/component-modal/src/redux/modal.js @@ -0,0 +1,21 @@ +const initialState = { + visible: false, + props: {}, +} + +const SET_MODAL_VISIBILTY = 'modal/SET_MODAL_VISIBILTY' + +export const setModalVisibility = (visible, props = {}) => ({ + type: SET_MODAL_VISIBILTY, + payload: { + visible, + props, + }, +}) + +export default (state = initialState, action = {}) => { + switch (action.type) { + default: + return state + } +} diff --git a/packages/components-faraday/package.json b/packages/components-faraday/package.json index 0c9e9ac697ea51bd8cd203f8135fba00cc3b33d8..1ecc99d925d2d44d55cd2eecc0cb558213c93f2b 100644 --- a/packages/components-faraday/package.json +++ b/packages/components-faraday/package.json @@ -6,6 +6,7 @@ "dependencies": { "@pubsweet/ui": "^0.1.1", "moment": "^2.20.1", + "portal-modal": "^1.0.3", "prop-types": "^15.5.10", "react": "^15.6.1", "react-dnd": "^2.5.4", diff --git a/packages/components-faraday/src/components/Dashboard/Dashboard.js b/packages/components-faraday/src/components/Dashboard/Dashboard.js index 5ca2c0e155ebd558cd51fdad43f95bc3e024f378..3b8b50aa75e72536377d3d4e7e437b0731087443 100644 --- a/packages/components-faraday/src/components/Dashboard/Dashboard.js +++ b/packages/components-faraday/src/components/Dashboard/Dashboard.js @@ -1,7 +1,9 @@ import React from 'react' import { get } from 'lodash' import { Button } from '@pubsweet/ui' +import styled from 'styled-components' import { compose, withHandlers } from 'recompose' +import { withModal } from 'pubsweet-component-modal/src/components' import classes from './Dashboard.local.scss' import AbstractModal from './AbstractModal' @@ -23,6 +25,7 @@ const Dashboard = ({ filterItems, abstractModal, setModal, + showModal, ...rest }) => ( <div className={classes.root}> @@ -32,6 +35,17 @@ const Dashboard = ({ <Button onClick={createDraftSubmission} primary> New </Button> + <Button + onClick={() => + showModal({ + onConfirm: () => alert('confirm'), + costel: true, + }) + } + primary + > + Show modal + </Button> </div> </div> <DashboardFilters @@ -49,7 +63,28 @@ const Dashboard = ({ </div> ) +const ModalRoot = styled.div` + width: 300px; + height: 400px; + background-color: gray; +` + +const ModalComponent = ({ hideModal, dismissable, onConfirm, costel }) => ( + <ModalRoot onClick={dismissable ? hideModal : null}> + This is our custom modal component. + <div> + <button onClick={onConfirm}>Yes</button> + <button onClick={hideModal}>Hide modal</button> + <span>{costel ? 'e costel' : 'nu e'}</span> + </div> + </ModalRoot> +) + export default compose( + withModal({ + modalComponent: ModalComponent, + overlayColor: 'rgba(255, 0,0,0.8)', + }), withHandlers({ getItems: ({ filters, diff --git a/packages/components-faraday/src/index.js b/packages/components-faraday/src/index.js index b417ecc0a0cfaa39581f13b4fd9fa74a6a82efe3..10dad084777d68e581bd79b6f900ae98d64ab1cc 100644 --- a/packages/components-faraday/src/index.js +++ b/packages/components-faraday/src/index.js @@ -4,6 +4,7 @@ module.exports = { reducers: { authors: () => require('./redux/authors').default, files: () => require('./redux/files').default, + modal: () => require('./redux/modal').default, }, }, } diff --git a/packages/components-faraday/src/redux/index.js b/packages/components-faraday/src/redux/index.js index d080497581f9a23bcc33b4fe5f80d14f84a2a034..bc48f2ff567e17a64eb57928d1222dc3382b2ab1 100644 --- a/packages/components-faraday/src/redux/index.js +++ b/packages/components-faraday/src/redux/index.js @@ -1 +1,2 @@ +export { default as modal } from './modal' export { default as authors } from './authors' diff --git a/packages/components-faraday/src/redux/modal.js b/packages/components-faraday/src/redux/modal.js new file mode 100644 index 0000000000000000000000000000000000000000..ba8a4ba264804681f2a9a070665e76db97c49b5d --- /dev/null +++ b/packages/components-faraday/src/redux/modal.js @@ -0,0 +1,3 @@ +import { modalReducer } from 'portal-modal' + +export default modalReducer diff --git a/packages/xpub-faraday/config/components.json b/packages/xpub-faraday/config/components.json index a499849bfa8629886b87f5a7e1bb4e22aaa68ea3..609da317e757cc371a1c3efe4d51b3cf79ebdd84 100644 --- a/packages/xpub-faraday/config/components.json +++ b/packages/xpub-faraday/config/components.json @@ -5,6 +5,7 @@ "xpub-faraday-server", "pubsweet-component-ink-backend", "pubsweet-component-wizard", + "pubsweet-component-modal", "pubsweet-components-faraday", "pubsweet-components-aws-s3", "pubsweet-component-invite" diff --git a/yarn.lock b/yarn.lock index 9463ab4846cd7d62670179e7e6ff2170af88085b..2abbb34822d21a0cccbdc1db238f8f2b0a23cb9d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -633,6 +633,27 @@ axobject-query@^0.1.0: dependencies: ast-types-flow "0.0.7" +babel-cli@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-cli/-/babel-cli-6.26.0.tgz#502ab54874d7db88ad00b887a06383ce03d002f1" + dependencies: + babel-core "^6.26.0" + babel-polyfill "^6.26.0" + babel-register "^6.26.0" + babel-runtime "^6.26.0" + commander "^2.11.0" + convert-source-map "^1.5.0" + fs-readdir-recursive "^1.0.0" + glob "^7.1.2" + lodash "^4.17.4" + output-file-sync "^1.1.2" + path-is-absolute "^1.0.1" + slash "^1.0.0" + source-map "^0.5.6" + v8flags "^2.1.1" + optionalDependencies: + chokidar "^1.6.1" + babel-code-frame@6.26.0, babel-code-frame@^6.11.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" @@ -1169,6 +1190,14 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" +babel-polyfill@^6.26.0: + version "6.26.0" + resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153" + dependencies: + babel-runtime "^6.26.0" + core-js "^2.5.0" + regenerator-runtime "^0.10.5" + babel-preset-env@^1.6.0: version "1.6.1" resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.6.1.tgz#a18b564cc9b9afdf4aae57ae3c1b0d99188e6f48" @@ -1879,7 +1908,7 @@ cheerio@^1.0.0-rc.2: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@^1.0.1, chokidar@^1.7.0: +chokidar@^1.0.1, chokidar@^1.6.1, chokidar@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: @@ -4283,6 +4312,10 @@ fs-extra@^4.0.1, fs-extra@^4.0.2: jsonfile "^4.0.0" universalify "^0.1.0" +fs-readdir-recursive@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz#e32fc030a2ccee44a6b5371308da54be0b397d27" + fs-write-stream-atomic@^1.0.8: version "1.0.10" resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" @@ -4613,7 +4646,7 @@ got@^6.7.1: unzip-response "^2.0.1" url-parse-lax "^1.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -4860,7 +4893,7 @@ hoist-non-react-statics@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" -hoist-non-react-statics@^2.1.0: +hoist-non-react-statics@^2.1.0, hoist-non-react-statics@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.0.tgz#d2ca2dfc19c5a91c5a6615ce8e564ef0347e2a40" @@ -6649,6 +6682,10 @@ lodash-es@^4.17.3, lodash-es@^4.2.0, lodash-es@^4.2.1: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7" +lodash-es@^4.17.5: + version "4.17.5" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.5.tgz#9fc6e737b1c4d151d8f9cae2247305d552ce748f" + lodash._reinterpolate@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -6746,7 +6783,7 @@ lodash@^4, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.13.1, lodash@^4.15.0, lodash@ version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" -lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.3.0: +lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.5, lodash@^4.3.0: version "4.17.5" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.5.tgz#99a92d65c0272debe8c96b6057bc8fbfa3bed511" @@ -7826,6 +7863,14 @@ osenv@0, osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +output-file-sync@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" + dependencies: + graceful-fs "^4.1.4" + mkdirp "^0.5.1" + object-assign "^4.1.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -8122,6 +8167,19 @@ pn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" +portal-modal@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/portal-modal/-/portal-modal-1.0.3.tgz#1fa92680c2699a8adf2e3c6f1cf21a14b41e3a08" + dependencies: + babel-cli "^6.26.0" + babel-core "^6.26.0" + babel-preset-es2015 "^6.24.1" + babel-preset-react "^6.24.1" + babel-preset-stage-2 "^6.24.1" + react "^16.2.0" + react-dom "^16.2.0" + react-redux "^5.0.6" + portfinder@^1.0.9: version "1.0.13" resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.13.tgz#bb32ecd87c27104ae6ee44b5a3ccbf0ebb1aede9" @@ -9484,6 +9542,17 @@ react-redux@^5.0.2, react-redux@^5.0.6: loose-envify "^1.1.0" prop-types "^15.5.10" +react-redux@^5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.0.7.tgz#0dc1076d9afb4670f993ffaef44b8f8c1155a4c8" + dependencies: + hoist-non-react-statics "^2.5.0" + invariant "^2.0.0" + lodash "^4.17.5" + lodash-es "^4.17.5" + loose-envify "^1.1.0" + prop-types "^15.6.0" + react-router-dom@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-4.2.2.tgz#c8a81df3adc58bba8a76782e946cbd4eae649b8d" @@ -9889,6 +9958,10 @@ regenerate@^1.2.1: version "1.3.3" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.3.tgz#0c336d3980553d755c39b586ae3b20aa49c82b7f" +regenerator-runtime@^0.10.5: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -11906,6 +11979,10 @@ use@^2.0.0: isobject "^3.0.0" lazy-cache "^2.0.2" +user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -11969,6 +12046,12 @@ uuid@^3.0.0, uuid@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14" +v8flags@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" + dependencies: + user-home "^1.1.1" + validate-npm-package-license@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"