webflow-designer-extension/src/components/Dropdown/Dropdown.tsx

117 lines
2.9 KiB
TypeScript
Raw Normal View History

2023-08-04 18:45:47 +02:00
import React, { useEffect, useRef, useState } from "react";
import { theme } from "../../theme";
import { Icon } from "../Icon";
2023-08-04 18:45:47 +02:00
export interface DropdownProps {
onChange: (value: string) => void;
options: Array<{ label: string; value: string }>;
selected?: string;
open?: boolean;
}
const DropdownOptions: React.FC<DropdownProps> = (props) => {
return (
<div
style={{
position: "absolute",
zIndex: 100,
...theme.background.secondary,
...theme.border.primary,
borderTop: 0,
top: 25,
width: "100%",
left: -1,
}}
>
2023-08-04 18:45:47 +02:00
{props.options.map(({ label, value }) => (
<div
style={{ display: "flex", padding: "4px 8px", cursor: "pointer" }}
onClick={() => {
props.onChange(value);
}}
>
<div style={{ marginRight: 10, width: 10 }}>
{props.selected === value ? <Icon name="check" /> : ""}
2023-08-04 18:45:47 +02:00
</div>
<div>{label}</div>
</div>
))}
</div>
);
};
/**
* Temp comp until @nocodelytics/components is ready
* We'll use <Timeframe /> which will also include types
*/
export const Dropdown: React.FC<DropdownProps> = (props) => {
if (!props.options.length) {
throw new Error(`Dropdown requires options`);
}
const [isOpen, setIsOpen] = useState<boolean>(props.open || false);
const [selected, setSelected] = useState<string>(
props.selected || props.options[0].value
);
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
function handleClickOutside(event: Event) {
if (ref.current && !ref.current.contains(event.target as Node)) {
setIsOpen(false);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref]);
return (
<div
ref={ref}
onClick={() => setIsOpen(!isOpen)}
style={{
position: "relative",
...theme.text.primary,
...theme.background.secondary,
...theme.border.primary,
cursor: "pointer",
maxWidth: 150,
}}
>
<div
style={{
padding: "0px 4px 0px 8px",
height: 24,
justifyContent: "unset",
gridAutoFlow: "column",
display: "grid",
alignItems: "center",
gap: 2,
2023-08-04 19:55:21 +02:00
lineHeight: 2.4,
2023-08-04 18:45:47 +02:00
}}
>
<span style={{ flex: 1 }}>
{props.options.find(({ value }) => selected === value)!.label}
</span>
<Icon
2023-08-04 19:55:21 +02:00
styles={{ textAlign: "right", marginRight: 12, marginLeft: 12 }}
name="chevron-down"
/>
2023-08-04 18:45:47 +02:00
</div>
{isOpen && (
<DropdownOptions
{...props}
selected={selected}
onChange={(value) => {
setIsOpen(false);
setSelected(value);
props.onChange(value);
}}
/>
)}
</div>
);
};