1- import { Handle , Node , NodeProps , Position , useReactFlow , useStore } from "@xyflow/react" ;
1+ import { Handle , Node , NodeProps , Position , useStore } from "@xyflow/react" ;
22import React , { CSSProperties , memo } from "react" ;
33import "./FunctionNodeComponent.style.scss" ;
44import { FunctionNodeComponentProps } from "./FunctionNodeComponent" ;
55import { FileTabsService } from "@code0-tech/pictor/dist/components/file-tabs/FileTabs.service" ;
6- import {
7- Badge , Card ,
8- Flex , Text , underlineBySeverity ,
9- useService ,
10- useStore as usePictorStore
11- } from "@code0-tech/pictor" ;
6+ import { Badge , Card , Flex , Text , underlineBySeverity , useService , useStore as usePictorStore } from "@code0-tech/pictor" ;
127import { useNodeValidation } from "@edition/flow/hooks/NodeValidation.hook" ;
13- import { IconNote } from "@tabler/icons-react" ;
8+ import { IconNote , IconVariable } from "@tabler/icons-react" ;
149import { FlowService } from "@edition/flow/services/Flow.service" ;
1510import { FunctionService } from "@edition/function/services/Function.service" ;
1611import { LiteralBadgeComponent } from "@edition/datatype/components/badges/LiteralBadgeComponent" ;
1712import { ReferenceBadgeComponent } from "@edition/datatype/components/badges/ReferenceBadgeComponent" ;
1813import { NodeBadgeComponent } from "@edition/datatype/components/badges/NodeBadgeComponent" ;
1914import { FunctionFileDefaultComponent } from "@edition/function/components/files/FunctionFileDefaultComponent" ;
15+ import { NodeFunction } from "@code0-tech/sagittarius-graphql-types" ;
2016
2117export type FunctionNodeDefaultComponentProps = NodeProps < Node < FunctionNodeComponentProps > >
2218
2319export const FunctionNodeDefaultComponent : React . FC < FunctionNodeDefaultComponentProps > = memo ( ( props ) => {
24- const { data, id, width = 0 , height = 0 } = props
20+ const { data, id} = props
2521
26- const viewportWidth = useStore ( s => s . width ) ;
27- const viewportHeight = useStore ( s => s . height ) ;
28- const flowInstance = useReactFlow ( )
2922 const fileTabsService = useService ( FileTabsService )
3023 const fileTabsStore = usePictorStore ( FileTabsService )
3124 const flowService = useService ( FlowService )
@@ -36,6 +29,7 @@ export const FunctionNodeDefaultComponent: React.FC<FunctionNodeDefaultComponent
3629 const node = React . useMemo ( ( ) => flowService . getNodeById ( data . flowId , data . nodeId ) , [ flowStore , data ] )
3730 const definition = React . useMemo ( ( ) => node ? functionService . getById ( node . functionDefinition ?. id ! ! ) : undefined , [ functionStore , data , node ] )
3831 const validation = useNodeValidation ( data . nodeId , data . flowId )
32+
3933 const activeTabId = React . useMemo ( ( ) => {
4034 return fileTabsService . getActiveTab ( ) ?. id
4135 } , [ fileTabsStore , fileTabsService ] ) ;
@@ -110,9 +104,9 @@ export const FunctionNodeDefaultComponent: React.FC<FunctionNodeDefaultComponent
110104 } ) , [ flowStore , functionStore , data , definition ] )
111105
112106 React . useEffect ( ( ) => {
113- if ( ! node ?. id ) return
107+ if ( ! node ?. id || ! id ) return
114108 fileTabsService . registerTab ( {
115- id : node . id ,
109+ id : id ,
116110 active : false ,
117111 closeable : true ,
118112 children : < >
@@ -121,7 +115,23 @@ export const FunctionNodeDefaultComponent: React.FC<FunctionNodeDefaultComponent
121115 </ > ,
122116 content : < FunctionFileDefaultComponent flowId = { props . data . flowId } node = { node } />
123117 } )
124- } , [ node ?. id , definition , data ] )
118+ } , [ ] )
119+
120+ const isReferenced = React . useMemo ( ( ) => {
121+
122+ const activeNode = flowService . getNodeById ( data . flowId , activeTabId as NodeFunction [ 'id' ] )
123+ const isActiveNodeReferencingCurrentNode = activeNode ?. parameters ?. nodes ?. some ( p => p ?. value ?. __typename === "ReferenceValue" && p . value . nodeFunctionId === node ?. id )
124+ const hasReferences = activeNode ?. parameters ?. nodes ?. some ( p => p ?. value ?. __typename === "ReferenceValue" )
125+
126+ if ( isActiveNodeReferencingCurrentNode ) {
127+ return true
128+ } else if ( hasReferences && ! isActiveNodeReferencingCurrentNode && activeTabId !== data . nodeId ) {
129+ return false
130+ }
131+
132+ return undefined
133+
134+ } , [ flowStore , activeTabId , data . flowId , node ] )
125135
126136 return (
127137 < Card
@@ -130,19 +140,11 @@ export const FunctionNodeDefaultComponent: React.FC<FunctionNodeDefaultComponent
130140 paddingSize = { "xs" }
131141 py = { "0.35" }
132142 outline = { firstItem . id === id }
133- borderColor = { activeTabId == node ?. id ? "info" : undefined }
134- className = { `d-flow-node ${ activeTabId == node ?. id ? "d-flow-node--active" : undefined } ` }
135- color = { "primary" }
136- onClick = { ( ) => {
137- flowInstance . setViewport ( {
138- x : ( viewportWidth / 2 ) + ( props . positionAbsoluteX * - 1 ) - ( width / 2 ) ,
139- y : ( viewportHeight / 2 ) + ( props . positionAbsoluteY * - 1 ) - ( height / 2 ) ,
140- zoom : 1
141- } , {
142- duration : 250 ,
143- } )
144- fileTabsService . activateTab ( node ?. id ! ! )
145- } } style = { { position : "relative" } } >
143+ borderColor = { activeTabId == id ? "info" : undefined }
144+ className = { `d-flow-node ${ activeTabId == id ? "d-flow-node--active" : "" } ${ isReferenced === false ? "d-flow-node--notReferenced" : "" } ` }
145+ color = { "primary" } style = { {
146+ ...( isReferenced === true ? { boxShadow : `0 0 5rem 0 ${ withAlpha ( data . color , 0.25 ) } ` } : { } ) ,
147+ } } >
146148
147149 < Handle
148150 isConnectable = { false }
@@ -161,10 +163,80 @@ export const FunctionNodeDefaultComponent: React.FC<FunctionNodeDefaultComponent
161163 className = { "d-flow-node__handle d-flow-node__handle--source" }
162164 position = { data . isParameter ? Position . Left : Position . Bottom }
163165 />
166+
167+ {
168+ isReferenced === true ? (
169+ < div className = { "d-flow-node__isReferenced" } style = { {
170+ position : "absolute" ,
171+ top : "50%" ,
172+ left : firstItem . id === id ? "-0.733rem" : "-0.5rem" ,
173+ transform : "translate(-100%, -50%)" ,
174+ display : "flex"
175+ } } >
176+ < IconVariable className = { "d-flow-node__isReferenced-icon" } color = { data . color } size = { 13 } />
177+ </ div >
178+ ) : null
179+ }
180+
181+
164182 < Flex align = { "center" } style = { { gap : "0.7rem" } } >
165183 < IconNote color = { data . color } size = { 16 } />
166184 < Text size = { "md" } > { displayMessage } </ Text >
167185 </ Flex >
168186 </ Card >
169187 ) ;
170188} )
189+
190+ type RGBA = {
191+ r : number
192+ g : number
193+ b : number
194+ a : number
195+ }
196+
197+ const clamp01 = ( v : number ) => Math . min ( Math . max ( v , 0 ) , 1 )
198+
199+ const parseCssColorToRgba = ( color : string ) : RGBA => {
200+ if ( typeof document === "undefined" ) {
201+ return { r : 0 , g : 0 , b : 0 , a : 1 }
202+ }
203+
204+ const el = document . createElement ( "span" )
205+ el . style . color = color
206+ document . body . appendChild ( el )
207+
208+ const computed = getComputedStyle ( el ) . color
209+ document . body . removeChild ( el )
210+
211+ const match = computed . match (
212+ / r g b a ? \( \s * ( [ \d . ] + ) \s * , \s * ( [ \d . ] + ) \s * , \s * ( [ \d . ] + ) (?: \s * , \s * ( [ \d . ] + ) ) ? \s * \) /
213+ )
214+
215+ if ( ! match ) {
216+ return { r : 0 , g : 0 , b : 0 , a : 1 }
217+ }
218+
219+ return {
220+ r : Math . round ( Number ( match [ 1 ] ) ) ,
221+ g : Math . round ( Number ( match [ 2 ] ) ) ,
222+ b : Math . round ( Number ( match [ 3 ] ) ) ,
223+ a : match [ 4 ] !== undefined ? Number ( match [ 4 ] ) : 1 ,
224+ }
225+ }
226+
227+ const mixColorRgb = ( color : string , level : number ) => {
228+ const w = clamp01 ( level * 0.1 )
229+
230+ const c1 = parseCssColorToRgba ( color )
231+ const c2 = parseCssColorToRgba ( "#070514" )
232+
233+ const mix = ( a : number , b : number ) =>
234+ Math . round ( a * ( 1 - w ) + b * w )
235+
236+ return `rgb(${ mix ( c1 . r , c2 . r ) } , ${ mix ( c1 . g , c2 . g ) } , ${ mix ( c1 . b , c2 . b ) } )`
237+ }
238+
239+ const withAlpha = ( color : string , alpha : number ) => {
240+ const c = parseCssColorToRgba ( color )
241+ return `rgba(${ c . r } , ${ c . g } , ${ c . b } , ${ clamp01 ( alpha ) } )`
242+ }
0 commit comments