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

+ + {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} + +
+
{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 @@ +