Introduce family of Panel components

pull/4043/head
Alex P 2018-07-27 16:35:31 -07:00
parent 34b9f720a0
commit a420e8439c
5 changed files with 261 additions and 0 deletions

View File

@ -0,0 +1,123 @@
/*
Panels
-----------------------------------------------------------------------------
*/
@import 'src/style/modules/influx-colors';
@import 'src/style/modules/variables';
@import 'src/style/modules/mixins';
$panel-gutter: 30px;
$panel-background: $g3-castle;
.panel {
display: flex;
flex-direction: column;
align-items: stretch;
margin-bottom: $panel-gutter;
}
.panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: $panel-gutter 0;
}
.panel-title {
font-weight: 400;
font-size: 19px;
color: $g12-forge;
letter-spacing: 0.015em;
margin: 0;
line-height: 1em;
@extend %no-user-select;
}
.panel-controls {
display: flex;
align-items: center;
&:nth-child(1) {
justify-content: flex-start;
> * {
margin-right: $ix-marg-b;
}
}
&:nth-child(2) {
justify-content: flex-end;
> * {
margin-left: $ix-marg-b;
}
}
}
.panel-body {
background-color: $panel-background;
padding: $panel-gutter;
.panel-header + &,
&:first-child {
border-top-left-radius: $ix-radius;
border-top-right-radius: $ix-radius;
}
&:last-child {
border-bottom-left-radius: $ix-radius;
border-bottom-right-radius: $ix-radius;
}
> *:first-child {
margin-top: 0;
}
> *:last-child {
margin-bottom: 0;
}
}
.panel-footer {
padding: $ix-marg-c $panel-gutter;
border-radius: 0 0 $ix-radius $ix-radius;
@include gradient-v($g2-kevlar, $panel-background);
color: $g9-mountain;
}
// Tables directly inside Panels
// ----------------------------------------------------------------------------
.panel > .table {
border-top: $ix-border;
* {
border-color: $g19-ghost;
}
}
.panel-header + .table {
border: none;
}
.panel > .table td:first-child,
.panel > .table th:first-child {
padding-left: $panel-gutter;
}
.panel > .table td:last-child,
.panel > .table th:last-child {
padding-right: $panel-gutter;
}
// Solid Panels
// ----------------------------------------------------------------------------
.panel.panel-solid {
background-color: $panel-background;
border-radius: $ix-radius;
.panel-header {
padding: $panel-gutter;
}
.panel-body {
background-color: transparent;
}
}
// Horizontal Rules directly inside Panels
// ----------------------------------------------------------------------------
.panel-body hr {
margin: $ix-marg-c 0;
}

View File

@ -0,0 +1,75 @@
// Libraries
import React, {Component, Children} from 'react'
import classnames from 'classnames'
// Components
import PanelHeader from 'src/reusable_ui/components/panel/PanelHeader'
import PanelBody from 'src/reusable_ui/components/panel/PanelBody'
import PanelFooter from 'src/reusable_ui/components/panel/PanelFooter'
// Styles
import 'src/reusable_ui/components/panel/Panel.scss'
import {ErrorHandling} from 'src/shared/decorators/errors'
export enum PanelType {
Default = '',
Solid = 'solid',
}
interface Props {
children: JSX.Element[]
type?: PanelType
}
@ErrorHandling
class Panel extends Component<Props> {
public static defaultProps: Partial<Props> = {
type: PanelType.Default,
}
public static Header = PanelHeader
public static Body = PanelBody
public static Footer = PanelFooter
public render() {
const {children} = this.props
this.validateChildren()
return <div className={this.className}>{children}</div>
}
private get className(): string {
const {type} = this.props
return classnames('panel', {'panel-solid': type === PanelType.Solid})
}
private validateChildren = (): void => {
const {children} = this.props
let invalidCount = 0
Children.forEach(children, (child: JSX.Element) => {
if (
child.type === PanelHeader ||
child.type === PanelBody ||
child.type === PanelFooter
) {
return
}
invalidCount += 1
return
})
if (invalidCount > 0) {
throw new Error(
'Panel expected children of type <Panel.Header>, <Panel.Body>, or <Panel.Footer>'
)
}
}
}
export default Panel

View File

@ -0,0 +1,19 @@
// Libraries
import React, {Component} from 'react'
import {ErrorHandling} from 'src/shared/decorators/errors'
interface Props {
children: JSX.Element[] | JSX.Element
}
@ErrorHandling
class PanelBody extends Component<Props> {
public render() {
const {children} = this.props
return <div className="panel-body">{children}</div>
}
}
export default PanelBody

View File

@ -0,0 +1,19 @@
// Libraries
import React, {Component} from 'react'
import {ErrorHandling} from 'src/shared/decorators/errors'
interface Props {
children: JSX.Element[]
}
@ErrorHandling
class PanelFooter extends Component<Props> {
public render() {
const {children} = this.props
return <div className="panel-footer">{children}</div>
}
}
export default PanelFooter

View File

@ -0,0 +1,25 @@
// Libraries
import React, {Component} from 'react'
import {ErrorHandling} from 'src/shared/decorators/errors'
interface Props {
children?: JSX.Element[]
title: string
}
@ErrorHandling
class PanelHeader extends Component<Props> {
public render() {
const {children, title} = this.props
return (
<div className="panel-header">
<div className="panel-title">{title}</div>
<div className="panel-controls">{children}</div>
</div>
)
}
}
export default PanelHeader