refactor(desktop): tighten the surface-var helper

Fold the null fallback into chatSurfaceRoot so both callers share one
target resolution, hoist the var names next to it, and drop the
duplicated rationale from the status-stack comment.
This commit is contained in:
Brooklyn Nicholson 2026-07-26 03:20:12 -05:00
parent c52bc5ec95
commit e7f4b95b47
4 changed files with 14 additions and 19 deletions

View file

@ -198,14 +198,12 @@ export function ComposerStatusStack({ queue, sessionId }: ComposerStatusStackPro
// height never sees it. Publish our own measured height — bucketed like the
// composer's, to avoid style invalidation churn — so the thread's
// last-message clearance can add it and the stack never hides messages.
// Scoped to THIS chat surface: tiles render their own stack beside the
// workspace pane, and a shared global would let the taller one dictate every
// thread's padding (see surface-vars.ts).
// Scoped to THIS surface: tiles render their own stack (see surface-vars.ts).
useLayoutEffect(() => {
const el = stackRef.current
if (!visible || !el) {
clearSurfaceVar(stackRef.current, STATUS_STACK_VAR)
clearSurfaceVar(el, STATUS_STACK_VAR)
return
}

View file

@ -57,7 +57,7 @@ describe('per-surface measured-height vars', () => {
const orphan = document.createElement('div')
document.body.append(orphan)
expect(chatSurfaceRoot(orphan)).toBeNull()
expect(chatSurfaceRoot(orphan)).toBe(document.documentElement)
setSurfaceVar(orphan, STATUS_STACK_VAR, '24px')
expect(document.documentElement.style.getPropertyValue(STATUS_STACK_VAR)).toBe('24px')

View file

@ -16,27 +16,25 @@
* there is no single correct value to remeasure to.
*/
/** Nearest enclosing chat surface, or `null` when the node is detached. */
export function chatSurfaceRoot(el: Element | null): HTMLElement | null {
return el?.closest<HTMLElement>('[data-chat-surface]') ?? null
}
export const COMPOSER_HEIGHT_VAR = '--composer-measured-height'
export const COMPOSER_SURFACE_HEIGHT_VAR = '--composer-surface-measured-height'
export const STATUS_STACK_VAR = '--status-stack-measured-height'
/**
* Set a measured-height var on the surface owning `el`. Falls back to the
* document root so a composer rendered outside a chat surface (the popped-out
* window) keeps behaving exactly as before.
* The surface owning `el`, falling back to the document root so a composer
* rendered outside a chat surface (the popped-out window) keeps behaving
* exactly as before.
*/
export function chatSurfaceRoot(el: Element | null): HTMLElement {
return el?.closest<HTMLElement>('[data-chat-surface]') ?? document.documentElement
}
/** Publish a measured-height var on the surface owning `el`. */
export function setSurfaceVar(el: Element | null, name: string, value: string): void {
const target = chatSurfaceRoot(el) ?? document.documentElement
target.style.setProperty(name, value)
chatSurfaceRoot(el).style.setProperty(name, value)
}
/** Clear a measured-height var from the surface owning `el`. */
export function clearSurfaceVar(el: Element | null, name: string): void {
const target = chatSurfaceRoot(el) ?? document.documentElement
target.style.removeProperty(name)
chatSurfaceRoot(el).style.removeProperty(name)
}

View file

@ -348,8 +348,7 @@
/* Space under last message vs overlay composer driven by the measured composer height (see composer/index.tsx)
plus the out-of-flow status stack's measured height (see status-stack/index.tsx) when one is showing.
Both inputs are republished per chat surface (see surface-vars.ts), and the calc is re-declared there so
each surface resolves against its OWN measurements a tile's tall stack must not pad another thread. */
These are the defaults; each chat surface re-declares the calc against its own measurements (see below). */
--status-stack-measured-height: 0px;
--thread-last-message-clearance: calc(var(--composer-measured-height) + var(--status-stack-measured-height) + 2rem);