Skip to content

Commit

Permalink
Merge pull request #675 from XYOracleNetwork/feature/popper-work
Browse files Browse the repository at this point in the history
module graph hover labels
  • Loading branch information
jonesmac authored Sep 28, 2023
2 parents 33f1ff6 + 7c5d3e2 commit 0062215
Show file tree
Hide file tree
Showing 26 changed files with 220 additions and 172 deletions.
4 changes: 2 additions & 2 deletions packages/sdk/packages/node-renderer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@xylabs/react-async-effect": "^3.0.6",
"@xylabs/react-flexbox": "^3.0.6",
"@xylabs/react-identicon": "^3.0.6",
"@xylabs/react-shared": "^3.0.6",
"@xyo-network/account-model": "^2.75.4",
"@xyo-network/archivist-model": "^2.75.4",
Expand All @@ -24,8 +25,7 @@
"@xyo-network/react-node": "workspace:~",
"@xyo-network/react-shared": "workspace:~",
"cytoscape": "^3.26.0",
"cytoscape-cola": "^2.5.1",
"cytoscape-popper": "^2.0.0"
"cytoscape-cola": "^2.5.1"
},
"peerDependencies": {
"@mui/icons-material": "^5",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CytoscapeOptions } from 'cytoscape'
import { LayoutOptions } from 'cytoscape'

