mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-11-20 17:21:24 +03:00
B: Fix tooltips for tabbed views
This commit is contained in:
parent
73e74bdd2d
commit
f63d9cf93e
|
|
@ -1,10 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useLayoutEffect } from 'react';
|
import { useLayoutEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { useConceptNavigation } from '@/app/navigation/navigation-context';
|
import { useConceptNavigation } from '@/app/navigation/navigation-context';
|
||||||
|
|
||||||
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
||||||
|
import { useResetAttribute } from '@/hooks/use-reset-attribute';
|
||||||
import { useAppLayoutStore } from '@/stores/app-layout';
|
import { useAppLayoutStore } from '@/stores/app-layout';
|
||||||
|
|
||||||
import { EditorOssCard } from './editor-oss-card';
|
import { EditorOssCard } from './editor-oss-card';
|
||||||
|
|
@ -22,6 +23,9 @@ export function OssTabs({ activeTab }: OssTabsProps) {
|
||||||
|
|
||||||
const hideFooter = useAppLayoutStore(state => state.hideFooter);
|
const hideFooter = useAppLayoutStore(state => state.hideFooter);
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
useResetAttribute(containerRef, 'data-tooltip-id');
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const oldTitle = document.title;
|
const oldTitle = document.title;
|
||||||
document.title = schema.title;
|
document.title = schema.title;
|
||||||
|
|
@ -68,7 +72,7 @@ export function OssTabs({ activeTab }: OssTabsProps) {
|
||||||
<TabLabel label='Граф' />
|
<TabLabel label='Граф' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<div className='overflow-x-hidden'>
|
<div ref={containerRef} className='overflow-x-hidden'>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<EditorOssCard />
|
<EditorOssCard />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { useWindowSize } from '@/hooks/use-window-size';
|
||||||
import { useFitHeight, useMainHeight } from '@/stores/app-layout';
|
import { useFitHeight, useMainHeight } from '@/stores/app-layout';
|
||||||
import { useModificationStore } from '@/stores/modification';
|
import { useModificationStore } from '@/stores/modification';
|
||||||
import { usePreferencesStore } from '@/stores/preferences';
|
import { usePreferencesStore } from '@/stores/preferences';
|
||||||
import { globalIDs, PARAMETER } from '@/utils/constants';
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
import { useMutatingRSForm } from '../../../backend/use-mutating-rsform';
|
import { useMutatingRSForm } from '../../../backend/use-mutating-rsform';
|
||||||
import { ViewConstituents } from '../../../components/view-constituents';
|
import { ViewConstituents } from '../../../components/view-constituents';
|
||||||
|
|
@ -43,7 +43,6 @@ export function EditorConstituenta() {
|
||||||
const { isModified } = useModificationStore();
|
const { isModified } = useModificationStore();
|
||||||
|
|
||||||
const [toggleReset, setToggleReset] = useState(false);
|
const [toggleReset, setToggleReset] = useState(false);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
|
||||||
|
|
||||||
const isProcessing = useMutatingRSForm();
|
const isProcessing = useMutatingRSForm();
|
||||||
const disabled = !activeCst || !isContentEditable || isProcessing;
|
const disabled = !activeCst || !isContentEditable || isProcessing;
|
||||||
|
|
@ -62,35 +61,6 @@ export function EditorConstituenta() {
|
||||||
}
|
}
|
||||||
}, [activeCst, selectedCst, setSelectedCst]);
|
}, [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<HTMLDivElement>) {
|
function handleInput(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -130,7 +100,6 @@ export function EditorConstituenta() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={containerRef}
|
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'relative ',
|
'relative ',
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useLayoutEffect } from 'react';
|
import { useLayoutEffect, useRef } from 'react';
|
||||||
|
|
||||||
import { useConceptNavigation } from '@/app/navigation/navigation-context';
|
import { useConceptNavigation } from '@/app/navigation/navigation-context';
|
||||||
|
|
||||||
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
import { TabLabel, TabList, TabPanel, Tabs } from '@/components/tabs';
|
||||||
|
import { useResetAttribute } from '@/hooks/use-reset-attribute';
|
||||||
import { useAppLayoutStore } from '@/stores/app-layout';
|
import { useAppLayoutStore } from '@/stores/app-layout';
|
||||||
import { useModificationStore } from '@/stores/modification';
|
import { useModificationStore } from '@/stores/modification';
|
||||||
|
|
||||||
|
|
@ -88,6 +89,9 @@ export function RSTabs({ activeID, activeTab }: RSTabsProps) {
|
||||||
navigateRSForm({ tab: index as RSTabID, activeID: selectedCst.length > 0 ? selectedCst.at(-1) : undefined });
|
navigateRSForm({ tab: index as RSTabID, activeID: selectedCst.length > 0 ? selectedCst.at(-1) : undefined });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
useResetAttribute(containerRef, 'data-tooltip-id');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedIndex={activeTab}
|
selectedIndex={activeTab}
|
||||||
|
|
@ -104,7 +108,7 @@ export function RSTabs({ activeID, activeTab }: RSTabsProps) {
|
||||||
<TabLabel label='Граф' />
|
<TabLabel label='Граф' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<div className='overflow-x-hidden'>
|
<div ref={containerRef} className='overflow-x-hidden'>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<EditorRSFormCard />
|
<EditorRSFormCard />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
|
||||||
36
rsconcept/frontend/src/hooks/use-reset-attribute.ts
Normal file
36
rsconcept/frontend/src/hooks/use-reset-attribute.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
|
export function useResetAttribute(elementRef: React.RefObject<HTMLElement | null>, 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]);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user