fix: use onDragEnd on Reorder.Item instead of onPointerUp on Group
The previous approach used onPointerUp on the Reorder.Group which fired unreliably — triggering on non-drag clicks and sometimes not at all after a drag. Moving to onDragEnd on each Reorder.Item gives clean, predictable drag-to-reorder behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ interface CandidateListItemProps {
|
|||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
onStatusChange: (status: "researching" | "ordered" | "arrived") => void;
|
onStatusChange: (status: "researching" | "ordered" | "arrived") => void;
|
||||||
delta?: CandidateDelta;
|
delta?: CandidateDelta;
|
||||||
|
onDragEnd?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RANK_COLORS = ["#D4AF37", "#C0C0C0", "#CD7F32"]; // gold, silver, bronze
|
const RANK_COLORS = ["#D4AF37", "#C0C0C0", "#CD7F32"]; // gold, silver, bronze
|
||||||
@@ -53,6 +54,7 @@ export function CandidateListItem({
|
|||||||
isActive,
|
isActive,
|
||||||
onStatusChange,
|
onStatusChange,
|
||||||
delta,
|
delta,
|
||||||
|
onDragEnd,
|
||||||
}: CandidateListItemProps) {
|
}: CandidateListItemProps) {
|
||||||
const controls = useDragControls();
|
const controls = useDragControls();
|
||||||
const { weight, price } = useFormatters();
|
const { weight, price } = useFormatters();
|
||||||
@@ -217,6 +219,7 @@ export function CandidateListItem({
|
|||||||
value={candidate}
|
value={candidate}
|
||||||
dragControls={controls}
|
dragControls={controls}
|
||||||
dragListener={false}
|
dragListener={false}
|
||||||
|
onDragEnd={onDragEnd}
|
||||||
className={sharedClassName}
|
className={sharedClassName}
|
||||||
>
|
>
|
||||||
{innerContent}
|
{innerContent}
|
||||||
|
|||||||
@@ -36,12 +36,11 @@ function ThreadDetailPage() {
|
|||||||
thread?.categoryId ?? 0,
|
thread?.categoryId ?? 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [tempItems, setTempItems] =
|
const [tempItems, setTempItems] = useState<
|
||||||
useState<typeof thread extends { candidates: infer C } ? C : never | null>(
|
NonNullable<typeof thread>["candidates"] | null
|
||||||
null,
|
>(null);
|
||||||
);
|
|
||||||
|
|
||||||
// Clear tempItems when server data changes (biome-ignore: thread?.candidates is intentional dep)
|
// Clear tempItems when server data changes
|
||||||
// biome-ignore lint/correctness/useExhaustiveDependencies: thread?.candidates is the intended trigger
|
// biome-ignore lint/correctness/useExhaustiveDependencies: thread?.candidates is the intended trigger
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTempItems(null);
|
setTempItems(null);
|
||||||
@@ -227,7 +226,6 @@ function ThreadDetailPage() {
|
|||||||
axis="y"
|
axis="y"
|
||||||
values={displayItems}
|
values={displayItems}
|
||||||
onReorder={setTempItems}
|
onReorder={setTempItems}
|
||||||
onPointerUp={handleDragEnd}
|
|
||||||
className="flex flex-col gap-2"
|
className="flex flex-col gap-2"
|
||||||
>
|
>
|
||||||
{displayItems.map((candidate, index) => (
|
{displayItems.map((candidate, index) => (
|
||||||
@@ -243,6 +241,7 @@ function ThreadDetailPage() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
delta={deltas[candidate.id]}
|
delta={deltas[candidate.id]}
|
||||||
|
onDragEnd={handleDragEnd}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Reorder.Group>
|
</Reorder.Group>
|
||||||
|
|||||||
Reference in New Issue
Block a user