@likec4/diagram 1.0.0-rc.1 → 1.0.0
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 +3 -29
- package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -1
- package/dist/xyflow/types.d.ts +1 -1
- package/package.json +4 -4
- 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 +3 -0
- 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);
|
|
@@ -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 {
|
|
@@ -847,9 +827,7 @@ svg.react-flow__connectionline {
|
|
|
847
827
|
}
|
|
848
828
|
.lbtzdo0 {
|
|
849
829
|
width: 100%;
|
|
850
|
-
width: -webkit-fill-available;
|
|
851
830
|
height: 100%;
|
|
852
|
-
height: -webkit-fill-available;
|
|
853
831
|
position: relative;
|
|
854
832
|
padding: 0;
|
|
855
833
|
margin: 0;
|
|
@@ -992,9 +970,7 @@ svg.react-flow__connectionline {
|
|
|
992
970
|
--_1b6tkn0: color-mix(in srgb, var(--likec4-element-stroke) 90%, var(--likec4-element-fill));
|
|
993
971
|
position: relative;
|
|
994
972
|
width: 100%;
|
|
995
|
-
width: -webkit-fill-available;
|
|
996
973
|
height: 100%;
|
|
997
|
-
height: -webkit-fill-available;
|
|
998
974
|
padding: 0;
|
|
999
975
|
margin: 0;
|
|
1000
976
|
}
|
|
@@ -1076,9 +1052,7 @@ svg.react-flow__connectionline {
|
|
|
1076
1052
|
--_1b6tkn1: calc(1.5rem * var(--mantine-scale));
|
|
1077
1053
|
position: relative;
|
|
1078
1054
|
width: 100%;
|
|
1079
|
-
width: -webkit-fill-available;
|
|
1080
1055
|
height: 100%;
|
|
1081
|
-
height: -webkit-fill-available;
|
|
1082
1056
|
padding: var(--_1b6tkn1);
|
|
1083
1057
|
display: flex;
|
|
1084
1058
|
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.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"clean": "run -T rimraf -v dist/* .tsbuildinfo"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@likec4/core": "1.0.0
|
|
53
|
+
"@likec4/core": "1.0.0",
|
|
54
54
|
"@mantine/core": "^7.9.0",
|
|
55
55
|
"@mantine/hooks": "^7.9.0",
|
|
56
56
|
"@react-hookz/web": "^24.0.4",
|
|
@@ -74,14 +74,14 @@
|
|
|
74
74
|
"@vanilla-extract/dynamic": "^2.1.0",
|
|
75
75
|
"@vanilla-extract/esbuild-plugin": "^2.3.5",
|
|
76
76
|
"@vitejs/plugin-react": "^4.2.1",
|
|
77
|
-
"@xyflow/react": "^12.0.0-next
|
|
77
|
+
"@xyflow/react": "^12.0.0-next",
|
|
78
78
|
"clsx": "^2.1.1",
|
|
79
79
|
"execa": "^8.0.1",
|
|
80
80
|
"khroma": "^2.1.0",
|
|
81
81
|
"react": "^18.2.0",
|
|
82
82
|
"react-dom": "^18.2.0",
|
|
83
83
|
"tilg": "^0.1.1",
|
|
84
|
-
"type-fest": "^4.18.
|
|
84
|
+
"type-fest": "^4.18.2",
|
|
85
85
|
"typescript": "^5.4.5",
|
|
86
86
|
"unbuild": "^2.0.0",
|
|
87
87
|
"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
|
|
|
@@ -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
|
|
|
@@ -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' }}
|
|
@@ -12,8 +12,6 @@ type ElementIconProps = {
|
|
|
12
12
|
|
|
13
13
|
export function ElementIcon({
|
|
14
14
|
node,
|
|
15
|
-
maxWidth,
|
|
16
|
-
paddingX = 32,
|
|
17
15
|
paddingY = 32
|
|
18
16
|
}: ElementIconProps) {
|
|
19
17
|
if (!node.icon) {
|
|
@@ -26,7 +24,7 @@ export function ElementIcon({
|
|
|
26
24
|
|
|
27
25
|
const firstLabelY = Math.floor(firstLabel.pt[1] - firstLabel.fontSize * 1.25)
|
|
28
26
|
const maxIconHeight = Math.floor(firstLabelY - paddingY - 16)
|
|
29
|
-
const maxIconWidth = maxWidth ?? node.width - paddingX * 2
|
|
27
|
+
// const maxIconWidth = maxWidth ?? node.width - paddingX * 2
|
|
30
28
|
|
|
31
29
|
// const centerY = paddingY + Math.floor(maxIconHeight / 2)
|
|
32
30
|
// const centerX = Math.floor(node.width / 2)
|
|
@@ -19,8 +19,8 @@ export const elementLink = style({
|
|
|
19
19
|
}
|
|
20
20
|
// fontSize: rem(10),
|
|
21
21
|
// height: 12,
|
|
22
|
-
// width:
|
|
23
|
-
// height:
|
|
22
|
+
// width: '100%',
|
|
23
|
+
// height: '100%',
|
|
24
24
|
// vars: {
|
|
25
25
|
// [stokeFillMix]: `color-mix(in srgb, ${vars.element.stroke} 90%, ${vars.element.fill})`
|
|
26
26
|
// }
|
|
@@ -68,9 +68,9 @@ export function ElementLink({
|
|
|
68
68
|
<span>links</span>
|
|
69
69
|
</UnstyledButton>
|
|
70
70
|
</HoverCardTarget>
|
|
71
|
-
<HoverCardDropdown p={'xs'}>
|
|
72
|
-
<Stack
|
|
73
|
-
{element.links.map((link
|
|
71
|
+
<HoverCardDropdown onClick={e => e.stopPropagation()} p={'xs'}>
|
|
72
|
+
<Stack gap={'xs'}>
|
|
73
|
+
{element.links.map((link) => (
|
|
74
74
|
<Group key={link} wrap="nowrap" gap={'sm'}>
|
|
75
75
|
<Box flex={'1'} style={{ overflow: 'clip', maxWidth: clamp(element.width, { min: 200, max: 400 }) }}>
|
|
76
76
|
<Anchor href={link} target="_blank" fz="13" truncate="end">
|
|
@@ -157,7 +157,6 @@ export function ElementNode({
|
|
|
157
157
|
))} */
|
|
158
158
|
}
|
|
159
159
|
<Handle
|
|
160
|
-
// @ts-expect-error
|
|
161
160
|
type="target"
|
|
162
161
|
position={Position.Top}
|
|
163
162
|
style={{ visibility: 'hidden' }}
|
|
@@ -204,7 +203,6 @@ export function ElementNode({
|
|
|
204
203
|
)}
|
|
205
204
|
</div>
|
|
206
205
|
<Handle
|
|
207
|
-
// @ts-expect-error
|
|
208
206
|
type="source"
|
|
209
207
|
position={Position.Bottom}
|
|
210
208
|
style={{ visibility: 'hidden' }}
|