generated from Exabyte-io/template-definitions
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #69 from Exabyte-io/feature/SOF-7287
Feature/SOF-7287 update: move ResizableDrawer component from Web-App here
- Loading branch information
Showing
4 changed files
with
349 additions
and
1 deletion.
There are no files selected for viewing
10 changes: 10 additions & 0 deletions
10
dist/mui/components/custom/resizable-drawer/ResizableDrawer.d.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import React from "react"; | ||
export default function ResizableDrawer({ children, open, onClose, refocusChild, childIdToRefocus, paperProps, containerRef, }: { | ||
children: React.ReactElement; | ||
open: boolean; | ||
onClose: () => void; | ||
refocusChild?: boolean; | ||
childIdToRefocus?: string; | ||
paperProps?: object; | ||
containerRef?: React.RefObject<HTMLDivElement>; | ||
}): React.JSX.Element; |
123 changes: 123 additions & 0 deletions
123
dist/mui/components/custom/resizable-drawer/ResizableDrawer.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
import CloseIcon from "@mui/icons-material/Close"; | ||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; | ||
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | ||
import Box from "@mui/material/Box"; | ||
import Drawer from "@mui/material/Drawer"; | ||
import { styled } from "@mui/material/styles"; | ||
import React, { useCallback, useEffect, useState } from "react"; | ||
function removeResizeListener({ resize, disableResize, refocusChild, childIdToRefocus, }) { | ||
var _a; | ||
document.removeEventListener("mousemove", resize); | ||
document.removeEventListener("mouseup", disableResize); | ||
if (refocusChild && childIdToRefocus) { | ||
(_a = document.getElementById(childIdToRefocus)) === null || _a === void 0 ? void 0 : _a.focus(); | ||
} | ||
} | ||
function addResizeListener({ resize, disableResize, }) { | ||
document.addEventListener("mousemove", resize); | ||
document.addEventListener("mouseup", disableResize); | ||
} | ||
const useResize = ({ minHeight, refocusChild, childIdToRefocus, }) => { | ||
const [isResizing, setIsResizing] = useState(false); | ||
const [height, setHeight] = useState(window.innerHeight / 2); | ||
const enableResize = useCallback(() => { | ||
setIsResizing(true); | ||
}, []); | ||
const disableResize = useCallback(() => { | ||
setIsResizing(false); | ||
}, []); | ||
const resize = useCallback((e) => { | ||
if (!isResizing) | ||
return; | ||
const newHeight = window.innerHeight - e.clientY; | ||
if (newHeight >= minHeight) | ||
setHeight(newHeight); | ||
}, [isResizing]); | ||
useEffect(() => { | ||
addResizeListener({ resize, disableResize }); | ||
return () => removeResizeListener({ resize, disableResize, refocusChild, childIdToRefocus }); | ||
}, [disableResize, resize]); | ||
useEffect(() => { | ||
if (isResizing) | ||
return; | ||
removeResizeListener({ resize, disableResize, refocusChild, childIdToRefocus }); | ||
}, [isResizing]); | ||
return { height, isResizing, setHeight, enableResize, disableResize }; | ||
}; | ||
const StyledBox = styled(Box)(({ theme }) => ({ | ||
backgroundColor: theme.palette.mode === "light" ? "#fff" : theme.palette.grey[800], | ||
})); | ||
const Puller = styled(Box)(({ theme, isResizing }) => ({ | ||
cursor: "row-resize", | ||
width: 30, | ||
height: 6, | ||
backgroundColor: isResizing ? theme === null || theme === void 0 ? void 0 : theme.palette.grey[300] : theme === null || theme === void 0 ? void 0 : theme.palette.grey[900], | ||
borderRadius: 3, | ||
position: "absolute", | ||
top: 8, | ||
left: "calc(50% - 15px)", | ||
})); | ||
const TRANSITION_DURATION = 500; // ms | ||
const DRAWER_MIN_HEGHT = 20; | ||
export default function ResizableDrawer({ children, open, onClose, refocusChild = false, childIdToRefocus, paperProps, containerRef, }) { | ||
const { height, setHeight, isResizing, enableResize, disableResize } = useResize({ | ||
minHeight: DRAWER_MIN_HEGHT, | ||
refocusChild, | ||
childIdToRefocus, | ||
}); | ||
// Styles to make the drawer fit the container | ||
const drawerStyles = containerRef && containerRef.current | ||
? { | ||
position: "absolute", | ||
left: containerRef.current.offsetLeft, | ||
bottom: window.innerHeight - containerRef.current.offsetHeight, | ||
maxHeight: containerRef.current.offsetHeight, | ||
width: containerRef.current.offsetWidth, | ||
boxSizing: "border-box", | ||
} | ||
: {}; | ||
const drawerPaperProps = { | ||
style: { | ||
...drawerStyles, | ||
height, | ||
// @ts-ignore | ||
...((paperProps === null || paperProps === void 0 ? void 0 : paperProps.style) || {}), | ||
}, | ||
}; | ||
const maximize = () => { | ||
var _a; | ||
const targetHeight = height < window.innerHeight / 3 ? window.innerHeight / 3 : window.innerHeight; | ||
setHeight(targetHeight); | ||
if (refocusChild && childIdToRefocus) { | ||
(_a = document.getElementById(childIdToRefocus)) === null || _a === void 0 ? void 0 : _a.focus(); | ||
} | ||
}; | ||
const minimize = () => { | ||
var _a; | ||
const targetHeight = height > window.innerHeight / 3 ? window.innerHeight / 3 : DRAWER_MIN_HEGHT; | ||
setHeight(targetHeight); | ||
if (refocusChild && childIdToRefocus) { | ||
(_a = document.getElementById(childIdToRefocus)) === null || _a === void 0 ? void 0 : _a.focus(); | ||
} | ||
}; | ||
return (React.createElement(Drawer, { variant: "persistent", anchor: "bottom", open: open, onClose: onClose, SlideProps: { | ||
direction: "up", | ||
timeout: TRANSITION_DURATION, | ||
in: true, | ||
appear: true, | ||
}, PaperProps: drawerPaperProps }, | ||
React.createElement(Box, { display: "flex", justifyContent: "right" }, | ||
React.createElement(KeyboardArrowUpIcon, { fontSize: "large", onClick: maximize, sx: { cursor: "pointer" } }), | ||
React.createElement(KeyboardArrowDownIcon, { fontSize: "large", onClick: minimize, sx: { cursor: "pointer" } }), | ||
React.createElement(CloseIcon, { fontSize: "large", onClick: onClose, sx: { cursor: "pointer" } })), | ||
React.createElement(StyledBox, { sx: { | ||
position: "absolute", | ||
borderTopLeftRadius: 8, | ||
borderTopRightRadius: 8, | ||
visibility: "visible", | ||
right: 0, | ||
left: 0, | ||
} }, | ||
React.createElement(Puller, { isResizing: isResizing, onMouseDown: enableResize, onMouseUp: disableResize })), | ||
children)); | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
215 changes: 215 additions & 0 deletions
215
src/mui/components/custom/resizable-drawer/ResizableDrawer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
import CloseIcon from "@mui/icons-material/Close"; | ||
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown"; | ||
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp"; | ||
import Box from "@mui/material/Box"; | ||
import Drawer from "@mui/material/Drawer"; | ||
import { styled, Theme } from "@mui/material/styles"; | ||
import React, { CSSProperties, useCallback, useEffect, useState } from "react"; | ||
|
||
type UseResizeProps = { | ||
minHeight: number; | ||
refocusChild?: boolean; | ||
childIdToRefocus?: string; | ||
}; | ||
|
||
type UseResizeReturn = { | ||
height: number; | ||
isResizing: boolean; | ||
setHeight: React.Dispatch<React.SetStateAction<number>>; | ||
enableResize: () => void; | ||
disableResize: () => void; | ||
}; | ||
|
||
interface ResizeListenerProps { | ||
resize: (e: MouseEvent) => void; | ||
disableResize: () => void; | ||
refocusChild?: boolean; | ||
childIdToRefocus?: string; | ||
} | ||
|
||
function removeResizeListener({ | ||
resize, | ||
disableResize, | ||
refocusChild, | ||
childIdToRefocus, | ||
}: ResizeListenerProps) { | ||
document.removeEventListener("mousemove", resize); | ||
document.removeEventListener("mouseup", disableResize); | ||
if (refocusChild && childIdToRefocus) { | ||
document.getElementById(childIdToRefocus)?.focus(); | ||
} | ||
} | ||
|
||
function addResizeListener({ | ||
resize, | ||
disableResize, | ||
}: Pick<ResizeListenerProps, "resize" | "disableResize">) { | ||
document.addEventListener("mousemove", resize); | ||
document.addEventListener("mouseup", disableResize); | ||
} | ||
|
||
const useResize = ({ | ||
minHeight, | ||
refocusChild, | ||
childIdToRefocus, | ||
}: UseResizeProps): UseResizeReturn => { | ||
const [isResizing, setIsResizing] = useState(false); | ||
const [height, setHeight] = useState(window.innerHeight / 2); | ||
const enableResize = useCallback(() => { | ||
setIsResizing(true); | ||
}, []); | ||
|
||
const disableResize = useCallback(() => { | ||
setIsResizing(false); | ||
}, []); | ||
|
||
const resize = useCallback( | ||
(e: MouseEvent) => { | ||
if (!isResizing) return; | ||
const newHeight = window.innerHeight - e.clientY; | ||
|
||
if (newHeight >= minHeight) setHeight(newHeight); | ||
}, | ||
[isResizing], | ||
); | ||
|
||
useEffect(() => { | ||
addResizeListener({ resize, disableResize }); | ||
|
||
return () => | ||
removeResizeListener({ resize, disableResize, refocusChild, childIdToRefocus }); | ||
}, [disableResize, resize]); | ||
|
||
useEffect(() => { | ||
if (isResizing) return; | ||
removeResizeListener({ resize, disableResize, refocusChild, childIdToRefocus }); | ||
}, [isResizing]); | ||
|
||
return { height, isResizing, setHeight, enableResize, disableResize }; | ||
}; | ||
|
||
const StyledBox = styled(Box)(({ theme }) => ({ | ||
backgroundColor: theme.palette.mode === "light" ? "#fff" : theme.palette.grey[800], | ||
})); | ||
|
||
const Puller = styled(Box)(({ theme, isResizing }: { theme?: Theme; isResizing: boolean }) => ({ | ||
cursor: "row-resize", | ||
width: 30, | ||
height: 6, | ||
backgroundColor: isResizing ? theme?.palette.grey[300] : theme?.palette.grey[900], | ||
borderRadius: 3, | ||
position: "absolute", | ||
top: 8, | ||
left: "calc(50% - 15px)", | ||
})); | ||
|
||
const TRANSITION_DURATION = 500; // ms | ||
const DRAWER_MIN_HEGHT = 20; | ||
export default function ResizableDrawer({ | ||
children, | ||
open, | ||
onClose, | ||
refocusChild = false, | ||
childIdToRefocus, | ||
paperProps, | ||
containerRef, | ||
}: { | ||
children: React.ReactElement; | ||
open: boolean; | ||
onClose: () => void; | ||
refocusChild?: boolean; | ||
childIdToRefocus?: string; | ||
paperProps?: object; | ||
containerRef?: React.RefObject<HTMLDivElement>; | ||
}) { | ||
const { height, setHeight, isResizing, enableResize, disableResize } = useResize({ | ||
minHeight: DRAWER_MIN_HEGHT, | ||
refocusChild, | ||
childIdToRefocus, | ||
}); | ||
|
||
// Styles to make the drawer fit the container | ||
const drawerStyles: CSSProperties = | ||
containerRef && containerRef.current | ||
? { | ||
position: "absolute", | ||
left: containerRef.current.offsetLeft, | ||
bottom: window.innerHeight - containerRef.current.offsetHeight, | ||
maxHeight: containerRef.current.offsetHeight, | ||
width: containerRef.current.offsetWidth, | ||
boxSizing: "border-box", | ||
} | ||
: {}; | ||
|
||
const drawerPaperProps = { | ||
style: { | ||
...drawerStyles, | ||
height, | ||
// @ts-ignore | ||
...(paperProps?.style || {}), | ||
}, | ||
}; | ||
|
||
const maximize = () => { | ||
const targetHeight = | ||
height < window.innerHeight / 3 ? window.innerHeight / 3 : window.innerHeight; | ||
setHeight(targetHeight); | ||
if (refocusChild && childIdToRefocus) { | ||
document.getElementById(childIdToRefocus)?.focus(); | ||
} | ||
}; | ||
|
||
const minimize = () => { | ||
const targetHeight = | ||
height > window.innerHeight / 3 ? window.innerHeight / 3 : DRAWER_MIN_HEGHT; | ||
setHeight(targetHeight); | ||
if (refocusChild && childIdToRefocus) { | ||
document.getElementById(childIdToRefocus)?.focus(); | ||
} | ||
}; | ||
|
||
return ( | ||
<Drawer | ||
variant="persistent" | ||
anchor="bottom" | ||
open={open} | ||
onClose={onClose} | ||
SlideProps={{ | ||
direction: "up", | ||
timeout: TRANSITION_DURATION, | ||
in: true, | ||
appear: true, | ||
}} | ||
PaperProps={drawerPaperProps}> | ||
<Box display="flex" justifyContent="right"> | ||
<KeyboardArrowUpIcon | ||
fontSize="large" | ||
onClick={maximize} | ||
sx={{ cursor: "pointer" }} | ||
/> | ||
<KeyboardArrowDownIcon | ||
fontSize="large" | ||
onClick={minimize} | ||
sx={{ cursor: "pointer" }} | ||
/> | ||
<CloseIcon fontSize="large" onClick={onClose} sx={{ cursor: "pointer" }} /> | ||
</Box> | ||
<StyledBox | ||
sx={{ | ||
position: "absolute", | ||
borderTopLeftRadius: 8, | ||
borderTopRightRadius: 8, | ||
visibility: "visible", | ||
right: 0, | ||
left: 0, | ||
}}> | ||
<Puller | ||
isResizing={isResizing} | ||
onMouseDown={enableResize} | ||
onMouseUp={disableResize} | ||
/> | ||
</StyledBox> | ||
{children} | ||
</Drawer> | ||
); | ||
} |