@@ -38,6 +38,8 @@ function App() {
3838 const [ insertAfterIndex , setInsertAfterIndex ] = useState ( null )
3939 const [ selectedSignIndex , setSelectedSignIndex ] = useState ( null )
4040 const [ contextMenu , setContextMenu ] = useState ( null )
41+ const [ draggedIndex , setDraggedIndex ] = useState ( null )
42+ const [ dragOverIndex , setDragOverIndex ] = useState ( null )
4143 const fileInputRef = useRef ( null )
4244
4345 const vpRef = useRef ( null )
@@ -169,16 +171,79 @@ function App() {
169171 }
170172 }
171173
174+ const handleDragStart = ( e ) => {
175+ const path = e . composedPath ( )
176+ const index = getIndexFromSign ( path )
177+ if ( index !== - 1 ) {
178+ setDraggedIndex ( index )
179+ e . dataTransfer . effectAllowed = 'move'
180+ }
181+ }
182+
183+ const handleDragOver = ( e ) => {
184+ e . preventDefault ( )
185+ e . dataTransfer . dropEffect = 'move'
186+
187+ const path = e . composedPath ( )
188+ const index = getIndexFromSign ( path )
189+ if ( index !== - 1 && index !== draggedIndex ) {
190+ setDragOverIndex ( index )
191+ }
192+ }
193+
194+ const handleDragEnd = ( ) => {
195+ setDraggedIndex ( null )
196+ setDragOverIndex ( null )
197+ }
198+
199+ const handleDrop = ( e ) => {
200+ e . preventDefault ( )
201+
202+ if ( draggedIndex === null ) return
203+
204+ const path = e . composedPath ( )
205+ const dropIndex = getIndexFromSign ( path )
206+
207+ if ( dropIndex !== - 1 && dropIndex !== draggedIndex ) {
208+ const newSigns = [ ...signs ]
209+ const [ draggedSign ] = newSigns . splice ( draggedIndex , 1 )
210+ newSigns . splice ( dropIndex , 0 , draggedSign )
211+ updateSignsWithHistory ( newSigns )
212+
213+ // Update selected index if needed
214+ if ( selectedSignIndex === draggedIndex ) {
215+ setSelectedSignIndex ( dropIndex )
216+ } else if ( selectedSignIndex !== null ) {
217+ if ( draggedIndex < selectedSignIndex && dropIndex >= selectedSignIndex ) {
218+ setSelectedSignIndex ( selectedSignIndex - 1 )
219+ } else if ( draggedIndex > selectedSignIndex && dropIndex <= selectedSignIndex ) {
220+ setSelectedSignIndex ( selectedSignIndex + 1 )
221+ }
222+ }
223+ }
224+
225+ setDraggedIndex ( null )
226+ setDragOverIndex ( null )
227+ }
228+
172229 vpElement . addEventListener ( 'click' , handleClick )
173230 vpElement . addEventListener ( 'dblclick' , handleDoubleClick )
174231 vpElement . addEventListener ( 'contextmenu' , handleContextMenu )
232+ vpElement . addEventListener ( 'dragstart' , handleDragStart )
233+ vpElement . addEventListener ( 'dragover' , handleDragOver )
234+ vpElement . addEventListener ( 'dragend' , handleDragEnd )
235+ vpElement . addEventListener ( 'drop' , handleDrop )
175236
176237 return ( ) => {
177238 vpElement . removeEventListener ( 'click' , handleClick )
178239 vpElement . removeEventListener ( 'dblclick' , handleDoubleClick )
179240 vpElement . removeEventListener ( 'contextmenu' , handleContextMenu )
241+ vpElement . removeEventListener ( 'dragstart' , handleDragStart )
242+ vpElement . removeEventListener ( 'dragover' , handleDragOver )
243+ vpElement . removeEventListener ( 'dragend' , handleDragEnd )
244+ vpElement . removeEventListener ( 'drop' , handleDrop )
180245 }
181- } , [ signs ] )
246+ } , [ signs , draggedIndex ] )
182247
183248 // Close context menu and clear selection when clicking anywhere outside
184249 useEffect ( ( ) => {
@@ -196,7 +261,7 @@ function App() {
196261 return ( ) => document . removeEventListener ( 'click' , handleClick )
197262 } , [ ] )
198263
199- // Update selected styles on signs in shadow DOM
264+ // Update selected styles and draggable attribute on signs in shadow DOM
200265 useEffect ( ( ) => {
201266 const vpElement = vpRef . current
202267 if ( ! vpElement ) return
@@ -208,6 +273,10 @@ function App() {
208273 const allSigns = Array . from ( vpElement . shadowRoot . querySelectorAll ( 'sgnw-sign, sgnw-symbol' ) )
209274
210275 allSigns . forEach ( ( sign , index ) => {
276+ // Make draggable
277+ sign . setAttribute ( 'draggable' , 'true' )
278+
279+ // Apply selection styles
211280 if ( index === selectedSignIndex ) {
212281 sign . style . outline = '3px solid #ef4444'
213282 sign . style . outlineOffset = '2px'
@@ -219,11 +288,21 @@ function App() {
219288 sign . style . backgroundColor = ''
220289 sign . style . borderRadius = ''
221290 }
291+
292+ // Apply drag styles
293+ if ( index === draggedIndex ) {
294+ sign . style . opacity = '0.5'
295+ } else if ( index === dragOverIndex ) {
296+ sign . style . borderLeft = '3px solid #3b82f6'
297+ } else {
298+ sign . style . opacity = ''
299+ sign . style . borderLeft = ''
300+ }
222301 } )
223302 } , 10 )
224303
225304 return ( ) => clearTimeout ( timeout )
226- } , [ selectedSignIndex , signs ] )
305+ } , [ selectedSignIndex , signs , draggedIndex , dragOverIndex ] )
227306
228307 // Keyboard shortcuts for undo/redo and selection
229308 useEffect ( ( ) => {
0 commit comments