diff --git a/packages/dnb-ui-lib/src/components/modal/Example.js b/packages/dnb-ui-lib/src/components/modal/Example.js index c2b9c70ceb2..4496ecc91cd 100644 --- a/packages/dnb-ui-lib/src/components/modal/Example.js +++ b/packages/dnb-ui-lib/src/components/modal/Example.js @@ -48,6 +48,22 @@ class Example extends PureComponent {


Focus me with Tab key + + `} + + + {/* @jsx */ ` + { + setTimeout(close, 3e3) + }} +> +

+ This Modal will close in 3 seconds. +

`}
diff --git a/packages/dnb-ui-lib/src/components/modal/Modal.js b/packages/dnb-ui-lib/src/components/modal/Modal.js index a0790462241..75ff2eef3fc 100644 --- a/packages/dnb-ui-lib/src/components/modal/Modal.js +++ b/packages/dnb-ui-lib/src/components/modal/Modal.js @@ -27,6 +27,8 @@ const renderProps = { on_open: null, on_close: null, on_close_prevent: null, + open_modal: null, + close_modal: null, modal_content: null } @@ -46,6 +48,7 @@ export const propTypes = { PropTypes.bool ]), prevent_close: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), + open_state: PropTypes.oneOf(['opened', 'closed']), class: PropTypes.string, // React props @@ -56,11 +59,15 @@ export const propTypes = { PropTypes.func ]), - // Web Component props - preventSetTriggerRef: PropTypes.bool, + // Events and functions on_open: PropTypes.func, on_close: PropTypes.func, on_close_prevent: PropTypes.func, + open_modal: PropTypes.func, + close_modal: PropTypes.func, + + // Web Component props + preventSetTriggerRef: PropTypes.bool, modal_content: PropTypes.oneOfType([ PropTypes.string, PropTypes.node, @@ -126,7 +133,23 @@ export default class Modal extends PureComponent { } } + static getDerivedStateFromProps(props, state) { + if (state._listenForPropChanges) { + switch (props.open_state) { + case 'opened': + state.modalActive = true + break + case 'closed': + state.modalActive = false + break + } + } + state._listenForPropChanges = true + return state + } + state = { + _listenForPropChanges: true, modalActive: false } @@ -153,19 +176,38 @@ export default class Modal extends PureComponent { } } + componentDidMount() { + const { open_modal, open_state } = this.props + if (typeof open_modal === 'function') { + open_modal(() => { + this.toggleOpenClose(null, true) + }, this) + } + if (open_state) { + this.handleSideEffects(this.state.modalActive) + } + } + componentWillUnmount() { + this.toggleOpenClose(null, false) + } + toggleOpenClose = (event = null, showModal = null) => { if (event && event.preventDefault) { event.preventDefault() } - Modal.insertModalRoot() - const modalActive = showModal !== null ? showModal : !this.state.modalActive this.setState({ - modalActive + modalActive, + _listenForPropChanges: false }) + this.handleSideEffects(modalActive) + } + handleSideEffects = modalActive => { + Modal.insertModalRoot() + // prevent scrolling on the background try { document.body.setAttribute( @@ -179,6 +221,15 @@ export default class Modal extends PureComponent { ) } + if (modalActive) { + if (typeof this.props.close_modal === 'function') { + this.props.close_modal(() => { + this.isClosing = false + this.toggleOpenClose(null, false) + }, this) + } + } + const id = this._id if (modalActive) { dispatchCustomElementEvent(this, 'on_open', { id }) @@ -214,9 +265,6 @@ export default class Modal extends PureComponent { this.toggleOpenClose(e, false) } } - componentWillUnmount() { - this.toggleOpenClose(null, false) - } render() { const { id, // eslint-disable-line diff --git a/packages/dnb-ui-lib/src/components/modal/__tests__/__snapshots__/Modal.test.js.snap b/packages/dnb-ui-lib/src/components/modal/__tests__/__snapshots__/Modal.test.js.snap index 1701cf671db..4e46d6c3be9 100644 --- a/packages/dnb-ui-lib/src/components/modal/__tests__/__snapshots__/Modal.test.js.snap +++ b/packages/dnb-ui-lib/src/components/modal/__tests__/__snapshots__/Modal.test.js.snap @@ -9,6 +9,7 @@ exports[`Modal component have to match snapshot 1`] = ` "children": "children", "class": "class", "className": "className", + "close_modal": [Function], "close_title": "close_title", "content_id": "content_id", "hide_close_button": "hide_close_button", @@ -18,6 +19,8 @@ exports[`Modal component have to match snapshot 1`] = ` "on_close": [Function], "on_close_prevent": [Function], "on_open": [Function], + "open_modal": [Function], + "open_state": "'opened'", "preventSetTriggerRef": true, "prevent_close": "prevent_close", "title": "title", @@ -67,6 +70,7 @@ exports[`Modal component have to match snapshot 1`] = ` } class={null} className={null} + close_modal={null} close_title="close_title" content_id="modal_content_id" hide_close_button={false} @@ -76,6 +80,7 @@ exports[`Modal component have to match snapshot 1`] = ` on_close={null} on_close_prevent={null} on_open={null} + open_modal={null} preventSetTriggerRef={true} prevent_close={false} title="modal_title" @@ -191,6 +196,7 @@ exports[`Modal component have to match snapshot 1`] = ` "children": "children", "class": "class", "className": "className", + "close_modal": [Function], "close_title": "close_title", "content_id": "content_id", "hide_close_button": "hide_close_button", @@ -200,6 +206,8 @@ exports[`Modal component have to match snapshot 1`] = ` "on_close": [Function], "on_close_prevent": [Function], "on_open": [Function], + "open_modal": [Function], + "open_state": "'opened'", "preventSetTriggerRef": true, "prevent_close": "prevent_close", "title": "title", @@ -250,6 +258,7 @@ exports[`Modal component have to match snapshot 1`] = ` class={null} className={null} closeModal={[Function]} + close_modal={null} close_title="close_title" content_id="modal_content_id" hide_close_button={false} @@ -258,6 +267,7 @@ exports[`Modal component have to match snapshot 1`] = ` on_close={null} on_close_prevent={null} on_open={null} + open_modal={null} prevent_close={false} title="modal_title" toggleOpenClose={[Function]} @@ -270,6 +280,7 @@ exports[`Modal component have to match snapshot 1`] = ` "children": "children", "class": "class", "className": "className", + "close_modal": [Function], "close_title": "close_title", "content_id": "content_id", "hide_close_button": "hide_close_button", @@ -279,6 +290,8 @@ exports[`Modal component have to match snapshot 1`] = ` "on_close": [Function], "on_close_prevent": [Function], "on_open": [Function], + "open_modal": [Function], + "open_state": "'opened'", "preventSetTriggerRef": true, "prevent_close": "prevent_close", "title": "title", @@ -329,6 +342,7 @@ exports[`Modal component have to match snapshot 1`] = ` class={null} className={null} closeModal={[Function]} + close_modal={null} close_title="close_title" content_id="modal_content_id" hide_close_button={false} @@ -337,6 +351,7 @@ exports[`Modal component have to match snapshot 1`] = ` on_close={null} on_close_prevent={null} on_open={null} + open_modal={null} prevent_close={false} title="modal_title" toggleOpenClose={[Function]} diff --git a/packages/dnb-ui-lib/src/components/modal/details.md b/packages/dnb-ui-lib/src/components/modal/details.md index 056af558670..2056a16495b 100644 --- a/packages/dnb-ui-lib/src/components/modal/details.md +++ b/packages/dnb-ui-lib/src/components/modal/details.md @@ -10,6 +10,9 @@ | `close_title` | _(optional)_ the title of the close button. Defaults to _Close Modal Window_ | | `hide_close_button` | _(optional)_ if set to true, the close button will now be shown | | `prevent_close` | _(optional)_ if set to `true` (boolean or string), then the user can't close the modal. | +| `open_state` | _(optional)_ use this prop to control the open/close state by setting either: `opened` or `closed` | +| `open_modal` | _(optional)_ set a function to call the callback function, once the modal should open: `open_modal={(open) => open()}` | +| `close_modal` | _(optional)_ set a function to call the callback function, once the modal should close: `close_modal={(close) => close()}` | | Events | Description | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | diff --git a/packages/dnb-ui-lib/stories/componentsStories.js b/packages/dnb-ui-lib/stories/componentsStories.js index 2cf2387cdf6..d6f9c9b1f6b 100644 --- a/packages/dnb-ui-lib/stories/componentsStories.js +++ b/packages/dnb-ui-lib/stories/componentsStories.js @@ -255,11 +255,40 @@ stories.push([ ) ]) -stories.push([ - 'Modal', - () => ( - - +class ModalCloseExample extends React.PureComponent { + state = { + open_state: null + } + + // constructor(props) { + // super(props) + // + // setTimeout(() => { + // this.setState({ + // open_state: 'opened' + // }) + // setTimeout(() => { + // this.setState({ + // open_state: 'closed' + // }) + // }, 3e3) + // }, 1e3) + // } + + render() { + return ( + { + // setTimeout(open, 3e3) + // }} + close_modal={close => { + console.log('Modal was opened') + setTimeout(close, 3e3) + }} + >

Some content

@@ -271,6 +300,31 @@ stories.push([

+ ) + } +} + +stories.push([ + 'Modal', + () => ( + + + +
+ +

Some content

+ Focus me with Tab key +
+ +

+ +

+
+
+
+ + +
) ])