mirror of https://github.com/langgenius/dify.git
block-selector
This commit is contained in:
parent
0759b29ca2
commit
ea76f46223
|
|
@ -1,137 +0,0 @@
|
|||
'use client'
|
||||
|
||||
import { useCallback, useRef, useState } from 'react'
|
||||
import { createContext, useContext } from 'use-context-selector'
|
||||
import type {
|
||||
OffsetOptions,
|
||||
Placement,
|
||||
} from '@floating-ui/react'
|
||||
import {
|
||||
FloatingPortal,
|
||||
flip,
|
||||
offset,
|
||||
shift,
|
||||
useDismiss,
|
||||
useFloating,
|
||||
useInteractions,
|
||||
} from '@floating-ui/react'
|
||||
import type { OnSelect } from './types'
|
||||
import BlockSelector from './index'
|
||||
|
||||
type UpdateParams = {
|
||||
from?: string
|
||||
placement?: Placement
|
||||
offset?: OffsetOptions
|
||||
open?: boolean
|
||||
className?: string
|
||||
callback?: OnSelect
|
||||
}
|
||||
export type BlockSelectorContextValue = {
|
||||
from: string
|
||||
open: boolean
|
||||
setOpen: (open: boolean) => void
|
||||
referenceRef: any
|
||||
floatingRef: any
|
||||
floatingStyles: React.CSSProperties
|
||||
getFloatingProps: any
|
||||
handleToggle: (v: UpdateParams) => void
|
||||
}
|
||||
|
||||
export const BlockSelectorContext = createContext<BlockSelectorContextValue>({
|
||||
from: '',
|
||||
open: false,
|
||||
setOpen: () => {},
|
||||
referenceRef: null,
|
||||
floatingRef: null,
|
||||
floatingStyles: {},
|
||||
getFloatingProps: () => {},
|
||||
handleToggle: () => {},
|
||||
})
|
||||
export const useBlockSelectorContext = () => useContext(BlockSelectorContext)
|
||||
|
||||
type BlockSelectorContextProviderProps = {
|
||||
children: React.ReactNode
|
||||
}
|
||||
export const BlockSelectorContextProvider = ({
|
||||
children,
|
||||
}: BlockSelectorContextProviderProps) => {
|
||||
const [from, setFrom] = useState('node')
|
||||
const [open, setOpen] = useState(false)
|
||||
const [placement, setPlacement] = useState<Placement>('top')
|
||||
const [offsetValue, setOffsetValue] = useState<OffsetOptions>(0)
|
||||
const [className, setClassName] = useState<string>('')
|
||||
const callbackRef = useRef<OnSelect | undefined>(undefined)
|
||||
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
placement,
|
||||
strategy: 'fixed',
|
||||
open,
|
||||
onOpenChange: setOpen,
|
||||
middleware: [
|
||||
flip(),
|
||||
shift(),
|
||||
offset(offsetValue),
|
||||
],
|
||||
})
|
||||
const dismiss = useDismiss(context)
|
||||
const { getFloatingProps } = useInteractions([
|
||||
dismiss,
|
||||
])
|
||||
|
||||
const handleToggle = useCallback(({
|
||||
from,
|
||||
open,
|
||||
placement,
|
||||
offset,
|
||||
className,
|
||||
callback,
|
||||
}: UpdateParams) => {
|
||||
setFrom(from || 'node')
|
||||
if (open !== undefined)
|
||||
setOpen(open)
|
||||
else
|
||||
setOpen(v => !v)
|
||||
setPlacement(placement || 'top')
|
||||
setOffsetValue(offset || 0)
|
||||
setClassName(className || '')
|
||||
callbackRef.current = callback
|
||||
}, [])
|
||||
|
||||
const handleSelect = useCallback<OnSelect>((type) => {
|
||||
if (callbackRef.current)
|
||||
callbackRef.current(type)
|
||||
setOpen(v => !v)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<BlockSelectorContext.Provider value={{
|
||||
from,
|
||||
open,
|
||||
setOpen,
|
||||
handleToggle,
|
||||
referenceRef: refs.setReference,
|
||||
floatingRef: refs.setFloating,
|
||||
floatingStyles,
|
||||
getFloatingProps,
|
||||
}}>
|
||||
{children}
|
||||
{
|
||||
open && (from === 'node' || from === 'panel') && (
|
||||
<FloatingPortal>
|
||||
<div
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
{...getFloatingProps()}
|
||||
className='z-[1000]'
|
||||
>
|
||||
<BlockSelector
|
||||
className={className}
|
||||
onSelect={handleSelect}
|
||||
/>
|
||||
</div>
|
||||
</FloatingPortal>
|
||||
)
|
||||
}
|
||||
</BlockSelectorContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
@ -1,30 +1,80 @@
|
|||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import type {
|
||||
OffsetOptions,
|
||||
Placement,
|
||||
} from '@floating-ui/react'
|
||||
import type { BlockEnum } from '../types'
|
||||
import Tabs from './tabs'
|
||||
import type { OnSelect } from './types'
|
||||
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import {
|
||||
Plus02,
|
||||
SearchLg,
|
||||
} from '@/app/components/base/icons/src/vender/line/general'
|
||||
|
||||
type NodeSelectorProps = {
|
||||
onSelect: OnSelect
|
||||
className?: string
|
||||
onSelect: (type: BlockEnum) => void
|
||||
trigger?: (open: boolean) => React.ReactNode
|
||||
placement?: Placement
|
||||
offset?: OffsetOptions
|
||||
popupClassName?: string
|
||||
asChild?: boolean
|
||||
}
|
||||
const NodeSelector: FC<NodeSelectorProps> = ({
|
||||
onSelect,
|
||||
className,
|
||||
trigger,
|
||||
placement = 'right',
|
||||
offset = 6,
|
||||
popupClassName,
|
||||
asChild,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false)
|
||||
return (
|
||||
<div className={`w-[256px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg ${className}`}>
|
||||
<div className='px-2 pt-2'>
|
||||
<div className='flex items-center px-2 rounded-lg bg-gray-100'>
|
||||
<SearchLg className='shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400' />
|
||||
<input
|
||||
className='grow px-0.5 py-[7px] text-[13px] bg-transparent appearance-none outline-none'
|
||||
placeholder='Search block'
|
||||
/>
|
||||
<PortalToFollowElem
|
||||
placement={placement}
|
||||
offset={offset}
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
>
|
||||
<PortalToFollowElemTrigger asChild={asChild} onClick={() => setOpen(v => !v)}>
|
||||
{
|
||||
trigger
|
||||
? trigger(open)
|
||||
: (
|
||||
<div
|
||||
className={`
|
||||
hidden absolute -right-2 top-4 items-center justify-center
|
||||
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10 group-hover:flex
|
||||
${open && '!flex'}
|
||||
`}
|
||||
>
|
||||
<Plus02 className='w-2.5 h-2.5 text-white' />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[1000]'>
|
||||
<div className={`w-[256px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg ${popupClassName}`}>
|
||||
<div className='px-2 pt-2'>
|
||||
<div className='flex items-center px-2 rounded-lg bg-gray-100'>
|
||||
<SearchLg className='shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400' />
|
||||
<input
|
||||
className='grow px-0.5 py-[7px] text-[13px] bg-transparent appearance-none outline-none'
|
||||
placeholder='Search block'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs onSelect={onSelect} />
|
||||
</div>
|
||||
</div>
|
||||
<Tabs onSelect={onSelect} />
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import {
|
|||
useState,
|
||||
} from 'react'
|
||||
import BlockIcon from '../block-icon'
|
||||
import type { OnSelect } from './types'
|
||||
import type { BlockEnum } from '../types'
|
||||
import {
|
||||
BLOCK_CLASSIFICATIONS,
|
||||
BLOCK_GROUP_BY_CLASSIFICATION,
|
||||
|
|
@ -12,7 +12,7 @@ import {
|
|||
} from './constants'
|
||||
|
||||
export type TabsProps = {
|
||||
onSelect: OnSelect
|
||||
onSelect: (type: BlockEnum) => void
|
||||
}
|
||||
const Tabs: FC<TabsProps> = ({
|
||||
onSelect,
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
import type { BlockEnum } from '../types'
|
||||
|
||||
export type OnSelect = (type: BlockEnum) => void
|
||||
|
|
@ -23,7 +23,6 @@ import DebugAndPreview from './debug-and-preview'
|
|||
import ZoomInOut from './zoom-in-out'
|
||||
import CustomEdge from './custom-edge'
|
||||
import type { Node } from './types'
|
||||
import { BlockSelectorContextProvider } from './block-selector/context'
|
||||
|
||||
const nodeTypes = {
|
||||
custom: CustomNode,
|
||||
|
|
@ -97,9 +96,7 @@ const WorkflowWrap: FC<WorkflowWrapProps> = ({
|
|||
handleAddNextNode,
|
||||
handleUpdateNodeData,
|
||||
}}>
|
||||
<BlockSelectorContextProvider>
|
||||
<Workflow />
|
||||
</BlockSelectorContextProvider>
|
||||
<Workflow />
|
||||
</WorkflowContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +0,0 @@
|
|||
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,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
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 -right-2 top-4 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)
|
||||
|
|
@ -9,7 +9,7 @@ import BlockIcon from '../../../block-icon'
|
|||
import type { Node } from '../../../types'
|
||||
import { BlockEnum } from '../../../types'
|
||||
import { useWorkflowContext } from '../../../context'
|
||||
import { useBlockSelectorContext } from '../../../block-selector/context'
|
||||
import BlockSelector from '../../../block-selector'
|
||||
import { Plus } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import Button from '@/app/components/base/button'
|
||||
|
||||
|
|
@ -19,23 +19,43 @@ type NextStepProps = {
|
|||
const NextStep: FC<NextStepProps> = ({
|
||||
selectedNode,
|
||||
}) => {
|
||||
const {
|
||||
from,
|
||||
open,
|
||||
referenceRef,
|
||||
handleToggle,
|
||||
} = useBlockSelectorContext()
|
||||
const {
|
||||
nodes,
|
||||
edges,
|
||||
handleAddNextNode,
|
||||
} = useWorkflowContext()
|
||||
const outgoers = useMemo(() => {
|
||||
return getOutgoers(selectedNode, nodes, edges)
|
||||
}, [selectedNode, nodes, edges])
|
||||
const handleSelectBlock = useCallback((type: BlockEnum) => {
|
||||
handleAddNextNode(selectedNode, type)
|
||||
}, [selectedNode, handleAddNextNode])
|
||||
|
||||
const renderAddNextNodeTrigger = useCallback((open: boolean) => {
|
||||
return (
|
||||
<div
|
||||
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 && '!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>
|
||||
)
|
||||
}, [])
|
||||
|
||||
const renderChangeCurrentNodeTrigger = useCallback((open: boolean) => {
|
||||
return (
|
||||
<Button
|
||||
className={`
|
||||
hidden group-hover:flex px-2 py-0 h-6 bg-white text-xs text-gray-700 font-medium rounded-md
|
||||
${open && '!bg-gray-100 !flex'}
|
||||
`}
|
||||
>
|
||||
Change
|
||||
</Button>
|
||||
)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className='flex py-1'>
|
||||
|
|
@ -55,54 +75,28 @@ const NextStep: FC<NextStepProps> = ({
|
|||
className='shrink-0 mr-1.5'
|
||||
/>
|
||||
<div className='grow'>{outgoer.data.name}</div>
|
||||
<div
|
||||
ref={from === 'panel' ? referenceRef : null}
|
||||
onClick={() => {
|
||||
handleToggle({
|
||||
from: 'panel',
|
||||
className: 'w-[328px]',
|
||||
placement: 'top-end',
|
||||
offset: {
|
||||
mainAxis: 6,
|
||||
crossAxis: 8,
|
||||
},
|
||||
})
|
||||
<BlockSelector
|
||||
onSelect={() => {}}
|
||||
placement='top-end'
|
||||
offset={{
|
||||
mainAxis: 6,
|
||||
crossAxis: 8,
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
className={`
|
||||
hidden group-hover:flex px-2 py-0 h-6 bg-white text-xs text-gray-700 font-medium rounded-md
|
||||
${open && '!bg-gray-100 !flex'}
|
||||
`}
|
||||
>
|
||||
Change
|
||||
</Button>
|
||||
</div>
|
||||
trigger={renderChangeCurrentNodeTrigger}
|
||||
popupClassName='!w-[328px]'
|
||||
/>
|
||||
</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>
|
||||
<BlockSelector
|
||||
onSelect={() => {}}
|
||||
placement='top'
|
||||
offset={0}
|
||||
trigger={renderAddNextNodeTrigger}
|
||||
popupClassName='!w-[328px]'
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,16 +5,13 @@ import type {
|
|||
import {
|
||||
cloneElement,
|
||||
memo,
|
||||
useCallback,
|
||||
useMemo,
|
||||
} from 'react'
|
||||
import type { NodeProps } from 'reactflow'
|
||||
import { getOutgoers } from 'reactflow'
|
||||
import { useWorkflowContext } from '../../context'
|
||||
import { BlockEnum } from '../../types'
|
||||
import NodeControl from '../../node-control'
|
||||
import BlockIcon from '../../block-icon'
|
||||
import AddNode from './components/add-node/index'
|
||||
import BlockSelector from '../../block-selector'
|
||||
|
||||
type BaseNodeProps = {
|
||||
children: ReactElement
|
||||
|
|
@ -27,34 +24,12 @@ const BaseNode: FC<BaseNodeProps> = ({
|
|||
}) => {
|
||||
const {
|
||||
nodes,
|
||||
edges,
|
||||
selectedNodeId,
|
||||
handleSelectedNodeIdChange,
|
||||
handleAddNextNode,
|
||||
} = useWorkflowContext()
|
||||
const currentNode = useMemo(() => {
|
||||
return nodes.find(node => node.id === nodeId)
|
||||
}, [nodeId, nodes])
|
||||
const outgoers = useMemo(() => {
|
||||
return getOutgoers(currentNode!, nodes, edges)
|
||||
}, [currentNode, nodes, edges])
|
||||
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
|
||||
|
|
@ -80,10 +55,9 @@ 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>
|
||||
<AddNode
|
||||
outgoers={outgoers}
|
||||
branches={branches}
|
||||
onAddNextNode={handleSelectBlock}
|
||||
<BlockSelector
|
||||
onSelect={() => {}}
|
||||
asChild
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ const CustomNode = ({
|
|||
type='target'
|
||||
position={Position.Left}
|
||||
className={`
|
||||
!top-4 !left-0 !w-4 !h-4 !bg-transparent !rounded-none !outline-none !border-none !translate-y-0 z-[1]
|
||||
!top-[17px] !left-0 !w-4 !h-4 !bg-transparent !rounded-none !outline-none !border-none !translate-y-0 z-[1]
|
||||
after:absolute after:w-0.5 after:h-2 after:-left-0.5 after:top-1 after:bg-primary-500
|
||||
${data.type === BlockEnum.Start && 'opacity-0'}
|
||||
`}
|
||||
|
|
@ -41,7 +41,7 @@ const CustomNode = ({
|
|||
type='source'
|
||||
position={Position.Right}
|
||||
className={`
|
||||
!top-4 !right-0 !w-4 !h-4 !bg-transparent !rounded-none !outline-none !border-none !translate-y-0
|
||||
!top-[17px] !right-0 !w-4 !h-4 !bg-transparent !rounded-none !outline-none !border-none !translate-y-0 z-[1]
|
||||
after:absolute after:w-0.5 after:h-2 after:-right-0.5 after:top-1 after:bg-primary-500
|
||||
`}
|
||||
/>
|
||||
|
|
|
|||
Loading…
Reference in New Issue