diff --git a/src/components/controls/panelChevron.tsx b/src/components/controls/panelChevron.tsx new file mode 100644 index 000000000..520a99fce --- /dev/null +++ b/src/components/controls/panelChevron.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import styled from 'styled-components'; +import { FaChevronRight, FaChevronDown } from "react-icons/fa"; + +const Container = styled.span` + padding-right: 6px; + color: ${(props) => props.theme.color}; +` + +type Props = { + show: boolean +} + +/** + * An interactive chevron to show/hide a panel's options. + */ +export const PanelChevron = ({ show }: Props) => { + const icon = show ? : + + return ( + + {icon} + + ) +} diff --git a/src/components/controls/panelHeader.tsx b/src/components/controls/panelHeader.tsx index fea38adb3..cd69ba568 100644 --- a/src/components/controls/panelHeader.tsx +++ b/src/components/controls/panelHeader.tsx @@ -2,6 +2,7 @@ import React from "react"; import { HeaderContainer } from "./styles"; import PanelToggle from "./panelToggle"; import { AnnotatedTitle } from "./annotatedTitle"; +import { PanelChevron } from "./panelChevron"; type Props = { /** Panel identifier used internally. */ @@ -16,6 +17,15 @@ type Props = { /** Indicates panel visibility. */ panelIsVisible: boolean + /** Indicates whether there are options for the panel. */ + hasOptions: boolean + + /** Indicates options visibility. */ + optionsAreVisible: boolean + + /** Update options visibility. */ + setOptionsAreVisible: React.Dispatch> + /** Indicates mobile display. */ mobile: boolean } @@ -23,13 +33,26 @@ type Props = { /** * A header used by all panel controls, containing an interactive title. */ -export const PanelHeader = ({ panel, title, tooltip, panelIsVisible, mobile }: Props) => { +export const PanelHeader = ({ panel, title, tooltip, panelIsVisible, hasOptions, optionsAreVisible, setOptionsAreVisible, mobile }: Props) => { + + let titleContainerProps = {} + + if (hasOptions) { + titleContainerProps = { + role: "button", + onClick: () => setOptionsAreVisible(!optionsAreVisible), + } + } + return ( - + + {hasOptions && } + + diff --git a/src/components/controls/panelSection.tsx b/src/components/controls/panelSection.tsx index b4c5a30a8..c66f5dc9f 100644 --- a/src/components/controls/panelSection.tsx +++ b/src/components/controls/panelSection.tsx @@ -30,6 +30,14 @@ export const PanelSection = ({ panel, title, tooltip, options=undefined, mobile const panelIsVisible = panelsToDisplay.includes(panel) + // Initially, panel visibility determines options visibility. + const [optionsAreVisible, setOptionsAreVisible] = React.useState(panelIsVisible); + + // Subsequent panel visibility updates also determines options visibility. + React.useEffect(() => { + setOptionsAreVisible(panelIsVisible) + }, [panelIsVisible]) + return ( - {panelIsVisible && options} + {optionsAreVisible && options} ); };