mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
feat(ui): bump react-resizable-panels, improve panel resize logic
This commit is contained in:
parent
2663a07e94
commit
2ffecef792
@ -95,7 +95,7 @@
|
||||
"react-icons": "^4.12.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-redux": "^9.0.4",
|
||||
"react-resizable-panels": "^1.0.5",
|
||||
"react-resizable-panels": "^1.0.6",
|
||||
"react-select": "5.7.7",
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"react-use": "^17.4.2",
|
||||
|
@ -135,8 +135,8 @@ dependencies:
|
||||
specifier: ^9.0.4
|
||||
version: 9.0.4(@types/react@18.2.46)(react@18.2.0)(redux@5.0.1)
|
||||
react-resizable-panels:
|
||||
specifier: ^1.0.5
|
||||
version: 1.0.5(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: ^1.0.6
|
||||
version: 1.0.6(react-dom@18.2.0)(react@18.2.0)
|
||||
react-select:
|
||||
specifier: 5.7.7
|
||||
version: 5.7.7(@types/react@18.2.46)(react-dom@18.2.0)(react@18.2.0)
|
||||
@ -11221,8 +11221,8 @@ packages:
|
||||
use-sidecar: 1.1.2(@types/react@18.2.46)(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react-resizable-panels@1.0.5(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-OP0whNQCko+f4BgoptGaeIc7StBRyeMeJ+8r/7rXACBDf9W5EcMWuM32hfqPDMenS2HFy/eZVi/r8XqK+ZIEag==}
|
||||
/react-resizable-panels@1.0.6(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-yZQiOP/uW2nTSdESDUBlBkQ1NQjUABpRKfBqonUQnNYSur7qRDy3W2wEEmrEyUY+W3opshpMiHf45zngIduJ0g==}
|
||||
peerDependencies:
|
||||
react: ^16.14.0 || ^17.0.0 || ^18.0.0
|
||||
react-dom: ^16.14.0 || ^17.0.0 || ^18.0.0
|
||||
|
@ -104,19 +104,7 @@ const GALLERY_MIN_SIZE_PCT = 20;
|
||||
const OPTIONS_PANEL_MIN_SIZE_PX = 430;
|
||||
const OPTIONS_PANEL_MIN_SIZE_PCT = 20;
|
||||
|
||||
const optionsPanelUsePanelOptions: UsePanelOptions = {
|
||||
unit: 'pixels',
|
||||
minSize: OPTIONS_PANEL_MIN_SIZE_PX,
|
||||
fallbackMinSizePct: OPTIONS_PANEL_MIN_SIZE_PCT,
|
||||
panelGroupID: 'app',
|
||||
};
|
||||
|
||||
const galleryPanelUsePanelOptions: UsePanelOptions = {
|
||||
unit: 'pixels',
|
||||
minSize: GALLERY_MIN_SIZE_PX,
|
||||
fallbackMinSizePct: GALLERY_MIN_SIZE_PCT,
|
||||
panelGroupID: 'app',
|
||||
};
|
||||
const appPanelGroupId = 'app-panel-group';
|
||||
|
||||
const InvokeTabs = () => {
|
||||
const activeTabIndex = useAppSelector(activeTabIndexSelector);
|
||||
@ -124,7 +112,7 @@ const InvokeTabs = () => {
|
||||
const enabledTabs = useAppSelector(enabledTabsSelector);
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
const panelGroupHandleRef = useRef<ImperativePanelGroupHandle>(null);
|
||||
const panelGroupRef = useRef<ImperativePanelGroupHandle>(null);
|
||||
const handleClickTab = useCallback((e: MouseEvent<HTMLElement>) => {
|
||||
if (e.target instanceof HTMLElement) {
|
||||
e.target.blur();
|
||||
@ -170,6 +158,28 @@ const InvokeTabs = () => {
|
||||
[dispatch, enabledTabs]
|
||||
);
|
||||
|
||||
const optionsPanelUsePanelOptions = useMemo<UsePanelOptions>(
|
||||
() => ({
|
||||
unit: 'pixels',
|
||||
minSize: OPTIONS_PANEL_MIN_SIZE_PX,
|
||||
fallbackMinSizePct: OPTIONS_PANEL_MIN_SIZE_PCT,
|
||||
panelGroupRef,
|
||||
panelGroupDirection: 'horizontal',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const galleryPanelUsePanelOptions = useMemo<UsePanelOptions>(
|
||||
() => ({
|
||||
unit: 'pixels',
|
||||
minSize: GALLERY_MIN_SIZE_PX,
|
||||
fallbackMinSizePct: GALLERY_MIN_SIZE_PCT,
|
||||
panelGroupRef,
|
||||
panelGroupDirection: 'horizontal',
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const panelStorage = usePanelStorage();
|
||||
|
||||
const {
|
||||
@ -227,8 +237,8 @@ const InvokeTabs = () => {
|
||||
<Spacer />
|
||||
</InvTabList>
|
||||
<PanelGroup
|
||||
ref={panelGroupHandleRef}
|
||||
id="app"
|
||||
ref={panelGroupRef}
|
||||
id={appPanelGroupId}
|
||||
autoSaveId="app"
|
||||
direction="horizontal"
|
||||
style={panelStyles}
|
||||
@ -237,7 +247,7 @@ const InvokeTabs = () => {
|
||||
{!NO_SIDE_PANEL_TABS.includes(activeTabName) && (
|
||||
<>
|
||||
<Panel
|
||||
id="options"
|
||||
id="options-panel"
|
||||
ref={optionsPanelRef}
|
||||
order={0}
|
||||
defaultSize={optionsPanelMinSize}
|
||||
@ -253,12 +263,13 @@ const InvokeTabs = () => {
|
||||
)}
|
||||
</Panel>
|
||||
<ResizeHandle
|
||||
id="options-main-handle"
|
||||
onDoubleClick={resetOptionsPanel}
|
||||
orientation="vertical"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Panel id="main" order={1} minSize={20}>
|
||||
<Panel id="main-panel" order={1} minSize={20}>
|
||||
<InvTabPanels w="full" h="full">
|
||||
{tabPanels}
|
||||
</InvTabPanels>
|
||||
@ -266,11 +277,12 @@ const InvokeTabs = () => {
|
||||
{!NO_GALLERY_TABS.includes(activeTabName) && (
|
||||
<>
|
||||
<ResizeHandle
|
||||
id="main-gallery-handle"
|
||||
onDoubleClick={resetGalleryPanel}
|
||||
orientation="vertical"
|
||||
/>
|
||||
<Panel
|
||||
id="gallery"
|
||||
id="gallery-panel"
|
||||
ref={galleryPanelRef}
|
||||
order={2}
|
||||
defaultSize={galleryPanelMinSize}
|
||||
|
@ -1,9 +1,15 @@
|
||||
import type { RefObject } from 'react';
|
||||
import { useCallback, useLayoutEffect, useRef, useState } from 'react';
|
||||
import type {
|
||||
ImperativePanelGroupHandle,
|
||||
ImperativePanelHandle,
|
||||
PanelOnCollapse,
|
||||
PanelOnExpand,
|
||||
} from 'react-resizable-panels';
|
||||
import {
|
||||
getPanelGroupElement,
|
||||
getResizeHandleElementsForGroup,
|
||||
} from 'react-resizable-panels';
|
||||
|
||||
export type UsePanelOptions =
|
||||
| { minSize: number; unit: 'percentages' }
|
||||
@ -11,46 +17,61 @@ export type UsePanelOptions =
|
||||
minSize: number;
|
||||
unit: 'pixels';
|
||||
fallbackMinSizePct: number;
|
||||
panelGroupID: string;
|
||||
panelGroupRef: RefObject<ImperativePanelGroupHandle>;
|
||||
panelGroupDirection: 'horizontal' | 'vertical';
|
||||
};
|
||||
|
||||
export const usePanel = (arg: UsePanelOptions) => {
|
||||
const panelHandleRef = useRef<ImperativePanelHandle>(null);
|
||||
const newMinSizeRef = useRef<number>(0);
|
||||
const currentSizeRef = useRef<number>(0);
|
||||
const [_minSize, _setMinSize] = useState<number>(
|
||||
arg.unit === 'percentages' ? arg.minSize : arg.fallbackMinSizePct
|
||||
);
|
||||
|
||||
// If the units are pixels, we need to calculate the min size as a percentage of the available space
|
||||
useLayoutEffect(() => {
|
||||
if (arg.unit === 'percentages') {
|
||||
if (arg.unit === 'percentages' || !arg.panelGroupRef.current) {
|
||||
return;
|
||||
}
|
||||
const panelGroupElement = document.querySelector(
|
||||
`[data-panel-group][data-panel-group-id="${arg.panelGroupID}"]`
|
||||
const panelGroupElement = getPanelGroupElement(
|
||||
arg.panelGroupRef.current.getId()
|
||||
);
|
||||
const panelGroupHandleElements = getResizeHandleElementsForGroup(
|
||||
arg.panelGroupRef.current.getId()
|
||||
);
|
||||
if (!panelGroupElement) {
|
||||
return;
|
||||
}
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (!panelHandleRef?.current) {
|
||||
return;
|
||||
}
|
||||
newMinSizeRef.current = (arg.minSize * 100) / entry.contentRect.width;
|
||||
currentSizeRef.current =
|
||||
panelHandleRef.current.getSize() ?? arg.fallbackMinSizePct;
|
||||
if (currentSizeRef.current < newMinSizeRef.current) {
|
||||
panelHandleRef.current.resize(newMinSizeRef.current);
|
||||
}
|
||||
_setMinSize(newMinSizeRef.current);
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
if (!panelHandleRef?.current) {
|
||||
return;
|
||||
}
|
||||
// Calculate the available space for the panel, minus the space taken by the handles
|
||||
let dim =
|
||||
arg.panelGroupDirection === 'horizontal'
|
||||
? panelGroupElement.offsetWidth
|
||||
: panelGroupElement.offsetHeight;
|
||||
|
||||
panelGroupHandleElements.forEach(
|
||||
(el) =>
|
||||
(dim -=
|
||||
arg.panelGroupDirection === 'horizontal'
|
||||
? el.offsetWidth
|
||||
: el.offsetHeight)
|
||||
);
|
||||
|
||||
// Calculate the min size as a percentage of the available space
|
||||
const minSize = (arg.minSize * 100) / dim;
|
||||
// Must store this to avoid race conditions
|
||||
const currentSize = panelHandleRef.current.getSize();
|
||||
// Resize if the current size is smaller than the new min size - happens when the window is resized smaller
|
||||
if (currentSize < minSize) {
|
||||
panelHandleRef.current.resize(minSize);
|
||||
}
|
||||
|
||||
_setMinSize(minSize);
|
||||
});
|
||||
|
||||
resizeObserver.observe(panelGroupElement);
|
||||
// _setMinSize(
|
||||
// (arg.minSize * 100) / panelGroupElement.getBoundingClientRect().width
|
||||
// );
|
||||
|
||||
return () => {
|
||||
resizeObserver.disconnect();
|
||||
|
Loading…
Reference in New Issue
Block a user