import { ReactNode, FC, useEffect, useState } from "react"; import styled from "styled-components"; import isDefined from "../../Core/isDefined"; import { IButtonProps, RawButton } from "../../Styled/Button"; import { IconProps, StyledIcon } from "../../Styled/Icon"; import Text from "../../Styled/Text"; import { CollapseIcon } from "../Custom/Collapsible/Collapsible"; export type PanelProps = { title?: string; icon?: IconProps["glyph"]; menuComponent?: ReactNode; children?: ReactNode; className?: string; /** Collapsible will replace menuComponent. Title must be defined */ collapsible?: boolean; isOpen?: boolean; /** Function is called whenever Collapsible is toggled (close or open). * Return value is `true` if the listener has consumed the event, `false` otherwise. */ onToggle?: (isOpen: boolean) => boolean | void; }; /** * A generic panel component for left, right, context items etc. */ export const Panel: FC = (props) => { const [isOpen, setIsOpen] = useState(false); useEffect(() => { if (isDefined(props.isOpen)) { setIsOpen(props.isOpen); } }, [props.isOpen]); const toggleOpen = () => { const newIsOpen = !isOpen; // Only update isOpen state if onToggle doesn't consume the event if (!props.onToggle || !props.onToggle(newIsOpen)) setIsOpen(newIsOpen); }; return props.title && props.collapsible ? ( {props.icon !== undefined ? ( ) : null} {props.title} {isOpen ? {props.children} : null} ) : ( {props.title !== undefined && ( {props.icon !== undefined ? ( ) : null} {props.title} {props.menuComponent} )} {props.children} ); }; /** Simple PanelButton - this mimics style of CollapsibleTitleBar */ export const PanelButton: FC<{ onClick: () => void; title: string }> = ({ onClick, title }) => ( {title} ); const Wrapper = styled.div` background-color: ${(p) => p.theme.darkWithOverlay}; margin: 15px 15px 0px 15px; padding: 15px; border-radius: 5px; `; const TitleBar = styled.div` box-sizing: border-box; display: flex; flex-direction: row; justify-content: space-between; align-items: center; border-bottom: 1px solid ${(p) => p.theme.darkLighter}; padding-bottom: 15px; margin-bottom: 5px; `; const CollapsibleTitleBar = styled(RawButton)< IButtonProps & { isOpen: boolean } >` text-align: left; box-sizing: border-box; display: flex; flex-direction: row; justify-content: space-between; align-items: center; padding-bottom: 15px; margin-bottom: 5px; ${(p) => (p.isOpen ? `border-bottom: 1px solid ${p.theme.darkLighter}` : "")}; `; const Title = styled(Text).attrs({ textLight: true, medium: true })` flex-grow: 1; `; const Icon = styled(StyledIcon).attrs({ styledWidth: "18px", styledHeight: "18px", light: true })``; const Content = styled.div` color: ${(p) => p.theme.textLight}; `;