import { jsx } from 'react/jsx-runtime'; import { useState, useRef, useEffect, useCallback, createContext, useContext } from 'react'; import { Box } from '@strapi/design-system'; import { styled } from 'styled-components'; /* ------------------------------------------------------------------------------------------------- * Context * -----------------------------------------------------------------------------------------------*/ const UploadDropZoneContext = /*#__PURE__*/ createContext(null); /* ------------------------------------------------------------------------------------------------- * Components * -----------------------------------------------------------------------------------------------*/ const DropZoneWrapper = styled(Box)` position: relative; display: flex; flex-direction: column; min-height: 100%; `; const UploadDropZoneProvider = ({ children, onDrop })=>{ const [isDragging, setIsDragging] = useState(false); const dragCounterRef = useRef(0); const contextValue = { isDragging }; useEffect(()=>{ const handleDragEnd = ()=>{ setIsDragging(false); dragCounterRef.current = 0; }; // Handle drag leaving the entire document/window const handleDocumentDragLeave = (e)=>{ // When relatedTarget is null, we're leaving the document entirely if (!e.relatedTarget) { setIsDragging(false); dragCounterRef.current = 0; } }; document.addEventListener('dragend', handleDragEnd); document.addEventListener('dragleave', handleDocumentDragLeave); return ()=>{ document.removeEventListener('dragend', handleDragEnd); document.removeEventListener('dragleave', handleDocumentDragLeave); }; }, []); const handleDragEnter = useCallback((e)=>{ e.preventDefault(); e.stopPropagation(); // Bidirectional guard with AssetsDndProvider — internal item drags must not // activate the upload overlay. See AssetsDndProvider.tsx. if (!e.dataTransfer.types.includes('Files')) { return; } dragCounterRef.current += 1; setIsDragging(true); }, []); const handleDragLeave = useCallback((e)=>{ e.preventDefault(); e.stopPropagation(); dragCounterRef.current -= 1; // Only set dragging to false if we've left the dropzone completely // (counter reaches 0 or negative) if (dragCounterRef.current <= 0) { setIsDragging(false); dragCounterRef.current = 0; } }, []); const handleDragOver = useCallback((e)=>{ e.preventDefault(); e.stopPropagation(); e.dataTransfer.dropEffect = 'copy'; }, []); const handleDrop = useCallback((e)=>{ e.preventDefault(); e.stopPropagation(); setIsDragging(false); dragCounterRef.current = 0; const { files } = e.dataTransfer; if (files?.length && onDrop) { onDrop(Array.from(files)); } }, [ onDrop ]); return /*#__PURE__*/ jsx(UploadDropZoneContext.Provider, { value: contextValue, children: /*#__PURE__*/ jsx(DropZoneWrapper, { "data-testid": "assets-dropzone", onDragEnter: handleDragEnter, onDragLeave: handleDragLeave, onDragOver: handleDragOver, onDrop: handleDrop, children: children }) }); }; /* ------------------------------------------------------------------------------------------------- * Hook * -----------------------------------------------------------------------------------------------*/ const useUploadDropZone = ()=>{ const context = useContext(UploadDropZoneContext); if (!context) { throw new Error('useUploadDropZone must be used within UploadDropZone'); } return { isDragging: context.isDragging }; }; export { UploadDropZoneProvider, useUploadDropZone }; //# sourceMappingURL=UploadDropZoneContext.mjs.map