mirror of
https://github.com/suitenumerique/meet.git
synced 2026-08-27 10:46:47 +00:00
♻️(feat) extract pip options menu component
keep pip options layout reusable and isolated
This commit is contained in:
@@ -2,9 +2,49 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { RiMoreFill } from '@remixicon/react'
|
import { RiMoreFill } from '@remixicon/react'
|
||||||
import { Button, Menu } from '@/primitives'
|
import { Button, Menu } from '@/primitives'
|
||||||
import { OptionsMenuItems } from './OptionsMenuItems'
|
import { OptionsMenuItems } from './OptionsMenuItems'
|
||||||
|
import { useOverlayPortalContainer } from '@/primitives/useOverlayPortalContainer'
|
||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
import { PipOptionsMenu } from './PipOptionsMenu'
|
||||||
|
|
||||||
export const OptionsButton = () => {
|
export const OptionsButton = () => {
|
||||||
const { t } = useTranslation('rooms')
|
const { t } = useTranslation('rooms')
|
||||||
|
const portalContainer = useOverlayPortalContainer()
|
||||||
|
const isInPiP =
|
||||||
|
portalContainer && portalContainer.ownerDocument !== document
|
||||||
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
const wrapperRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isOpen || !isInPiP) return
|
||||||
|
const doc = wrapperRef.current?.ownerDocument ?? document
|
||||||
|
|
||||||
|
const handlePointerDown = (event: PointerEvent) => {
|
||||||
|
const target = event.target as Node | null
|
||||||
|
const wrapper = wrapperRef.current
|
||||||
|
if (!wrapper || !target) return
|
||||||
|
if (!wrapper.contains(target)) {
|
||||||
|
setIsOpen(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
doc.addEventListener('pointerdown', handlePointerDown, true)
|
||||||
|
return () => {
|
||||||
|
doc.removeEventListener('pointerdown', handlePointerDown, true)
|
||||||
|
}
|
||||||
|
}, [isInPiP, isOpen])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (isInPiP) {
|
||||||
|
return (
|
||||||
|
<PipOptionsMenu
|
||||||
|
wrapperRef={wrapperRef}
|
||||||
|
isOpen={isOpen}
|
||||||
|
setIsOpen={setIsOpen}
|
||||||
|
label={t('options.buttonLabel')}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Menu variant="dark">
|
<Menu variant="dark">
|
||||||
|
|||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { RiMoreFill } from '@remixicon/react'
|
||||||
|
import { Box, Button } from '@/primitives'
|
||||||
|
import { css } from '@/styled-system/css'
|
||||||
|
import { OptionsMenuItems } from './OptionsMenuItems'
|
||||||
|
|
||||||
|
type PipOptionsMenuProps = {
|
||||||
|
wrapperRef: React.RefObject<HTMLDivElement>
|
||||||
|
isOpen: boolean
|
||||||
|
setIsOpen: (isOpen: boolean) => void
|
||||||
|
label: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PipOptionsMenu = ({
|
||||||
|
wrapperRef,
|
||||||
|
isOpen,
|
||||||
|
setIsOpen,
|
||||||
|
label,
|
||||||
|
}: PipOptionsMenuProps) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
ref={wrapperRef}
|
||||||
|
className={css({
|
||||||
|
position: 'relative',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
id="room-options-trigger"
|
||||||
|
square
|
||||||
|
variant="primaryDark"
|
||||||
|
aria-label={label}
|
||||||
|
tooltip={label}
|
||||||
|
onPress={() => setIsOpen(!isOpen)}
|
||||||
|
>
|
||||||
|
<RiMoreFill />
|
||||||
|
</Button>
|
||||||
|
{isOpen && (
|
||||||
|
<div
|
||||||
|
className={css({
|
||||||
|
position: 'absolute',
|
||||||
|
left: '50%',
|
||||||
|
bottom: 'calc(100% + 0.85rem)',
|
||||||
|
transform: 'translateX(-50%)',
|
||||||
|
zIndex: 10,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<Box size="sm" type="popover" variant="dark">
|
||||||
|
<OptionsMenuItems />
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user