diff --git a/web/src/components/Shell.jsx b/web/src/components/Shell.jsx index ca8ee6a..efa9521 100644 --- a/web/src/components/Shell.jsx +++ b/web/src/components/Shell.jsx @@ -399,10 +399,7 @@ export default function Shell({ api }) { }) const onResize = () => { - const el = document.getElementById(`terminal-${tabId}`) - if (el && el.style.display !== 'none') { - fitAddon.fit() - } + fitAddon.fit() } const resizeObserver = new ResizeObserver(onResize) @@ -429,27 +426,23 @@ export default function Shell({ api }) { }, []) useEffect(() => { - const tab = tabs.find(t => t.id === activeTab) - if (!tab) return - let cancelled = false const pending = [] - const tryInit = (attempt) => { - if (cancelled || attempt > 20) return + const tryInitTab = (tab, attempt) => { + if (cancelled || attempt > 30) return const shellCol = document.querySelector('.shell-terminal-col') if (!shellCol || shellCol.offsetParent === null) { - pending.push(setTimeout(() => tryInit(attempt + 1), 150)) + pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 150)) return } const container = document.getElementById(`terminal-${tab.id}`) if (!container) { - pending.push(setTimeout(() => tryInit(attempt + 1), 100)) + pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 100)) return } - if (activeTabRef.current !== tab.id) return - if (container.offsetHeight === 0 || container.style.display === 'none') { - pending.push(setTimeout(() => tryInit(attempt + 1), 100)) + if (container.offsetHeight === 0) { + pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 100)) return } if (!tabsRef.current[tab.id]) { @@ -457,29 +450,39 @@ export default function Shell({ api }) { } requestAnimationFrame(() => { if (cancelled) return - if (activeTabRef.current !== tab.id) return const entry = tabsRef.current[tab.id] if (entry) entry.fitAddon.fit() }) } - tryInit(0) + for (const tab of tabs) { + if (!tabsRef.current[tab.id]) { + tryInitTab(tab, 0) + } + } + return () => { cancelled = true pending.forEach(clearTimeout) } - }, [activeTab, initTerminal]) + }, [tabs, initTerminal]) + + useEffect(() => { + const entry = tabsRef.current[activeTab] + if (entry) { + requestAnimationFrame(() => { + if (activeTabRef.current === activeTab) { + entry.fitAddon.fit() + } + }) + } + }, [activeTab]) useEffect(() => { const iv = setInterval(() => { - for (const tab of tabs) { - const entry = tabsRef.current[tab.id] - if (entry) { - const el = document.getElementById(`terminal-${tab.id}`) - if (el && el.style.display !== 'none') { - entry.fitAddon.fit() - } - } + const entry = tabsRef.current[activeTabRef.current] + if (entry) { + entry.fitAddon.fit() } }, 2000) return () => clearInterval(iv) @@ -844,8 +847,7 @@ export default function Shell({ api }) {
))} diff --git a/web/src/styles/global.css b/web/src/styles/global.css index 94e7be2..2ccf368 100644 --- a/web/src/styles/global.css +++ b/web/src/styles/global.css @@ -386,6 +386,12 @@ input::placeholder { color: var(--text-disabled); } .shell-xterm-instance { position: absolute; inset: 0; + visibility: hidden; + pointer-events: none; +} +.shell-xterm-instance.active { + visibility: visible; + pointer-events: auto; } .shell-xterm-instance .xterm { height: 100%; }