From f63d9cf93ee50356435fba0ed0d088b571e48353 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Mon, 17 Nov 2025 15:11:50 +0300 Subject: [PATCH] B: Fix tooltips for tabbed views --- .../features/oss/pages/oss-page/oss-tabs.tsx | 8 +++-- .../editor-constituenta.tsx | 33 +---------------- .../rsform/pages/rsform-page/rstabs.tsx | 8 +++-- .../frontend/src/hooks/use-reset-attribute.ts | 36 +++++++++++++++++++ 4 files changed, 49 insertions(+), 36 deletions(-) create mode 100644 rsconcept/frontend/src/hooks/use-reset-attribute.ts diff --git a/rsconcept/frontend/src/features/oss/pages/oss-page/oss-tabs.tsx b/rsconcept/frontend/src/features/oss/pages/oss-page/oss-tabs.tsx index ce93b880..108d576a 100644 --- a/rsconcept/frontend/src/features/oss/pages/oss-page/oss-tabs.tsx +++ b/rsconcept/frontend/src/features/oss/pages/oss-page/oss-tabs.tsx @@ -1,10 +1,11 @@ 'use client'; -import { useLayoutEffect } from 'react'; +import { useLayoutEffect, useRef } from 'react'; import { useConceptNavigation } from '@/app/navigation/navigation-context'; import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs'; +import { useResetAttribute } from '@/hooks/use-reset-attribute'; import { useAppLayoutStore } from '@/stores/app-layout'; import { EditorOssCard } from './editor-oss-card'; @@ -22,6 +23,9 @@ export function OssTabs({ activeTab }: OssTabsProps) { const hideFooter = useAppLayoutStore(state => state.hideFooter); + const containerRef = useRef(null); + useResetAttribute(containerRef, 'data-tooltip-id'); + useLayoutEffect(() => { const oldTitle = document.title; document.title = schema.title; @@ -68,7 +72,7 @@ export function OssTabs({ activeTab }: OssTabsProps) { -
+
diff --git a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/editor-constituenta.tsx b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/editor-constituenta.tsx index 05618809..7e49c3e2 100644 --- a/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/editor-constituenta.tsx +++ b/rsconcept/frontend/src/features/rsform/pages/rsform-page/editor-constituenta/editor-constituenta.tsx @@ -9,7 +9,7 @@ import { useWindowSize } from '@/hooks/use-window-size'; import { useFitHeight, useMainHeight } from '@/stores/app-layout'; import { useModificationStore } from '@/stores/modification'; import { usePreferencesStore } from '@/stores/preferences'; -import { globalIDs, PARAMETER } from '@/utils/constants'; +import { globalIDs } from '@/utils/constants'; import { useMutatingRSForm } from '../../../backend/use-mutating-rsform'; import { ViewConstituents } from '../../../components/view-constituents'; @@ -43,7 +43,6 @@ export function EditorConstituenta() { const { isModified } = useModificationStore(); const [toggleReset, setToggleReset] = useState(false); - const containerRef = useRef(null); const isProcessing = useMutatingRSForm(); const disabled = !activeCst || !isContentEditable || isProcessing; @@ -62,35 +61,6 @@ export function EditorConstituenta() { } }, [activeCst, selectedCst, setSelectedCst]); - useEffect(() => { - // Trigger tooltip re-initialization after component mounts and tab becomes visible - // This ensures tooltips work when loading the page directly with this tab active - // React-tabs hides inactive panels with CSS (display: none), so react-tooltip v5 - // needs to re-scan the DOM when elements become visible - const timeoutId = setTimeout(() => { - if (!containerRef.current) { - return; - } - - // Force react-tooltip to re-scan by temporarily removing and re-adding data-tooltip-id - // This triggers react-tooltip's internal MutationObserver to re-register the elements - const tooltipElements = containerRef.current.querySelectorAll('[data-tooltip-id]'); - tooltipElements.forEach(element => { - if (element instanceof HTMLElement) { - const tooltipId = element.getAttribute('data-tooltip-id'); - if (tooltipId) { - element.removeAttribute('data-tooltip-id'); - requestAnimationFrame(() => { - element.setAttribute('data-tooltip-id', tooltipId); - }); - } - } - }); - }, PARAMETER.minimalTimeout); - - return () => clearTimeout(timeoutId); - }, []); - function handleInput(event: React.KeyboardEvent) { if (disabled) { return; @@ -130,7 +100,6 @@ export function EditorConstituenta() { return (
0 ? selectedCst.at(-1) : undefined }); } + const containerRef = useRef(null); + useResetAttribute(containerRef, 'data-tooltip-id'); + return ( -
+
diff --git a/rsconcept/frontend/src/hooks/use-reset-attribute.ts b/rsconcept/frontend/src/hooks/use-reset-attribute.ts new file mode 100644 index 00000000..39b46790 --- /dev/null +++ b/rsconcept/frontend/src/hooks/use-reset-attribute.ts @@ -0,0 +1,36 @@ +'use client'; + +import { useEffect } from 'react'; + +import { PARAMETER } from '@/utils/constants'; + +export function useResetAttribute(elementRef: React.RefObject, attribute: string) { + useEffect(() => { + // Trigger tooltip re-initialization after component mounts and tab becomes visible + // This ensures tooltips work when loading the page directly with this tab active + // React-tabs hides inactive panels with CSS (display: none), so react-tooltip v5 + // needs to re-scan the DOM when elements become visible + const timeoutId = setTimeout(() => { + if (!elementRef.current) { + return; + } + + // Force react-tooltip to re-scan by temporarily removing and re-adding data-tooltip-id + // This triggers react-tooltip's internal MutationObserver to re-register the elements + const tooltipElements = elementRef.current.querySelectorAll(`[${attribute}]`); + tooltipElements.forEach(element => { + if (element instanceof HTMLElement) { + const value = element.getAttribute(attribute); + if (value) { + element.removeAttribute(attribute); + requestAnimationFrame(() => { + element.setAttribute(attribute, value); + }); + } + } + }); + }, PARAMETER.minimalTimeout); + + return () => clearTimeout(timeoutId); + }, [elementRef, attribute]); +}