Skip to content

Commit

Permalink
feat(elements-core): make sidebar resizable (stoplightio#2268)
Browse files Browse the repository at this point in the history
* fix(elements-core): make sidebar resizable

* fix(elements-core): make useResizer private. fix types (stoplightio#2268)

* fix(elements-core): use React without imports (stoplightio#2268)

* fix(elements-core): set min sidebar width to default value (stoplightio#2268)

* Apply suggestions from code review

Co-authored-by: Jakub Rożek <[email protected]>

* feat(elements-core): suppress linter error (stoplightio#2268)

* feat(elements-core): set cursor by style property

* fix(elements-core): set limits for the currentSidebarWidth (stoplightio#2268)

* fix(elements-core): set suitable resize icon (stoplightio#2268)

Co-authored-by: Jakub Rożek <[email protected]>
Co-authored-by: Jakub Rożek <[email protected]>
  • Loading branch information
3 people authored Nov 15, 2022
1 parent 330258f commit ccb97b3
Showing 1 changed file with 72 additions and 16 deletions.
88 changes: 72 additions & 16 deletions packages/elements-core/src/components/Layout/SidebarLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ type SidebarLayoutProps = {
};

const MAX_CONTENT_WIDTH = 1800;
const SIDEBAR_WIDTH = 300;
const SIDEBAR_MIN_WIDTH = 300;
const SIDEBAR_MAX_WIDTH = 1.5 * SIDEBAR_MIN_WIDTH;

export const SidebarLayout = React.forwardRef<HTMLDivElement, SidebarLayoutProps>(
({ sidebar, children, maxContentWidth = MAX_CONTENT_WIDTH, sidebarWidth = SIDEBAR_WIDTH }, ref) => {
({ sidebar, children, maxContentWidth = MAX_CONTENT_WIDTH, sidebarWidth = SIDEBAR_MIN_WIDTH }, ref) => {
const scrollRef = React.useRef<HTMLDivElement | null>(null);
const [sidebarRef, currentSidebarWidth, startResizing] = useResizer(sidebarWidth);
const { pathname } = useLocation();

React.useEffect(() => {
Expand All @@ -25,27 +27,81 @@ export const SidebarLayout = React.forwardRef<HTMLDivElement, SidebarLayoutProps
return (
<Flex ref={ref} className="sl-elements-api" pin h="full">
<Flex
direction="col"
bg="canvas-100"
borderR
pt={8}
pos="sticky"
pinY
overflowY="auto"
style={{
width: `calc((100% - ${maxContentWidth}px) / 2 + ${sidebarWidth}px)`,
paddingLeft: `calc((100% - ${maxContentWidth}px) / 2)`,
minWidth: `${sidebarWidth}px`,
}}
ref={sidebarRef}
onMouseDown={(e: React.MouseEvent<HTMLElement>) => e.preventDefault()}
style={{ maxWidth: `${SIDEBAR_MAX_WIDTH}px` }}
>
{sidebar}
<Flex
direction="col"
bg="canvas-100"
borderR
pt={8}
pos="sticky"
pinY
overflowY="auto"
style={{
paddingLeft: `calc((100% - ${maxContentWidth}px) / 2)`,
width: `${currentSidebarWidth}px`,
minWidth: `${SIDEBAR_MIN_WIDTH}px`,
}}
>
{sidebar}
</Flex>
<Flex
justifySelf="end"
flexGrow={0}
flexShrink={0}
resize="x"
onMouseDown={startResizing}
style={{ width: '1em', flexBasis: '6px', cursor: 'ew-resize' }}
/>
</Flex>

<Box ref={scrollRef} bg="canvas" px={24} flex={1} w="full" overflowY="auto">
<Box style={{ maxWidth: `${maxContentWidth - sidebarWidth}px` }} py={16}>
<Box style={{ maxWidth: `${maxContentWidth - currentSidebarWidth}px` }} py={16}>
{children}
</Box>
</Box>
</Flex>
);
},
);

type SidebarRef = React.Ref<HTMLDivElement>;
type SidebarWidth = number;
type StartResizingFn = () => void;

function useResizer(sidebarWidth: number): [SidebarRef, SidebarWidth, StartResizingFn] {
const sidebarRef = React.useRef<HTMLDivElement | null>(null);
const [isResizing, setIsResizing] = React.useState(false);
const [currentSidebarWidth, setCurrentSidebarWidth] = React.useState(sidebarWidth);

const startResizing = React.useCallback(() => {
setIsResizing(true);
}, []);

const stopResizing = React.useCallback(() => {
setIsResizing(false);
}, []);

const resize = React.useCallback(
mouseMoveEvent => {
if (isResizing) {
const value = mouseMoveEvent.clientX - sidebarRef.current!.getBoundingClientRect().left;
setCurrentSidebarWidth(Math.min(Math.max(SIDEBAR_MIN_WIDTH, value), SIDEBAR_MAX_WIDTH));
}
},
[isResizing],
);

React.useEffect(() => {
window.addEventListener('mousemove', resize);
window.addEventListener('mouseup', stopResizing, { passive: true });
return () => {
window.removeEventListener('mousemove', resize);
window.removeEventListener('mouseup', stopResizing);
};
}, [resize, stopResizing]);

return [sidebarRef, currentSidebarWidth, startResizing];
}

0 comments on commit ccb97b3

Please sign in to comment.