React IDE page shell (#14988)

* React IDE page shell

* Set the maximum height of the symbol palette to 336px

* Tidy export

* Remove unnecessary destructuring

* Update comment

* Optimize toggle

Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>

* Change snap-to-collapse threshold to 5%

* Synchronize left column width between history and editor views and remove duplication in ide-page

* Replace resizer dots with SVG

* Rermove unnecessary import and comment the remaining ones

* Use block prepend to avoid duplication

* Improve vertical content divider styling

* Implement fixed width during container resize on left column

* Change IDE page file extension

* Refactor fixed-size panel into a hook and use for chat panel

---------

Co-authored-by: Alf Eaton <alf.eaton@overleaf.com>
GitOrigin-RevId: aa881e48a2838a192b6f8f9e16e561f5cd706bd3
This commit is contained in:
Tim Down
2023-10-03 08:04:04 +00:00
committed by Copybot
co-authored by Alf Eaton
parent afcac7af86
commit ea1fc5f74e
27 changed files with 819 additions and 1 deletions
@@ -0,0 +1,19 @@
import { RefObject, useEffect } from 'react'
import { ImperativePanelHandle } from 'react-resizable-panels'
export default function useCollapsiblePanel(
panelIsOpen: boolean,
panelRef: RefObject<ImperativePanelHandle>
) {
useEffect(() => {
const panel = panelRef.current
if (!panel) {
return
}
if (panelIsOpen) {
panel.expand()
} else {
panel.collapse()
}
}, [panelIsOpen, panelRef])
}
@@ -0,0 +1,66 @@
import { useCallback, useEffect, useRef, useState } from 'react'
import { ImperativePanelHandle } from 'react-resizable-panels'
import { PanelGroupOnLayout } from 'react-resizable-panels/src/types'
export default function useFixedSizeColumn(
defaultSize: number,
isOpen: boolean
) {
const fixedPanelRef = useRef<ImperativePanelHandle>(null)
const fixedPanelWidthRef = useRef({ size: defaultSize, pixels: 0 })
const [initialLayoutDone, setInitialLayoutDone] = useState(false)
const measureFixedPanelSizePixels = useCallback(() => {
return fixedPanelRef.current?.getSize('pixels') || 0
}, [fixedPanelRef])
const handleLayout = useCallback(
sizes => {
// Measure the pixel width here because it's not always up to date in the
// panel's onResize
fixedPanelWidthRef.current = {
size: sizes[0],
pixels: measureFixedPanelSizePixels(),
}
setInitialLayoutDone(true)
},
[measureFixedPanelSizePixels]
) as PanelGroupOnLayout
useEffect(() => {
if (!isOpen) {
return
}
// Only start watching for resizes once the initial layout is done,
// otherwise we could measure the fixed column while it has zero width and
// collapse it
if (!initialLayoutDone || !fixedPanelRef.current) {
return
}
const fixedPanelElement = document.querySelector(
`[data-panel-id="${fixedPanelRef.current.getId()}"]`
)
const panelGroupElement = fixedPanelElement?.closest('[data-panel-group]')
if (!panelGroupElement || !fixedPanelElement) {
return
}
const resizeObserver = new ResizeObserver(() => {
fixedPanelRef.current?.resize(fixedPanelWidthRef.current.pixels, 'pixels')
})
resizeObserver.observe(panelGroupElement)
return () => resizeObserver.unobserve(panelGroupElement)
}, [fixedPanelRef, measureFixedPanelSizePixels, initialLayoutDone, isOpen])
return {
fixedPanelRef,
fixedPanelWidthRef,
handleLayout,
}
}