import React, { ReactNode, useState, useEffect, useCallback } from "react";
import Icon, { IconName, IconSize } from "./Icon";
import { CommonComponentProps, Classes } from "./common";
import Text, { TextType } from "./Text";
import { Popover, Position } from "@blueprintjs/core";
import styled from "constants/DefaultTheme";
import { Colors } from "constants/Colors";
export type DropdownOption = {
label?: string;
value?: string;
id?: string;
icon?: IconName;
subText?: string;
iconSize?: IconSize;
iconColor?: string;
onSelect?: (value?: string) => void;
};
export interface DefaultDropDownValueNodeProps {
selected: DropdownOption;
showLabelOnly?: boolean;
isOpen?: boolean;
}
export interface RenderDropdownOptionType {
option: DropdownOption;
optionClickHandler?: (dropdownOption: DropdownOption) => void;
}
type RenderOption = ({
option,
optionClickHandler,
}: RenderDropdownOptionType) => ReactNode;
export type DropdownProps = CommonComponentProps & {
options: DropdownOption[];
selected: DropdownOption;
onSelect?: (value?: string) => void;
width?: string;
height?: string;
showLabelOnly?: boolean;
optionWidth?: string;
showDropIcon?: boolean;
headerLabel?: string;
SelectedValueNode?: typeof DefaultDropDownValueNode;
bgColor?: string;
renderOption?: RenderOption;
};
export const DropdownContainer = styled.div<{ width: string; height: string }>`
width: ${(props) => props.width};
height: ${(props) => props.height};
position: relative;
`;
const Selected = styled.div<{
isOpen: boolean;
disabled?: boolean;
height: string;
bgColor?: string;
}>`
padding: ${(props) => props.theme.spaces[2]}px
${(props) => props.theme.spaces[3]}px;
background: ${(props) =>
props.disabled
? props.theme.colors.dropdown.header.disabledBg
: !!props.bgColor
? props.bgColor
: props.theme.colors.dropdown.header.bg};
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: ${(props) => props.height};
cursor: pointer;
${(props) =>
props.isOpen
? `border: 1px solid ${
!!props.bgColor ? props.bgColor : props.theme.colors.info.main
}`
: props.disabled
? `border: 1px solid ${props.theme.colors.dropdown.header.disabledBg}`
: `border: 1px solid ${
!!props.bgColor
? props.bgColor
: props.theme.colors.dropdown.header.bg
}`};
${(props) =>
props.isOpen && !props.disabled ? "box-sizing: border-box" : null};
${(props) =>
props.isOpen && !props.disabled && !props.bgColor
? "box-shadow: 0px 0px 4px 4px rgba(203, 72, 16, 0.18)"
: null};
.${Classes.TEXT} {
${(props) =>
props.disabled
? `color: ${props.theme.colors.dropdown.header.disabledText}`
: `color: ${
!!props.bgColor
? Colors.WHITE
: props.theme.colors.dropdown.header.text
}`};
}
`;
const DropdownWrapper = styled.div<{
width: string;
}>`
width: ${(props) => props.width};
z-index: 1;
background-color: ${(props) => props.theme.colors.propertyPane.radioGroupBg};
margin-top: ${(props) => -props.theme.spaces[3]}px;
padding: ${(props) => props.theme.spaces[3]}px 0;
`;
const OptionWrapper = styled.div<{
selected: boolean;
}>`
padding: ${(props) => props.theme.spaces[2] + 1}px
${(props) => props.theme.spaces[5]}px;
cursor: pointer;
display: flex;
align-items: center;
background-color: ${(props) =>
props.selected ? props.theme.colors.propertyPane.dropdownSelectBg : null};
&&& svg {
rect {
fill: ${(props) => props.theme.colors.dropdownIconBg};
}
}
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.propertyPane.label};
}
.${Classes.ICON} {
margin-right: ${(props) => props.theme.spaces[5]}px;
svg {
path {
${(props) =>
props.selected
? `fill: ${props.theme.colors.dropdown.selected.icon}`
: `fill: ${props.theme.colors.dropdown.icon}`};
}
}
}
&:hover {
background-color: ${(props) => props.theme.colors.dropdown.hovered.bg};
&&& svg {
rect {
fill: ${(props) => props.theme.colors.textOnDarkBG};
}
}
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.textOnDarkBG};
}
.${Classes.ICON} {
svg {
path {
fill: ${(props) => props.theme.colors.dropdown.hovered.icon};
}
}
}
}
`;
const LabelWrapper = styled.div<{ label?: string }>`
display: flex;
flex-direction: column;
align-items: flex-start;
span:last-child {
margin-top: ${(props) => props.theme.spaces[2] - 1}px;
}
&:hover {
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.dropdown.selected.text};
}
}
`;
const StyledSubText = styled(Text)`
margin-left: auto;
&& {
color: ${(props) => props.theme.colors.apiPane.body.text};
}
`;
const HeaderWrapper = styled.div`
color: #6d6d6d;
font-size: 10px;
padding: 0px 7px 7px 7px;
`;
const SelectedDropDownHolder = styled.div`
display: flex;
align-items: center;
`;
const SelectedIcon = styled(Icon)`
margin-right: 6px;
& > div:first-child {
height: 18px;
width: 18px;
svg {
height: 18px;
width: 18px;
rect {
fill: ${(props) => props.theme.colors.dropdownIconBg};
rx: 0;
}
path {
fill: ${(props) => props.theme.colors.propertyPane.label};
}
}
}
`;
export function DefaultDropDownValueNode({
selected,
showLabelOnly,
}: DefaultDropDownValueNodeProps) {
return (
{selected.icon ? (
) : null}
{showLabelOnly ? selected.label : selected.value}
);
}
export default function Dropdown(props: DropdownProps) {
const {
onSelect,
showDropIcon = true,
SelectedValueNode = DefaultDropDownValueNode,
renderOption,
} = { ...props };
const [isOpen, setIsOpen] = useState(false);
const [selected, setSelected] = useState(props.selected);
useEffect(() => {
setSelected(props.selected);
}, [props.selected]);
const optionClickHandler = useCallback(
(option: DropdownOption) => {
setSelected(option);
setIsOpen(false);
onSelect && onSelect(option.value);
option.onSelect && option.onSelect(option.value);
},
[onSelect],
);
return (
setIsOpen(state)}
popoverClassName={props.className}
position={Position.BOTTOM_LEFT}
>
setIsOpen(!isOpen)}
>
{showDropIcon && }
{props.headerLabel && (
{props.headerLabel}
)}
{props.options.map((option: DropdownOption, index: number) => {
if (renderOption) {
return renderOption({
option,
optionClickHandler,
});
}
return (
optionClickHandler(option)}
selected={selected.value === option.value}
>
{option.icon ? (
) : null}
{props.showLabelOnly ? (
{option.label}
) : option.label && option.value ? (
{option.value}
{option.label}
) : (
{option.value}
)}
{option.subText ? (
{option.subText}
) : null}
);
})}
);
}