Files
frontend-app-authoring/src/generic/resizable/Resizable.tsx
Navin Karkera bb6b2ab33c feat: container info sidebar and add sidebar updates (#2830)
* Adds section, subsection and unit sidebar info tab in course outline as described in https://github.com/openedx/frontend-app-authoring/issues/2638
* Updates the sidebar design and behaviour as per https://github.com/openedx/frontend-app-authoring/issues/2826
* Updates course outline to use react query and removes redux store usage as much as possible. Updated parts that require absolutely cannot work without redux without heavy refactoring (will require quiet some time) to work in tandem with react-query.
2026-02-09 11:03:27 -05:00

74 lines
2.2 KiB
TypeScript

import { useWindowSize } from '@openedx/paragon';
import React, {
useRef, useState, useCallback, useMemo,
} from 'react';
const MIN_WIDTH = 440; // px
interface ResizableBoxProps {
children: React.ReactNode;
minWidth?: number;
maxWidth?: number
}
/**
* Creates a resizable box that can be dragged to resize the width from the left side.
*/
export const ResizableBox = ({
children,
minWidth = MIN_WIDTH,
maxWidth,
}: ResizableBoxProps) => {
const boxRef = useRef<HTMLDivElement>(null);
const [width, setWidth] = useState<number>(minWidth); // initial width
const { width: windowWidth } = useWindowSize();
// Store the start values while dragging
const startXRef = useRef<number>(0);
const startWidthRef = useRef<number>(0);
const defaultMaxWidth = useMemo(() => {
if (!windowWidth) {
return Infinity;
}
return Math.abs(windowWidth * 0.65);
}, [windowWidth]);
const onMouseMove = useCallback((e: MouseEvent) => {
const dx = e.clientX - startXRef.current; // positive = mouse moved right
const newWidth = Math.min(
Math.max(startWidthRef.current - dx, minWidth),
maxWidth || defaultMaxWidth,
);
setWidth(newWidth);
}, [maxWidth, minWidth, defaultMaxWidth]);
const onMouseUp = useCallback(() => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}, [onMouseMove]);
const onMouseDown = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
e.preventDefault(); // prevent text selection
startXRef.current = e.clientX;
startWidthRef.current = width;
// Attach listeners to the whole document so dragging works even outside the box
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
}, [width]);
return (
<div
className="resizable"
ref={boxRef}
style={{ width: `${width}px` }}
>
{/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */}
<div className="resizable-handle" onMouseDown={onMouseDown} />
<div className="w-100">
{children}
</div>
</div>
);
};