diff --git a/docs/components/Layout/index.jsx b/docs/components/Layout/index.jsx
index 525eafdf2..78e892f90 100644
--- a/docs/components/Layout/index.jsx
+++ b/docs/components/Layout/index.jsx
@@ -60,6 +60,7 @@ import HoverDropdownMenuExample from '../../examples/HoverDropdownMenuExample';
import NavigationExample from '../../examples/NavigationExample';
import OverlayLoaderExample from '../../examples/OverlayLoaderExample';
import SearchExample from '../../examples/SearchExample';
+import ActionPanelExample from '../../examples/ActionPanelExample';
import './styles.scss';
import '../../examples/styles.scss';
@@ -97,6 +98,7 @@ const componentsBySection = {
dialogue: ['popover', 'help-icon-popover', 'avatar'],
modals: ['confirm-modal'],
search: ['search', 'tag'],
+ panels: ['action-panel'],
grouping: [
'page-title',
'card',
@@ -225,6 +227,9 @@ class PageLayout extends React.Component {
+
+
+
diff --git a/docs/examples/ActionPanelExample.jsx b/docs/examples/ActionPanelExample.jsx
new file mode 100644
index 000000000..cd2616e15
--- /dev/null
+++ b/docs/examples/ActionPanelExample.jsx
@@ -0,0 +1,125 @@
+import React from 'react';
+import Example from '../components/Example';
+import { Button, ActionPanel } from '../../src';
+import SvgSymbol from 'alexandria/SvgSymbol';
+
+class ActionPanelExample extends React.PureComponent {
+ constructor() {
+ super();
+ this.state = {
+ showActionPanel: false,
+ };
+ this.toggleActionPanel = this.toggleActionPanel.bind(this);
+ }
+
+ toggleActionPanel() {
+ this.setState({ showActionPanel: !this.state.showActionPanel });
+ }
+
+ render() {
+ return (
+
+ Static markup
+
+
+ Australia hosts a rich biodiversity. Compared to other regions of the world, it has a unique wildlife.
+ Endemic animals roam freely in the wild. Some of them are Australia's cultural icons such as the
+ kangaroos, koalas, and emus.
+
+ }
+ />
+
+
+
Demo
+
Action Panel as a modal
+ {this.state.showActionPanel && (
+
Action}
+ isModal
+ children={
+
+ Native mammals include the dingoes or wild dogs, numbats, quolls, and Tasmanian devils. Dingoes are
+ the largest carnivorous mammals that populate the wilds of mainland Australia. But the smaller numbats
+ and Tasmanian devils, which are house cat-like size can be seen only in wildlife parks. You can also
+ spot them in the wilds of Tasmania.
+
+ }
+ />
+ )}
+
+
+ );
+ }
+}
+
+const exampleProps = {
+ componentName: 'Action Panel',
+ designNotes:
Action panel can be used as a modal or a information display panel.
,
+ exampleCodeSnippet: `
+ `,
+ propTypeSectionArray: [
+ {
+ propTypes: [
+ {
+ propType: 'title',
+ type: 'string',
+ },
+ {
+ propType: 'className',
+ type: 'string',
+ },
+ {
+ propType: 'size',
+ type: "oneOf: 'small', 'medium', 'large'",
+ defaultValue: 'large',
+ note: 'small - 500px, medium - 700px, large- 1000px',
+ },
+ {
+ propType: 'onClose',
+ type: 'func',
+ },
+ {
+ propType: 'children',
+ type: 'node',
+ },
+ {
+ propType: 'actionButton',
+ type: 'node',
+ defaultValue: 'null',
+ },
+ {
+ propType: 'isModal',
+ type: 'bool',
+ defaultValue: 'false',
+ },
+ {
+ propType: 'closeIcon',
+ type: 'node',
+ defaultValue: (
+
+
+
+ ),
+ },
+ ],
+ },
+ ],
+};
+
+export default () => (
+
+
+
+);
diff --git a/src/components/adslot-ui/ActionPanel/index.jsx b/src/components/adslot-ui/ActionPanel/index.jsx
new file mode 100644
index 000000000..0ba80f84e
--- /dev/null
+++ b/src/components/adslot-ui/ActionPanel/index.jsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classNames from 'classnames';
+import Button from 'react-bootstrap/lib/Button';
+import './styles.scss';
+
+const ActionPanel = ({ title, className, size, onClose, children, actionButton, isModal, closeIcon }) => (
+
+
+
+ {title}
+
+
+ {actionButton ? 'Cancel' : closeIcon}
+
+ {actionButton}
+
+
+
{children}
+
+
+);
+
+ActionPanel.propTypes = {
+ title: PropTypes.string.isRequired,
+ className: PropTypes.string,
+ // large is intended to be used in a modal
+ size: PropTypes.oneOf(['small', 'medium', 'large']),
+ onClose: PropTypes.func.isRequired,
+ children: PropTypes.node.isRequired,
+ actionButton: PropTypes.node,
+ closeIcon: PropTypes.node,
+ isModal: PropTypes.bool,
+};
+
+ActionPanel.defaultProps = {
+ size: 'large',
+ actionButton: null,
+ isModal: false,
+ closeIcon:
,
+};
+
+export default ActionPanel;
diff --git a/src/components/adslot-ui/ActionPanel/index.spec.jsx b/src/components/adslot-ui/ActionPanel/index.spec.jsx
new file mode 100644
index 000000000..3b7af72dc
--- /dev/null
+++ b/src/components/adslot-ui/ActionPanel/index.spec.jsx
@@ -0,0 +1,38 @@
+import _ from 'lodash';
+import React from 'react';
+import { shallow } from 'enzyme';
+import { ActionPanel } from 'adslot-ui';
+import Button from 'react-bootstrap/lib/Button';
+
+describe('ActionPanelComponent', () => {
+ const makeProps = override =>
+ _.merge(
+ {
+ title: 'Action Panel',
+ size: 'small',
+ onClose: _.noop,
+ children: content
,
+ },
+ override
+ );
+
+ it('should render with defaults', () => {
+ const wrapper = shallow( );
+ const headerElement = wrapper.find('.aui--action-panel-header');
+ expect(headerElement).to.have.length(1);
+ expect(headerElement.find('.title').text()).to.equal('Action Panel');
+
+ const bodyElement = wrapper.find('.aui--action-panel-body');
+ expect(bodyElement).to.have.length(1);
+ });
+
+ it('should render as a modal', () => {
+ const wrapper = shallow(
+ Action })} />
+ );
+ expect(wrapper.prop('className')).to.equal('aui--action-panel-wrapper aui--action-panel-wrapper-backdrop');
+
+ const actionPanelElement = wrapper.find('.aui--action-panel');
+ expect(actionPanelElement.prop('className')).to.equal('aui--action-panel is-large action-modal');
+ });
+});
diff --git a/src/components/adslot-ui/ActionPanel/styles.scss b/src/components/adslot-ui/ActionPanel/styles.scss
new file mode 100644
index 000000000..efe10072c
--- /dev/null
+++ b/src/components/adslot-ui/ActionPanel/styles.scss
@@ -0,0 +1,140 @@
+@import '~styles/border';
+@import '~styles/color';
+@import '~styles/font-size';
+@import '~styles/variable';
+@import '~styles/font-weight';
+@import '~styles/icon';
+
+.aui--action-panel {
+ min-width: 300px;
+ max-width: 900px;
+ min-height: 100px;
+ z-index: $zindex-popover;
+ border: $border-lighter;
+ border-radius: 2px;
+
+ &.action-modal {
+ position: fixed;
+ top: 30px;
+ background-color: $color-white ;
+ margin: 30px auto;
+ border: 0;
+ }
+
+ &.is-small {
+ width: 500px;
+ }
+
+ &.is-medium {
+ width: 700px;
+ }
+
+ &.is-large {
+ width: 1000px;
+ }
+
+ &-header {
+ height: 48px;
+ color: $color-gray-darkest;
+ padding: 12px;
+ border-bottom: $border-lighter;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .title {
+ font-size: $font-size-header;
+ font-weight: $font-weight-bold;
+ }
+
+ svg {
+ fill: $color-gray-darker;
+ }
+
+ .close-svg-icon {
+ padding: 0;
+ width: 26px;
+ height: 26px;
+ }
+
+ .close-button.btn {
+ background-color: transparent;
+ color: $color-inverse;
+
+ > div {
+ display: inline-flex;
+ }
+ }
+
+ .close-icon {
+ width: 16px;
+ height: 16px;
+ background-repeat: no-repeat;
+ background-size: contain;
+ background-image: url('~styles/icons/close.svg');
+ }
+
+ .btn {
+ border: 0;
+ outline: 0;
+ margin: 0 0 0 6px;
+ box-shadow: none;
+ border-radius: 2px;
+ background-color: $color-white;
+ color: $color-blue;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+
+ &:focus:active,
+ &:hover:active {
+ background-color: transparent;
+ }
+ }
+
+ &.has-actions {
+ background-color: $color-blue;
+ color: $color-inverse;
+
+ .actions {
+ .btn {
+ &:hover {
+ color: $color-blue;
+ }
+
+ svg {
+ fill: $color-inverse;
+ }
+ }
+
+ .btn:hover {
+ background-color: $color-inverse;
+
+ svg {
+ fill: $color-blue;
+ }
+ }
+ }
+ }
+ }
+
+ &-body {
+ padding: 30px;
+ }
+
+ &-wrapper-backdrop {
+ position: fixed;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ background-color: $color-gray-dark;
+ width: 100%;
+ z-index: 1040;
+ display: flex;
+ justify-content: center;
+ opacity: .9;
+ }
+}
+
+
+
diff --git a/src/components/adslot-ui/index.js b/src/components/adslot-ui/index.js
index 5f3651030..3baa2bdb0 100644
--- a/src/components/adslot-ui/index.js
+++ b/src/components/adslot-ui/index.js
@@ -32,6 +32,7 @@ import fastStatelessWrapper from 'adslot-ui/fastStatelessWrapper';
import InformationBox from 'adslot-ui/InformationBox';
import Nav from 'adslot-ui/Navigation';
import OverlayLoader from 'adslot-ui/OverlayLoader';
+import ActionPanel from 'adslot-ui/ActionPanel';
export {
Accordion,
@@ -68,4 +69,5 @@ export {
InformationBox,
HoverDropdownMenu,
OverlayLoader,
+ ActionPanel,
};
diff --git a/src/index.js b/src/index.js
index cb40e9657..7e1a37c01 100644
--- a/src/index.js
+++ b/src/index.js
@@ -77,6 +77,7 @@ import {
InformationBox,
HoverDropdownMenu,
OverlayLoader,
+ ActionPanel,
} from 'adslot-ui';
export {
@@ -145,4 +146,5 @@ export {
InformationBox,
HoverDropdownMenu,
OverlayLoader,
+ ActionPanel,
};
diff --git a/src/styles/icons/close.svg b/src/styles/icons/close.svg
new file mode 100644
index 000000000..fdde96274
--- /dev/null
+++ b/src/styles/icons/close.svg
@@ -0,0 +1 @@
+