Commit 671654da authored by StyleZhang's avatar StyleZhang

add node

parent 31490417
......@@ -22,6 +22,7 @@ type UpdateParams = {
from?: string
placement?: Placement
offset?: OffsetOptions
open?: boolean
className?: string
callback?: OnSelect
}
......@@ -30,6 +31,9 @@ export type BlockSelectorContextValue = {
open: boolean
setOpen: (open: boolean) => void
referenceRef: any
floatingRef: any
floatingStyles: React.CSSProperties
getFloatingProps: any
handleToggle: (v: UpdateParams) => void
}
......@@ -38,6 +42,9 @@ export const BlockSelectorContext = createContext<BlockSelectorContextValue>({
open: false,
setOpen: () => {},
referenceRef: null,
floatingRef: null,
floatingStyles: {},
getFloatingProps: () => {},
handleToggle: () => {},
})
export const useBlockSelectorContext = () => useContext(BlockSelectorContext)
......@@ -73,13 +80,17 @@ export const BlockSelectorContextProvider = ({
const handleToggle = useCallback(({
from,
open,
placement,
offset,
className,
callback,
}: UpdateParams) => {
setFrom(from || 'node')
setOpen(v => !v)
if (open !== undefined)
setOpen(open)
else
setOpen(v => !v)
setPlacement(placement || 'top')
setOffsetValue(offset || 0)
setClassName(className || '')
......@@ -99,10 +110,13 @@ export const BlockSelectorContextProvider = ({
setOpen,
handleToggle,
referenceRef: refs.setReference,
floatingRef: refs.setFloating,
floatingStyles,
getFloatingProps,
}}>
{children}
{
open && (
open && (from === 'node' || from === 'panel') && (
<FloatingPortal>
<div
ref={refs.setFloating}
......
import { useState } from 'react'
import {
flip,
offset,
shift,
useDismiss,
useFloating,
useInteractions,
} from '@floating-ui/react'
export const useAddBranch = () => {
const [isOpen, setIsOpen] = useState(false)
const [dismissEnable, setDismissEnable] = useState(true)
const { refs, floatingStyles, context } = useFloating({
placement: 'bottom',
strategy: 'fixed',
open: isOpen,
onOpenChange: setIsOpen,
middleware: [
flip(),
shift(),
offset(4),
],
})
const dismiss = useDismiss(context, {
enabled: dismissEnable,
})
const { getFloatingProps } = useInteractions([
dismiss,
])
return {
refs,
floatingStyles,
getFloatingProps,
isOpen,
setIsOpen,
setDismissEnable,
}
}
import type { FC, MouseEvent } from 'react'
import {
memo,
useMemo,
} from 'react'
import { FloatingPortal } from '@floating-ui/react'
import { useBlockSelectorContext } from '../../../../block-selector/context'
import type {
BlockEnum,
Node,
} from '../../../../types'
import { useAddBranch } from './hooks'
import { Plus02 } from '@/app/components/base/icons/src/vender/line/general'
type AddNodeProps = {
outgoers: Node[]
onAddNextNode: (type: BlockEnum) => void
branches?: { id: string; name: string }[]
}
const AddNode: FC<AddNodeProps> = ({
onAddNextNode,
branches,
}) => {
const {
refs,
isOpen,
setIsOpen,
setDismissEnable,
floatingStyles,
getFloatingProps,
} = useAddBranch()
const {
from,
open,
referenceRef,
handleToggle,
} = useBlockSelectorContext()
const hasBranches = branches && !!branches.length
const handleAdd = (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation()
if (hasBranches)
return setIsOpen(v => !v)
handleToggle({
placement: 'right',
offset: 6,
callback: onAddNextNode,
})
}
const buttonRef = useMemo(() => {
if (hasBranches)
return refs.setReference
if (from === 'node')
return referenceRef
return null
}, [from, hasBranches, referenceRef, refs.setReference])
const buttonShouldShow = useMemo(() => {
if (hasBranches && isOpen)
return true
return open && from === 'node'
}, [from, hasBranches, isOpen, open])
return (
<>
<div
ref={buttonRef}
onClick={handleAdd}
className={`
hidden absolute -bottom-2 left-1/2 -translate-x-1/2 items-center justify-center
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10 group-hover:flex
${buttonShouldShow && '!flex'}
`}
>
<Plus02 className='w-2.5 h-2.5 text-white' />
</div>
{
isOpen && hasBranches && (
<FloatingPortal>
<div
ref={refs.setFloating}
style={floatingStyles}
{...getFloatingProps()}
className='p-1 w-[108px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'
>
{
branches.map(branch => (
<div
key={branch.id}
className='flex items-center px-3 pr-2 h-[30px] text-[13px] font-medium text-gray-700 cursor-pointer rounded-lg hover:bg-gray-50'
onClick={() => {
setDismissEnable(false)
handleToggle({
open: true,
placement: 'right',
offset: 6,
callback: onAddNextNode,
})
}}
>
{branch.name}
</div>
))
}
</div>
</FloatingPortal>
)
}
</>
)
}
export default memo(AddNode)
......@@ -6,10 +6,8 @@ import {
} from 'react'
import { getOutgoers } from 'reactflow'
import BlockIcon from '../../../block-icon'
import type {
BlockEnum,
Node,
} from '../../../types'
import type { Node } from '../../../types'
import { BlockEnum } from '../../../types'
import { useWorkflowContext } from '../../../context'
import { useBlockSelectorContext } from '../../../block-selector/context'
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
......@@ -46,30 +44,6 @@ const NextStep: FC<NextStepProps> = ({
</div>
<div className='shrink-0 w-6'></div>
<div className='grow'>
{
!outgoers.length && (
<div
onClick={() => {
handleToggle({
from: 'panel',
className: 'w-[328px]',
callback: handleSelectBlock,
})
}}
ref={from === 'panel' ? referenceRef : null}
className={`
flex items-center px-2 w-[328px] h-9 rounded-lg border border-dashed border-gray-200 bg-gray-50
hover:bg-gray-100 text-xs text-gray-500 cursor-pointer
${open && from === 'panel' && '!bg-gray-100'}
`}
>
<div className='flex items-center justify-center mr-1.5 w-5 h-5 rounded-[5px] bg-gray-200'>
<Plus className='w-3 h-3' />
</div>
SELECT NEXT BLOCK
</div>
)
}
{
!!outgoers.length && outgoers.map(outgoer => (
<div
......@@ -88,7 +62,10 @@ const NextStep: FC<NextStepProps> = ({
from: 'panel',
className: 'w-[328px]',
placement: 'top-end',
offset: 6,
offset: {
mainAxis: 6,
crossAxis: 8,
},
})
}}
>
......@@ -104,6 +81,30 @@ const NextStep: FC<NextStepProps> = ({
</div>
))
}
{
(!outgoers.length || selectedNode.data.type === BlockEnum.IfElse) && (
<div
onClick={() => {
handleToggle({
from: 'panel',
className: 'w-[328px]',
callback: handleSelectBlock,
})
}}
ref={from === 'panel' ? referenceRef : null}
className={`
flex items-center px-2 w-[328px] h-9 rounded-lg border border-dashed border-gray-200 bg-gray-50
hover:bg-gray-100 text-xs text-gray-500 cursor-pointer
${open && from === 'panel' && '!bg-gray-100'}
`}
>
<div className='flex items-center justify-center mr-1.5 w-5 h-5 rounded-[5px] bg-gray-200'>
<Plus className='w-3 h-3' />
</div>
SELECT NEXT BLOCK
</div>
)
}
</div>
</div>
)
......
......@@ -11,11 +11,10 @@ import {
import type { NodeProps } from 'reactflow'
import { getOutgoers } from 'reactflow'
import { useWorkflowContext } from '../../context'
import type { BlockEnum } from '../../types'
import { useBlockSelectorContext } from '../../block-selector/context'
import { BlockEnum } from '../../types'
import NodeControl from '../../node-control'
import BlockIcon from '../../block-icon'
import { Plus02 } from '@/app/components/base/icons/src/vender/line/general'
import AddNode from './components/add-node/index'
type BaseNodeProps = {
children: ReactElement
......@@ -33,12 +32,6 @@ const BaseNode: FC<BaseNodeProps> = ({
handleSelectedNodeIdChange,
handleAddNextNode,
} = useWorkflowContext()
const {
from,
open,
referenceRef,
handleToggle,
} = useBlockSelectorContext()
const currentNode = useMemo(() => {
return nodes.find(node => node.id === nodeId)
}, [nodeId, nodes])
......@@ -48,6 +41,20 @@ const BaseNode: FC<BaseNodeProps> = ({
const handleSelectBlock = useCallback((type: BlockEnum) => {
handleAddNextNode(currentNode!, type)
}, [currentNode, handleAddNextNode])
const branches = useMemo(() => {
if (data.type === BlockEnum.IfElse) {
return [
{
id: '1',
name: 'Is True',
},
{
id: '2',
name: 'Is False',
},
]
}
}, [data])
return (
<div
......@@ -73,28 +80,11 @@ const BaseNode: FC<BaseNodeProps> = ({
<div className='px-3 pt-1 pb-1 text-xs text-gray-500'>
Define the initial parameters for launching a workflow
</div>
{
!outgoers.length && (
<div
ref={from === 'node' ? referenceRef : null}
onClick={(e) => {
e.stopPropagation()
handleToggle({
placement: 'right',
offset: 6,
callback: handleSelectBlock,
})
}}
className={`
hidden absolute -bottom-2 left-1/2 -translate-x-1/2 items-center justify-center
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10 group-hover:flex
${open && from === 'node' && '!flex'}
`}
>
<Plus02 className='w-2.5 h-2.5 text-white' />
</div>
)
}
<AddNode
outgoers={outgoers}
branches={branches}
onAddNextNode={handleSelectBlock}
/>
</div>
)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment