SwiftUI onDrop not working with DropDelegate on iOS18

I am new to SwiftUI, and I wrote a ReorderableForEach struct with onDrag and onDrop, which is working well on iOS17. However it's not wokring on iOS18 beta1 or beta2 on my iPhone or simulator. When I long press the item, nothing happens.

When I remove onDrop, I can perform a Drag animation, so I think something wrong with my onDrop code.

the whole code:

import UIKit
import SwiftUI

public typealias Reorderable = Identifiable & Equatable

struct GridData: Identifiable, Equatable {
    let id: Int
}

public struct ReorderableForEach<Item: Reorderable, Content: View, Preview: View>: View {
    @Binding
    private var active: Item?
    
    @State
    private var hasChangedLocation = false
    
    private let items: [Item]
    private let content: (Item) -> Content
    private let preview: ((Item) -> Preview)?
    private let moveAction: (IndexSet, Int) -> Void
    private var onDropAction: ((Item) -> Void)?
    private var allowReorder: Bool
    
    public init(
        _ items: [Item],
        active: Binding<Item?>,
        allowReorder: Bool,
        @ViewBuilder content: @escaping (Item) -> Content,
        @ViewBuilder preview: @escaping (Item) -> Preview,
        moveAction: @escaping (IndexSet, Int) -> Void,
        onDropAction: ((Item) -> Void)? = nil
    ) {
        self.items = items
        self._active = active
        self.allowReorder = allowReorder
        self.content = content
        self.preview = preview
        self.moveAction = moveAction
        self.onDropAction = onDropAction
    }
    
    public init(
        _ items: [Item],
        active: Binding<Item?>,
        allowReorder: Bool,
        @ViewBuilder content: @escaping (Item) -> Content,
        moveAction: @escaping (IndexSet, Int) -> Void,
        onDropAction: ((Item) -> Void)? = nil
    ) where Preview == EmptyView {
        self.items = items
        self._active = active
        self.allowReorder = allowReorder
        self.content = content
        self.preview = nil
        self.moveAction = moveAction
        self.onDropAction = onDropAction
    }
    
    public var body: some View {
        ForEach(items) { item in
            if !allowReorder {
                contentView(for: item)
            }
            else if let preview {
                contentView(for: item)
                    .onDrag {
                        return dragData(for: item)
                    } preview: {
                        preview(item)
                    }
            } else {
                contentView(for: item)
                    .onDrag {
                        return dragData(for: item)
                    }
            }
        }
    }
    
    private func contentView(for item: Item) -> some View {
        content(item)
            .opacity(active == item && hasChangedLocation ? 0.5 : 1)
            .onDrop(
                of: [.text],
                delegate: ReorderableDragRelocateDelegate(
                    item: item,
                    items: items,
                    active: $active,
                    hasChangedLocation: $hasChangedLocation
                ) { from, to in
                    withAnimation {
                        moveAction(from, to)
                    }
                } onDropAction: { item in
                    onDropAction?(item)
                }
            )
    }
    
    private func dragData(for item: Item) -> NSItemProvider {
        active = item
        return NSItemProvider(object: "\(item.id)" as NSString)
    }
}

struct ReorderableDragRelocateDelegate<Item: Reorderable>: DropDelegate {
    let item: Item
    var items: [Item]
    
    @Binding var active: Item?
    @Binding var hasChangedLocation: Bool
    
    var moveAction: (IndexSet, Int) -> Void
    var onDropAction: ((Item) -> Void)?
    
    func dropEntered(info: DropInfo) {
        guard item != active, let current = active else { return }
        guard let from = items.firstIndex(of: current) else { return }
        guard let to = items.firstIndex(of: item) else { return }
        
        hasChangedLocation = true
        
        if items[to] != current {
            moveAction(IndexSet(integer: from), to > from ? to + 1 : to)
  
        }
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        DropProposal(operation: .move)
    }
    
    func performDrop(info: DropInfo) -> Bool {
        hasChangedLocation = false
        active = nil
        onDropAction?(item)
        return true
    }
}

struct ReorderableDropOutsideDelegate<Item: Reorderable>: DropDelegate {
    
    @Binding
    var active: Item?
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        DropProposal(operation: .move)
    }
    
    func performDrop(info: DropInfo) -> Bool {
        active = nil
        return true
    }
}

public extension View {
    func reorderableForEachContainer<Item: Reorderable>(
        active: Binding<Item?>
    ) -> some View {
        onDrop(of: [.text], delegate: ReorderableDropOutsideDelegate(active: active))
    }
}

#Preview {
    ReorderableForEach(
        (1...10).map { GridData(id: $0) },
        active: .constant(nil),
        allowReorder: true
    ) { item in
        Text("Item \(item.id)")
            .padding()
            .background(Color.blue)
            .cornerRadius(8)
    } preview: { item in
        Text("Preview \(item.id)")
            .padding()
            .background(Color.red)
            .cornerRadius(8)
    } moveAction: { from, to in
        print("Move from \(from) to \(to)")
    }
}

Am I missing something or this is a bug on iOS18?
Thanks in advance.

Have you verified that reorderableForEachContainer modifier is applied to the view?

SwiftUI onDrop not working with DropDelegate on iOS18
 
 
Q