Skip to content

Commit

Permalink
187932225 movable modals (#1358)
Browse files Browse the repository at this point in the history
* Makes modals movable

* Fixes not being able to input anything into the modals

* PR fix - could not use `forwardRef` as it is a React ref

* PR Fix
  • Loading branch information
eireland authored Jul 22, 2024
1 parent 5de06ff commit b6be1f2
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 14 deletions.
15 changes: 15 additions & 0 deletions v3/src/components/codap-modal.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
@import "./vars.scss";
$header-height: 30px;
$modal-height: 350px;
$modal-width: 350px;

.chakra-modal__content {
font-family: "museo-sans", sans-serif;
Expand Down Expand Up @@ -74,3 +76,16 @@ $header-height: 30px;
background-color: white;
}
}

.codap-modal-content {
position: absolute !important;
margin-top: 0 !important;
}

.chakra-modal__content-container {
position: absolute !important;
}

.chakra-modal__overlay {
opacity: 0.01 !important;
}
122 changes: 108 additions & 14 deletions v3/src/components/codap-modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Modal, ModalContent, ModalOverlay } from "@chakra-ui/react"
import React, { ReactNode, forwardRef } from "react"
import { Modal, ModalContent, ModalOverlay, useMergeRefs } from "@chakra-ui/react"
import React, { ReactNode, forwardRef, useEffect, useRef, useState } from "react"

import "./codap-modal.scss"

Expand All @@ -15,28 +15,122 @@ interface IProps {
}

export const CodapModal = forwardRef(({
children, closeOnOverlayClick=true, initialRef, isOpen, onClick, onClose, modalWidth, modalHeight
}: IProps, ref: React.LegacyRef<HTMLElement> | undefined) => {
children, initialRef, isOpen, onClick, onClose, modalWidth, modalHeight
}: IProps, ref: React.Ref<HTMLElement> | undefined) => {

return (
<Modal
closeOnOverlayClick={closeOnOverlayClick}
data-testid="codap-modal"
initialFocusRef={initialRef}
isOpen={isOpen}
onClose={onClose}
size="xs"
>
<ModalOverlay />
<ModalContent
className="codap-modal-content"
h={modalHeight || "500px"}
onClick={onClick}
ref={ref}
w={modalWidth || "400px"}
>
{children}
</ModalContent>
<DraggableModalContent
fRef={ref}
modalWidth={modalWidth}
modalHeight={modalHeight}
onClick={onClick}
isOpen={isOpen}
>
{children}
</DraggableModalContent>
</Modal>
)
})
CodapModal.displayName = "CodapModal"

interface IDraggableModalContentProps {
children: ReactNode
modalWidth?: string
modalHeight?: string
onClick?: () => void
fRef: React.Ref<HTMLElement> | undefined
isOpen: boolean
}

const DraggableModalContent = ({children, modalWidth, modalHeight, onClick, fRef, isOpen
}: IDraggableModalContentProps) => {
const [modalPos, setModalPos] = useState({left: 350, top: 250})
const modalRef = useRef<HTMLElement | null>(null)
const mergedRef = useMergeRefs(fRef, modalRef)

useEffect(() => {
const modalElement = modalRef.current
if (!modalElement) {
return
}

let isDragging = false
let startX = 0
let startY = 0
let initialX = 0
let initialY = 0

const handleMouseDown = (e: MouseEvent) => {
e.stopPropagation()
isDragging = true
startX = e.clientX
startY = e.clientY
if (modalElement) {
initialX = modalElement.offsetLeft
initialY = modalElement.offsetTop
}

document.addEventListener("mousemove", handleMouseMove)
document.addEventListener("mouseup", handleMouseUp)
}

const handleMouseMove = (e: MouseEvent) => {
if (isDragging) {
const deltaX = e.clientX - startX
const deltaY = e.clientY - startY
modalElement.style.left = `${initialX + deltaX}px`
modalElement.style.top = `${initialY + deltaY}px`
setModalPos({left: initialX + deltaX, top: initialY + deltaY})
}
}

const handleMouseUp = (e: MouseEvent) => {
isDragging = false
document.removeEventListener("mousemove", handleMouseMove)
document.removeEventListener("mouseup", handleMouseUp)
}

modalElement.addEventListener("mousedown", handleMouseDown)

return () => {
modalElement.removeEventListener("mousedown", handleMouseDown)
document.removeEventListener("mousemove", handleMouseMove)
document.removeEventListener("mouseup", handleMouseUp)
}
}, [])



const style: React.CSSProperties = {
width: modalWidth || "400px",
height: modalHeight || "400px",
cursor: "move",
top: modalPos.top,
left: modalPos.left,
position: "absolute"
}

const varStyle = {
"--modal-width": modalWidth || "400px",
"--modal-height": modalHeight || "400px"
}

return (
<ModalContent
ref={mergedRef}
style={{...style, ...varStyle}}
onClick={onClick}
className="codap-modal-content"
>
{children}
</ModalContent>
)
}

0 comments on commit b6be1f2

Please sign in to comment.