mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
Set up basic drag connection block into sub block. For now only finished short-input.
This commit is contained in:
+11
-7
@@ -178,28 +178,32 @@ function WorkflowCanvas() {
|
||||
event.preventDefault()
|
||||
|
||||
try {
|
||||
const data = JSON.parse(event.dataTransfer.getData('application/json'))
|
||||
|
||||
// Early return if this is a connection block drag
|
||||
if (data.type === 'connectionBlock') {
|
||||
return
|
||||
}
|
||||
|
||||
const reactFlowBounds = event.currentTarget.getBoundingClientRect()
|
||||
const position = project({
|
||||
x: event.clientX - reactFlowBounds.left,
|
||||
y: event.clientY - reactFlowBounds.top,
|
||||
})
|
||||
|
||||
const { type } = JSON.parse(
|
||||
event.dataTransfer.getData('application/json')
|
||||
)
|
||||
const blockConfig = getBlock(type)
|
||||
const blockConfig = getBlock(data.type)
|
||||
|
||||
if (!blockConfig) {
|
||||
console.error('Invalid block type:', type)
|
||||
console.error('Invalid block type:', data.type)
|
||||
return
|
||||
}
|
||||
|
||||
const id = crypto.randomUUID()
|
||||
const name = `${blockConfig.toolbar.title} ${
|
||||
Object.values(blocks).filter((b) => b.type === type).length + 1
|
||||
Object.values(blocks).filter((b) => b.type === data.type).length + 1
|
||||
}`
|
||||
|
||||
addBlock(id, type, name, position)
|
||||
addBlock(id, data.type, name, position)
|
||||
} catch (err) {
|
||||
console.error('Error dropping block:', err)
|
||||
}
|
||||
|
||||
@@ -3,9 +3,13 @@ import { Card } from '@/components/ui/card'
|
||||
|
||||
interface ConnectionBlocksProps {
|
||||
blockId: string
|
||||
setIsConnecting: (isConnecting: boolean) => void
|
||||
}
|
||||
|
||||
export function ConnectionBlocks({ blockId }: ConnectionBlocksProps) {
|
||||
export function ConnectionBlocks({
|
||||
blockId,
|
||||
setIsConnecting,
|
||||
}: ConnectionBlocksProps) {
|
||||
const { incomingConnections, hasIncomingConnections } =
|
||||
useBlockConnections(blockId)
|
||||
|
||||
@@ -13,10 +17,11 @@ export function ConnectionBlocks({ blockId }: ConnectionBlocksProps) {
|
||||
|
||||
const handleDragStart = (e: React.DragEvent, connection: any) => {
|
||||
e.stopPropagation() // Prevent parent drag handlers from firing
|
||||
setIsConnecting(true)
|
||||
e.dataTransfer.setData(
|
||||
'application/json',
|
||||
JSON.stringify({
|
||||
type: 'connection',
|
||||
type: 'connectionBlock',
|
||||
connectionData: {
|
||||
id: connection.id,
|
||||
name: connection.name,
|
||||
@@ -28,6 +33,10 @@ export function ConnectionBlocks({ blockId }: ConnectionBlocksProps) {
|
||||
e.dataTransfer.effectAllowed = 'copy'
|
||||
}
|
||||
|
||||
const handleDragEnd = (e: React.DragEvent) => {
|
||||
setIsConnecting(false)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="absolute -left-[180px] top-0 space-y-2 flex flex-col items-end w-[160px]">
|
||||
{incomingConnections.map((connection) => (
|
||||
@@ -35,6 +44,7 @@ export function ConnectionBlocks({ blockId }: ConnectionBlocksProps) {
|
||||
key={connection.id}
|
||||
draggable
|
||||
onDragStart={(e) => handleDragStart(e, connection)}
|
||||
onDragEnd={handleDragEnd}
|
||||
className="group flex items-center rounded-lg border bg-card p-2 shadow-sm transition-colors hover:bg-accent/50 cursor-grab active:cursor-grabbing w-fit"
|
||||
>
|
||||
<div className="text-sm">
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
import { useSubBlockValue } from '../hooks/use-sub-block-value'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface ShortInputProps {
|
||||
placeholder?: string
|
||||
password?: boolean
|
||||
blockId: string
|
||||
subBlockId: string
|
||||
isConnecting: boolean
|
||||
}
|
||||
|
||||
export function ShortInput({
|
||||
@@ -14,16 +16,12 @@ export function ShortInput({
|
||||
subBlockId,
|
||||
placeholder,
|
||||
password,
|
||||
isConnecting,
|
||||
}: ShortInputProps) {
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
const [value, setValue] = useSubBlockValue(blockId, subBlockId)
|
||||
|
||||
const displayValue =
|
||||
password && !isFocused
|
||||
? '•'.repeat(value?.toString().length ?? 0)
|
||||
: value?.toString() ?? ''
|
||||
|
||||
useEffect(() => {
|
||||
if (inputRef.current && isFocused) {
|
||||
const input = inputRef.current
|
||||
@@ -32,16 +30,49 @@ export function ShortInput({
|
||||
}
|
||||
}, [value, isFocused])
|
||||
|
||||
const handleDrop = (e: React.DragEvent<HTMLInputElement>) => {
|
||||
e.preventDefault()
|
||||
try {
|
||||
const data = JSON.parse(e.dataTransfer.getData('application/json'))
|
||||
if (data.type === 'connectionBlock') {
|
||||
const currentValue = value?.toString() ?? ''
|
||||
const newValue =
|
||||
currentValue +
|
||||
data.connectionData.name.replace(' ', '').toLowerCase() +
|
||||
(data.connectionData.outputType === 'any'
|
||||
? '.res'
|
||||
: `.${data.connectionData.outputType}`)
|
||||
setValue(newValue)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to parse drop data:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleDragOver = (e: React.DragEvent<HTMLInputElement>) => {
|
||||
e.preventDefault() // This is needed to allow drops
|
||||
}
|
||||
|
||||
const displayValue =
|
||||
password && !isFocused
|
||||
? '•'.repeat(value?.toString().length ?? 0)
|
||||
: value?.toString() ?? ''
|
||||
|
||||
return (
|
||||
<Input
|
||||
ref={inputRef}
|
||||
className="w-full placeholder:text-muted-foreground/50 allow-scroll"
|
||||
className={cn(
|
||||
'w-full placeholder:text-muted-foreground/50 allow-scroll',
|
||||
isConnecting && 'border-blue-500'
|
||||
)}
|
||||
placeholder={placeholder ?? ''}
|
||||
type="text"
|
||||
value={displayValue}
|
||||
onChange={(e) => setValue(e.target.value)}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
onDrop={handleDrop}
|
||||
onDragOver={handleDragOver}
|
||||
autoComplete="off"
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -10,9 +10,10 @@ import { Code } from './components/code'
|
||||
interface SubBlockProps {
|
||||
blockId: string
|
||||
config: SubBlockConfig
|
||||
isConnecting: boolean
|
||||
}
|
||||
|
||||
export function SubBlock({ blockId, config }: SubBlockProps) {
|
||||
export function SubBlock({ blockId, config, isConnecting }: SubBlockProps) {
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
e.stopPropagation()
|
||||
}
|
||||
@@ -26,6 +27,7 @@ export function SubBlock({ blockId, config }: SubBlockProps) {
|
||||
subBlockId={config.id}
|
||||
placeholder={config.placeholder}
|
||||
password={config.password}
|
||||
isConnecting={isConnecting}
|
||||
/>
|
||||
)
|
||||
case 'long-input':
|
||||
|
||||
@@ -5,6 +5,7 @@ import { Handle, Position } from 'reactflow'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { ActionBar } from './components/action-bar/action-bar'
|
||||
import { ConnectionBlocks } from './components/connection-blocks/connection-blocks'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface WorkflowBlockProps {
|
||||
id: string
|
||||
@@ -23,6 +24,8 @@ export function WorkflowBlock({
|
||||
selected,
|
||||
}: WorkflowBlockProps) {
|
||||
const { toolbar, workflow } = config
|
||||
// Dragging connection state
|
||||
const [isConnecting, setIsConnecting] = useState(false)
|
||||
|
||||
function groupSubBlocks(subBlocks: SubBlockConfig[]) {
|
||||
const rows: SubBlockConfig[][] = []
|
||||
@@ -53,7 +56,7 @@ export function WorkflowBlock({
|
||||
return (
|
||||
<Card className="w-[320px] shadow-md select-none group relative cursor-default">
|
||||
{selected && <ActionBar blockId={id} />}
|
||||
<ConnectionBlocks blockId={id} />
|
||||
<ConnectionBlocks blockId={id} setIsConnecting={setIsConnecting} />
|
||||
|
||||
<Handle
|
||||
type="target"
|
||||
@@ -88,7 +91,11 @@ export function WorkflowBlock({
|
||||
subBlock.layout === 'half' ? 'flex-1' : 'w-full'
|
||||
}`}
|
||||
>
|
||||
<SubBlock blockId={id} config={subBlock} />
|
||||
<SubBlock
|
||||
blockId={id}
|
||||
config={subBlock}
|
||||
isConnecting={isConnecting}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user