Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
import { type DragEvent as ReactDragEvent, useRef, useState } from 'react'
|
||||
|
||||
import { triggerHaptic } from '@/lib/haptics'
|
||||
|
||||
import { extractDroppedFiles, HERMES_PATHS_MIME, partitionDroppedFiles } from '../../hooks/use-composer-actions'
|
||||
import { dragHasAttachments, droppedFileInlineRefs, type InlineRefInput } from '../inline-refs'
|
||||
import type { ChatBarProps } from '../types'
|
||||
|
||||
interface UseComposerDropArgs {
|
||||
cwd: ChatBarProps['cwd']
|
||||
insertInlineRefs: (refs: InlineRefInput[]) => boolean
|
||||
onAttachDroppedItems: ChatBarProps['onAttachDroppedItems']
|
||||
requestMainFocus: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Drag-and-drop attachment engine. Splits drops by origin: in-app drags
|
||||
* (project tree / gutter) stay inline `@file:`/`@line:` refs the gateway
|
||||
* resolves directly; OS/Finder drops (absolute local paths a remote gateway
|
||||
* can't read, image bytes vision needs) route through the upload pipeline.
|
||||
* Off the keystroke path; consumes `insertInlineRefs` + the attach handler.
|
||||
*/
|
||||
export function useComposerDrop({
|
||||
cwd,
|
||||
insertInlineRefs,
|
||||
onAttachDroppedItems,
|
||||
requestMainFocus
|
||||
}: UseComposerDropArgs) {
|
||||
const [dragActive, setDragActive] = useState(false)
|
||||
const dragDepthRef = useRef(0)
|
||||
|
||||
const resetDragState = () => {
|
||||
dragDepthRef.current = 0
|
||||
setDragActive(false)
|
||||
}
|
||||
|
||||
const handleDragEnter = (event: ReactDragEvent<HTMLFormElement>) => {
|
||||
if (!onAttachDroppedItems || !dragHasAttachments(event.dataTransfer, HERMES_PATHS_MIME)) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
dragDepthRef.current += 1
|
||||
|
||||
if (!dragActive) {
|
||||
setDragActive(true)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDragOver = (event: ReactDragEvent<HTMLFormElement>) => {
|
||||
if (!onAttachDroppedItems || !dragHasAttachments(event.dataTransfer, HERMES_PATHS_MIME)) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
event.dataTransfer.dropEffect = 'copy'
|
||||
}
|
||||
|
||||
const handleDragLeave = (event: ReactDragEvent<HTMLFormElement>) => {
|
||||
if (!onAttachDroppedItems) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
dragDepthRef.current = Math.max(0, dragDepthRef.current - 1)
|
||||
|
||||
if (dragDepthRef.current === 0) {
|
||||
setDragActive(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDrop = (event: ReactDragEvent<HTMLFormElement>) => {
|
||||
if (!onAttachDroppedItems) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
resetDragState()
|
||||
|
||||
const candidates = extractDroppedFiles(event.dataTransfer)
|
||||
|
||||
if (candidates.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// In-app drags (project tree / gutter) are workspace-relative paths the
|
||||
// gateway resolves directly, so they stay inline @file:/@line: refs. OS
|
||||
// drops are absolute local paths a remote gateway can't read (and images
|
||||
// need byte upload for vision), so route them through the upload pipeline.
|
||||
const { inAppRefs, osDrops } = partitionDroppedFiles(candidates)
|
||||
const refs = droppedFileInlineRefs(inAppRefs, cwd)
|
||||
|
||||
if (refs.length && insertInlineRefs(refs)) {
|
||||
triggerHaptic('selection')
|
||||
}
|
||||
|
||||
if (osDrops.length) {
|
||||
void Promise.resolve(onAttachDroppedItems(osDrops)).then(attached => {
|
||||
if (attached) {
|
||||
triggerHaptic('selection')
|
||||
requestMainFocus()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleInputDragOver = (event: ReactDragEvent<HTMLDivElement>) => {
|
||||
if (!dragHasAttachments(event.dataTransfer, HERMES_PATHS_MIME)) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
event.dataTransfer.dropEffect = 'copy'
|
||||
}
|
||||
|
||||
const handleInputDrop = (event: ReactDragEvent<HTMLDivElement>) => {
|
||||
if (!dragHasAttachments(event.dataTransfer, HERMES_PATHS_MIME)) {
|
||||
return
|
||||
}
|
||||
|
||||
const candidates = extractDroppedFiles(event.dataTransfer)
|
||||
|
||||
if (!candidates.length) {
|
||||
return
|
||||
}
|
||||
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
resetDragState()
|
||||
|
||||
// Dropping straight onto the text box used to inline-ref *every* file —
|
||||
// including OS/Finder drops, whose absolute local path a remote gateway
|
||||
// can't read and whose image bytes never reached vision. Split by origin:
|
||||
// in-app drags stay inline refs; OS drops go through the upload pipeline.
|
||||
// (When no upload handler is wired, fall back to inline refs for all.)
|
||||
const attach = onAttachDroppedItems
|
||||
const { inAppRefs, osDrops } = partitionDroppedFiles(candidates)
|
||||
const refs = droppedFileInlineRefs(attach ? inAppRefs : candidates, cwd)
|
||||
|
||||
if (refs.length && insertInlineRefs(refs)) {
|
||||
triggerHaptic('selection')
|
||||
}
|
||||
|
||||
if (attach && osDrops.length) {
|
||||
void Promise.resolve(attach(osDrops)).then(attached => {
|
||||
if (attached) {
|
||||
triggerHaptic('selection')
|
||||
requestMainFocus()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dragActive,
|
||||
handleDragEnter,
|
||||
handleDragLeave,
|
||||
handleDragOver,
|
||||
handleDrop,
|
||||
handleInputDragOver,
|
||||
handleInputDrop
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user