export const ConcentricLayout: CytoscapeOptions['layout'] = {
export const ConcentricLayout: LayoutOptions = {
concentric: function (node) {
return node.degree()
},
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { forwardRef, useEffect, useState } from 'react'
import { useCytoscapeInstance } from '../contexts'
import { NodeRelationalGraphProps } from './lib'

export const NodeRelationalGraphFlexBox = forwardRef<HTMLDivElement, NodeRelationalGraphProps>(({ actions, options, ...props }, ref) => {
export const NodeRelationalGraphFlexBox = forwardRef<HTMLDivElement, NodeRelationalGraphProps>(({ actions, children, options, ...props }, ref) => {
const [cy, setCy] = useState<Core>()
const { setCy: setCyContext } = useCytoscapeInstance()
const sharedRef = useShareForwardedRef(ref)
Expand Down Expand Up @@ -43,6 +43,7 @@ export const NodeRelationalGraphFlexBox = forwardRef<HTMLDivElement, NodeRelatio
</ActionsContainer>
{/* Cytoscape Element */}
<FlexCol alignItems="stretch" height="100%" position="absolute" ref={sharedRef} width="100%"></FlexCol>
{children}
</FlexCol>
)
})
Expand Down
13 changes: 0 additions & 13 deletions packages/sdk/packages/node-renderer/src/components/WithCola.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { use } from 'cytoscape'
import cola from 'cytoscape-cola'
import popper from 'cytoscape-popper'
import { PropsWithChildren, useEffect, useState } from 'react'

export const WithExtensions: React.FC<PropsWithChildren> = ({ children }) => {
const [initialized, setInitialized] = useState(false)
useEffect(() => {
use(cola)
use(popper)
setInitialized(true)
}, [])

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export * from './lib'
export * from './ModuleCardParser'
export * from './module'
export * from './ProvidedNodeRenderer'
export * from './RelationalGraph'
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { FlexBoxProps } from '@xylabs/react-flexbox'
import { CytoscapeOptions } from 'cytoscape'
import { ReactNode } from 'react'
import { PropsWithChildren, ReactNode } from 'react'

export interface NodeRelationalGraphProps extends FlexBoxProps {
export interface NodeRelationalGraphProps extends PropsWithChildren<FlexBoxProps> {
actions?: ReactNode
options?: CytoscapeOptions
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Meta, StoryObj } from '@storybook/react'
import { MemoryArchivist, MemoryArchivistConfigSchema } from '@xyo-network/archivist'
import { IdWitness, IdWitnessConfigSchema } from '@xyo-network/id-plugin'

import { ModuleCardParser } from './ModuleCardParser'
import { ModuleCardParser } from './CardParser'

const meta: Meta<typeof ModuleCardParser> = {
component: ModuleCardParser,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { asArchivistInstance } from '@xyo-network/archivist-model'
import { asDivinerInstance } from '@xyo-network/diviner-model'
import { asArchivistInstance, isArchivistInstance } from '@xyo-network/archivist-model'
import { asDivinerInstance, isDivinerInstance } from '@xyo-network/diviner-model'
import { ModuleInstance } from '@xyo-network/module'
import { ArchivistCard } from '@xyo-network/react-archivist'
import { DivinerCard, ModuleCard } from '@xyo-network/react-module'
Expand All @@ -10,9 +10,9 @@ export interface ModuleCardParserProps {

export const ModuleCardParser: React.FC<ModuleCardParserProps> = ({ module }) => {
switch (true) {
case module?.config.schema.includes('archivist'):
case isArchivistInstance(module):
return <ArchivistCard module={asArchivistInstance(module)} />
case module?.config.schema.includes('diviner'):
case isDivinerInstance(module):
return <DivinerCard module={asDivinerInstance(module)} />
default:
return <ModuleCard module={module} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { useWallet, WalletProvider } from '@xyo-network/react-wallet'
import { MemorySentinel, SentinelConfigSchema } from '@xyo-network/sentinel'
import { useState } from 'react'

import { CytoscapeInstanceProvider } from '../contexts'
import { ModuleGraphFlexBox } from './ModuleGraphFlexBox'
import { CytoscapeInstanceProvider } from '../../../contexts'
import { ModuleGraphFlexBox } from './GraphFlexBox'

const nodeUrl = 'http://localhost:8080/node'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Button } from '@mui/material'
import { FlexBoxProps } from '@xylabs/react-flexbox'
import { ModuleInstance } from '@xyo-network/module'

import { useHoveredNode, useNewElements, useRelationalGraphOptions, useRenderNewElements, useSelectedElement } from '../../../hooks'
import { WithExtensions } from '../../cytoscape-extensions'
import { NodeRelationalGraphFlexBox } from '../../RelationalGraph'
import { ModuleGraphNodeHover } from './NodeHover'

export interface ModuleGraphFlexBoxProps extends FlexBoxProps {
rootModule?: ModuleInstance | null
}

export const ModuleGraphFlexBox: React.FC<ModuleGraphFlexBoxProps> = ({ rootModule, ...props }) => {
const { handleToggleLabels, hideLabels, options } = useRelationalGraphOptions(rootModule ?? undefined)
const selectedElement = useSelectedElement()
const newElements = useNewElements(selectedElement)
const renderedElements = useRenderNewElements(newElements, hideLabels)
const hoveredNode = useHoveredNode(renderedElements)

return (
<WithExtensions>
<NodeRelationalGraphFlexBox
actions={
<Button size={'small'} onClick={handleToggleLabels} variant="contained">
Toggle Labels
</Button>
}
options={options}
{...props}
>
<ModuleGraphNodeHover node={hoveredNode} />
</NodeRelationalGraphFlexBox>
</WithExtensions>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { NodeSingular } from 'cytoscape'
import { useLayoutEffect, useRef, useState } from 'react'

import { ModuleHoverPopper } from './Popper'

export interface ModuleHoverProps {
node?: NodeSingular
}

export const ModuleGraphNodeHover: React.FC<ModuleHoverProps> = ({ node }) => {
const { address, name } = node?.data() ?? {}
const [boundingBox, setBoundingBox] = useState(node?.renderedBoundingBox())
const ref = useRef<HTMLDivElement>(null)
const [currentEl, setCurrentEl] = useState<HTMLDivElement | null>(null)

useLayoutEffect(() => {
if (node && ref.current) {
setBoundingBox(node.renderedBoundingBox())
setCurrentEl(ref.current)
}

const listener = () => {
setBoundingBox(node?.renderedBoundingBox())
}

node?.on('position', listener)

return () => {
node?.off('position', undefined, listener)
}
}, [node])

return (
<>
{node ? (
<>
<div
ref={ref}
style={{
// backgroundColor: '#fff',
// opacity: 0.25,
cursor: 'pointer',
height: boundingBox?.h,
left: boundingBox?.x1,
pointerEvents: 'none',
position: 'absolute',
top: boundingBox?.y1,
width: boundingBox?.w,
}}
></div>
<ModuleHoverPopper address={address} element={currentEl} name={name} placement={'top'} open />
</>
) : null}
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { alpha, Chip, Popper, PopperProps, Theme, Typography } from '@mui/material'
import { FlexCol, FlexRow } from '@xylabs/react-flexbox'
import { Identicon } from '@xylabs/react-identicon'

export interface ModuleHoverPopperProps extends PopperProps {
address?: string
element?: HTMLElement | null
name?: string
}

export const ModuleHoverPopper: React.FC<ModuleHoverPopperProps> = ({ address, element, name, ...props }) => {
return (
<Popper anchorEl={element} {...props}>
<FlexCol gap={2} p={2} paper sx={{ backgroundColor: (theme: Theme) => alpha(theme.palette.background.paper, 0.95) }}>
<FlexRow gap={2}>
<Identicon value={address} size={24} />
<Typography>{name}</Typography>
</FlexRow>
<Chip label={address} color={'primary'} />
</FlexCol>
</Popper>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './GraphFlexBox'
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './CardParser'
export * from './graph'
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './useAddNewElements'
export * from './useCytoscapeElements'
export * from './useCytoscapeOptions'
export * from './useHoveredNode'
export * from './useNewElements'
export * from './usePopperListener'
export * from './useRelationalGraphOptions'
export * from './useRenderNewElements'
export * from './useSelectedElement'

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { NodeCollection, NodeSingular } from 'cytoscape'
import { useCallback, useEffect, useState } from 'react'

import { useCytoscapeInstance } from '../../contexts'

export const useHoveredNode = (renderedElements?: NodeCollection) => {
const { cy } = useCytoscapeInstance(true)
const [hoveredNode, setHoveredNode] = useState<NodeSingular>()

const nodeListener = useCallback((node: NodeSingular) => {
node.on('mouseover tap', () => {
setHoveredNode(node)
})
node.on('mouseout', () => {
setHoveredNode(undefined)
})
}, [])

useEffect(() => {
if (renderedElements) {
renderedElements.nodes().forEach(nodeListener)
}
}, [nodeListener, renderedElements])

useEffect(() => {
cy?.ready(() => {
cy.nodes().forEach(nodeListener)
})
}, [cy, nodeListener])

return hoveredNode
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useModuleFromNode } from '@xyo-network/react-node'
import { NodeDataDefinition } from 'cytoscape'
import { useEffect, useState } from 'react'
import { NodeSingular } from 'cytoscape'
import { useEffect } from 'react'

import { useCytoscapeInstance } from '../../contexts'
import { useCytoscapeElements } from './useCytoscapeElements'

export const useNewElements = () => {
export const useNewElements = (selectedElement?: NodeSingular) => {
const { cy } = useCytoscapeInstance(true)
const [selectedElement, setSelectedElement] = useState<NodeDataDefinition>()
const { address: selectedAddress } = selectedElement?.data() ?? {}
const [module] = useModuleFromNode(selectedAddress)
const newElements = useCytoscapeElements(module)
Expand All @@ -19,5 +18,5 @@ export const useNewElements = () => {
}
}, [cy, selectedAddress])

return { newElements, setSelectedElement }
return newElements
}
Loading

0 comments on commit 0062215

Please sign in to comment.