/** * Copyright 2018-present Facebook. * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * @format */ import Interactive from './Interactive'; import FlexColumn from './FlexColumn'; import {colors} from './colors'; import {Component} from 'react'; import styled from 'react-emotion'; import { BackgroundClipProperty, HeightProperty, WidthProperty, BackgroundColorProperty, } from 'csstype'; import React from 'react'; const SidebarInteractiveContainer = styled(Interactive)({ flex: 'none', }); type SidebarPosition = 'left' | 'top' | 'right' | 'bottom'; const SidebarContainer = styled(FlexColumn)( (props: { position: 'right' | 'top' | 'left' | 'bottom'; backgroundColor?: BackgroundClipProperty; overflow?: boolean; }) => ({ backgroundColor: props.backgroundColor || colors.macOSTitleBarBackgroundBlur, borderLeft: props.position === 'right' ? '1px solid #b3b3b3' : 'none', borderTop: props.position === 'bottom' ? '1px solid #b3b3b3' : 'none', borderRight: props.position === 'left' ? '1px solid #b3b3b3' : 'none', borderBottom: props.position === 'top' ? '1px solid #b3b3b3' : 'none', height: '100%', overflowX: 'hidden', overflowY: 'auto', textOverflow: props.overflow ? 'ellipsis' : 'auto', whiteSpace: props.overflow ? 'nowrap' : 'normal', }), ); type SidebarProps = { /** * Position of the sidebar. */ position: SidebarPosition; /** * Default width of the sidebar. Only used for left/right sidebars. */ width?: number; /** * Minimum sidebar width. Only used for left/right sidebars. */ minWidth?: number; /** * Maximum sidebar width. Only used for left/right sidebars. */ maxWidth?: number; /** * Default height of the sidebar. */ height?: number; /** * Minimum sidebar height. Only used for top/bottom sidebars. */ minHeight?: number; /** * Maximum sidebar height. Only used for top/bottom sidebars. */ maxHeight?: number; /** * Background color. */ backgroundColor?: BackgroundColorProperty; /** * Callback when the sidebar size ahs changed. */ onResize?: (width: number, height: number) => void; /** * Contents of the sidebar. */ children?: React.ReactNode; /** * Class name to customise styling. */ className?: string; }; type SidebarState = { width?: WidthProperty; height?: HeightProperty; userChange: boolean; }; /** * A resizable sidebar. */ export default class Sidebar extends Component { constructor(props: SidebarProps, context: Object) { super(props, context); this.state = { userChange: false, width: props.width, height: props.height, }; } static defaultProps = { position: 'left', }; componentWillReceiveProps(nextProps: SidebarProps) { if (!this.state.userChange) { this.setState({width: nextProps.width, height: nextProps.height}); } } onResize = (width: number, height: number) => { const {onResize} = this.props; if (onResize) { onResize(width, height); } else { this.setState({userChange: true, width, height}); } }; render() { const {backgroundColor, onResize, position, children} = this.props; let height: number; let minHeight: number; let maxHeight: number; let width: number; let minWidth: number; let maxWidth: number; const resizable: {[key: string]: boolean} = {}; if (position === 'left') { resizable.right = true; ({width, minWidth, maxWidth} = this.props); } else if (position === 'top') { resizable.bottom = true; ({height, minHeight, maxHeight} = this.props); } else if (position === 'right') { resizable.left = true; ({width, minWidth, maxWidth} = this.props); } else if (position === 'bottom') { resizable.top = true; ({height, minHeight, maxHeight} = this.props); } const horizontal = position === 'left' || position === 'right'; if (horizontal) { width = width == null ? 200 : width; minWidth = minWidth == null ? 100 : minWidth; maxWidth = maxWidth == null ? 600 : maxWidth; } else { height = height == null ? 200 : height; minHeight = minHeight == null ? 100 : minHeight; maxHeight = maxHeight == null ? 600 : maxHeight; } return ( {children} ); } }