I'm using hello-pangea/dnd to have a drag and drop area, I want to be able to drag and drop sections to reorder them in a list.
However, I don't want to just have a handle, I want to be able to drag them from anywhere in the div. I'm able to go that, but to add something else to it, I would like to have an interactive area dedicated to something else in that div, that wouldn't be affected by the drag and drop.
To illustrate my issue, I would like to be able to drag and drop by clicking and dragging the collapsible-header area 
But to also exclude the svg from the drag and drop area, if I interact with the svg, I don't want to drag the whole entire section to be moved, I want to be able to move around the blue handles on the svg, 
I tried different solutions but haven't been successful.
Here is my code:
import { DraggableProvidedDragHandleProps } from "@hello-pangea/dnd"; import CollapsibleSection from "../collapsibleSection"; export interface StatsSectionProps { isExpanded: boolean; onToggle: () => void; dragHandleProps?: DraggableProvidedDragHandleProps; } export const StatsSection: React.FC<StatsSectionProps> = ({ isExpanded, onToggle, dragHandleProps }) => ( <CollapsibleSection header={<h3>Stats</h3>} isExpanded={isExpanded} onToggle={onToggle} dragHandleProps={dragHandleProps}> <div className="stats-info"> <p>Statistical information will be displayed here.</p> </div> </CollapsibleSection> ); export interface SpanSectionProps { isExpanded: boolean; onToggle: () => void; timePeriod: { totalDays: number; monthsAndDays: string; yearsMonthsDays: string; xAxisLabels: string; startDate: string; endDate: string; }; dragHandleProps?: DraggableProvidedDragHandleProps; onDateChange: (startDate: string, endDate: string) => void; } export const SpanSection: React.FC<SpanSectionProps> = ({isExpanded, onToggle, timePeriod, dragHandleProps, onDateChange}) => { const [localTimePeriod, setLocalTimePeriod] = useState(timePeriod); useEffect(() => { setLocalTimePeriod(timePeriod); }, [timePeriod]); const handleDateChange = (startDate: string, endDate: string) => { setLocalTimePeriod(prev => ({ ...prev, startDate, endDate })); onDateChange(startDate, endDate); }; return ( <div className="span-section" style={{ width: '100%' }}> <CollapsibleSection header={ <TimelineAxis fixedStartDate={timePeriod.startDate} fixedEndDate={timePeriod.endDate} initialStartDate={localTimePeriod.startDate} initialEndDate={localTimePeriod.endDate} onDateChange={handleDateChange} /> } isExpanded={isExpanded} onToggle={onToggle} dragHandleProps={dragHandleProps} > <div className="time-period-info"> <p>Start date: {localTimePeriod.startDate}</p> <p>End date: {localTimePeriod.endDate}</p> <p>Total days: {localTimePeriod.totalDays}</p> <p>Months and days: {localTimePeriod.monthsAndDays}</p> <p>Years, months, and days: {localTimePeriod.yearsMonthsDays}</p> <p>X axis labels: {localTimePeriod.xAxisLabels}</p> </div> </CollapsibleSection> </div> ); }; import React, { useRef, useEffect, useState, useCallback } from 'react'; import * as d3 from 'd3'; interface TimelineAxisProps { fixedStartDate: string; fixedEndDate: string; initialStartDate: string; initialEndDate: string; onDateChange: (startDate: string, endDate: string) => void; } const TimelineAxis: React.FC<TimelineAxisProps> = ({ fixedStartDate, fixedEndDate, initialStartDate, initialEndDate, onDateChange }) => { const [width, setWidth] = useState(0); const svgRef = useRef<SVGSVGElement>(null); const [startDate, setStartDate] = useState(initialStartDate); const [endDate, setEndDate] = useState(initialEndDate); const parseDate = d3.timeParse('%d/%m/%Y'); const formatDate = d3.timeFormat('%d/%m/%Y'); const updateWidth = useCallback(() => { if (svgRef.current) { const newWidth = svgRef.current.getBoundingClientRect().width; setWidth(newWidth); } }, []); useEffect(() => { updateWidth(); window.addEventListener('resize', updateWidth); return () => window.removeEventListener('resize', updateWidth); }, [updateWidth]); const fixedStart = parseDate(fixedStartDate); const fixedEnd = parseDate(fixedEndDate); const start = parseDate(startDate); const end = parseDate(endDate); if (!fixedStart || !fixedEnd || !start || !end) return null; const years = d3.timeYear.range(fixedStart, d3.timeYear.offset(fixedEnd, 1)); const scale = d3.scaleTime() .domain([fixedStart, fixedEnd]) .range([30, width - 30]); const getVisibleYears = (years: Date[], scale: d3.ScaleTime<number, number>): Date[] => { if (years.length <= 1) return years; const totalSpace = Math.abs(scale(years[years.length - 1]) - scale(years[0])); const averageSpace = totalSpace / (years.length - 1); const minSpaceBetweenLabels = 50; let step; if (averageSpace >= minSpaceBetweenLabels) { step = 1; } else if (averageSpace * 2 >= minSpaceBetweenLabels) { step = 2; } else if (averageSpace * 3 >= minSpaceBetweenLabels) { step = 3; } else { step = 4; } return years.filter((_, index) => index % step === 0); }; const visibleYears = getVisibleYears(years, scale); const handleDrag = (isStart: boolean) => (event: React.MouseEvent<SVGCircleElement>) => { event.preventDefault(); event.stopPropagation(); const svg = svgRef.current; if (!svg) return; const startDrag = (e: MouseEvent) => { e.preventDefault(); const mouseX = e.clientX - svg.getBoundingClientRect().left; const date = scale.invert(mouseX); const formattedDate = formatDate(date); if (isStart) { if (date >= fixedStart && date < end) { setStartDate(formattedDate); onDateChange(formattedDate, endDate); } } else { if (date <= fixedEnd && date > start) { setEndDate(formattedDate); onDateChange(startDate, formattedDate); } } }; const stopDrag = () => { document.removeEventListener('mousemove', startDrag); document.removeEventListener('mouseup', stopDrag); }; document.addEventListener('mousemove', startDrag); document.addEventListener('mouseup', stopDrag); }; const handleSvgClick = (event: React.MouseEvent<SVGSVGElement>) => { event.stopPropagation(); }; return ( <svg ref={svgRef} width="100%" height="60" onClick={handleSvgClick}> <line x1="30" y1="30" x2={width - 30} y2="30" stroke="currentColor" /> {visibleYears.map((year, index) => ( <g key={index} transform={`translate(${scale(year)}, 0)`}> <line x1="0" y1="25" x2="0" y2="35" stroke="currentColor" /> <text x="0" y="20" textAnchor="middle" fontSize="12">{year.getFullYear()}</text> </g> ))} <circle cx={scale(start)} cy="30" r="8" fill="var(--primary-color, blue)" cursor="ew-resize" onMouseDown={handleDrag(true)} /> <circle cx={scale(end)} cy="30" r="8" fill="var(--primary-color, blue)" cursor="ew-resize" onMouseDown={handleDrag(false)} /> <text x={scale(start)} y="50" textAnchor="middle" fontSize="12">{startDate}</text> <text x={scale(end)} y="50" textAnchor="middle" fontSize="12">{endDate}</text> </svg> ); }; export default TimelineAxis; interface SectionsProps { variables: Omit<VariablesSectionProps, 'dragHandleProps'>; span: Omit<SpanSectionProps, 'dragHandleProps'>; predictions: Omit<PredictionsSectionProps, 'dragHandleProps'>; stats: Omit<StatsSectionProps, 'dragHandleProps'>; } type SectionKey = keyof SectionsProps; const DraggableSections: React.FC<{ sectionsProps: SectionsProps }> = ({ sectionsProps }) => { const [sections, setSections] = useState<Array<{ id: SectionKey; component: React.ComponentType<any> }>>([ { id: 'span', component: SpanSection }, { id: 'stats', component: StatsSection }, ]); const onDragEnd = (result: any) => { if (!result.destination) return; const items = Array.from(sections); const [reorderedItem] = items.splice(result.source.index, 1); items.splice(result.destination.index, 0, reorderedItem); setSections(items); }; return ( <DragDropContext onDragEnd={onDragEnd}> <Droppable droppableId="sections"> {(provided) => ( <div {...provided.droppableProps} ref={provided.innerRef}> {sections.map((section, index) => { const SectionComponent = section.component; return ( <Draggable key={section.id} draggableId={section.id} index={index}> {(provided, snapshot) => ( <div ref={provided.innerRef} {...provided.draggableProps} className={`draggable-section ${snapshot.isDragging ? 'is-dragging' : ''}`}> <SectionComponent {...sectionsProps[section.id]} dragHandleProps={provided.dragHandleProps} /> </div> )} </Draggable> ); })} {provided.placeholder} </div> )} </Droppable> </DragDropContext> ); }; export default DraggableSections; I haven't been able to find a working solution so far. Would you have any idea/suggestion on how to approach or solve this?
