1
0
Fork 0
freesewing/sites/shared/components/wrappers/modal.mjs
joostdecock 967ed3c443 fix: Allow clicks in modal wrapper content
This raises the content inside the modal wrapper and stops propagation
of clicks. This fixes #5527 which closed the modal when people were
trying to select a different tab in the modal content.

On desktop, you can still close the modal by clicking outside of the
content. However, on mobile, the modal fills the entire screen so there
is no way to click outside and close the modal.
So this also includes a change that adds a close button to the bottom
right corner (only shown on mobile).
2023-11-26 11:42:50 +01:00

94 lines
2.8 KiB
JavaScript

// __SDEFILE__ - This file is a dependency for the stand-alone environment
import { useState, useEffect, useContext } from 'react'
import { useSwipeable } from 'react-swipeable'
import { ModalContext } from 'shared/context/modal-context.mjs'
import { CloseIcon } from 'shared/components/icons.mjs'
const slideClasses = {
left: '-translate-x-full',
right: 'translate-x-full',
top: '-translate-y-full',
bottom: 'translate-y-full',
}
export const ModalWrapper = ({
children = null,
flex = 'row',
justify = 'center',
items = 'center',
bg = 'base-100 lg:bg-base-300',
bgOpacity = '100 lg:bg-opacity-95',
bare = false,
keepOpenOnClick = false,
slideFrom = 'left',
keepOpenOnSwipe = false,
fullWidth = false,
}) => {
const { clearModal } = useContext(ModalContext)
const [animate, setAnimate] = useState('in')
const close = (evt) => {
// Only process the first swipe event
if (evt?.event) evt.event.stopPropagation()
setAnimate('out')
window.setTimeout(clearModal, 150)
}
const swipeActions = {}
if (!keepOpenOnSwipe) {
if (slideFrom === 'left') swipeActions.onSwipedLeft = close
else if (slideFrom === 'right') swipeActions.onSwipedRight = close
else if (slideFrom === 'top') swipeActions.onSwipedUp = close
else if (slideFrom === 'bottom') swipeActions.onSwipedDown = close
}
const swipeHandlers = useSwipeable({
...swipeActions,
trackMouse: true,
})
useEffect(() => {
// only turn off animation if it's animating in
if (animate === 'in') setAnimate(false)
}, [animate])
// CSS classes for animation
const animation = animate
? `lg:opacity-0 ${slideClasses[slideFrom]} lg:translate-x-0 lg:translate-y-0`
: 'opacity-100 translate-none'
const stopClick = (evt) => evt.stopPropagation()
return (
<div
ref={swipeHandlers.ref}
onMouseDown={swipeHandlers.onMouseDown}
className={`fixed top-0 left-0 m-0 p-0 shadow w-full h-screen
transform-all duration-150 ${animation}
bg-${bg} bg-opacity-${bgOpacity} z-50 hover:cursor-pointer
flex flex-${flex} justify-${justify} items-${items} lg:p-12`}
onClick={keepOpenOnClick ? null : close}
>
{bare ? (
children
) : (
<div
onClick={stopClick}
className={`z-30 bg-base-100 p-4 lg:px-8 lg:rounded-lg lg:shadow-lg max-h-full overflow-auto hover:cursor-default ${
fullWidth ? 'w-full' : ''
}`}
>
{children}
{!keepOpenOnClick && (
<button
className="fixed bottom-2 right-2 btn btn-neutral btn-circle lg:hidden"
onClick={keepOpenOnClick ? null : close}
>
<CloseIcon className="w-8 h-8" />
</button>
)}
</div>
)}
</div>
)
}