@likec4/diagram 1.0.0-rc.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.props.d.ts +6 -3
- package/dist/StaticLikeC4Diagram.d.ts +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.mjs +124 -221
- package/dist/mantine/EnsureMantine.d.ts +2 -3
- package/dist/style.css +4 -33
- package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -1
- package/dist/xyflow/types.d.ts +1 -1
- package/package.json +14 -12
- package/src/LikeC4Diagram.props.ts +12 -8
- package/src/LikeC4Diagram.tsx +3 -3
- package/src/StaticLikeC4Diagram.tsx +0 -1
- package/src/globals.css.ts +1 -1
- package/src/index.ts +1 -2
- package/src/mantine/EnsureMantine.tsx +8 -18
- package/src/mantine/theme.ts +1 -0
- package/src/ui/KeepAspectRatio.css.ts +2 -2
- package/src/ui/OptionsPanel.tsx +1 -1
- package/src/ui/options/NodeOptions.tsx +1 -2
- package/src/xyflow/FitviewOnDiagramChange.tsx +1 -1
- package/src/xyflow/SyncWithDiagram.tsx +23 -81
- package/src/xyflow/XYFlowEvents.tsx +1 -2
- package/src/xyflow/XYFlowWrapper.tsx +3 -7
- package/src/xyflow/edges/RelationshipEdge.tsx +4 -5
- package/src/xyflow/edges/edges.css.ts +7 -4
- package/src/xyflow/nodes/compound/CompoundNode.css.ts +3 -2
- package/src/xyflow/nodes/compound/CompoundNode.tsx +2 -2
- package/src/xyflow/nodes/element/ElementIcon.tsx +1 -3
- package/src/xyflow/nodes/element/ElementLink.css.ts +2 -2
- package/src/xyflow/nodes/element/ElementLink.tsx +3 -3
- package/src/xyflow/nodes/element/ElementNode.tsx +0 -2
- package/src/xyflow/nodes/element/element.css.ts +4 -4
- package/src/xyflow/types.ts +11 -2
- package/dist/EmbeddedLikeC4Diagram.css.d.ts +0 -5
- package/dist/EmbeddedLikeC4Diagram.d.ts +0 -17
- package/src/EmbeddedLikeC4Diagram.css.ts +0 -35
- package/src/EmbeddedLikeC4Diagram.tsx +0 -101
package/dist/style.css
CHANGED
|
@@ -724,27 +724,6 @@ svg.react-flow__connectionline {
|
|
|
724
724
|
--likec4-relation-lineColor: #6366f1;
|
|
725
725
|
--likec4-relation-labelBg: #1e1b4b;
|
|
726
726
|
--likec4-relation-labelColor: #818cf8;
|
|
727
|
-
}._1yqpph0 {
|
|
728
|
-
background-color: transparent;
|
|
729
|
-
}
|
|
730
|
-
._1yqpph1 {
|
|
731
|
-
padding: 0;
|
|
732
|
-
height: 100%;
|
|
733
|
-
}
|
|
734
|
-
._1yqpph2 {
|
|
735
|
-
position: absolute;
|
|
736
|
-
top: 1rem;
|
|
737
|
-
left: 1rem;
|
|
738
|
-
}
|
|
739
|
-
._1yqpph3 {
|
|
740
|
-
position: absolute;
|
|
741
|
-
top: 1rem;
|
|
742
|
-
right: 1rem;
|
|
743
|
-
}
|
|
744
|
-
@media (min-width: 62em) {
|
|
745
|
-
._1yqpph4 {
|
|
746
|
-
--cb-size: var(--cb-size-lg);
|
|
747
|
-
}
|
|
748
727
|
}.react-flow._2h8g8h0 {
|
|
749
728
|
--xy-background-color: var(--likec4-background-color);
|
|
750
729
|
--xy-background-pattern-color: var(--likec4-background-pattern-color);
|
|
@@ -761,9 +740,7 @@ svg.react-flow__connectionline {
|
|
|
761
740
|
display: none;
|
|
762
741
|
}._14qhjro0 {
|
|
763
742
|
width: 100%;
|
|
764
|
-
width: -webkit-fill-available;
|
|
765
743
|
height: 100%;
|
|
766
|
-
height: -webkit-fill-available;
|
|
767
744
|
padding: 0;
|
|
768
745
|
}._1lmzt1h0 {
|
|
769
746
|
top: var(--likec4-options-panel-top, 1rem);
|
|
@@ -779,7 +756,7 @@ svg.react-flow__connectionline {
|
|
|
779
756
|
}
|
|
780
757
|
[data-mantine-color-scheme="dark"] .bexn7q0 {
|
|
781
758
|
--xy-edge-label-color: var(--likec4-relation-labelColor);
|
|
782
|
-
--xy-edge-label-background-color: color-mix(in srgb, var(--likec4-relation-labelBg), transparent
|
|
759
|
+
--xy-edge-label-background-color: color-mix(in srgb, var(--likec4-relation-labelBg), transparent 55%);
|
|
783
760
|
}
|
|
784
761
|
.bexn7q0[data-edge-hovered='true'] {
|
|
785
762
|
--xy-edge-stroke: color-mix(in srgb, var(--likec4-relation-lineColor), white 30%);
|
|
@@ -789,6 +766,9 @@ svg.react-flow__connectionline {
|
|
|
789
766
|
--xy-edge-stroke-width: 2.5;
|
|
790
767
|
}
|
|
791
768
|
.react-flow__edges > svg {
|
|
769
|
+
mix-blend-mode: screen;
|
|
770
|
+
}
|
|
771
|
+
:where([data-mantine-color-scheme="dark"]) .react-flow__edges > svg {
|
|
792
772
|
mix-blend-mode: lighten;
|
|
793
773
|
}
|
|
794
774
|
.bexn7q1 {
|
|
@@ -825,9 +805,6 @@ svg.react-flow__connectionline {
|
|
|
825
805
|
transform: var(--bexn7q6);
|
|
826
806
|
will-change: transform;
|
|
827
807
|
}
|
|
828
|
-
[data-mantine-color-scheme="dark"] .bexn7q7 {
|
|
829
|
-
mix-blend-mode: luminosity;
|
|
830
|
-
}
|
|
831
808
|
.bexn7q7[data-edge-hovered="true"] {
|
|
832
809
|
transition: all 140ms ease-out;
|
|
833
810
|
transform: var(--bexn7q6) scale(1.1);
|
|
@@ -847,9 +824,7 @@ svg.react-flow__connectionline {
|
|
|
847
824
|
}
|
|
848
825
|
.lbtzdo0 {
|
|
849
826
|
width: 100%;
|
|
850
|
-
width: -webkit-fill-available;
|
|
851
827
|
height: 100%;
|
|
852
|
-
height: -webkit-fill-available;
|
|
853
828
|
position: relative;
|
|
854
829
|
padding: 0;
|
|
855
830
|
margin: 0;
|
|
@@ -992,9 +967,7 @@ svg.react-flow__connectionline {
|
|
|
992
967
|
--_1b6tkn0: color-mix(in srgb, var(--likec4-element-stroke) 90%, var(--likec4-element-fill));
|
|
993
968
|
position: relative;
|
|
994
969
|
width: 100%;
|
|
995
|
-
width: -webkit-fill-available;
|
|
996
970
|
height: 100%;
|
|
997
|
-
height: -webkit-fill-available;
|
|
998
971
|
padding: 0;
|
|
999
972
|
margin: 0;
|
|
1000
973
|
}
|
|
@@ -1076,9 +1049,7 @@ svg.react-flow__connectionline {
|
|
|
1076
1049
|
--_1b6tkn1: calc(1.5rem * var(--mantine-scale));
|
|
1077
1050
|
position: relative;
|
|
1078
1051
|
width: 100%;
|
|
1079
|
-
width: -webkit-fill-available;
|
|
1080
1052
|
height: 100%;
|
|
1081
|
-
height: -webkit-fill-available;
|
|
1082
1053
|
padding: var(--_1b6tkn1);
|
|
1083
1054
|
display: flex;
|
|
1084
1055
|
flex-direction: column;
|
|
@@ -6,5 +6,5 @@ type ElementIconProps = {
|
|
|
6
6
|
paddingX?: number | undefined;
|
|
7
7
|
paddingY?: number | undefined;
|
|
8
8
|
};
|
|
9
|
-
export declare function ElementIcon({ node,
|
|
9
|
+
export declare function ElementIcon({ node, paddingY }: ElementIconProps): JSX.Element | null;
|
|
10
10
|
export {};
|
package/dist/xyflow/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SetReadonly, SetRequired, Simplify } from 'type-fest';
|
|
2
2
|
import { MouseEvent as ReactMouseEvent } from 'react';
|
|
3
|
-
import { Edge, InternalNode, Node,
|
|
3
|
+
import { Edge, EdgeMouseHandler, InternalNode, Node, NodeMouseHandler, OnMoveEnd, OnMoveStart, ReactFlowInstance, ReactFlowState } from '@xyflow/react';
|
|
4
4
|
import { BBox, DiagramEdge, DiagramNode, Fqn, Point } from '@likec4/core';
|
|
5
5
|
|
|
6
6
|
export type ElementNodeData = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/diagram",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -40,19 +40,17 @@
|
|
|
40
40
|
"./style.css": "./dist/style.css"
|
|
41
41
|
}
|
|
42
42
|
},
|
|
43
|
-
"packageManager": "yarn@4.
|
|
43
|
+
"packageManager": "yarn@4.2.2",
|
|
44
44
|
"scripts": {
|
|
45
45
|
"typecheck": "tsc",
|
|
46
46
|
"prepack": "vite build --mode production",
|
|
47
47
|
"build:turbo": "run -T turbo build --filter='diagram'",
|
|
48
48
|
"build": "vite build --mode development && tsc -b",
|
|
49
49
|
"lint": "run -T eslint src/ --fix",
|
|
50
|
-
"clean": "run -T rimraf -v dist/* .tsbuildinfo"
|
|
50
|
+
"clean": "run -T rimraf -v -g 'dist/*' .tsbuildinfo"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@likec4/core": "1.0.
|
|
54
|
-
"@mantine/core": "^7.9.0",
|
|
55
|
-
"@mantine/hooks": "^7.9.0",
|
|
53
|
+
"@likec4/core": "1.0.1",
|
|
56
54
|
"@react-hookz/web": "^24.0.4",
|
|
57
55
|
"esm-env": "^1.0.0",
|
|
58
56
|
"fast-equals": "^5.0.1",
|
|
@@ -61,27 +59,31 @@
|
|
|
61
59
|
"zustand": "^4.5.2"
|
|
62
60
|
},
|
|
63
61
|
"peerDependencies": {
|
|
64
|
-
"
|
|
65
|
-
"
|
|
62
|
+
"@mantine/core": "^7.9.0",
|
|
63
|
+
"@mantine/hooks": "^7.9.0",
|
|
64
|
+
"react": "^18.3.1",
|
|
65
|
+
"react-dom": "^18.3.1"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@lume/kiwi": "^0.4.3",
|
|
69
|
+
"@mantine/core": "^7.9.0",
|
|
70
|
+
"@mantine/hooks": "^7.9.0",
|
|
69
71
|
"@mantine/vanilla-extract": "^7.9.0",
|
|
70
72
|
"@total-typescript/ts-reset": "^0.5.1",
|
|
71
|
-
"@types/react": "
|
|
72
|
-
"@types/react-dom": "
|
|
73
|
+
"@types/react": "18.2.0",
|
|
74
|
+
"@types/react-dom": "18.2.4",
|
|
73
75
|
"@vanilla-extract/css": "^1.15.1",
|
|
74
76
|
"@vanilla-extract/dynamic": "^2.1.0",
|
|
75
77
|
"@vanilla-extract/esbuild-plugin": "^2.3.5",
|
|
76
78
|
"@vitejs/plugin-react": "^4.2.1",
|
|
77
|
-
"@xyflow/react": "^12.0.0-next
|
|
79
|
+
"@xyflow/react": "^12.0.0-next",
|
|
78
80
|
"clsx": "^2.1.1",
|
|
79
81
|
"execa": "^8.0.1",
|
|
80
82
|
"khroma": "^2.1.0",
|
|
81
83
|
"react": "^18.2.0",
|
|
82
84
|
"react-dom": "^18.2.0",
|
|
83
85
|
"tilg": "^0.1.1",
|
|
84
|
-
"type-fest": "^4.18.
|
|
86
|
+
"type-fest": "^4.18.2",
|
|
85
87
|
"typescript": "^5.4.5",
|
|
86
88
|
"unbuild": "^2.0.0",
|
|
87
89
|
"vite": "^5.2.11",
|
|
@@ -15,12 +15,14 @@ import type { XYBackgroundProps } from './xyflow/XYFlowBackground'
|
|
|
15
15
|
|
|
16
16
|
export type DiagramNodeWithNavigate = Simplify<SetRequired<DiagramNode, 'navigateTo'>>
|
|
17
17
|
|
|
18
|
-
export type OnNavigateTo =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
export type OnNavigateTo = {
|
|
19
|
+
(
|
|
20
|
+
to: ViewID,
|
|
21
|
+
event: ReactMouseEvent,
|
|
22
|
+
element: DiagramNodeWithNavigate,
|
|
23
|
+
xynode: XYFlowNode
|
|
24
|
+
): void
|
|
25
|
+
}
|
|
24
26
|
export type OnNodeClick = (
|
|
25
27
|
event: {
|
|
26
28
|
element: DiagramNode
|
|
@@ -62,7 +64,9 @@ export type Change =
|
|
|
62
64
|
export type ChangeEvent = {
|
|
63
65
|
changes: NonEmptyArray<Change>
|
|
64
66
|
}
|
|
65
|
-
export type OnChange =
|
|
67
|
+
export type OnChange = {
|
|
68
|
+
(event: ChangeEvent): void
|
|
69
|
+
}
|
|
66
70
|
export type LikeC4ColorScheme = 'light' | 'dark'
|
|
67
71
|
|
|
68
72
|
export interface LikeC4DiagramProperties {
|
|
@@ -76,7 +80,7 @@ export interface LikeC4DiagramProperties {
|
|
|
76
80
|
*
|
|
77
81
|
* @example 'light' | 'dark'
|
|
78
82
|
*/
|
|
79
|
-
colorScheme?: LikeC4ColorScheme | undefined
|
|
83
|
+
// colorScheme?: LikeC4ColorScheme | undefined
|
|
80
84
|
|
|
81
85
|
/**
|
|
82
86
|
* Show/hide controls menu
|
package/src/LikeC4Diagram.tsx
CHANGED
|
@@ -5,7 +5,8 @@ import { rootClassName } from './globals.css'
|
|
|
5
5
|
import { cssDisablePan, cssNoControls, cssReactFlow, cssTransparentBg } from './LikeC4Diagram.css'
|
|
6
6
|
import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
|
|
7
7
|
import { EnsureMantine } from './mantine/EnsureMantine'
|
|
8
|
-
import { DiagramContextProvider
|
|
8
|
+
import { DiagramContextProvider } from './state/DiagramContext'
|
|
9
|
+
import { WhenInitialized } from './state/WhenInitialized'
|
|
9
10
|
import { KeepAspectRatio } from './ui/KeepAspectRatio'
|
|
10
11
|
import OptionsPanel from './ui/OptionsPanel'
|
|
11
12
|
import { diagramViewToXYFlowData } from './xyflow/diagram-to-xyflow'
|
|
@@ -20,7 +21,6 @@ export function LikeC4Diagram({
|
|
|
20
21
|
className,
|
|
21
22
|
fitView = true,
|
|
22
23
|
fitViewPadding = 0,
|
|
23
|
-
colorScheme,
|
|
24
24
|
readonly = true,
|
|
25
25
|
pannable = true,
|
|
26
26
|
zoomable = true,
|
|
@@ -61,7 +61,7 @@ export function LikeC4Diagram({
|
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
63
|
return (
|
|
64
|
-
<EnsureMantine
|
|
64
|
+
<EnsureMantine>
|
|
65
65
|
<XYFlowProvider
|
|
66
66
|
fitView={fitView}
|
|
67
67
|
{...initialRef.current}
|
package/src/globals.css.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ThemeColor } from '@likec4/core'
|
|
2
2
|
import { defaultTheme } from '@likec4/core'
|
|
3
|
-
import { createGlobalTheme
|
|
3
|
+
import { createGlobalTheme } from '@vanilla-extract/css'
|
|
4
4
|
import { omit } from 'remeda'
|
|
5
5
|
import { mantine } from './mantine.css'
|
|
6
6
|
import { vars } from './theme.css'
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import '@xyflow/react/dist/style.css'
|
|
2
2
|
import './globals.css'
|
|
3
3
|
|
|
4
|
-
export { EmbeddedLikeC4Diagram } from './EmbeddedLikeC4Diagram'
|
|
5
4
|
export { LikeC4Diagram } from './LikeC4Diagram'
|
|
6
5
|
export { StaticLikeC4Diagram } from './StaticLikeC4Diagram'
|
|
7
6
|
|
|
8
|
-
export
|
|
7
|
+
export * from './hooks'
|
|
9
8
|
export type * from './LikeC4Diagram'
|
|
10
9
|
export type * from './LikeC4Diagram.props'
|
|
11
10
|
export type * from './StaticLikeC4Diagram'
|
|
@@ -1,24 +1,14 @@
|
|
|
1
|
-
import { MantineContext
|
|
1
|
+
import { MantineContext } from '@mantine/core'
|
|
2
2
|
import { type PropsWithChildren, useContext } from 'react'
|
|
3
|
-
import type { LikeC4DiagramProperties } from '../LikeC4Diagram.props'
|
|
4
|
-
import { theme } from './theme'
|
|
5
3
|
|
|
6
|
-
type EnsureMantineProps = PropsWithChildren<
|
|
4
|
+
type EnsureMantineProps = PropsWithChildren<{}>
|
|
7
5
|
|
|
8
|
-
export function EnsureMantine({
|
|
6
|
+
export function EnsureMantine({ children }: EnsureMantineProps) {
|
|
9
7
|
const mantineCtx = useContext(MantineContext)
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
|
|
9
|
+
if (!mantineCtx) {
|
|
10
|
+
throw new Error('LikeC4Diagram must be a child of MantineProvider')
|
|
12
11
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{...(colorScheme && {
|
|
16
|
-
forceColorScheme: colorScheme
|
|
17
|
-
})}
|
|
18
|
-
theme={theme}
|
|
19
|
-
defaultColorScheme="auto"
|
|
20
|
-
>
|
|
21
|
-
{children}
|
|
22
|
-
</MantineProvider>
|
|
23
|
-
)
|
|
12
|
+
|
|
13
|
+
return <>{children}</>
|
|
24
14
|
}
|
package/src/mantine/theme.ts
CHANGED
package/src/ui/OptionsPanel.tsx
CHANGED
|
@@ -11,7 +11,7 @@ const OptionsPanelMemo = /* @__PURE__ */ memo(function OptionsPanel() {
|
|
|
11
11
|
const [selectedNodes, setSelectedNodes] = useState([] as string[])
|
|
12
12
|
|
|
13
13
|
useOnSelectionChange({
|
|
14
|
-
onChange: ({ nodes
|
|
14
|
+
onChange: ({ nodes }) => {
|
|
15
15
|
const next = nodes.map(n => n.id).sort()
|
|
16
16
|
setSelectedNodes(prev => {
|
|
17
17
|
return shallowEqual(prev, next) ? prev : next
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from '@mantine/core'
|
|
22
22
|
import { hasAtLeast, keys, takeWhile } from 'remeda'
|
|
23
23
|
import { useDiagramStoreApi } from '../../state'
|
|
24
|
-
import {
|
|
24
|
+
import { useXYNodesData } from '../../xyflow/hooks'
|
|
25
25
|
import { XYFlowNode } from '../../xyflow/types'
|
|
26
26
|
|
|
27
27
|
// const ColorPanel = () => {
|
|
@@ -54,7 +54,6 @@ type XYNodesData = Pick<XYFlowNode, 'id' | 'data' | 'type'>
|
|
|
54
54
|
export function NodeOptions({ selectedNodeIds }: { selectedNodeIds: string[] }) {
|
|
55
55
|
const diagramApi = useDiagramStoreApi()
|
|
56
56
|
const nodes = useXYNodesData(selectedNodeIds)
|
|
57
|
-
const api = useXYFlow()
|
|
58
57
|
if (!hasAtLeast(nodes, 1)) {
|
|
59
58
|
return null
|
|
60
59
|
}
|
|
@@ -38,7 +38,7 @@ function FitViewOnDiagramChanges() {
|
|
|
38
38
|
const diagramApi = useDiagramStoreApi()
|
|
39
39
|
const [viewportMoved, setViewportMoved] = useState(diagramApi.getState().viewportChanged)
|
|
40
40
|
const [processedChangeId, setProcessed] = useState(diagramChangeId(diagramApi.getState()))
|
|
41
|
-
const [pendingChangeId, setPending] = useDebouncedState(processedChangeId,
|
|
41
|
+
const [pendingChangeId, setPending] = useDebouncedState(processedChangeId, 100)
|
|
42
42
|
|
|
43
43
|
const isReady = useNodesInitialized({
|
|
44
44
|
includeHiddenNodes: true
|
|
@@ -1,30 +1,15 @@
|
|
|
1
1
|
import { deepEqual as eq, shallowEqual } from 'fast-equals'
|
|
2
2
|
import { useXYFlow, useXYStoreApi } from './hooks'
|
|
3
|
-
import type {
|
|
3
|
+
import type { XYFlowNode } from './types'
|
|
4
4
|
|
|
5
|
-
import { memo,
|
|
6
|
-
import {
|
|
5
|
+
import { memo, useEffect } from 'react'
|
|
6
|
+
import { useDiagramStoreApi } from '../state'
|
|
7
7
|
import { diagramViewToXYFlowData } from './diagram-to-xyflow'
|
|
8
8
|
import { toDomPrecision } from './utils'
|
|
9
9
|
|
|
10
10
|
const isSameNode = (a: XYFlowNode) => (b: XYFlowNode) =>
|
|
11
11
|
a.id === b.id && a.type === b.type && Object.is(a.parentId, b.parentId)
|
|
12
12
|
|
|
13
|
-
function hasNoChanges(existing: XYFlowNode, update: XYFlowNode) {
|
|
14
|
-
return existing.id === update.id
|
|
15
|
-
&& existing.type === update.type
|
|
16
|
-
&& existing.parentId == update.parentId
|
|
17
|
-
&& eq(existing.data.element, update.data.element)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function edgeHasNoChanges(existing: XYFlowEdge, update: XYFlowEdge) {
|
|
21
|
-
return existing.id === update.id
|
|
22
|
-
&& existing.type === update.type
|
|
23
|
-
&& existing.source === update.source
|
|
24
|
-
&& existing.target === update.target
|
|
25
|
-
&& eq(existing.data, update.data)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
13
|
/**
|
|
29
14
|
* Syncs the diagram state with the XYFlow instance
|
|
30
15
|
*/
|
|
@@ -33,51 +18,6 @@ export const SyncWithDiagram = memo(() => {
|
|
|
33
18
|
const xyflowApi = useXYStoreApi()
|
|
34
19
|
const diagramStoreApi = useDiagramStoreApi()
|
|
35
20
|
|
|
36
|
-
const correctPosition = useCallback((
|
|
37
|
-
lastOnNavigate: NonNullable<DiagramState['lastOnNavigate']>,
|
|
38
|
-
nodes: DiagramState['view']['nodes']
|
|
39
|
-
) => {
|
|
40
|
-
// const {
|
|
41
|
-
// lastOnNavigate,
|
|
42
|
-
// view: {
|
|
43
|
-
// nodes,
|
|
44
|
-
// id: viewId
|
|
45
|
-
// }
|
|
46
|
-
// } = diagramStoreApi.getState()
|
|
47
|
-
// if (lastOnNavigate.toView !== viewId || lastOnNavigate.positionCorrected) {
|
|
48
|
-
// return
|
|
49
|
-
// }
|
|
50
|
-
|
|
51
|
-
const elFrom = lastOnNavigate.element
|
|
52
|
-
const elTo = nodes.find(n => n.id === elFrom.id)
|
|
53
|
-
if (elTo) {
|
|
54
|
-
const centerFrom = lastOnNavigate.elementCenterScreenPosition,
|
|
55
|
-
centerTo = xyflow.flowToScreenPosition({
|
|
56
|
-
x: elTo.position[0] + elTo.width / 2,
|
|
57
|
-
y: elTo.position[1] + elTo.height / 2
|
|
58
|
-
}),
|
|
59
|
-
diff = {
|
|
60
|
-
x: toDomPrecision(centerFrom.x - centerTo.x),
|
|
61
|
-
y: toDomPrecision(centerFrom.y - centerTo.y)
|
|
62
|
-
}
|
|
63
|
-
requestAnimationFrame(() => {
|
|
64
|
-
xyflowApi.getState().panBy(diff)
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
queueMicrotask(() => {
|
|
68
|
-
diagramStoreApi.setState(
|
|
69
|
-
{
|
|
70
|
-
lastOnNavigate: {
|
|
71
|
-
...lastOnNavigate,
|
|
72
|
-
positionCorrected: true
|
|
73
|
-
}
|
|
74
|
-
},
|
|
75
|
-
false,
|
|
76
|
-
'positionCorrected'
|
|
77
|
-
)
|
|
78
|
-
})
|
|
79
|
-
}, [diagramStoreApi, xyflowApi])
|
|
80
|
-
|
|
81
21
|
useEffect(() => {
|
|
82
22
|
return diagramStoreApi.subscribe(
|
|
83
23
|
// selector
|
|
@@ -123,28 +63,30 @@ export const SyncWithDiagram = memo(() => {
|
|
|
123
63
|
)
|
|
124
64
|
|
|
125
65
|
if (lastOnNavigate?.toView === viewId && !lastOnNavigate.positionCorrected) {
|
|
126
|
-
// correctPosition(
|
|
127
|
-
// lastOnNavigate,
|
|
128
|
-
// nodes
|
|
129
|
-
// )
|
|
130
66
|
const elFrom = lastOnNavigate.element
|
|
131
67
|
const elTo = nodes.find(n => n.id === elFrom.id)
|
|
132
68
|
if (elTo) {
|
|
133
|
-
const centerFrom = lastOnNavigate.elementCenterScreenPosition
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
// y: elFrom.position[1] + elFrom.height / 2
|
|
137
|
-
// }),
|
|
138
|
-
centerTo = xyflow.flowToScreenPosition({
|
|
139
|
-
x: elTo.position[0] + elTo.width / 2,
|
|
140
|
-
y: elTo.position[1] + elTo.height / 2
|
|
141
|
-
}),
|
|
142
|
-
diff = {
|
|
143
|
-
x: toDomPrecision(centerFrom.x - centerTo.x),
|
|
144
|
-
y: toDomPrecision(centerFrom.y - centerTo.y)
|
|
145
|
-
}
|
|
69
|
+
const centerFrom = lastOnNavigate.elementCenterScreenPosition
|
|
70
|
+
const nextZoom = Math.min(elFrom.width / elTo.width, elFrom.height / elTo.height)
|
|
71
|
+
|
|
146
72
|
requestAnimationFrame(() => {
|
|
147
73
|
requestAnimationFrame(() => {
|
|
74
|
+
const v = xyflow.getViewport()
|
|
75
|
+
if (nextZoom < v.zoom) {
|
|
76
|
+
xyflow.setViewport({
|
|
77
|
+
x: v.x,
|
|
78
|
+
y: v.y,
|
|
79
|
+
zoom: nextZoom
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
const centerTo = xyflow.flowToScreenPosition({
|
|
83
|
+
x: elTo.position[0] + elTo.width / 2,
|
|
84
|
+
y: elTo.position[1] + elTo.height / 2
|
|
85
|
+
}),
|
|
86
|
+
diff = {
|
|
87
|
+
x: toDomPrecision(centerFrom.x - centerTo.x),
|
|
88
|
+
y: toDomPrecision(centerFrom.y - centerTo.y)
|
|
89
|
+
}
|
|
148
90
|
xyflowApi.getState().panBy(diff)
|
|
149
91
|
})
|
|
150
92
|
})
|
|
@@ -165,7 +107,7 @@ export const SyncWithDiagram = memo(() => {
|
|
|
165
107
|
equalityFn: shallowEqual
|
|
166
108
|
}
|
|
167
109
|
)
|
|
168
|
-
}, [xyflow, xyflowApi, diagramStoreApi
|
|
110
|
+
}, [xyflow, xyflowApi, diagramStoreApi])
|
|
169
111
|
|
|
170
112
|
return null
|
|
171
113
|
})
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { EdgeMouseHandler, NodeMouseHandler, OnMoveEnd, OnMoveStart, Viewport } from '@xyflow/react'
|
|
1
|
+
import type { EdgeMouseHandler, NodeMouseHandler, OnMoveEnd } from '@xyflow/react'
|
|
3
2
|
import type { MouseEvent as ReactMouseEvent } from 'react'
|
|
4
3
|
import { useMemo, useRef } from 'react'
|
|
5
4
|
import { useDiagramStoreApi } from '../state'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMantineColorScheme } from '@mantine/core'
|
|
2
|
-
import { Controls, ReactFlow
|
|
3
|
-
import { type CSSProperties, memo, type PropsWithChildren
|
|
2
|
+
import { Controls, ReactFlow } from '@xyflow/react'
|
|
3
|
+
import { type CSSProperties, memo, type PropsWithChildren } from 'react'
|
|
4
4
|
import type { SetNonNullable, Simplify } from 'type-fest'
|
|
5
5
|
import type { LikeC4DiagramProperties } from '../LikeC4Diagram.props'
|
|
6
6
|
import { type DiagramState, useDiagramState, useDiagramStoreApi } from '../state'
|
|
@@ -13,10 +13,6 @@ import { XYFlowEdge, XYFlowNode } from './types'
|
|
|
13
13
|
import { XYFlowBackground } from './XYFlowBackground'
|
|
14
14
|
import { useXYFlowEvents } from './XYFlowEvents'
|
|
15
15
|
|
|
16
|
-
// @ts-expect-error - typing in @xyflow/react
|
|
17
|
-
const ReactFlow: (props: ReactFlowProps<XYFlowNode, XYFlowEdge> & RefAttributes<HTMLDivElement>) => JSX.Element =
|
|
18
|
-
GenericReactFlow
|
|
19
|
-
|
|
20
16
|
const nodeTypes = {
|
|
21
17
|
element: ElementNode,
|
|
22
18
|
compound: CompoundNode
|
|
@@ -89,7 +85,7 @@ function XYFlowWrapper({
|
|
|
89
85
|
const colorMode = colorScheme !== 'auto' ? colorScheme : undefined
|
|
90
86
|
|
|
91
87
|
return (
|
|
92
|
-
<ReactFlow
|
|
88
|
+
<ReactFlow<XYFlowNode, XYFlowEdge>
|
|
93
89
|
className={className}
|
|
94
90
|
style={style}
|
|
95
91
|
{...colorMode && { colorMode }}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { invariant, type NonEmptyArray, nonNullable, type Point } from '@likec4/core'
|
|
2
|
-
import { Box
|
|
2
|
+
import { Box } from '@mantine/core'
|
|
3
3
|
import { assignInlineVars } from '@vanilla-extract/dynamic'
|
|
4
4
|
import type { EdgeProps, XYPosition } from '@xyflow/react'
|
|
5
5
|
import { EdgeLabelRenderer, getBezierPath } from '@xyflow/react'
|
|
@@ -93,8 +93,8 @@ const isEqualProps = (prev: EdgeProps<XYFlowEdge>, next: EdgeProps<XYFlowEdge>)
|
|
|
93
93
|
export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(function RelationshipEdgeR({
|
|
94
94
|
id,
|
|
95
95
|
data,
|
|
96
|
-
selected,
|
|
97
|
-
markerEnd,
|
|
96
|
+
selected: _selected,
|
|
97
|
+
markerEnd: _markerEnd,
|
|
98
98
|
style,
|
|
99
99
|
source,
|
|
100
100
|
target,
|
|
@@ -109,8 +109,7 @@ export const RelationshipEdge = /* @__PURE__ */ memo<EdgeProps<XYFlowEdge>>(func
|
|
|
109
109
|
|
|
110
110
|
invariant(data, 'data is required')
|
|
111
111
|
const {
|
|
112
|
-
edge
|
|
113
|
-
controlPoints
|
|
112
|
+
edge
|
|
114
113
|
} = data
|
|
115
114
|
// const edgePath = bezierPath(edge.points)
|
|
116
115
|
|
|
@@ -15,7 +15,7 @@ export const container = style({
|
|
|
15
15
|
[mantine.darkSelector]: {
|
|
16
16
|
vars: {
|
|
17
17
|
[xyvars.edge.labelColor]: vars.relation.labelColor,
|
|
18
|
-
[xyvars.edge.labelBgColor]: `color-mix(in srgb, ${vars.relation.labelBgColor}, transparent
|
|
18
|
+
[xyvars.edge.labelBgColor]: `color-mix(in srgb, ${vars.relation.labelBgColor}, transparent 55%)`
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
// [mantine.lightSelector]: {
|
|
@@ -46,6 +46,9 @@ globalStyle(`.react-flow__edge.selected ${container}`, {
|
|
|
46
46
|
})
|
|
47
47
|
|
|
48
48
|
globalStyle(`.react-flow__edges > svg`, {
|
|
49
|
+
mixBlendMode: 'screen'
|
|
50
|
+
})
|
|
51
|
+
globalStyle(`:where([data-mantine-color-scheme="dark"]) .react-flow__edges > svg`, {
|
|
49
52
|
mixBlendMode: 'lighten'
|
|
50
53
|
})
|
|
51
54
|
|
|
@@ -102,9 +105,9 @@ export const edgeLabel = style({
|
|
|
102
105
|
[varLabelY]: '50%'
|
|
103
106
|
},
|
|
104
107
|
selectors: {
|
|
105
|
-
[mantine.darkSelector]: {
|
|
106
|
-
|
|
107
|
-
},
|
|
108
|
+
// [mantine.darkSelector]: {
|
|
109
|
+
// mixBlendMode: 'luminosity'
|
|
110
|
+
// },
|
|
108
111
|
'&[data-edge-hovered="true"]': {
|
|
109
112
|
transition: 'all 140ms ease-out',
|
|
110
113
|
transform: `${varTranslate} scale(1.1)`
|
|
@@ -4,8 +4,8 @@ import { mantine } from '../../../mantine.css'
|
|
|
4
4
|
import { vars } from '../../../theme.css'
|
|
5
5
|
|
|
6
6
|
export const cssContainer = style({
|
|
7
|
-
width:
|
|
8
|
-
height:
|
|
7
|
+
width: '100%',
|
|
8
|
+
height: '100%',
|
|
9
9
|
position: 'relative',
|
|
10
10
|
padding: 0,
|
|
11
11
|
margin: 0
|
|
@@ -40,6 +40,7 @@ export const cssCompound = style({
|
|
|
40
40
|
}
|
|
41
41
|
})
|
|
42
42
|
|
|
43
|
+
// @ts-ignore
|
|
43
44
|
const cssTransparentCompound = style({
|
|
44
45
|
width: '100%',
|
|
45
46
|
height: '100%',
|
|
@@ -16,6 +16,8 @@ type CompoundNodeProps = Pick<
|
|
|
16
16
|
NodeProps<CompoundXYFlowNode>,
|
|
17
17
|
'id' | 'data' | 'width' | 'height' | 'selected'
|
|
18
18
|
>
|
|
19
|
+
|
|
20
|
+
// @ts-ignore
|
|
19
21
|
const isEqualProps = (prev: CompoundNodeProps, next: CompoundNodeProps) => (
|
|
20
22
|
prev.id === next.id
|
|
21
23
|
&& prev.selected === next.selected
|
|
@@ -72,7 +74,6 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>(function
|
|
|
72
74
|
}}
|
|
73
75
|
>
|
|
74
76
|
<Handle
|
|
75
|
-
// @ts-expect-error
|
|
76
77
|
type="target"
|
|
77
78
|
position={Position.Top}
|
|
78
79
|
style={{ visibility: 'hidden' }}
|
|
@@ -95,7 +96,6 @@ export const CompoundNodeMemo = /* @__PURE__ */ memo<CompoundNodeProps>(function
|
|
|
95
96
|
</div>
|
|
96
97
|
{isnavigable && <NavigateToBtn xynodeId={id} className={cssNavigateBtn} />}
|
|
97
98
|
<Handle
|
|
98
|
-
// @ts-expect-error
|
|
99
99
|
type="source"
|
|
100
100
|
position={Position.Bottom}
|
|
101
101
|
style={{ visibility: 'hidden' }}
|