From 0c0ee7129240ca73c2cb0a26ec8c99940a494f13 Mon Sep 17 00:00:00 2001 From: Piotr Rudnicki Date: Mon, 2 Sep 2024 12:43:11 +0200 Subject: [PATCH] [Nu-1780] add new icon --- .../client/src/assets/img/advanced-search.svg | 1 + .../src/components/table/SearchFilter.tsx | 27 +++++++ .../themed/InputWithAdvancedSearchOptions.tsx | 79 +++++++++++++++++++ .../src/components/themed/SearchInput.tsx | 16 ++++ .../toolbars/search/AdvancedSearchOptions.tsx | 5 ++ .../toolbars/search/SearchPanel.tsx | 22 ++++-- 6 files changed, 144 insertions(+), 6 deletions(-) create mode 100644 designer/client/src/assets/img/advanced-search.svg create mode 100644 designer/client/src/components/themed/InputWithAdvancedSearchOptions.tsx create mode 100644 designer/client/src/components/toolbars/search/AdvancedSearchOptions.tsx diff --git a/designer/client/src/assets/img/advanced-search.svg b/designer/client/src/assets/img/advanced-search.svg new file mode 100644 index 00000000000..645aba94cfc --- /dev/null +++ b/designer/client/src/assets/img/advanced-search.svg @@ -0,0 +1 @@ + diff --git a/designer/client/src/components/table/SearchFilter.tsx b/designer/client/src/components/table/SearchFilter.tsx index 5941c62f254..a8f50fbaaed 100644 --- a/designer/client/src/components/table/SearchFilter.tsx +++ b/designer/client/src/components/table/SearchFilter.tsx @@ -1,6 +1,7 @@ import { css, cx } from "@emotion/css"; import React from "react"; import SearchSvg from "../../assets/img/search.svg"; +import AdvancedSearchSvg from "../../assets/img/advanced-search.svg"; import DeleteSvg from "../../assets/img/toolbarButtons/delete.svg"; import { useTheme } from "@mui/material"; @@ -9,6 +10,32 @@ const flex = css({ flex: 1, }); +export function AdvancedOptionsIcon(props: { + isActive?: boolean; + collapseHandler: React.Dispatch>; +}): JSX.Element { + const theme = useTheme(); + + const toggleCollapseHandler = () => { + props.collapseHandler((p) => !p); + }; + + return ( + + ); +} + export function SearchIcon(props: { isEmpty?: boolean }): JSX.Element { const theme = useTheme(); return ( diff --git a/designer/client/src/components/themed/InputWithAdvancedSearchOptions.tsx b/designer/client/src/components/themed/InputWithAdvancedSearchOptions.tsx new file mode 100644 index 00000000000..726bcbb42cc --- /dev/null +++ b/designer/client/src/components/themed/InputWithAdvancedSearchOptions.tsx @@ -0,0 +1,79 @@ +import { css, cx } from "@emotion/css"; +import { styled, useTheme } from "@mui/material"; +import React, { forwardRef, PropsWithChildren, ReactElement, useCallback, useImperativeHandle, useRef } from "react"; +import { AdvancedOptionsIcon, ClearIcon } from "../table/SearchFilter"; +import { InputProps, ThemedInput } from "./ThemedInput"; + +type Props = PropsWithChildren & { + onClear?: () => void; + onAddonClick?: () => void; +}; + +export type Focusable = { + focus: (options?: FocusOptions) => void; +}; + +export const InputWithAdvancedSearchOptions = forwardRef(function InputWithIcon( + { children, onAddonClick, onClear, ...props }, + forwardedRef, +): ReactElement { + const theme = useTheme(); + + const size = theme.custom.spacing.controlHeight; + + const wrapperWithAddonStyles = css({ + position: "relative", + display: "flex", + flexDirection: "row", + }); + + const addonWrapperStyles = css({ + position: "absolute", + top: 0, + right: 0, + height: size, + display: "flex", + padding: size / 4, + }); + + const addonStyles = css({ + display: "flex", + width: size / 2, + height: size / 2, + marginLeft: size / 4, + }); + + const ref = useRef(); + const focus = useCallback( + (options?: FocusOptions) => { + const input = ref.current; + input.focus({ preventScroll: true }); + input.setSelectionRange(0, props.value.length); + setTimeout(() => { + if (options?.preventScroll) return; + input.scrollIntoView({ behavior: "smooth", block: "center" }); + }, theme.transitions.duration.standard); + }, + [props.value.length, theme.transitions.duration.standard], + ); + + useImperativeHandle(forwardedRef, () => ({ focus }), [focus]); + + return ( +
+ +
+ {!!props.value && onClear && ( +
+ +
+ )} + {children && ( +
focus())}> + {children} +
+ )} +
+
+ ); +}); diff --git a/designer/client/src/components/themed/SearchInput.tsx b/designer/client/src/components/themed/SearchInput.tsx index 9cbbfc4e3e5..d9397fba6c1 100644 --- a/designer/client/src/components/themed/SearchInput.tsx +++ b/designer/client/src/components/themed/SearchInput.tsx @@ -1,5 +1,6 @@ import { styled } from "@mui/material"; import { InputWithIcon } from "./InputWithIcon"; +import { InputWithAdvancedSearchOptions } from "./InputWithAdvancedSearchOptions"; export const SearchInputWithIcon = styled(InputWithIcon)(({ theme }) => ({ ...theme.typography.body2, @@ -15,3 +16,18 @@ export const SearchInputWithIcon = styled(InputWithIcon)(({ theme }) => ({ boxShadow: "none", }, })); + +export const SearchInputWithAdvancedOptions = styled(InputWithAdvancedSearchOptions)(({ theme }) => ({ + ...theme.typography.body2, + width: "100%", + borderRadius: 0, + height: "36px !important", + color: theme.palette.text.secondary, + padding: "6px 12px !important", + backgroundColor: `${theme.palette.background.paper} !important`, + border: "none", + outline: "none !important", + "&:focus": { + boxShadow: "none", + }, +})); diff --git a/designer/client/src/components/toolbars/search/AdvancedSearchOptions.tsx b/designer/client/src/components/toolbars/search/AdvancedSearchOptions.tsx new file mode 100644 index 00000000000..ce4b131f781 --- /dev/null +++ b/designer/client/src/components/toolbars/search/AdvancedSearchOptions.tsx @@ -0,0 +1,5 @@ +import React from "react"; + +export function AdvancedSearchOptions() { + return

ADVANCED_SEARCH_OPTIONS

; +} diff --git a/designer/client/src/components/toolbars/search/SearchPanel.tsx b/designer/client/src/components/toolbars/search/SearchPanel.tsx index 8a0a0322dfb..09cf97d2186 100644 --- a/designer/client/src/components/toolbars/search/SearchPanel.tsx +++ b/designer/client/src/components/toolbars/search/SearchPanel.tsx @@ -1,24 +1,31 @@ import { isEmpty } from "lodash"; -import React, { ReactElement, useCallback, useRef, useState } from "react"; +import React, { ReactElement, useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; -import { SearchIcon } from "../../table/SearchFilter"; +import { AdvancedOptionsIcon, SearchIcon } from "../../table/SearchFilter"; import { Focusable } from "../../themed/InputWithIcon"; import { ToolbarPanelProps } from "../../toolbarComponents/DefaultToolbarPanel"; import { ToolbarWrapper } from "../../toolbarComponents/toolbarWrapper/ToolbarWrapper"; import { SearchResults } from "./SearchResults"; -import { SearchInputWithIcon } from "../../themed/SearchInput"; +import { SearchInputWithAdvancedOptions, SearchInputWithIcon } from "../../themed/SearchInput"; import { EventTrackingSelector, getEventTrackingProps } from "../../../containers/event-tracking"; +import { Collapse } from "@mui/material"; +import { AdvancedSearchOptions } from "./AdvancedSearchOptions"; export function SearchPanel(props: ToolbarPanelProps): ReactElement { const { t } = useTranslation(); const [filter, setFilter] = useState(""); const clearFilter = useCallback(() => setFilter(""), []); + const [advancedOptionsCollapsed, setAdvancedOptionsCollapsed] = useState(true); const searchRef = useRef(); + useEffect(() => { + setAdvancedOptionsCollapsed(false); + }, [filter]); + return ( searchRef.current?.focus()}> - - - + + + + + );