diff --git a/packages/power-bi/package.json b/packages/power-bi/package.json index 30e1279b4..778f69c8b 100644 --- a/packages/power-bi/package.json +++ b/packages/power-bi/package.json @@ -1,6 +1,6 @@ { "name": "@equinor/workspace-powerbi", - "version": "3.0.7", + "version": "3.0.8", "type": "module", "sideEffects": false, "license": "MIT", @@ -55,4 +55,3 @@ }, "gitHead": "6407f12589214b96228ab87d32a211f7c1cd6ba4" } - diff --git a/packages/power-bi/src/lib/components/Header/Header.tsx b/packages/power-bi/src/lib/components/Header/Header.tsx index 830b7d4b4..af579d937 100644 --- a/packages/power-bi/src/lib/components/Header/Header.tsx +++ b/packages/power-bi/src/lib/components/Header/Header.tsx @@ -1,6 +1,7 @@ import { Button, Icon, Search } from '@equinor/eds-core-react'; import { useState } from 'react'; import styled from 'styled-components'; +import useClickOutside from '../../hooks/useClickOutside'; import { FilterClearIcon } from '../../icons'; import { FilterController } from '../Filter/Filter'; import { Case, Switch } from '../switch/Switch'; @@ -20,6 +21,7 @@ type HeaderProps = { deselectAllValues: () => Promise; hasActiveFilters: boolean; searchValue: string | undefined; + container: React.RefObject; }; export const Header = ({ @@ -30,8 +32,19 @@ export const Header = ({ searchValue, hasActiveFilters, deselectAllValues, + container, }: HeaderProps): JSX.Element => { const [isSearchActive, setIsSearchActive] = useState(false); + + useClickOutside( + container, + () => { + setIsSearchActive(false); + onSearch(undefined); + }, + isSearchActive + ); + return ( @@ -44,10 +57,6 @@ export const Header = ({ aria-label="filter group" onKeyPress={(e) => e.key === 'Enter' && handleEnterPress()} onChange={(e) => onSearch(e.target.value)} - onBlur={() => { - setIsSearchActive(false); - onSearch(undefined); - }} /> diff --git a/packages/power-bi/src/lib/components/filterItems/FilterItems.tsx b/packages/power-bi/src/lib/components/filterItems/FilterItems.tsx index a4dd566fa..560445825 100644 --- a/packages/power-bi/src/lib/components/filterItems/FilterItems.tsx +++ b/packages/power-bi/src/lib/components/filterItems/FilterItems.tsx @@ -31,6 +31,7 @@ export const FilterItems = ({ const handleOnSearchChange = (value: string | undefined) => { setSearchValue(value); }; + const ref = useRef(null); const filterValues = Object.values(group?.value ?? '(Blank)'); const searchedFilterItems = useMemo(() => searchFilterItems(filterValues, searchValue), [filterValues, searchValue]); @@ -51,7 +52,7 @@ export const FilterItems = ({ }); return ( - +
controller.deselectAllValues(group, filterValues[0])} onSearch={handleOnSearchChange} searchEnabled={group.filterVals.length > 7} + container={ref} /> diff --git a/packages/power-bi/src/lib/hooks/useClickOutside.ts b/packages/power-bi/src/lib/hooks/useClickOutside.ts new file mode 100644 index 000000000..b7226eb5c --- /dev/null +++ b/packages/power-bi/src/lib/hooks/useClickOutside.ts @@ -0,0 +1,30 @@ +import { RefObject, useEffect, useRef } from 'react'; + +const useClickOutside = (elementRef: RefObject, callback: () => void, isActive = true) => { + const callbackRef = useRef(callback); + + const isClickInsideElement = (target: EventTarget | null): boolean => { + return elementRef.current ? elementRef.current.contains(target as Node) : false; + }; + + const handleClick = (e: MouseEvent) => { + if (isActive && !isClickInsideElement(e.target)) { + callbackRef.current(); + } + }; + + useEffect(() => { + callbackRef.current = callback; + }, [callback]); + + useEffect(() => { + if (isActive) { + document.addEventListener('mouseup', handleClick); + return () => { + document.removeEventListener('mouseup', handleClick); + }; + } + }, [isActive, elementRef]); +}; + +export default useClickOutside;