backpack-ui
Version:
Lonely Planet's Components
325 lines (272 loc) • 6.62 kB
JSX
import React from "react";
import radium, { Style } from "radium";
import cn from "classnames";
import assign from "object-assign";
import { color } from "../../../settings.json";
import Heading from "../heading";
import Icon from "../icon";
class SidebarSection extends React.Component {
constructor(props) {
super(props);
this.state = {
collapsed: props.collapsed,
};
this.onClick = this.onClick.bind(this);
}
onClick(event) {
this.setState({
collapsed: !this.state.collapsed,
});
event.preventDefault();
}
render() {
const {
children,
title,
icon,
collapsed,
background,
scopedStyles,
modifier,
contentType,
noMargin,
first,
} = this.props;
const styles = {
container: {
base: assign({}, {
fontSize: "11px",
paddingBottom: "35px",
position: "relative",
}, !first && {
borderTop: `1px solid ${color.gray}`,
paddingTop: "20px",
}),
background: {
backgroundColor: "#e9f2f8", // This color does not exist in settings
borderTop: 0,
marginLeft: "-20px",
paddingBottom: "40px",
paddingLeft: "20px",
paddingRight: "20px",
paddingTop: "20px",
width: "calc(100% + 40px)",
},
booking: !background ? {
paddingBottom: "62px",
} : {},
checkboxes: {
paddingBottom: "54px",
},
map: {
paddingBottom: 0,
paddingTop: 0,
},
collapsed: {
paddingBottom: 0,
paddingTop: 0,
},
},
header: {
base: {
position: "relative",
},
},
collapsibleHeading: {
base: {
backgroundColor: "transparent",
display: "block",
paddingBottom: "17px",
paddingTop: "20px",
position: "relative",
textAlign: "left",
width: "100%",
},
},
content: {
base: {
marginTop: "14px",
},
booking: background ? {
marginTop: "32px",
} : {
marginTop: "22px",
},
checkboxes: {
marginTop: "16px",
},
map: {
marginTop: 0,
},
slider: {
marginTop: "36px",
},
indented: {
marginLeft: "20px",
},
collapsed: {
display: "none",
marginTop: "-1px",
paddingBottom: "57px",
},
expanded: {
display: "block",
},
},
toggleIcon: {
base: {
backgroundColor: "transparent",
color: color.blue,
fontSize: "9px",
marginTop: "-3px",
position: "absolute",
right: 0,
top: "50%",
},
},
};
const heading = (
<Heading
level={4}
weight="thick"
importance="normal"
size="small"
caps
>
{icon &&
<Icon
name={icon}
size="small"
inline="before"
color={background ? "" : "gray"}
/>
}
{title}
</Heading>
);
const collapsibleHeading = (
<button
style={styles.collapsibleHeading.base}
onClick={this.onClick}
>
{heading}
<Icon
name={this.state.collapsed ? "triangle-down" : "triangle-up"}
style={styles.toggleIcon.base}
label="Expand"
/>
</button>
);
return (
<section
className={cn(
"SidebarSection",
background && "SidebarSection--background",
collapsed && "SidebarSection--expandable",
modifier && `SidebarSection--${modifier}`
)}
style={[
styles.container.base,
collapsed && styles.container.collapsed,
background && styles.container.background,
contentType && styles.container[contentType],
]}
>
{scopedStyles &&
<Style
scopeSelector=".SidebarSection"
rules={{
ul: {
listStyle: "none",
},
}}
/>
}
<header
className="SidebarSection-header"
style={styles.header.base}
>
{collapsed && collapsibleHeading}
{!collapsed && heading}
</header>
<div
className="SidebarSection-content"
style={[
!noMargin && styles.content.base,
icon && styles.content.indented,
collapsed && styles.content.collapsed,
!this.state.collapsed && styles.content.expanded,
contentType && styles.content[contentType],
]}
aria-hidden={this.state.collapsed}
>
{children}
</div>
</section>
);
}
}
SidebarSection.propTypes = {
/**
* Content for the section
*/
children: React.PropTypes.node.isRequired,
/**
* The name of the section
*/
title: React.PropTypes.string.isRequired,
/**
* The name of an icon to be placed to the left of the title
*/
icon: React.PropTypes.string,
/**
* Should the section be collapsed and expandable
*/
collapsed: React.PropTypes.bool,
/**
* Should the section be boxed in with a blue background
*/
background: React.PropTypes.bool,
/**
* Should the component include scoped styles (for user generated content)
*/
scopedStyles: React.PropTypes.bool,
/**
* A modifier classname to be appended to base classname; usually this is used
* as a layout styling hook within an SCSS file, so be careful when removing
*/
modifier: React.PropTypes.string,
/**
* A keyword to define the type of content within `SidebarSection-content`,
* used to provide additional styling
*/
contentType: React.PropTypes.oneOf([
"",
"booking",
"checkboxes",
"map",
"slider",
]),
/**
* Should the component have top margin
*/
noMargin: React.PropTypes.bool,
/**
* Denotes that this is the first section in the sidebar; removes the top
* border and padding
*/
first: React.PropTypes.bool,
};
SidebarSection.defaultProps = {
children: null,
title: "",
icon: "",
collapsed: false,
background: false,
scopedStyles: false,
modifier: "",
contentType: "",
noMargin: false,
first: false,
};
export default radium(SidebarSection);