Commit 59d8f926 authored by StyleZhang's avatar StyleZhang

block-selector

parent c6f1900a
...@@ -11,45 +11,10 @@ const initialNodes = [ ...@@ -11,45 +11,10 @@ const initialNodes = [
position: { x: 330, y: 30 }, position: { x: 330, y: 30 },
data: { type: 'start' }, data: { type: 'start' },
}, },
{
id: '2',
type: 'custom',
position: { x: 330, y: 212 },
data: { type: 'start' },
},
{
id: '3',
type: 'custom',
position: { x: 150, y: 394 },
data: { type: 'start' },
},
{
id: '4',
type: 'custom',
position: { x: 510, y: 394 },
data: { type: 'start' },
},
] ]
const initialEdges = [ const initialEdges = [
{
id: '1',
source: '1',
target: '2',
type: 'custom',
},
{
id: '2',
source: '2',
target: '3',
type: 'custom',
},
{
id: '3',
source: '2',
target: '4',
type: 'custom',
},
] ]
const Page: FC = () => { const Page: FC = () => {
......
import type { FC, ReactElement } from 'react' import type { FC, ReactElement } from 'react'
import { import {
memo, memo,
useCallback,
useState, useState,
} from 'react' } from 'react'
import Tabs from './tabs' import type {
OffsetOptions,
Placement,
} from '@floating-ui/react'
import { import {
PortalToFollowElem, FloatingPortal,
PortalToFollowElemContent, flip,
PortalToFollowElemTrigger, offset,
} from '@/app/components/base/portal-to-follow-elem' shift,
useClick,
useDismiss,
useFloating,
useInteractions,
} from '@floating-ui/react'
import Tabs from './tabs'
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general' import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
type NodeSelectorProps = { type NodeSelectorProps = {
children: ReactElement placement?: Placement
offset?: OffsetOptions
className?: string
children: (props: any) => ReactElement
} }
const NodeSelector: FC<NodeSelectorProps> = ({ const NodeSelector: FC<NodeSelectorProps> = ({
placement = 'top',
offset: offsetValue = 0,
className,
children, children,
}) => { }) => {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const handleTrigger: any = useCallback((e: MouseEvent) => { const { refs, floatingStyles, context } = useFloating({
e.stopPropagation() placement,
setOpen(v => !v) strategy: 'fixed',
}, []) open,
onOpenChange: setOpen,
middleware: [
flip(),
shift(),
offset(offsetValue),
],
})
const click = useClick(context)
const dismiss = useDismiss(context, {
bubbles: false,
})
const { getReferenceProps, getFloatingProps } = useInteractions([
click,
dismiss,
])
return ( return (
<PortalToFollowElem <>
open={open} {children({ ...getReferenceProps(), ref: refs.setReference, open })}
onOpenChange={setOpen} {
placement='right-start' open && (
> <FloatingPortal>
<PortalToFollowElemTrigger onClick={handleTrigger}> <div
{children} ref={refs.setFloating}
</PortalToFollowElemTrigger> style={floatingStyles}
<PortalToFollowElemContent className='z-50'> {...getFloatingProps()}
<div className='w-[256px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'> className='z-[1000]'
<div className='px-2 pt-2'> >
<div className='flex items-center px-2 rounded-lg bg-gray-100'> <div className={`w-[256px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg ${className}`}>
<SearchLg className='shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400' /> <div className='px-2 pt-2'>
<input <div className='flex items-center px-2 rounded-lg bg-gray-100'>
className='grow px-0.5 py-[7px] text-[13px] bg-transparent appearance-none outline-none' <SearchLg className='shrink-0 ml-[1px] mr-[5px] w-3.5 h-3.5 text-gray-400' />
placeholder='Search block' <input
/> className='grow px-0.5 py-[7px] text-[13px] bg-transparent appearance-none outline-none'
placeholder='Search block'
/>
</div>
</div>
<Tabs />
</div>
</div> </div>
</div> </FloatingPortal>
<Tabs /> )
</div> }
</PortalToFollowElemContent> </>
</PortalToFollowElem>
) )
} }
......
import type { FC } from 'react' import type { FC } from 'react'
import { import {
memo, memo,
useCallback,
useMemo, useMemo,
} from 'react' } from 'react'
import { getOutgoers } from 'reactflow' import { getOutgoers } from 'reactflow'
...@@ -25,6 +26,42 @@ const NextStep: FC<NextStepProps> = ({ ...@@ -25,6 +26,42 @@ const NextStep: FC<NextStepProps> = ({
return getOutgoers(selectedNode, nodes, edges) return getOutgoers(selectedNode, nodes, edges)
}, [selectedNode, nodes, edges]) }, [selectedNode, nodes, edges])
const renderBlockSelectorChildren = useCallback(({ open, ref, ...restProps }: any) => {
return (
<div
{...restProps}
ref={ref}
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 renderBlockSelectorButtonChildren = useCallback(({ open, ref, ...restProps }: any) => {
return (
<div
{...restProps}
ref={ref}
>
<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>
)
}, [])
return ( return (
<div className='flex py-1'> <div className='flex py-1'>
<div className='shrink-0 relative flex items-center justify-center w-9 h-9 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-xs'> <div className='shrink-0 relative flex items-center justify-center w-9 h-9 bg-white rounded-lg border-[0.5px] border-gray-200 shadow-xs'>
...@@ -34,13 +71,8 @@ const NextStep: FC<NextStepProps> = ({ ...@@ -34,13 +71,8 @@ const NextStep: FC<NextStepProps> = ({
<div className='grow'> <div className='grow'>
{ {
!outgoers.length && ( !outgoers.length && (
<BlockSelector> <BlockSelector className='!w-[328px]'>
<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'> {renderBlockSelectorChildren}
<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> </BlockSelector>
) )
} }
...@@ -55,10 +87,11 @@ const NextStep: FC<NextStepProps> = ({ ...@@ -55,10 +87,11 @@ const NextStep: FC<NextStepProps> = ({
className='shrink-0 mr-1.5' className='shrink-0 mr-1.5'
/> />
<div className='grow'>{outgoer.data.name}</div> <div className='grow'>{outgoer.data.name}</div>
<BlockSelector> <BlockSelector
<Button className='hidden group-hover:flex px-2 py-0 h-6 bg-white text-xs text-gray-700 font-medium rounded-md'> placement='top-end'
Change offset={6}
</Button> >
{renderBlockSelectorButtonChildren}
</BlockSelector> </BlockSelector>
</div> </div>
)) ))
......
...@@ -2,7 +2,11 @@ import type { ...@@ -2,7 +2,11 @@ import type {
FC, FC,
ReactNode, ReactNode,
} from 'react' } from 'react'
import { memo, useMemo } from 'react' import {
memo,
useCallback,
useMemo,
} from 'react'
import { import {
getOutgoers, getOutgoers,
useNodeId, useNodeId,
...@@ -33,6 +37,23 @@ const BaseNode: FC<BaseNodeProps> = ({ ...@@ -33,6 +37,23 @@ const BaseNode: FC<BaseNodeProps> = ({
const outgoers = useMemo(() => { const outgoers = useMemo(() => {
return getOutgoers(currentNode!, nodes, edges) return getOutgoers(currentNode!, nodes, edges)
}, [currentNode, nodes, edges]) }, [currentNode, nodes, edges])
const renderBlockSelectorChildren = useCallback(({ open, ref, ...restProps }: any) => {
return (
<div onClick={e => e.stopPropagation()}>
<div
{...restProps}
ref={ref}
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 && '!flex'}
`}
>
<Plus className='w-2.5 h-2.5 text-white' />
</div>
</div>
)
}, [])
return ( return (
<div <div
...@@ -57,17 +78,16 @@ const BaseNode: FC<BaseNodeProps> = ({ ...@@ -57,17 +78,16 @@ const BaseNode: FC<BaseNodeProps> = ({
<div className='px-3 pt-1 pb-1 text-xs text-gray-500'> <div className='px-3 pt-1 pb-1 text-xs text-gray-500'>
Define the initial parameters for launching a workflow Define the initial parameters for launching a workflow
</div> </div>
<BlockSelector> {
<div !outgoers.length && (
className={` <BlockSelector
hidden absolute -bottom-2 left-1/2 -translate-x-1/2 items-center justify-center placement='right'
w-4 h-4 rounded-full bg-primary-600 cursor-pointer z-10 offset={6}
${!outgoers.length && 'group-hover:flex'} >
`} {renderBlockSelectorChildren}
> </BlockSelector>
<Plus className='w-2.5 h-2.5 text-white' /> )
</div> }
</BlockSelector>
</div> </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