2021-12-16 10:43:49 +01:00
|
|
|
import { useEventListener, Stack, Flex, Portal } from '@chakra-ui/react'
|
2022-01-18 18:25:18 +01:00
|
|
|
import { DraggableStep, Step, Table } from 'models'
|
|
|
|
import { useDnd } from 'contexts/DndContext'
|
2021-12-22 14:59:07 +01:00
|
|
|
import { Coordinates } from 'contexts/GraphContext'
|
2022-01-12 09:10:59 +01:00
|
|
|
import { useMemo, useState } from 'react'
|
2021-12-16 10:43:49 +01:00
|
|
|
import { StepNode, StepNodeOverlay } from './StepNode'
|
2022-01-12 09:10:59 +01:00
|
|
|
import { useTypebot } from 'contexts/TypebotContext'
|
2021-12-16 10:43:49 +01:00
|
|
|
|
|
|
|
export const StepsList = ({
|
|
|
|
blockId,
|
|
|
|
steps,
|
|
|
|
}: {
|
|
|
|
blockId: string
|
2022-01-06 09:40:56 +01:00
|
|
|
steps: Table<Step>
|
2021-12-16 10:43:49 +01:00
|
|
|
}) => {
|
2022-01-12 09:10:59 +01:00
|
|
|
const {
|
|
|
|
draggedStep,
|
|
|
|
setDraggedStep,
|
|
|
|
draggedStepType,
|
|
|
|
mouseOverBlockId,
|
|
|
|
setDraggedStepType,
|
|
|
|
setMouseOverBlockId,
|
|
|
|
} = useDnd()
|
|
|
|
const { createStep } = useTypebot()
|
2021-12-16 10:43:49 +01:00
|
|
|
const [expandedPlaceholderIndex, setExpandedPlaceholderIndex] = useState<
|
|
|
|
number | undefined
|
|
|
|
>()
|
2022-01-12 09:10:59 +01:00
|
|
|
const showSortPlaceholders = useMemo(
|
|
|
|
() => mouseOverBlockId === blockId && (draggedStep || draggedStepType),
|
|
|
|
[mouseOverBlockId, blockId, draggedStep, draggedStepType]
|
|
|
|
)
|
2021-12-16 10:43:49 +01:00
|
|
|
const [position, setPosition] = useState({
|
|
|
|
x: 0,
|
|
|
|
y: 0,
|
|
|
|
})
|
|
|
|
const [relativeCoordinates, setRelativeCoordinates] = useState({ x: 0, y: 0 })
|
|
|
|
|
|
|
|
const handleStepMove = (event: MouseEvent) => {
|
|
|
|
if (!draggedStep) return
|
|
|
|
const { clientX, clientY } = event
|
|
|
|
setPosition({
|
|
|
|
...position,
|
|
|
|
x: clientX - relativeCoordinates.x,
|
|
|
|
y: clientY - relativeCoordinates.y,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
useEventListener('mousemove', handleStepMove)
|
|
|
|
|
|
|
|
const handleMouseMove = (event: React.MouseEvent) => {
|
|
|
|
if (!draggedStep) return
|
|
|
|
const element = event.currentTarget as HTMLDivElement
|
|
|
|
const rect = element.getBoundingClientRect()
|
|
|
|
const y = event.clientY - rect.top
|
|
|
|
if (y < 20) setExpandedPlaceholderIndex(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleMouseUp = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
|
|
if (expandedPlaceholderIndex === undefined) return
|
|
|
|
e.stopPropagation()
|
2022-01-12 09:10:59 +01:00
|
|
|
setMouseOverBlockId(undefined)
|
2021-12-16 10:43:49 +01:00
|
|
|
setExpandedPlaceholderIndex(undefined)
|
2022-01-12 09:10:59 +01:00
|
|
|
if (draggedStepType) {
|
|
|
|
createStep(blockId, draggedStepType, expandedPlaceholderIndex)
|
|
|
|
setDraggedStepType(undefined)
|
|
|
|
}
|
|
|
|
if (draggedStep) {
|
|
|
|
createStep(blockId, draggedStep, expandedPlaceholderIndex)
|
|
|
|
setDraggedStep(undefined)
|
|
|
|
}
|
2021-12-16 10:43:49 +01:00
|
|
|
}
|
|
|
|
|
2021-12-22 14:59:07 +01:00
|
|
|
const handleStepMouseDown = (
|
|
|
|
{ absolute, relative }: { absolute: Coordinates; relative: Coordinates },
|
2022-01-08 07:40:55 +01:00
|
|
|
step: DraggableStep
|
2021-12-22 14:59:07 +01:00
|
|
|
) => {
|
|
|
|
setPosition(absolute)
|
|
|
|
setRelativeCoordinates(relative)
|
2022-01-12 09:10:59 +01:00
|
|
|
setMouseOverBlockId(blockId)
|
2021-12-16 10:43:49 +01:00
|
|
|
setDraggedStep(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleMouseOnTopOfStep = (stepIndex: number) => {
|
|
|
|
if (!draggedStep && !draggedStepType) return
|
|
|
|
setExpandedPlaceholderIndex(stepIndex === 0 ? 0 : stepIndex)
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleMouseOnBottomOfStep = (stepIndex: number) => {
|
|
|
|
if (!draggedStep && !draggedStepType) return
|
|
|
|
setExpandedPlaceholderIndex(stepIndex + 1)
|
|
|
|
}
|
2022-01-07 07:03:08 +01:00
|
|
|
|
2021-12-16 10:43:49 +01:00
|
|
|
return (
|
|
|
|
<Stack
|
|
|
|
spacing={1}
|
|
|
|
onMouseUpCapture={handleMouseUp}
|
|
|
|
onMouseMove={handleMouseMove}
|
|
|
|
transition="none"
|
|
|
|
>
|
|
|
|
<Flex
|
|
|
|
h={
|
|
|
|
showSortPlaceholders && expandedPlaceholderIndex === 0
|
|
|
|
? '50px'
|
|
|
|
: '2px'
|
|
|
|
}
|
2022-01-19 09:44:21 +01:00
|
|
|
bgColor={'gray.300'}
|
2021-12-16 10:43:49 +01:00
|
|
|
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
|
|
|
|
rounded="lg"
|
|
|
|
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
|
|
|
/>
|
2022-01-06 09:40:56 +01:00
|
|
|
{steps.allIds.map((stepId, idx) => (
|
|
|
|
<Stack key={stepId} spacing={1}>
|
2021-12-16 10:43:49 +01:00
|
|
|
<StepNode
|
2022-01-06 09:40:56 +01:00
|
|
|
key={stepId}
|
|
|
|
step={steps.byId[stepId]}
|
|
|
|
isConnectable={steps.allIds.length - 1 === idx}
|
2021-12-16 10:43:49 +01:00
|
|
|
onMouseMoveTopOfElement={() => handleMouseOnTopOfStep(idx)}
|
|
|
|
onMouseMoveBottomOfElement={() => {
|
|
|
|
handleMouseOnBottomOfStep(idx)
|
|
|
|
}}
|
|
|
|
onMouseDown={handleStepMouseDown}
|
|
|
|
/>
|
|
|
|
<Flex
|
|
|
|
h={
|
|
|
|
showSortPlaceholders && expandedPlaceholderIndex === idx + 1
|
|
|
|
? '50px'
|
|
|
|
: '2px'
|
|
|
|
}
|
2022-01-19 09:44:21 +01:00
|
|
|
bgColor={'gray.300'}
|
2021-12-16 10:43:49 +01:00
|
|
|
visibility={showSortPlaceholders ? 'visible' : 'hidden'}
|
|
|
|
rounded="lg"
|
|
|
|
transition={showSortPlaceholders ? 'height 200ms' : 'none'}
|
|
|
|
/>
|
|
|
|
</Stack>
|
|
|
|
))}
|
|
|
|
{draggedStep && draggedStep.blockId === blockId && (
|
|
|
|
<Portal>
|
|
|
|
<StepNodeOverlay
|
|
|
|
step={draggedStep}
|
2022-01-03 17:39:59 +01:00
|
|
|
pos="fixed"
|
|
|
|
top="0"
|
|
|
|
left="0"
|
2021-12-16 10:43:49 +01:00
|
|
|
style={{
|
|
|
|
transform: `translate(${position.x}px, ${position.y}px) rotate(-2deg)`,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
</Portal>
|
|
|
|
)}
|
|
|
|
</Stack>
|
|
|
|
)
|
|
|
|
}
|