mirror of
https://github.com/usememos/memos.git
synced 2025-04-10 07:41:09 +02:00
* #1952 Fix incorrect localization key for sign-up failure message * feat: add typeScript support to enforce valid translation keys * feat: add typeScript support to enforce valid translation keys * fix lint errors * fix lint error
114 lines
3.0 KiB
TypeScript
114 lines
3.0 KiB
TypeScript
import { Tooltip } from "@mui/joy";
|
|
import { memo, useEffect, useRef } from "react";
|
|
import { useTranslate } from "@/utils/i18n";
|
|
import useToggle from "@/hooks/useToggle";
|
|
import Icon from "../Icon";
|
|
import "@/less/common/selector.less";
|
|
|
|
interface SelectorItem {
|
|
text: string;
|
|
value: string;
|
|
}
|
|
|
|
interface Props {
|
|
className?: string;
|
|
value: string;
|
|
dataSource: SelectorItem[];
|
|
handleValueChanged?: (value: string) => void;
|
|
disabled?: boolean;
|
|
tooltipTitle?: string;
|
|
}
|
|
|
|
const nullItem = {
|
|
text: "common.select" as const,
|
|
value: "",
|
|
};
|
|
|
|
const Selector: React.FC<Props> = (props: Props) => {
|
|
const { className, dataSource, handleValueChanged, value, disabled, tooltipTitle } = props;
|
|
const t = useTranslate();
|
|
const [showSelector, toggleSelectorStatus] = useToggle(false);
|
|
|
|
const selectorElRef = useRef<HTMLDivElement>(null);
|
|
|
|
let currentItem = { text: t(nullItem.text), value: nullItem.value };
|
|
for (const d of dataSource) {
|
|
if (d.value === value) {
|
|
currentItem = d;
|
|
break;
|
|
}
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (showSelector) {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (!selectorElRef.current?.contains(event.target as Node)) {
|
|
toggleSelectorStatus(false);
|
|
}
|
|
};
|
|
window.addEventListener("click", handleClickOutside, {
|
|
capture: true,
|
|
once: true,
|
|
});
|
|
}
|
|
}, [showSelector]);
|
|
|
|
const handleItemClick = (item: SelectorItem) => {
|
|
if (handleValueChanged) {
|
|
handleValueChanged(item.value);
|
|
}
|
|
toggleSelectorStatus(false);
|
|
};
|
|
|
|
const handleCurrentValueClick = (event: React.MouseEvent) => {
|
|
if (disabled) return;
|
|
event.stopPropagation();
|
|
toggleSelectorStatus();
|
|
};
|
|
|
|
return (
|
|
<Tooltip title={tooltipTitle} hidden={!disabled}>
|
|
<div className={`selector-wrapper ${className ?? ""} `} ref={selectorElRef}>
|
|
<div
|
|
className={`current-value-container ${showSelector ? "active" : ""} ${disabled && "selector-disabled"}`}
|
|
onClick={handleCurrentValueClick}
|
|
>
|
|
{disabled && (
|
|
<span className="lock-text">
|
|
<Icon.Lock className="icon-img" />
|
|
</span>
|
|
)}
|
|
<span className="value-text">{currentItem.text}</span>
|
|
{!disabled && (
|
|
<span className="arrow-text">
|
|
<Icon.ChevronDown className="icon-img" />
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
<div className={`items-wrapper ${showSelector ? "" : "!hidden"}`}>
|
|
{dataSource.length > 0 ? (
|
|
dataSource.map((d) => {
|
|
return (
|
|
<div
|
|
className={`item-container ${d.value === value ? "selected" : ""}`}
|
|
key={d.value}
|
|
onClick={() => {
|
|
handleItemClick(d);
|
|
}}
|
|
>
|
|
{d.text}
|
|
</div>
|
|
);
|
|
})
|
|
) : (
|
|
<p className="tip-text">{t("common.null")}</p>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Tooltip>
|
|
);
|
|
};
|
|
|
|
export default memo(Selector);
|