diff --git a/src/assets/style/primereact.css b/src/assets/style/primereact.css index ccd9810a05..c3c30aa8c3 100644 --- a/src/assets/style/primereact.css +++ b/src/assets/style/primereact.css @@ -76,3 +76,4 @@ @import '../../components/treeselect/TreeSelect.css'; @import '../../components/virtualscroller/VirtualScroller.css'; @import '../../components/speeddial/SpeedDial.css'; +@import '../../components/blockui/BlockUI.css'; diff --git a/src/components/blockui/BlockUI.css b/src/components/blockui/BlockUI.css new file mode 100644 index 0000000000..4c72858af0 --- /dev/null +++ b/src/components/blockui/BlockUI.css @@ -0,0 +1,30 @@ +.p-blockui-container { + position: relative; +} + +.p-blockui { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: transparent; + opacity: 1; + transition-property: background-color, opacity; + display: flex; + align-items: center; + justify-content: center; +} + +.p-blockui.p-component-overlay { + position: absolute; +} + +.p-blockui-document.p-component-overlay { + position: fixed; +} + +.p-blockui.p-blockui-leave.p-component-overlay { + opacity: 0; + background-color: transparent; +} diff --git a/src/components/blockui/BlockUI.d.ts b/src/components/blockui/BlockUI.d.ts new file mode 100644 index 0000000000..2ff5bd0781 --- /dev/null +++ b/src/components/blockui/BlockUI.d.ts @@ -0,0 +1,18 @@ +import * as React from 'react'; + +export interface BlockUIProps { + id?: string; + blocked?: boolean; + fullScreen?: boolean; + baseZIndex?: number; + autoZIndex?: boolean; + style?: object; + className?: string; + onBlocked?(): void; + onUnblocked?(): void; +} + +export declare class BlockUI extends React.Component { + public block(): void; + public unblock(): void; +} diff --git a/src/components/blockui/BlockUI.js b/src/components/blockui/BlockUI.js new file mode 100644 index 0000000000..fda7f1d18d --- /dev/null +++ b/src/components/blockui/BlockUI.js @@ -0,0 +1,130 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { classNames, DomHandler, ObjectUtils, ZIndexUtils } from '../utils/Utils'; +import { Portal } from '../portal/Portal'; + +export class BlockUI extends Component { + + static defaultProps = { + id: null, + blocked: false, + fullScreen: false, + baseZIndex: 0, + autoZIndex: true, + style: null, + className: null, + template: null, + onBlocked: null, + onUnblocked: null + }; + + static propTypes = { + id: PropTypes.string, + blocked: PropTypes.bool, + fullScreen: PropTypes.bool, + baseZIndex: PropTypes.number, + autoZIndex: PropTypes.bool, + style: PropTypes.object, + className: PropTypes.string, + template: PropTypes.any, + onBlocked: PropTypes.func, + onUnblocked: PropTypes.func + }; + + constructor(props) { + super(props); + + this.state = { + visible: props.blocked + }; + + this.block = this.block.bind(this); + this.unblock = this.unblock.bind(this); + this.onPortalMounted = this.onPortalMounted.bind(this); + } + + block() { + this.setState({ visible: true }); + } + + unblock() { + DomHandler.addClass(this.mask, 'p-blockui-leave'); + this.mask.addEventListener('transitionend', () => { + ZIndexUtils.clear(this.mask); + this.setState({ visible: false }, () => { + this.props.fullScreen && DomHandler.removeClass(document.body, 'p-overflow-hidden'); + this.props.onUnblocked && this.props.onUnblocked(); + }); + }); + } + + onPortalMounted() { + if (this.props.fullScreen) { + DomHandler.addClass(document.body, 'p-overflow-hidden'); + document.activeElement.blur(); + } + + if (this.mask) { + setTimeout(() => { + DomHandler.addClass(this.mask, 'p-component-overlay'); + }, 1); + } + + if (this.props.autoZIndex) { + ZIndexUtils.set(this.props.fullScreen ? 'modal' : 'overlay', this.mask, this.props.baseZIndex); + } + + this.props.onBlocked && this.props.onBlocked(); + } + + renderMask() { + if (this.state.visible) { + const className = classNames('p-blockui', { + 'p-blockui-document': this.props.fullScreen + }, this.props.className); + const content = this.props.template ? ObjectUtils.getJSXElement(this.props.template, this.props) : null; + const mask = ( +
this.mask = el} className={className} style={this.props.style}> + {content} +
+ ); + + return ( + + ); + } + + return null; + } + + componentDidMount() { + if (this.state.visible) { + this.block(); + } + } + + componentDidUpdate(prevProps, prevState) { + if (prevProps.blocked !== this.props.blocked) { + this.props.blocked ? this.block() : this.unblock(); + } + } + + componentWillUnmount() { + if (this.props.fullScreen) { + DomHandler.removeClass(document.body, 'p-overflow-hidden'); + } + + ZIndexUtils.clear(this.mask); + } + + render() { + const mask = this.renderMask(); + + return ( +
this.container = el} id={this.props.id} className="p-blockui-container"> + {this.props.children} + {mask} +
+ ); + } +} diff --git a/src/components/primereact.all.js b/src/components/primereact.all.js index 2383e2b872..ecfb9eca2b 100644 --- a/src/components/primereact.all.js +++ b/src/components/primereact.all.js @@ -94,3 +94,4 @@ export * from './tristatecheckbox/TriStateCheckbox'; export * from './utils/Utils'; export * from './virtualscroller/VirtualScroller'; export * from './speeddial/SpeedDial'; +export * from './blockui/BlockUI';