mirror of
https://github.com/stablyai/orca.git
synced 2026-10-28 16:02:55 +00:00
perf(plugins): rebuild the panel frame only when its baked theme values change
The revision keys the panel iframe, so every bump destroys the sandboxed frame and its in-panel state. It counted root attribute mutations, but --workspace-sidebar-live-width is written every rAF of a sidebar drag, so dragging with a panel open blanked it ~60x/sec. Compare the two values the shell actually bakes in instead. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -67,4 +67,40 @@ describe('usePluginPanelThemeRevision', () => {
|
||||
|
||||
expect(revisions.at(-1)).toBe(before)
|
||||
})
|
||||
|
||||
// The revision keys the panel iframe, so a bump here destroys in-panel state.
|
||||
it('ignores root custom properties the panel shell does not bake in', async () => {
|
||||
const { revisions } = renderProbe()
|
||||
const before = revisions.at(-1)
|
||||
|
||||
// Written every rAF while dragging the sidebar divider.
|
||||
for (const width of [240, 241, 242, 243]) {
|
||||
document.documentElement.style.setProperty('--workspace-sidebar-live-width', `${width}px`)
|
||||
await flushObserver()
|
||||
}
|
||||
|
||||
expect(revisions.at(-1)).toBe(before)
|
||||
})
|
||||
|
||||
it('ignores a class change that leaves the color scheme alone', async () => {
|
||||
const { revisions } = renderProbe()
|
||||
const before = revisions.at(-1)
|
||||
|
||||
document.documentElement.classList.add('theme-transition-disabled')
|
||||
await flushObserver()
|
||||
|
||||
expect(revisions.at(-1)).toBe(before)
|
||||
})
|
||||
|
||||
it('bumps once when a token settles on a new value', async () => {
|
||||
const { revisions } = renderProbe()
|
||||
const before = revisions.at(-1)
|
||||
|
||||
document.documentElement.style.setProperty('--background', '#111')
|
||||
await flushObserver()
|
||||
document.documentElement.style.setProperty('--background', '#111')
|
||||
await flushObserver()
|
||||
|
||||
expect(revisions.at(-1)).toBe(before! + 1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,10 +1,28 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { buildPanelDesignTokenCss, currentPanelColorScheme } from './plugin-panel-design-token-css'
|
||||
|
||||
/** Changes whenever root theme classes/tokens may have changed. */
|
||||
/** The exact shell inputs; anything else on the root must not rebuild the frame. */
|
||||
function readPanelThemeSnapshot(): string {
|
||||
return `${currentPanelColorScheme()}|${buildPanelDesignTokenCss()}`
|
||||
}
|
||||
|
||||
/** Changes only when the values baked into the panel shell actually change. */
|
||||
export function usePluginPanelThemeRevision(): number {
|
||||
const [revision, setRevision] = useState(0)
|
||||
// Why: the revision keys the panel iframe, so remounting it destroys in-panel
|
||||
// state. Root style writes fire at rAF cadence during a sidebar drag, so
|
||||
// compare the baked values instead of counting mutations.
|
||||
const snapshotRef = useRef<string | null>(null)
|
||||
useEffect(() => {
|
||||
const observer = new MutationObserver(() => setRevision((current) => current + 1))
|
||||
snapshotRef.current ??= readPanelThemeSnapshot()
|
||||
const observer = new MutationObserver(() => {
|
||||
const snapshot = readPanelThemeSnapshot()
|
||||
if (snapshot === snapshotRef.current) {
|
||||
return
|
||||
}
|
||||
snapshotRef.current = snapshot
|
||||
setRevision((current) => current + 1)
|
||||
})
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ['class', 'style']
|
||||
|
||||
Reference in New Issue
Block a user