fix(terminal): init all tabs on load, fix excessive zoom
All checks were successful
Beta Release / beta (push) Successful in 46s
All checks were successful
Beta Release / beta (push) Successful in 46s
Use visibility:hidden instead of display:none for inactive terminal tabs so xterm containers retain their dimensions. This allows all terminals to initialize independently and prevents fitAddon from miscalculating cell sizes on zero-height containers. 💘 Generated with Crush Assisted-by: GLM-5.1 via Crush <crush@charm.land>
This commit is contained in:
@@ -399,10 +399,7 @@ export default function Shell({ api }) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const onResize = () => {
|
const onResize = () => {
|
||||||
const el = document.getElementById(`terminal-${tabId}`)
|
fitAddon.fit()
|
||||||
if (el && el.style.display !== 'none') {
|
|
||||||
fitAddon.fit()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resizeObserver = new ResizeObserver(onResize)
|
const resizeObserver = new ResizeObserver(onResize)
|
||||||
@@ -429,27 +426,23 @@ export default function Shell({ api }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tab = tabs.find(t => t.id === activeTab)
|
|
||||||
if (!tab) return
|
|
||||||
|
|
||||||
let cancelled = false
|
let cancelled = false
|
||||||
const pending = []
|
const pending = []
|
||||||
|
|
||||||
const tryInit = (attempt) => {
|
const tryInitTab = (tab, attempt) => {
|
||||||
if (cancelled || attempt > 20) return
|
if (cancelled || attempt > 30) 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(() => tryInit(attempt + 1), 150))
|
pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 150))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const container = document.getElementById(`terminal-${tab.id}`)
|
const container = document.getElementById(`terminal-${tab.id}`)
|
||||||
if (!container) {
|
if (!container) {
|
||||||
pending.push(setTimeout(() => tryInit(attempt + 1), 100))
|
pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 100))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (activeTabRef.current !== tab.id) return
|
if (container.offsetHeight === 0) {
|
||||||
if (container.offsetHeight === 0 || container.style.display === 'none') {
|
pending.push(setTimeout(() => tryInitTab(tab, attempt + 1), 100))
|
||||||
pending.push(setTimeout(() => tryInit(attempt + 1), 100))
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!tabsRef.current[tab.id]) {
|
if (!tabsRef.current[tab.id]) {
|
||||||
@@ -457,29 +450,39 @@ export default function Shell({ api }) {
|
|||||||
}
|
}
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
if (cancelled) return
|
if (cancelled) return
|
||||||
if (activeTabRef.current !== tab.id) return
|
|
||||||
const entry = tabsRef.current[tab.id]
|
const entry = tabsRef.current[tab.id]
|
||||||
if (entry) entry.fitAddon.fit()
|
if (entry) entry.fitAddon.fit()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
tryInit(0)
|
for (const tab of tabs) {
|
||||||
|
if (!tabsRef.current[tab.id]) {
|
||||||
|
tryInitTab(tab, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true
|
cancelled = true
|
||||||
pending.forEach(clearTimeout)
|
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(() => {
|
useEffect(() => {
|
||||||
const iv = setInterval(() => {
|
const iv = setInterval(() => {
|
||||||
for (const tab of tabs) {
|
const entry = tabsRef.current[activeTabRef.current]
|
||||||
const entry = tabsRef.current[tab.id]
|
if (entry) {
|
||||||
if (entry) {
|
entry.fitAddon.fit()
|
||||||
const el = document.getElementById(`terminal-${tab.id}`)
|
|
||||||
if (el && el.style.display !== 'none') {
|
|
||||||
entry.fitAddon.fit()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, 2000)
|
}, 2000)
|
||||||
return () => clearInterval(iv)
|
return () => clearInterval(iv)
|
||||||
@@ -844,8 +847,7 @@ export default function Shell({ api }) {
|
|||||||
<div
|
<div
|
||||||
key={tab.id}
|
key={tab.id}
|
||||||
id={`terminal-${tab.id}`}
|
id={`terminal-${tab.id}`}
|
||||||
className="shell-xterm-instance"
|
className={`shell-xterm-instance${activeTab === tab.id ? ' active' : ''}`}
|
||||||
style={{ display: activeTab === tab.id ? 'block' : 'none' }}
|
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -386,6 +386,12 @@ input::placeholder { color: var(--text-disabled); }
|
|||||||
.shell-xterm-instance {
|
.shell-xterm-instance {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0;
|
inset: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
.shell-xterm-instance.active {
|
||||||
|
visibility: visible;
|
||||||
|
pointer-events: auto;
|
||||||
}
|
}
|
||||||
.shell-xterm-instance .xterm { height: 100%; }
|
.shell-xterm-instance .xterm { height: 100%; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user