Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
demountable
/
wp-content
/
plugins
/
extendify
/
src
/
Agent
/
components
/
layouts
:
DragResizeLayout.jsx
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
import { Tooltip } from '@wordpress/components'; import { createPortal, useState, useCallback, useEffect, } from '@wordpress/element'; import { __, _x } from '@wordpress/i18n'; import { Icon, close } from '@wordpress/icons'; import { AnimatePresence, motion } from 'framer-motion'; import { useDraggable } from '@agent/hooks/useDraggable'; import { usePortal } from '@agent/hooks/usePortal'; import { useResizable } from '@agent/hooks/useResizable'; import { useGlobalStore } from '@agent/state/global'; // TODO: some of the bound checking isn't working that well. // For example, the user shrinks the height of the browser. // On reload this should at least put the window in bounds. // Maybe a resize observer would be useful. export const DragResizeLayout = ({ children }) => { const [el, setEl] = useState(null); const mountNode = usePortal('extendify-agent-mount'); const { open, x: top, y: left, width, height, setOpen, setSize, setPosition, } = useGlobalStore(); // So it will re-render the hooks when mounted const ref = useCallback( (node) => requestAnimationFrame(() => setEl(node)), [], ); useDraggable({ el, open, initialPosition: { x: top, y: left }, onDragEnd: (x, y) => { setPosition(x, y); window.dispatchEvent( new CustomEvent('extendify-agent:drag-end', { detail: { x, y }, }), ); }, }); useResizable({ el, open, initialSize: { width, height }, onResizeEnd: (width, height) => { setSize(width, height); window.dispatchEvent( new CustomEvent('extendify-agent:resize-end', { detail: { width, height }, }), ); }, }); useEffect(() => { if (!el || !open) return; // If it's not intersecting, close it const observer = new IntersectionObserver((entries) => { if (!entries[0].isIntersecting) setOpen(false); }); observer.observe(el); return () => observer.disconnect(); }, [el, open, setOpen]); const closeAgent = () => { setOpen(false); window.dispatchEvent(new CustomEvent('extendify-agent:closed-button')); }; if (!mountNode || !open) return null; return createPortal( <AnimatePresence> <motion.div key="agent-popout-modal" id="extendify-agent-popout-modal" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ y: 0, opacity: 0 }} transition={{ duration: 0.4, delay: 0.1 }} className="fixed bottom-0 right-0 z-higher flex max-h-full max-w-full flex-col rounded-lg border border-solid border-gray-300 bg-white shadow-2xl-flipped rtl:left-0 rtl:right-auto" style={{ top, left, width, height }} ref={ref}> <> <div className="group flex shrink-0 items-center justify-between overflow-hidden rounded-t-[calc(0.5rem-1px)] bg-banner-main text-banner-text"> <div data-extendify-agent-handle draggable className="flex h-full flex-grow cursor-grab select-none items-center justify-between gap-1 p-0 py-3"> <div className="flex h-5 justify-center gap-2 px-4 rtl:after:-right-0"> <div className="flex h-5 max-w-[9rem] overflow-hidden"> <img className="max-h-full max-w-full object-contain" src={window.extSharedData.partnerLogo} alt={window.extSharedData.partnerName} /> </div> <div className="flex items-center rounded-lg bg-banner-text px-2 font-sans text-xs leading-none text-banner-main"> {_x('beta', 'Feature in beta status', 'extendify-local')} </div> </div> <div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100"> <DragButton /> </div> </div> <Tooltip text={__('Close window', 'extendify-local')}> <button type="button" className="relative z-10 flex h-full items-center rounded-none border-0 bg-banner-main py-3 pe-4 ps-2 text-banner-text outline-none ring-design-main focus:shadow-none focus:outline-none focus-visible:outline-design-main" onClick={closeAgent}> <Icon className="pointer-events-none fill-current leading-none" icon={close} size={18} /> <span className="sr-only"> {__('Close window', 'extendify-local')} </span> </button> </Tooltip> </div> {children} <div data-extendify-agent-resize className="absolute -bottom-2 -right-2 z-high h-6 w-6"> <div className="h-6 w-6 cursor-se-resize" /> </div> </> </motion.div> </AnimatePresence>, mountNode, ); }; const DragButton = (props) => { return ( <div style={{ userSelect: 'none' }} className="relative flex" {...props}> <Icon className="pointer-events-none text-banner-text" icon={ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" className="pointer-events-none" aria-hidden="true" focusable="false"> {/* hardcoded to use currentColor */} <path fill="currentColor" d="M8 7h2V5H8v2zm0 6h2v-2H8v2zm0 6h2v-2H8v2zm6-14v2h2V5h-2zm0 8h2v-2h-2v2zm0 6h2v-2h-2v2z"></path> </svg> } size={24} /> <span className="sr-only">{__('Drag to move', 'extendify-local')}</span> </div> ); };