From 0e3466e82b9cf8ce9989c83966093f7a7711b24b Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 15 Feb 2021 21:12:48 +0300 Subject: [PATCH 1/3] Manual handling of popovers visibility --- .../handle-popover-visibility.tsx | 62 ++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx index fdc80926e6e7..0ee63a0934ac 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx @@ -2,33 +2,79 @@ // // SPDX-License-Identifier: MIT -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import Popover, { PopoverProps } from 'antd/lib/popover'; +type PopoverTypeListener = (activePopover: string | null) => void; + +let listeners: PopoverTypeListener[] = []; +function updateActivePopoverType(activePopover: string | null): void { + for (const listener of listeners) { + listener(activePopover); + } +} + +function subscribePopoverUpdate(onUpdate: PopoverTypeListener): void { + listeners.push(onUpdate); +} + +function unsubscribePopoverUpdate(onUpdate: PopoverTypeListener): void { + listeners = listeners.filter((listener: PopoverTypeListener) => listener !== onUpdate); +} + +function useCurrentActivePopover(): string | null { + const [activePopover, setActivePopover] = useState(null); + + useEffect(() => { + const listener: PopoverTypeListener = (newActivePopover: string | null) => { + setActivePopover(newActivePopover); + }; + + subscribePopoverUpdate(listener); + + return () => unsubscribePopoverUpdate(listener); + }); + + return activePopover; +} + export default function withVisibilityHandling(WrappedComponent: typeof Popover, popoverType: string) { return (props: PopoverProps): JSX.Element => { const [initialized, setInitialized] = useState(false); const [visible, setVisible] = useState(false); - let { overlayClassName } = props; - if (typeof overlayClassName !== 'string') overlayClassName = ''; + const currentActivePopover = useCurrentActivePopover(); + const { overlayClassName, ...rest } = props; + const overlayClassNames = typeof overlayClassName === 'string' ? overlayClassName.split(/\s+/) : []; - overlayClassName += ` cvat-${popoverType}-popover`; + const popoverClassName = `cvat-${popoverType}-popover`; + overlayClassNames.push(popoverClassName); if (visible) { - overlayClassName += ` cvat-${popoverType}-popover-visible`; + const visiblePopoverClassName = `cvat-${popoverType}-popover-visible`; + overlayClassNames.push(visiblePopoverClassName); } const callback = (event: Event): void => { if ((event as AnimationEvent).animationName === 'antZoomBigIn') { + updateActivePopoverType(popoverType); setVisible(true); } }; return ( { - if (!_visible) setVisible(false); + if (!_visible) { + setVisible(false); + } else { + // Hide other popovers + const element = window.document.getElementsByClassName(`${popoverClassName}`)[0]; + if (element) { + element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })); + } + } if (!initialized) { const self = window.document.getElementsByClassName(`cvat-${popoverType}-popover`)[0]; self?.addEventListener('animationend', callback); From 302256a41fc9536783ea1611156d345811e56665 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 15 Feb 2021 21:36:05 +0300 Subject: [PATCH 2/3] Updated version & changelog, added minor comments --- CHANGELOG.md | 1 + cvat-ui/package-lock.json | 2 +- cvat-ui/package.json | 2 +- .../controls-side-bar/handle-popover-visibility.tsx | 5 +++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8704ef4bdbc6..22db3b13341f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bumped nuclio version to 1.5.16 - All methods for interative segmentation accept negative points as well - Persistent queue added to logstash () +- Improved maintanance of popups visibility () ### Deprecated diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json index 7cf48b4c8558..6721bac83203 100644 --- a/cvat-ui/package-lock.json +++ b/cvat-ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.14.2", + "version": "1.14.3", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/cvat-ui/package.json b/cvat-ui/package.json index f5f695f8a077..2b9ff23dad05 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.14.2", + "version": "1.14.3", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx index 0ee63a0934ac..32abeda93771 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx @@ -27,13 +27,14 @@ function useCurrentActivePopover(): string | null { useEffect(() => { const listener: PopoverTypeListener = (newActivePopover: string | null) => { + // updating the state leads to rerender of dependent components setActivePopover(newActivePopover); }; + // subscribe on mount and unsubscribe on unmount subscribePopoverUpdate(listener); - return () => unsubscribePopoverUpdate(listener); - }); + }, []); return activePopover; } From 490a5c73475b392caebece150d373e9a0b40354b Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Mon, 15 Feb 2021 21:44:01 +0300 Subject: [PATCH 3/3] Removed extra user hook --- .../handle-popover-visibility.tsx | 40 +------------------ 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx index 32abeda93771..2ef920fff0a8 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/handle-popover-visibility.tsx @@ -2,48 +2,13 @@ // // SPDX-License-Identifier: MIT -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import Popover, { PopoverProps } from 'antd/lib/popover'; -type PopoverTypeListener = (activePopover: string | null) => void; - -let listeners: PopoverTypeListener[] = []; -function updateActivePopoverType(activePopover: string | null): void { - for (const listener of listeners) { - listener(activePopover); - } -} - -function subscribePopoverUpdate(onUpdate: PopoverTypeListener): void { - listeners.push(onUpdate); -} - -function unsubscribePopoverUpdate(onUpdate: PopoverTypeListener): void { - listeners = listeners.filter((listener: PopoverTypeListener) => listener !== onUpdate); -} - -function useCurrentActivePopover(): string | null { - const [activePopover, setActivePopover] = useState(null); - - useEffect(() => { - const listener: PopoverTypeListener = (newActivePopover: string | null) => { - // updating the state leads to rerender of dependent components - setActivePopover(newActivePopover); - }; - - // subscribe on mount and unsubscribe on unmount - subscribePopoverUpdate(listener); - return () => unsubscribePopoverUpdate(listener); - }, []); - - return activePopover; -} - export default function withVisibilityHandling(WrappedComponent: typeof Popover, popoverType: string) { return (props: PopoverProps): JSX.Element => { const [initialized, setInitialized] = useState(false); const [visible, setVisible] = useState(false); - const currentActivePopover = useCurrentActivePopover(); const { overlayClassName, ...rest } = props; const overlayClassNames = typeof overlayClassName === 'string' ? overlayClassName.split(/\s+/) : []; @@ -56,7 +21,6 @@ export default function withVisibilityHandling(WrappedComponent: typeof Popover, const callback = (event: Event): void => { if ((event as AnimationEvent).animationName === 'antZoomBigIn') { - updateActivePopoverType(popoverType); setVisible(true); } }; @@ -64,7 +28,7 @@ export default function withVisibilityHandling(WrappedComponent: typeof Popover, return ( { if (!_visible) {