diff --git a/src/renderer/components/SettingsPanel.tsx b/src/renderer/components/SettingsPanel.tsx index 6b93946..4704bb4 100644 --- a/src/renderer/components/SettingsPanel.tsx +++ b/src/renderer/components/SettingsPanel.tsx @@ -1,5 +1,6 @@ import { useLayoutEffect, useMemo, useRef, type CSSProperties, type JSX } from 'react' import { buildAnalyzerGridTemplateColumns } from '../analyzerLayout' +import { resolveMainWindowSettingsPanelHeight } from '../mainWindowSettings' import ScopeSettingsSection from './ScopeSettingsSection' import { useSettingsStore } from '../stores/settingsStore' @@ -31,7 +32,7 @@ export default function SettingsPanel({ onHeightChange }: SettingsPanelProps): J const reportHeight = (): void => { cancelAnimationFrame(frameId) frameId = requestAnimationFrame(() => { - onHeightChange(Math.ceil(panelElement.scrollHeight)) + onHeightChange(resolveMainWindowSettingsPanelHeight(panelElement, scopeTrackRef.current)) }) } diff --git a/src/renderer/mainWindowSettings.ts b/src/renderer/mainWindowSettings.ts index f9572c9..d93577c 100644 --- a/src/renderer/mainWindowSettings.ts +++ b/src/renderer/mainWindowSettings.ts @@ -1,3 +1,23 @@ +function parseCssPixels(value: string): number { + const parsed = Number.parseFloat(value) + return Number.isFinite(parsed) ? parsed : 0 +} + +export function resolveMainWindowSettingsPanelHeight( + panelElement: HTMLElement, + contentElement: HTMLElement | null, +): number { + if (!contentElement) { + return Math.ceil(panelElement.scrollHeight) + } + + const panelStyle = getComputedStyle(panelElement) + const verticalPadding = parseCssPixels(panelStyle.paddingTop) + + parseCssPixels(panelStyle.paddingBottom) + + return Math.ceil(contentElement.scrollHeight + verticalPadding) +} + export function resolveMainWindowSettingsHeight( settingsOpen: boolean, settingsPanelHeight: number, diff --git a/test/renderer-helpers.test.ts b/test/renderer-helpers.test.ts index 02c407b..416f312 100644 --- a/test/renderer-helpers.test.ts +++ b/test/renderer-helpers.test.ts @@ -13,7 +13,10 @@ import { getHorizontalWheelScrollResult, normalizeWheelDelta, } from '../src/renderer/utils/horizontalWheelScroll' -import { resolveMainWindowSettingsHeight } from '../src/renderer/mainWindowSettings' +import { + resolveMainWindowSettingsHeight, + resolveMainWindowSettingsPanelHeight, +} from '../src/renderer/mainWindowSettings' import { formatAstraTime, getAstraPlaybackProgress, @@ -2670,6 +2673,32 @@ test('resolveMainWindowSettingsHeight waits for real measurements instead of usi assert.equal(resolveMainWindowSettingsHeight(true, 312, 96), 408) }) +test('resolveMainWindowSettingsPanelHeight uses intrinsic scope-track height when the panel is stretched', () => { + const globalWithStyle = globalThis as typeof globalThis & { + getComputedStyle?: (element: Element) => CSSStyleDeclaration + } + const previousGetComputedStyle = globalWithStyle.getComputedStyle + + globalWithStyle.getComputedStyle = () => ({ + paddingTop: '10px', + paddingBottom: '4px', + }) as CSSStyleDeclaration + + try { + const stretchedPanel = { scrollHeight: 640 } as HTMLElement + const collapsedScopeTrack = { scrollHeight: 220.25 } as HTMLElement + + assert.equal(resolveMainWindowSettingsPanelHeight(stretchedPanel, collapsedScopeTrack), 235) + assert.equal(resolveMainWindowSettingsPanelHeight(stretchedPanel, null), 640) + } finally { + if (previousGetComputedStyle) { + globalWithStyle.getComputedStyle = previousGetComputedStyle + } else { + delete globalWithStyle.getComputedStyle + } + } +}) + test('expanded main-window bounds can push upward into an overlapping display above', () => { const resolved = resolveExpandedMainWindowBounds( { x: 700, y: 1110, width: 900, height: 180 },