diff --git a/docs/components/Layout/index.jsx b/docs/components/Layout/index.jsx
index 1290bff8f..9577d60dc 100644
--- a/docs/components/Layout/index.jsx
+++ b/docs/components/Layout/index.jsx
@@ -60,6 +60,7 @@ import InformationBoxExample from '../../examples/InformationBoxExample';
import SplitPaneExample from '../../examples/SplitPaneExample';
import HoverDropdownMenuExample from '../../examples/HoverDropdownMenuExample';
import NavigationExample from '../../examples/NavigationExample';
+import OverlayLoaderExample from '../../examples/OverlayLoaderExample';
import './styles.scss';
import '../../examples/styles.scss';
@@ -93,7 +94,7 @@ const componentsBySection = {
'stats-and-data': ['count-badge', 'statistic', 'totals', 'slicey'],
'icons-and-graphics': ['svg-symbol', 'svg-symbol-circle'],
navigation: ['breadcrumb', 'tab', 'hover-dropdown-menu', 'navigation-tabs'],
- 'feedback-and-states': ['alert', 'empty', 'spinner', 'pretty-diff', 'status-pill'],
+ 'feedback-and-states': ['alert', 'empty', 'spinner', 'overlay-loader', 'pretty-diff', 'status-pill'],
dialogue: ['popover', 'help-icon-popover', 'avatar'],
modals: ['confirm-modal'],
search: ['search', 'search-bar', 'tag'],
@@ -213,6 +214,7 @@ class PageLayout extends React.Component {
+
diff --git a/docs/examples/OverlayLoaderExample.jsx b/docs/examples/OverlayLoaderExample.jsx
new file mode 100644
index 000000000..63a27eb18
--- /dev/null
+++ b/docs/examples/OverlayLoaderExample.jsx
@@ -0,0 +1,104 @@
+import React from 'react';
+import Example from '../components/Example';
+import { OverlayLoader, Button } from '../../src';
+
+class OverlayLoaderExample extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ showDisabledLoader: false,
+ showLoader: false,
+ };
+ this.toggleLoader = this.toggleLoader.bind(this);
+ this.toggleDisabledLoader = this.toggleDisabledLoader.bind(this);
+ this.handleKeyPress = this.handleKeyPress.bind(this);
+ }
+
+ handleKeyPress(event) {
+ if (event.keyCode === 27) {
+ this.toggleDisabledLoader();
+ }
+ }
+
+ toggleLoader() {
+ this.setState(prevState => ({ showLoader: !prevState.showLoader }));
+ }
+
+ toggleDisabledLoader() {
+ this.setState(
+ prevState => ({ showDisabledLoader: !prevState.showDisabledLoader, showLoader: false }),
+ () => {
+ const eventTrigger = this.state.showDisabledLoader ? window.addEventListener : window.removeEventListener;
+ eventTrigger('keydown', this.handleKeyPress);
+ }
+ );
+ }
+
+ render() {
+ return (
+
+ Static markup
+
+
+
+
+
+
Demo
+
+ {this.state.showLoader && }
+
+ {this.state.showDisabledLoader && }
+
+
+ );
+ }
+}
+
+const exampleProps = {
+ componentName: 'Overlay Loader',
+ notes: `Fixed position loader which provides user experience for page loading or interim loading states`,
+ exampleCodeSnippet: `
+ // Static Markup Loaders
+
+
+
+ // Demo Loaders
+
+
+ `,
+ propTypeSectionArray: [
+ {
+ propTypes: [
+ {
+ defaultValue: 'Loading',
+ propType: 'heading',
+ type: 'string',
+ },
+ {
+ propType: 'top',
+ type: 'number',
+ note: 'Position from top of DOM',
+ defaultValue: '320',
+ },
+ {
+ propType: 'text',
+ type: 'string',
+ },
+ {
+ propType: 'disableBackground',
+ defaultValue: 'false',
+ type: 'bool',
+ note: 'prevents event propogation',
+ },
+ ],
+ },
+ ],
+};
+
+export default () => (
+
+
+
+);
diff --git a/docs/examples/styles.scss b/docs/examples/styles.scss
index aca7bfb67..990932840 100644
--- a/docs/examples/styles.scss
+++ b/docs/examples/styles.scss
@@ -107,6 +107,26 @@
}
}
}
+
+ &.overlay-loader-example {
+ .static-markup {
+ display: flex;
+ margin-bottom: 50px;
+ width: 300px;
+
+ .aui--overlay-loader {
+ position: inherit;
+
+ .loader {
+ position: inherit;
+ }
+
+ + .aui--overlay-loader {
+ margin-right: 10px;
+ }
+ }
+ }
+ }
}
.full-width {
diff --git a/src/components/adslot-ui/OverlayLoader/index.jsx b/src/components/adslot-ui/OverlayLoader/index.jsx
new file mode 100644
index 000000000..690e9d4d8
--- /dev/null
+++ b/src/components/adslot-ui/OverlayLoader/index.jsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+// import ReactDOM from 'react-dom';
+import { Spinner } from 'alexandria';
+import './styles.scss';
+
+const OverlayLoader = ({ text, top, heading, disableBackground }) => (
+ event.stopPropagation() } : {})}
+ >
+
+
+ {heading}
+ {text && {text}}
+
+
+);
+
+OverlayLoader.defaultProps = {
+ heading: 'Loading',
+ top: 320,
+ disableBackground: false,
+};
+
+OverlayLoader.propTypes = {
+ heading: PropTypes.string,
+ text: PropTypes.string,
+ top: PropTypes.number,
+ disableBackground: PropTypes.bool,
+};
+
+export default OverlayLoader;
diff --git a/src/components/adslot-ui/OverlayLoader/index.spec.jsx b/src/components/adslot-ui/OverlayLoader/index.spec.jsx
new file mode 100644
index 000000000..2f5ed67c4
--- /dev/null
+++ b/src/components/adslot-ui/OverlayLoader/index.spec.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import sinon from 'sinon';
+import { mount, shallow } from 'enzyme';
+import OverlayLoader from 'adslot-ui/OverlayLoader';
+
+describe('Overlay Loader Component', () => {
+ it('should render Overlay Loader', () => {
+ const wrapper = shallow();
+ expect(wrapper.find('.aui--overlay-loader')).to.have.length(1);
+ expect(wrapper.find('.loader-heading').text()).to.equal('Loading');
+ });
+
+ it('should stop event propogation when disabled background', () => {
+ const eventStub = sinon.stub();
+ const wrapper = mount(
+ eventStub} className="my-div">
+
+
+ );
+ expect(wrapper.find(OverlayLoader)).to.have.length(1);
+ expect(wrapper.find('.loader-heading').text()).to.equal('Loading');
+ wrapper.find('.my-div').simulate('click');
+ wrapper.find(OverlayLoader).simulate('click');
+ expect(eventStub.called).to.equal(false);
+ });
+});
diff --git a/src/components/adslot-ui/OverlayLoader/styles.scss b/src/components/adslot-ui/OverlayLoader/styles.scss
new file mode 100644
index 000000000..ba5ee9d34
--- /dev/null
+++ b/src/components/adslot-ui/OverlayLoader/styles.scss
@@ -0,0 +1,54 @@
+@import '~styles/variable';
+
+.aui--overlay-loader {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ top: 10px;
+ z-index: $zindex-popover;
+
+ &-disabled {
+ position: fixed;
+ }
+
+ .loader {
+ position: fixed;
+ left: 50%;
+ width: 96px;
+ min-height: 132px;
+ background-color: $color-gray-white;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ padding: 20px;
+ border-radius: 5px;
+ border: 1px solid $color-gray-light;
+ font-weight: $font-weight-bold;
+ opacity: .9;
+ line-height: 14px;
+
+ .loader-heading {
+ color: $color-gray-darker;
+ }
+
+ .loader-text {
+ margin-top: 5px;
+ color: $color-gray;
+ width: 65px;
+ text-align: center;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ word-break: break-word;
+ }
+
+ .spinner-medium {
+ height: 40px;
+ width: 40px;
+ margin-bottom: 20px;
+ border-bottom-color: $color-gray-darker;
+ border-left-color: $color-gray-darker;
+ border-right-color: $color-gray-darker;
+ border-width: 5px;
+ }
+ }
+}
diff --git a/src/components/adslot-ui/index.js b/src/components/adslot-ui/index.js
index c54f7af24..27604c532 100644
--- a/src/components/adslot-ui/index.js
+++ b/src/components/adslot-ui/index.js
@@ -32,6 +32,7 @@ import HoverDropdownMenu from 'adslot-ui/HoverDropdownMenu';
import fastStatelessWrapper from 'adslot-ui/fastStatelessWrapper';
import InformationBox from 'adslot-ui/InformationBox';
import Nav from 'adslot-ui/Navigation';
+import OverlayLoader from 'adslot-ui/OverlayLoader';
export {
Accordion,
@@ -68,4 +69,5 @@ export {
UserListPicker,
InformationBox,
HoverDropdownMenu,
+ OverlayLoader,
};
diff --git a/src/index.js b/src/index.js
index d4e6ac5d8..8032f76cf 100644
--- a/src/index.js
+++ b/src/index.js
@@ -77,6 +77,7 @@ import {
UserListPicker,
InformationBox,
HoverDropdownMenu,
+ OverlayLoader,
} from 'adslot-ui';
export {
@@ -145,4 +146,5 @@ export {
UserListPicker,
InformationBox,
HoverDropdownMenu,
+ OverlayLoader,
};
diff --git a/src/styles/variable.scss b/src/styles/variable.scss
index 755f40154..bcbb05f0f 100644
--- a/src/styles/variable.scss
+++ b/src/styles/variable.scss
@@ -127,6 +127,8 @@ $popover-border-color: $color-border-lighter;
$popover-arrow-width: 5px;
$popover-arrow-outer-color: $popover-border-color;
$popover-title-bg: $color-background;
+$zindex-popover: 1060;
+
// == TreePicker
$treepicker-height: 500px;