|
@@ -0,0 +1,145 @@
|
|
|
+import { Box, SvgIcon, TextField, Theme, styled } from "@mui/material";
|
|
|
+import Tooltip from "@mui/material/Tooltip";
|
|
|
+import { ChangeEvent, useState } from "react";
|
|
|
+
|
|
|
+import { useTranslation } from "react-i18next";
|
|
|
+import matchCaseIcon from "@/assets/image/component/match_case.svg?react";
|
|
|
+import matchWholeWordIcon from "@/assets/image/component/match_whole_word.svg?react";
|
|
|
+import useRegularExpressionIcon from "@/assets/image/component/use_regular_expression.svg?react";
|
|
|
+
|
|
|
+type SearchProps = {
|
|
|
+ placeholder?: string;
|
|
|
+ onSearch: (
|
|
|
+ match: (content: string) => boolean,
|
|
|
+ search: (contents: string[]) => string[],
|
|
|
+ state: {
|
|
|
+ input: string;
|
|
|
+ matchCase: boolean;
|
|
|
+ matchWholeWord: boolean;
|
|
|
+ useRegularExpression: boolean;
|
|
|
+ }
|
|
|
+ ) => void;
|
|
|
+};
|
|
|
+
|
|
|
+export const BaseSearchBox = styled((props: SearchProps) => {
|
|
|
+ const { t } = useTranslation();
|
|
|
+ const [matchCase, setMatchCase] = useState(true);
|
|
|
+ const [matchWholeWord, setMatchWholeWord] = useState(false);
|
|
|
+ const [useRegularExpression, setUseRegularExpression] = useState(false);
|
|
|
+ const [errorMessage, setErrorMessage] = useState("");
|
|
|
+
|
|
|
+ const iconStyle = {
|
|
|
+ style: {
|
|
|
+ height: "24px",
|
|
|
+ width: "24px",
|
|
|
+ cursor: "pointer",
|
|
|
+ } as React.CSSProperties,
|
|
|
+ inheritViewBox: true,
|
|
|
+ };
|
|
|
+ const active = "var(--primary-main)";
|
|
|
+
|
|
|
+ const onChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
|
+ props.onSearch(
|
|
|
+ (content) => doSearch([content], e.target?.value ?? "").length > 0,
|
|
|
+ (contents: string[]) => doSearch(contents, e.target?.value ?? ""),
|
|
|
+ {
|
|
|
+ input: e.target?.value ?? "",
|
|
|
+ matchCase,
|
|
|
+ matchWholeWord,
|
|
|
+ useRegularExpression,
|
|
|
+ }
|
|
|
+ );
|
|
|
+ };
|
|
|
+
|
|
|
+ const doSearch = (searchList: string[], searchItem: string) => {
|
|
|
+ setErrorMessage("");
|
|
|
+ return searchList.filter((item) => {
|
|
|
+ try {
|
|
|
+ let searchItemCopy = searchItem;
|
|
|
+ if (!matchCase) {
|
|
|
+ item = item.toLowerCase();
|
|
|
+ searchItemCopy = searchItemCopy.toLowerCase();
|
|
|
+ }
|
|
|
+ if (matchWholeWord) {
|
|
|
+ const regex = new RegExp(`\\b${searchItemCopy}\\b`);
|
|
|
+ if (useRegularExpression) {
|
|
|
+ const regexWithOptions = new RegExp(searchItemCopy);
|
|
|
+ return regexWithOptions.test(item) && regex.test(item);
|
|
|
+ } else {
|
|
|
+ return regex.test(item);
|
|
|
+ }
|
|
|
+ } else if (useRegularExpression) {
|
|
|
+ const regex = new RegExp(searchItemCopy);
|
|
|
+ return regex.test(item);
|
|
|
+ } else {
|
|
|
+ return item.includes(searchItemCopy);
|
|
|
+ }
|
|
|
+ } catch (e) {
|
|
|
+ setErrorMessage(`${e}`);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ return (
|
|
|
+ <Tooltip title={errorMessage} placement="bottom-start">
|
|
|
+ <TextField
|
|
|
+ hiddenLabel
|
|
|
+ fullWidth
|
|
|
+ size="small"
|
|
|
+ autoComplete="off"
|
|
|
+ variant="outlined"
|
|
|
+ spellCheck="false"
|
|
|
+ placeholder={props.placeholder ?? t("Filter conditions")}
|
|
|
+ sx={{ input: { py: 0.65, px: 1.25 } }}
|
|
|
+ onChange={onChange}
|
|
|
+ InputProps={{
|
|
|
+ sx: { pr: 1 },
|
|
|
+ endAdornment: (
|
|
|
+ <Box display="flex">
|
|
|
+ <Tooltip title={t("Match Case")}>
|
|
|
+ <div>
|
|
|
+ <SvgIcon
|
|
|
+ component={matchCaseIcon}
|
|
|
+ {...iconStyle}
|
|
|
+ sx={{ fill: matchCase ? active : undefined }}
|
|
|
+ onClick={() => {
|
|
|
+ setMatchCase(!matchCase);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </Tooltip>
|
|
|
+ <Tooltip title={t("Match Whole Word")}>
|
|
|
+ <div>
|
|
|
+ <SvgIcon
|
|
|
+ component={matchWholeWordIcon}
|
|
|
+ {...iconStyle}
|
|
|
+ sx={{ fill: matchWholeWord ? active : undefined }}
|
|
|
+ onClick={() => {
|
|
|
+ setMatchWholeWord(!matchWholeWord);
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </Tooltip>
|
|
|
+ <Tooltip title={t("Use Regular Expression")}>
|
|
|
+ <div>
|
|
|
+ <SvgIcon
|
|
|
+ component={useRegularExpressionIcon}
|
|
|
+ sx={{ fill: useRegularExpression ? active : undefined }}
|
|
|
+ {...iconStyle}
|
|
|
+ onClick={() => {
|
|
|
+ setUseRegularExpression(!useRegularExpression);
|
|
|
+ }}
|
|
|
+ />{" "}
|
|
|
+ </div>
|
|
|
+ </Tooltip>
|
|
|
+ </Box>
|
|
|
+ ),
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Tooltip>
|
|
|
+ );
|
|
|
+})(({ theme }) => ({
|
|
|
+ "& .MuiInputBase-root": {
|
|
|
+ background: theme.palette.mode === "light" ? "#fff" : undefined,
|
|
|
+ },
|
|
|
+}));
|