Skip to content
Open

Dev #21

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,125 changes: 378 additions & 747 deletions examples/package-lock.json

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,26 @@
},
"dependencies": {
"@emotion/styled": "^11.14.1",
"@mui/material": "^7.3.6",
"@mui/styled-engine-sc": "^7.3.6",
"@mui/material": "^9.3.1",
"@mui/styled-engine-sc": "^9.3.0",
"@yworks/react-yfiles-orgchart": "../",
"react": "^19.2.3",
"react-dom": "^19.2.3",
"react-router-dom": "^7.10.1",
"styled-components": "^6.1.19"
"react": "^19.2.8",
"react-dom": "^19.2.8",
"react-router-dom": "^7.18.2",
"styled-components": "^6.5.1"
},
"devDependencies": {
"@playwright/test": "^1.57.0",
"@playwright/test": "^1.62.1",
"@types/node": "^25.0.0",
"@types/react": "^19.2.7",
"@types/react-dom": "^19.2.3",
"@typescript-eslint/eslint-plugin": "^8.49.0",
"@typescript-eslint/parser": "^8.49.0",
"@vitejs/plugin-react": "^6.0.2",
"eslint": "^9.39.1",
"eslint-plugin-react-hooks": "^7.0.1",
"eslint-plugin-react-refresh": "^0.4.24",
"typescript": "^5.9.3",
"vite": "^8.0.16"
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.4",
"@typescript-eslint/eslint-plugin": "^8.66.0",
"@typescript-eslint/parser": "^8.66.0",
"@vitejs/plugin-react": "^6.0.5",
"eslint": "^10.8.1",
"eslint-plugin-react-hooks": "^7.1.1",
"eslint-plugin-react-refresh": "^0.5.3",
"typescript": "^6.0.3",
"vite": "^8.2.0"
}
}
5 changes: 3 additions & 2 deletions examples/tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"compilerOptions": {
"target": "ES2020",
"target": "es2023",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"lib": ["es2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

Expand All @@ -13,6 +13,7 @@
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["node"],

/* Linting */
"strict": true,
Expand Down
5 changes: 3 additions & 2 deletions examples/tsconfig.node.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "bundler",
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": true,
"types": ["node"]
},
"include": ["vite.config.ts"]
"include": ["vite.config.ts", "playwright.config.ts"]
}
17 changes: 9 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yworks/react-yfiles-orgchart",
"version": "2.1.1",
"version": "3.0.0",
"author": {
"name": "yFiles for HTML team @ yWorks GmbH",
"email": "yfileshtml@yworks.com"
Expand Down Expand Up @@ -38,23 +38,24 @@
"types": "./dist/index.d.ts",
"scripts": {
"tsc": "tsc",
"dev": "tsup --watch --sourcemap --dts --format esm src/index.ts && api-extractor run --local",
"build": "tsup --clean --dts --format esm src/index.ts && api-extractor run --local"
"dev": "tsdown --watch --sourcemap --dts --format esm src/index.ts && api-extractor run --local",
"build": "tsdown --clean --dts --format esm src/index.ts && api-extractor run --local"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18",
"@yfiles/yfiles": ">=30"
"@yfiles/yfiles": ">=31"
},
"devDependencies": {
"@types/react": ">=18",
"@types/react-dom": ">=18",
"@microsoft/api-extractor": "^7.55.2",
"tsup": "^8.5.1",
"typescript": "^5.9.3"
"@microsoft/api-extractor": "^7.58.12",
"tsdown": "^0.22.14",
"@tsdown/css": "^0.22.14",
"typescript": "^6.0.3"
},
"dependencies": {
"@yworks/react-yfiles-core": "^3.1.0"
"@yworks/react-yfiles-core": "^4.0.0"
},
"files": [
"LICENSE",
Expand Down
55 changes: 25 additions & 30 deletions src/OrgChart.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import {
ComponentType,
CSSProperties,
Dispatch,
PropsWithChildren,
SetStateAction,
type ComponentType,
type CSSProperties,
type Dispatch,
type JSX,
type PropsWithChildren,
type SetStateAction,
useEffect,
useLayoutEffect,
useMemo,
Expand All @@ -12,29 +13,29 @@ import {
import {
Arrow,
ArrowType,
FilteredGraphWrapper,
GraphComponent,
GraphViewerInputMode,
IGraph,
INode,
type FilteredGraphWrapper,
type GraphComponent,
type GraphViewerInputMode,
type IGraph,
type INode,
PolylineEdgeStyle,
Size
} from '@yfiles/yfiles'
import {
checkLicense,
checkStylesheetLoaded,
ContextMenu,
ContextMenuItemProvider,
EdgeStyle as ConnectionStyle,
type ContextMenuItemProvider,
type EdgeStyle as ConnectionStyle,
LicenseError,
NodeRenderInfo,
type NodeRenderInfo,
Popup,
ReactComponentHtmlNodeStyle,
ReactNodeRendering,
RenderContextMenuProps,
RenderNodeProps as RenderItemProps,
RenderPopupProps,
RenderTooltipProps,
type RenderContextMenuProps,
type RenderNodeProps as RenderItemProps,
type RenderPopupProps,
type RenderTooltipProps,
Tooltip,
useGraphSearch,
useReactNodeRendering,
Expand All @@ -56,7 +57,7 @@ import {
import { setPortStylesToFirstOutgoingPorts } from './styles/orgchart-port-style.ts'
import { RenderOrgChartItem } from './styles/Templates.tsx'
import { initializeGraphManager } from './core/data-loading.ts'
import { OrgChartModel, OrgChartModelInternal } from './OrgChartModel.ts'
import type { OrgChartModel, OrgChartModelInternal } from './OrgChartModel.ts'

/**
* The item's unique id.
Expand Down Expand Up @@ -250,14 +251,7 @@ export interface OrgChartProps<TOrgChartItem extends OrgChartItem, TNeedle> {
* The optional position of the popup. The default is 'top'.
*/
popupPosition?:
| 'right'
| 'top'
| 'top-right'
| 'top-left'
| 'bottom'
| 'bottom-right'
| 'bottom-left'
| 'left'
'right' | 'top' | 'top-right' | 'top-left' | 'bottom' | 'bottom-right' | 'bottom-left' | 'left'
/**
* An optional component used for rendering a custom popup.
*/
Expand Down Expand Up @@ -300,7 +294,7 @@ function App() {
*/
export function OrgChart<TOrgChartItem extends OrgChartItem = CustomOrgChartItem, TNeedle = string>(
props: OrgChartProps<TOrgChartItem, TNeedle> & PropsWithChildren
) {
): JSX.Element {
if (!checkLicense()) {
return (
<LicenseError
Expand Down Expand Up @@ -382,7 +376,7 @@ const OrgChartCore = withGraphComponent(
useEffect(() => {
const hoverItemChangedListener = initializeHover(onItemHover, graphComponent)

return () => {
return (): void => {
// clean up
hoverItemChangedListener &&
(graphComponent.inputMode as GraphViewerInputMode).itemHoverInputMode.removeEventListener(
Expand All @@ -404,7 +398,7 @@ const OrgChartCore = withGraphComponent(
(graphComponent.graph as FilteredGraphWrapper).wrappedGraph!
)

return () => {
return (): void => {
// clean up the listeners
currentItemChangedListener &&
graphComponent.removeEventListener('current-item-changed', currentItemChangedListener)
Expand All @@ -425,7 +419,8 @@ const OrgChartCore = withGraphComponent(

const graphSearch = useGraphSearch(graphComponent, searchNeedle, onSearch)
// provide search hits on the context
orgChartGraph.getSearchHits = () => graphSearch.matchingNodes.map((n: INode) => n.tag)
orgChartGraph.getSearchHits = (): TOrgChartItem[] =>
graphSearch.matchingNodes.map((n: INode) => n.tag)

// fit graph after initial measurement
const [finishedInitialMeasurement, setFinishedInitialMeasurement] = useState(false)
Expand Down
12 changes: 6 additions & 6 deletions src/OrgChartModel.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { GraphComponent, Command, IEdge, IGraph, INode } from '@yfiles/yfiles'
import { OrgChartConnection, OrgChartItem } from './OrgChart'
import { CollapsibleTree } from './core/CollapsibleTree'
import { Command, type GraphComponent, type IEdge, type IGraph, type INode } from '@yfiles/yfiles'
import type { OrgChartConnection, OrgChartItem } from './OrgChart'
import { type CollapsibleTree } from './core/CollapsibleTree'
import {
exportImageAndSave,
type ExportSettings,
Expand Down Expand Up @@ -161,15 +161,15 @@ export function createOrgChartModel(

// this is a hack so we have something like `await nextTick()`
// that we can use instead of `setTimeout()`
const setRenderedCallback = (cb: () => void) => {
const setRenderedCallback = (cb: () => void): void => {
onRenderedCallback = cb
}
const onRendered = () => {
const onRendered = (): void => {
onRenderedCallback?.()
onRenderedCallback = null
}

function zoomTo(items: (OrgChartItem | OrgChartConnection<OrgChartItem>)[]) {
function zoomTo(items: (OrgChartItem | OrgChartConnection<OrgChartItem>)[]): void {
if (items.length === 0) {
return
}
Expand Down
43 changes: 22 additions & 21 deletions src/OrgChartProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { createContext, PropsWithChildren, useContext, useMemo } from 'react'
import { createContext, type JSX, type PropsWithChildren, useContext, useMemo } from 'react'
import { CollapsibleTree } from './core/CollapsibleTree'
import type { GraphComponent, INode } from '@yfiles/yfiles'
import { useGraphComponent, withGraphComponentProvider } from '@yworks/react-yfiles-core'
import { createOrgChartModel, OrgChartModel } from './OrgChartModel'
import { createOrgChartModel, type OrgChartModel } from './OrgChartModel'

const OrgChartContext = createContext<OrgChartModel | null>(null)

Expand Down Expand Up @@ -95,25 +95,26 @@ const gcToModel = new WeakMap<GraphComponent, OrgChartModel>()
* }
* ```
*/
export const OrgChartProvider = withGraphComponentProvider(({ children }: PropsWithChildren) => {
const graphComponent = useGraphComponent()
export const OrgChartProvider: (props: PropsWithChildren) => JSX.Element =
withGraphComponentProvider(({ children }: PropsWithChildren) => {
const graphComponent = useGraphComponent()

if (!graphComponent) {
return children
}

const orgChart = useMemo(() => {
if (gcToModel.has(graphComponent)) {
return gcToModel.get(graphComponent)!
if (!graphComponent) {
return children
}
const collapsibleTree = new CollapsibleTree(graphComponent)
graphComponent.graph = collapsibleTree.filteredGraph
collapsibleTree.isAssistantNode = (node: INode): boolean => node.tag?.assistant ?? false
// TODO provide customizable out-edge comparer
const orgChartModel = createOrgChartModel(collapsibleTree, graphComponent)
gcToModel.set(graphComponent, orgChartModel)
return orgChartModel
}, [graphComponent])

return <OrgChartContext.Provider value={orgChart}>{children}</OrgChartContext.Provider>
})
const orgChart = useMemo(() => {
if (gcToModel.has(graphComponent)) {
return gcToModel.get(graphComponent)!
}
const collapsibleTree = new CollapsibleTree(graphComponent)
graphComponent.graph = collapsibleTree.filteredGraph
collapsibleTree.isAssistantNode = (node: INode): boolean => node.tag?.assistant ?? false
// TODO provide customizable out-edge comparer
const orgChartModel = createOrgChartModel(collapsibleTree, graphComponent)
gcToModel.set(graphComponent, orgChartModel)
return orgChartModel
}, [graphComponent])

return <OrgChartContext.Provider value={orgChart}>{children}</OrgChartContext.Provider>
})
14 changes: 8 additions & 6 deletions src/core/CollapsibleTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import {
LayoutAnchoringPolicy,
LayoutAnchoringStage,
LayoutAnchoringStageData,
LayoutData,
type LayoutData,
LayoutExecutor,
type LayoutGraph,
type LayoutNode,
Expand Down Expand Up @@ -367,7 +367,7 @@ export class CollapsibleTree {
this._graphComponent.fitGraphBounds()
}

isTree() {
isTree(): boolean {
return new GraphStructureAnalyzer(this.completeGraph).isTree()
}

Expand Down Expand Up @@ -419,7 +419,7 @@ export class CollapsibleTree {
this._graphComponent.zoomToAnimated(targetBounds.toRect().getEnlarged(200))
}

private unhideNode(item: INode) {
private unhideNode(item: INode): void {
if (!this.filteredGraph.nodes.includes(item)) {
// the given node is hidden, make it visible
this.showItem(item)
Expand Down Expand Up @@ -478,7 +478,7 @@ export class CollapsibleTree {
// we mark a node as the center node
layoutData.items.add(
new LayoutAnchoringStageData({
nodeAnchoringPolicies: node =>
nodeAnchoringPolicies: (node: INode): LayoutAnchoringPolicy =>
centerNode === node ? LayoutAnchoringPolicy.CENTER : LayoutAnchoringPolicy.NONE
})
)
Expand Down Expand Up @@ -569,9 +569,11 @@ export class CollapsibleTree {
})
}

private createConfiguredNonTreeLayoutData(incrementalNodes: Set<INode> = new Set()) {
private createConfiguredNonTreeLayoutData(
incrementalNodes: Set<INode> = new Set()
): HierarchicalLayoutData {
return new HierarchicalLayoutData({
sourceGroupIds: (edge: IEdge) => edge.sourceNode + '_source',
sourceGroupIds: (edge: IEdge): string => edge.sourceNode + '_source',
incrementalNodes: incrementalNodes
})
}
Expand Down
Loading