fix(terminal): detect shell tab visibility via MutationObserver
All checks were successful
Beta Release / beta (push) Successful in 49s
All checks were successful
Beta Release / beta (push) Successful in 49s
Shell is always mounted inside a display:none parent when the app loads on a different tab. Added MutationObserver on the wrapper to detect when the shell tab becomes visible and initialize/fit all pending terminals at that moment. Removed attempt limit so retries continue until the tab is actually shown. 💘 Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
@@ -425,15 +425,36 @@ export default function Shell({ api }) {
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
const initPendingTabs = useCallback(() => {
|
||||||
|
for (const tab of tabsRef.current._tabList || []) {
|
||||||
|
if (!tabsRef.current[tab.id]) {
|
||||||
|
const container = document.getElementById(`terminal-${tab.id}`)
|
||||||
|
if (container && container.offsetHeight > 0) {
|
||||||
|
initTerminal(tab.id, tab)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
for (const tab of tabsRef.current._tabList || []) {
|
||||||
|
const entry = tabsRef.current[tab.id]
|
||||||
|
if (entry) entry.fitAddon.fit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [initTerminal])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
tabsRef.current._tabList = tabs
|
||||||
|
}, [tabs])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
const pending = []
|
const pending = []
|
||||||
|
|
||||||
const tryInitTab = (tab, attempt) => {
|
const tryInitTab = (tab, attempt) => {
|
||||||
if (cancelled || attempt > 30) return
|
if (cancelled) return
|
||||||
const shellCol = document.querySelector('.shell-terminal-col')
|
const shellCol = document.querySelector('.shell-terminal-col')
|
||||||
if (!shellCol || shellCol.offsetParent === null) {
|
if (!shellCol || shellCol.offsetParent === null) {
|
||||||
pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 150))
|
pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 200))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const container = document.getElementById(`terminal-${tab.id}`)
|
const container = document.getElementById(`terminal-${tab.id}`)
|
||||||
@@ -461,11 +482,23 @@ export default function Shell({ api }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wrapper = document.querySelector('.shell-layout')?.parentElement
|
||||||
|
let observer
|
||||||
|
if (wrapper) {
|
||||||
|
observer = new MutationObserver(() => {
|
||||||
|
if (!wrapper.classList.contains('tab-hidden') && wrapper.offsetParent !== null) {
|
||||||
|
initPendingTabs()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
observer.observe(wrapper, { attributes: true, attributeFilter: ['class'] })
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true
|
cancelled = true
|
||||||
pending.forEach(clearTimeout)
|
pending.forEach(clearTimeout)
|
||||||
|
observer?.disconnect()
|
||||||
}
|
}
|
||||||
}, [tabs, initTerminal])
|
}, [tabs, initTerminal, initPendingTabs])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const entry = tabsRef.current[activeTab]
|
const entry = tabsRef.current[activeTab]
|
||||||
@@ -480,6 +513,8 @@ export default function Shell({ api }) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const iv = setInterval(() => {
|
const iv = setInterval(() => {
|
||||||
|
const wrapper = document.querySelector('.shell-layout')?.parentElement
|
||||||
|
if (wrapper && wrapper.classList.contains('tab-hidden')) return
|
||||||
const entry = tabsRef.current[activeTabRef.current]
|
const entry = tabsRef.current[activeTabRef.current]
|
||||||
if (entry) {
|
if (entry) {
|
||||||
entry.fitAddon.fit()
|
entry.fitAddon.fit()
|
||||||
|
|||||||
Reference in New Issue
Block a user