@likec4/diagram 1.39.5 → 1.41.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/bundle/{chunk-CW_KClZe.js → chunk-FGcODVxo.js} +1059 -1023
- package/bundle/custom.js +61 -60
- package/bundle/index.js +2932 -764
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.js +7 -4
- package/dist/LikeC4Diagram.props.d.ts +6 -1
- package/dist/base/const.d.ts +9 -0
- package/dist/base/const.js +10 -1
- package/dist/base/index.d.ts +1 -0
- package/dist/base/primitives/MarkdownBlock.js +2 -0
- package/dist/base/primitives/edge/EdgeLabel.js +2 -1
- package/dist/base/primitives/edge/EdgeLabelContainer.js +10 -4
- package/dist/base/primitives/edge/EdgePath.js +17 -8
- package/dist/base/primitives/edge/edge.css.d.ts +0 -1
- package/dist/base/primitives/edge/edge.css.js +6 -14
- package/dist/base/primitives/element/ElementActionButtons.js +1 -3
- package/dist/base/primitives/element/ElementNodeContainer.d.ts +0 -6
- package/dist/base/primitives/element/ElementNodeContainer.js +3 -26
- package/dist/base/primitives/element/ElementTitle.js +2 -2
- package/dist/base/types.d.ts +3 -3
- package/dist/bundle/LikeC4View.js +4 -12
- package/dist/bundle/LikeC4View.props.d.ts +12 -3
- package/dist/bundle/custom.js +1 -1
- package/dist/components/Link.js +28 -20
- package/dist/custom/customNodes.d.ts +6 -0
- package/dist/custom/customNodes.js +2 -1
- package/dist/custom/index.js +1 -1
- package/dist/hooks/useDiagram.d.ts +5 -1
- package/dist/hooks/useDiagram.js +3 -0
- package/dist/hooks/useXYFlow.d.ts +4 -439
- package/dist/likec4diagram/DiagramUI.js +1 -1
- package/dist/likec4diagram/DiagramXYFlow.js +8 -4
- package/dist/likec4diagram/convert-to-xyflow.d.ts +14 -0
- package/dist/likec4diagram/convert-to-xyflow.js +29 -0
- package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +4 -4
- package/dist/likec4diagram/custom/edges/RelationshipEdge.js +0 -1
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.d.ts +3 -0
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.js +71 -0
- package/dist/likec4diagram/custom/index.js +7 -2
- package/dist/likec4diagram/custom/nodes/ElementActions.d.ts +2 -1
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.d.ts +4 -0
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.js +157 -0
- package/dist/likec4diagram/custom/nodes/index.d.ts +1 -0
- package/dist/likec4diagram/custom/nodes/nodes.d.ts +1 -2
- package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +31 -27
- package/dist/likec4diagram/types.d.ts +41 -7
- package/dist/likec4diagram/xyflow-diagram/diagram-view.d.ts +11 -0
- package/dist/likec4diagram/{useViewToNodesEdges.js → xyflow-diagram/diagram-view.js} +4 -13
- package/dist/likec4diagram/xyflow-sequence/_types.d.ts +41 -0
- package/dist/likec4diagram/xyflow-sequence/const.d.ts +17 -0
- package/dist/likec4diagram/xyflow-sequence/const.js +16 -0
- package/dist/likec4diagram/xyflow-sequence/layouter.d.ts +46 -0
- package/dist/likec4diagram/xyflow-sequence/layouter.js +408 -0
- package/dist/likec4diagram/xyflow-sequence/sequence-view.d.ts +7 -0
- package/dist/likec4diagram/xyflow-sequence/sequence-view.js +273 -0
- package/dist/likec4diagram/xyflow-sequence/utils.d.ts +14 -0
- package/dist/likec4diagram/xyflow-sequence/utils.js +92 -0
- package/dist/navigationpanel/NavigationPanelControls.js +2 -2
- package/dist/navigationpanel/controls/ViewDetailsCard.js +27 -12
- package/dist/navigationpanel/dropdown/ProjectsMenu.js +53 -44
- package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.d.ts +1 -2
- package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.js +10 -41
- package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +292 -0
- package/dist/navigationpanel/walkthrough/DynamicViewControls.js +119 -0
- package/dist/navigationpanel/walkthrough/index.d.ts +2 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.js +7 -1
- package/dist/overlays/element-details/ElementDetailsCard.js +17 -19
- package/dist/overlays/relationship-details/RelationshipDetails.js +4 -1
- package/dist/overlays/relationship-details/layout.d.ts +3 -2
- package/dist/overlays/relationship-details/layout.js +1 -2
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -1
- package/dist/overlays/relationships-browser/layout.js +1 -1
- package/dist/search/components/ElementsColumn.js +1 -1
- package/dist/state/DiagramActorProvider.d.ts +3 -2
- package/dist/state/DiagramActorProvider.js +40 -41
- package/dist/state/assign.js +11 -4
- package/dist/state/diagram-machine.d.ts +224 -194
- package/dist/state/diagram-machine.js +170 -63
- package/dist/state/utils.d.ts +7 -1
- package/dist/state/utils.js +67 -7
- package/dist/styles-min.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css2.js +1 -1
- package/package.json +8 -7
- package/panda.buildinfo.json +45 -24
- package/src/LikeC4Diagram.props.ts +14 -1
- package/src/LikeC4Diagram.tsx +7 -4
- package/src/base/const.ts +12 -0
- package/src/base/index.ts +2 -0
- package/src/base/primitives/MarkdownBlock.tsx +2 -0
- package/src/base/primitives/edge/EdgeLabel.tsx +23 -19
- package/src/base/primitives/edge/EdgeLabelContainer.tsx +12 -7
- package/src/base/primitives/edge/EdgePath.tsx +25 -14
- package/src/base/primitives/edge/edge.css.ts +5 -14
- package/src/base/primitives/element/ElementActionButtons.tsx +1 -3
- package/src/base/primitives/element/ElementNodeContainer.tsx +3 -30
- package/src/base/primitives/element/ElementTitle.tsx +2 -3
- package/src/base/types.ts +7 -5
- package/src/bundle/LikeC4View.props.ts +14 -3
- package/src/bundle/LikeC4View.tsx +4 -14
- package/src/bundle/ReactLikeC4.tsx +1 -2
- package/src/components/Link.tsx +21 -18
- package/src/custom/customNodes.ts +7 -0
- package/src/hooks/useDiagram.ts +10 -0
- package/src/likec4diagram/DiagramUI.tsx +1 -1
- package/src/likec4diagram/DiagramXYFlow.tsx +10 -5
- package/src/likec4diagram/convert-to-xyflow.ts +45 -0
- package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +0 -1
- package/src/likec4diagram/custom/edges/SequenceStepEdge.tsx +65 -0
- package/src/likec4diagram/custom/index.ts +7 -1
- package/src/likec4diagram/custom/nodes/ElementActions.tsx +4 -2
- package/src/likec4diagram/custom/nodes/SequenceActorNode.tsx +175 -0
- package/src/likec4diagram/custom/nodes/index.ts +1 -0
- package/src/likec4diagram/custom/nodes/nodes.tsx +1 -1
- package/src/likec4diagram/relationship-popover/RelationshipPopover.tsx +36 -30
- package/src/likec4diagram/types.ts +96 -13
- package/src/likec4diagram/{useViewToNodesEdges.ts → xyflow-diagram/diagram-view.ts} +7 -28
- package/src/likec4diagram/xyflow-sequence/_types.ts +45 -0
- package/src/likec4diagram/xyflow-sequence/const.ts +37 -0
- package/src/likec4diagram/xyflow-sequence/layouter.ts +567 -0
- package/src/likec4diagram/xyflow-sequence/sequence-view.ts +337 -0
- package/src/likec4diagram/xyflow-sequence/utils.ts +112 -0
- package/src/navigationpanel/NavigationPanelControls.tsx +2 -2
- package/src/navigationpanel/controls/ViewDetailsCard.tsx +29 -12
- package/src/navigationpanel/dropdown/ProjectsMenu.tsx +5 -1
- package/src/navigationpanel/walkthrough/ActiveWalkthroughControls.tsx +5 -40
- package/src/navigationpanel/walkthrough/DynamicViewControls.tsx +125 -0
- package/src/navigationpanel/walkthrough/index.tsx +2 -1
- package/src/overlays/element-details/ElementDetailsCard.css.ts +7 -1
- package/src/overlays/element-details/ElementDetailsCard.tsx +24 -25
- package/src/overlays/relationship-details/RelationshipDetails.tsx +5 -2
- package/src/overlays/relationship-details/layout.ts +4 -3
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -1
- package/src/overlays/relationships-browser/layout.ts +1 -1
- package/src/search/components/ElementsColumn.tsx +1 -1
- package/src/state/DiagramActorProvider.tsx +46 -51
- package/src/state/assign.ts +18 -5
- package/src/state/diagram-machine.ts +207 -75
- package/src/state/utils.ts +81 -7
- package/dist/likec4diagram/useViewToNodesEdges.d.ts +0 -12
package/src/base/types.ts
CHANGED
|
@@ -15,11 +15,11 @@ type RFEdge<
|
|
|
15
15
|
type ReactFlowNodeProps<
|
|
16
16
|
NodeData extends Record<string, unknown> = Record<string, unknown>,
|
|
17
17
|
NodeType extends string | undefined = string | undefined,
|
|
18
|
-
> = RF.NodeProps<
|
|
18
|
+
> = RF.NodeProps<RF.Node<NodeData, NodeType>>
|
|
19
19
|
type ReactFlowEdgeProps<
|
|
20
20
|
EdgeData extends Record<string, unknown> = Record<string, unknown>,
|
|
21
21
|
EdgeType extends string | undefined = string | undefined,
|
|
22
|
-
> = RF.EdgeProps<
|
|
22
|
+
> = RF.EdgeProps<RF.Edge<EdgeData, EdgeType>>
|
|
23
23
|
|
|
24
24
|
export namespace Base {
|
|
25
25
|
// 'immediate' means that the node is dimmed without delay
|
|
@@ -156,9 +156,11 @@ export type NodeProps<T extends Record<string, unknown> = {}, NodeType extends s
|
|
|
156
156
|
/**
|
|
157
157
|
* ReactFlow Custom Edge properties with BaseEdgeData at least
|
|
158
158
|
*/
|
|
159
|
-
export type EdgeProps<T extends Record<string, unknown> = {}, EdgeType extends string = string> =
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
export type EdgeProps<T extends Record<string, unknown> = {}, EdgeType extends string = string> = Simplify<
|
|
160
|
+
SetRequired<
|
|
161
|
+
ReactFlowEdgeProps<Base.EdgeData & T, EdgeType>,
|
|
162
|
+
'data'
|
|
163
|
+
>
|
|
162
164
|
>
|
|
163
165
|
|
|
164
166
|
export type ReactFlowNode<Data extends Record<string, unknown>, NodeType extends string> = SetRequired<
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type * as t from '@likec4/core/types'
|
|
2
|
-
import type { WhereOperator } from '@likec4/core/types'
|
|
3
2
|
import type { CSSProperties } from 'react'
|
|
4
3
|
import type {
|
|
5
4
|
CustomNodes,
|
|
@@ -109,10 +108,16 @@ export interface LikeC4ViewProps<A extends t.aux.Any = t.aux.UnknownLayouted> {
|
|
|
109
108
|
|
|
110
109
|
/**
|
|
111
110
|
* If Walkthrough for dynamic views should be enabled
|
|
112
|
-
* @default
|
|
111
|
+
* @default false
|
|
113
112
|
*/
|
|
114
113
|
enableDynamicViewWalkthrough?: boolean | undefined
|
|
115
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Default dynamic view display variant
|
|
117
|
+
* @default 'diagram'
|
|
118
|
+
*/
|
|
119
|
+
dynamicViewVariant?: t.DynamicViewDisplayVariant | undefined
|
|
120
|
+
|
|
116
121
|
/**
|
|
117
122
|
* Enable popup with element details
|
|
118
123
|
* @default false
|
|
@@ -145,7 +150,7 @@ export interface LikeC4ViewProps<A extends t.aux.Any = t.aux.UnknownLayouted> {
|
|
|
145
150
|
*/
|
|
146
151
|
reduceGraphics?: 'auto' | boolean | undefined
|
|
147
152
|
|
|
148
|
-
where?: WhereOperator<A> | undefined
|
|
153
|
+
where?: t.WhereOperator<A> | undefined
|
|
149
154
|
|
|
150
155
|
/**
|
|
151
156
|
* Override some react flow props
|
|
@@ -228,6 +233,12 @@ export interface LikeC4BrowserProps {
|
|
|
228
233
|
*/
|
|
229
234
|
enableDynamicViewWalkthrough?: boolean | undefined
|
|
230
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Default dynamic view display variant
|
|
238
|
+
* @default 'diagram'
|
|
239
|
+
*/
|
|
240
|
+
dynamicViewVariant?: t.DynamicViewDisplayVariant | undefined
|
|
241
|
+
|
|
231
242
|
/**
|
|
232
243
|
* Enable popup with element details
|
|
233
244
|
* @default true
|
|
@@ -5,9 +5,9 @@ import { shallowEqual, useCallbackRef } from '@mantine/hooks'
|
|
|
5
5
|
import { IconX } from '@tabler/icons-react'
|
|
6
6
|
import { memo, useState } from 'react'
|
|
7
7
|
import { isBoolean } from 'remeda'
|
|
8
|
+
import { FitViewPaddings } from '../base/const'
|
|
8
9
|
import { FramerMotionConfig } from '../context/FramerMotionConfig'
|
|
9
10
|
import { LikeC4Diagram } from '../LikeC4Diagram'
|
|
10
|
-
import type { ViewPadding } from '../LikeC4Diagram.props'
|
|
11
11
|
import { useLikeC4Model } from '../likec4model/useLikeC4Model'
|
|
12
12
|
import { Overlay } from '../overlays/overlay/Overlay'
|
|
13
13
|
import type { LikeC4ViewProps } from './LikeC4View.props'
|
|
@@ -37,13 +37,6 @@ export function LikeC4View<A extends t.aux.Any = t.aux.UnknownLayouted>({
|
|
|
37
37
|
return <LikeC4ViewInner view={view.$view} {...props} />
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
const DEFAULT_BROWSER_PADDING: ViewPadding = {
|
|
41
|
-
top: '50px',
|
|
42
|
-
bottom: '16px',
|
|
43
|
-
left: '16px',
|
|
44
|
-
right: '16px',
|
|
45
|
-
}
|
|
46
|
-
|
|
47
40
|
type LikeC4ViewInnerProps<A extends t.aux.Any> = Omit<LikeC4ViewProps<A>, 'viewId'> & {
|
|
48
41
|
view: t.DiagramView<A>
|
|
49
42
|
}
|
|
@@ -56,8 +49,6 @@ const LikeC4ViewInner = memo<LikeC4ViewInnerProps<t.aux.UnknownLayouted>>(({
|
|
|
56
49
|
colorScheme: explicitColorScheme,
|
|
57
50
|
injectFontCss = true,
|
|
58
51
|
controls = false,
|
|
59
|
-
fitView = true,
|
|
60
|
-
fitViewPadding = '16px',
|
|
61
52
|
background = 'transparent',
|
|
62
53
|
browser = true,
|
|
63
54
|
showDiagramTitle = false,
|
|
@@ -129,8 +120,8 @@ const LikeC4ViewInner = memo<LikeC4ViewInnerProps<t.aux.UnknownLayouted>>(({
|
|
|
129
120
|
pannable={pannable}
|
|
130
121
|
zoomable={zoomable}
|
|
131
122
|
background={background}
|
|
132
|
-
fitView={
|
|
133
|
-
fitViewPadding={
|
|
123
|
+
fitView={true}
|
|
124
|
+
fitViewPadding={FitViewPaddings.default}
|
|
134
125
|
showDiagramTitle={showDiagramTitle}
|
|
135
126
|
showNotations={showNotations && hasNotations}
|
|
136
127
|
enableDynamicViewWalkthrough={enableDynamicViewWalkthrough}
|
|
@@ -152,7 +143,6 @@ const LikeC4ViewInner = memo<LikeC4ViewInnerProps<t.aux.UnknownLayouted>>(({
|
|
|
152
143
|
// so we don't want enable search and hotkeys
|
|
153
144
|
enableSearch={false}
|
|
154
145
|
{...isBrowserEnabled && {
|
|
155
|
-
onNavigateTo: onNavigateTo,
|
|
156
146
|
onCanvasClick: onNavigateToThisView,
|
|
157
147
|
onNodeClick: onNavigateToThisView,
|
|
158
148
|
}}
|
|
@@ -176,8 +166,8 @@ const LikeC4ViewInner = memo<LikeC4ViewInnerProps<t.aux.UnknownLayouted>>(({
|
|
|
176
166
|
controls="next"
|
|
177
167
|
readonly
|
|
178
168
|
fitView
|
|
179
|
-
fitViewPadding={DEFAULT_BROWSER_PADDING}
|
|
180
169
|
{...props}
|
|
170
|
+
fitViewPadding={FitViewPaddings.withControls}
|
|
181
171
|
{...browserProps}
|
|
182
172
|
showNotations={(browserProps.showNotations ?? true) &&
|
|
183
173
|
(browserView.notation?.nodes.length ?? 0) > 0}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type * as t from '@likec4/core/types'
|
|
2
|
-
import type { DiagramView } from '@likec4/core/types'
|
|
3
2
|
import { cx } from '@likec4/styles/css'
|
|
4
3
|
import { type CSSProperties } from 'react'
|
|
5
4
|
import { isFunction, isString } from 'remeda'
|
|
@@ -65,7 +64,7 @@ export function ReactLikeC4<A extends t.aux.Any = t.aux.UnknownLayouted>({
|
|
|
65
64
|
}
|
|
66
65
|
|
|
67
66
|
type ReactLikeC4InnerProps<A extends t.aux.Any> = Omit<ReactLikeC4Props<A>, 'viewId'> & {
|
|
68
|
-
view: DiagramView<A>
|
|
67
|
+
view: t.DiagramView<A>
|
|
69
68
|
}
|
|
70
69
|
function ReactLikeC4Inner<A extends t.aux.Any>({
|
|
71
70
|
className,
|
package/src/components/Link.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Link as LinkData } from '@likec4/core'
|
|
2
2
|
import { css, cx } from '@likec4/styles/css'
|
|
3
|
+
import { styled } from '@likec4/styles/jsx'
|
|
3
4
|
import { type BadgeProps, ActionIcon, Badge, CopyButton } from '@mantine/core'
|
|
4
5
|
import { IconCheck, IconCopy } from '@tabler/icons-react'
|
|
5
6
|
import { forwardRef } from 'react'
|
|
@@ -72,29 +73,31 @@ export const Link = forwardRef<HTMLDivElement, Omit<BadgeProps, 'children' | 'cl
|
|
|
72
73
|
userSelect: 'none',
|
|
73
74
|
pointerEvents: 'none',
|
|
74
75
|
_groupHover: {
|
|
75
|
-
color: '[
|
|
76
|
+
color: '[var(--badge-color)]',
|
|
76
77
|
opacity: .7,
|
|
77
78
|
},
|
|
78
79
|
},
|
|
79
80
|
}),
|
|
80
|
-
label: css({
|
|
81
|
-
'& > a': {
|
|
82
|
-
color: '[inherit]',
|
|
83
|
-
cursor: 'pointer',
|
|
84
|
-
transition: 'fast',
|
|
85
|
-
opacity: {
|
|
86
|
-
base: 0.7,
|
|
87
|
-
_hover: 1,
|
|
88
|
-
},
|
|
89
|
-
textDecoration: {
|
|
90
|
-
base: 'none',
|
|
91
|
-
_hover: 'underline',
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
}),
|
|
95
81
|
}}
|
|
96
82
|
>
|
|
97
|
-
<a
|
|
83
|
+
<styled.a
|
|
84
|
+
href={url}
|
|
85
|
+
target="_blank"
|
|
86
|
+
style={{
|
|
87
|
+
color: 'var(--badge-color)',
|
|
88
|
+
cursor: 'pointer',
|
|
89
|
+
}}
|
|
90
|
+
css={{
|
|
91
|
+
transition: 'fast',
|
|
92
|
+
opacity: {
|
|
93
|
+
base: 0.7,
|
|
94
|
+
_hover: 1,
|
|
95
|
+
},
|
|
96
|
+
textDecoration: {
|
|
97
|
+
base: 'none',
|
|
98
|
+
_hover: 'underline',
|
|
99
|
+
},
|
|
100
|
+
}}>
|
|
98
101
|
{isGithub && (
|
|
99
102
|
<GithubIcon
|
|
100
103
|
height="12"
|
|
@@ -102,7 +105,7 @@ export const Link = forwardRef<HTMLDivElement, Omit<BadgeProps, 'children' | 'cl
|
|
|
102
105
|
style={{ verticalAlign: 'middle', marginRight: '4px' }} />
|
|
103
106
|
)}
|
|
104
107
|
{isGithub ? url.replace(GITHUB_PREFIX, '') : url}
|
|
105
|
-
</a>
|
|
108
|
+
</styled.a>
|
|
106
109
|
</Badge>
|
|
107
110
|
)
|
|
108
111
|
},
|
|
@@ -266,10 +266,17 @@ export type CustomViewGroupNodeProps = {
|
|
|
266
266
|
nodeModel: NodeModel.IsGroup<Any>
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
export const sequenceActorNode: CustomNodeComponent<CustomSequenceActorNodeProps> = customDiagramNode as any
|
|
270
|
+
export type CustomSequenceActorNodeProps = {
|
|
271
|
+
nodeProps: NodeProps<Types.SequenceActorNodeData, 'seq-actor'>
|
|
272
|
+
nodeModel: NodeModel.WithElement<Any>
|
|
273
|
+
}
|
|
274
|
+
|
|
269
275
|
export interface CustomNodes {
|
|
270
276
|
element?: FunctionComponent<NodeProps<Types.ElementNodeData, 'element'>>
|
|
271
277
|
deployment?: FunctionComponent<NodeProps<Types.DeploymentElementNodeData, 'deployment'>>
|
|
272
278
|
compoundElement?: FunctionComponent<NodeProps<Types.CompoundElementNodeData, 'compound-element'>>
|
|
273
279
|
compoundDeployment?: FunctionComponent<NodeProps<Types.CompoundDeploymentNodeData, 'compound-deployment'>>
|
|
274
280
|
viewGroup?: FunctionComponent<NodeProps<Types.ViewGroupNodeData, 'view-group'>>
|
|
281
|
+
sequenceActor?: FunctionComponent<NodeProps<Types.SequenceActorNodeData, 'seq-actor'>>
|
|
275
282
|
}
|
package/src/hooks/useDiagram.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
type DiagramEdge,
|
|
4
4
|
type DiagramNode,
|
|
5
5
|
type DiagramView,
|
|
6
|
+
type DynamicViewDisplayVariant,
|
|
6
7
|
type NodeId,
|
|
7
8
|
type NodeNotation as ElementNotation,
|
|
8
9
|
type scalar,
|
|
@@ -115,6 +116,11 @@ export interface DiagramApi {
|
|
|
115
116
|
highlightNotation(notation: ElementNotation, kind?: string): void
|
|
116
117
|
unhighlightNotation(): void
|
|
117
118
|
openSearch(searchValue?: string): void
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Switch dynamic view display variant
|
|
122
|
+
*/
|
|
123
|
+
switchDynamicViewVariant(variant: DynamicViewDisplayVariant): void
|
|
118
124
|
}
|
|
119
125
|
|
|
120
126
|
/**
|
|
@@ -246,6 +252,10 @@ export function useDiagram(): DiagramApi {
|
|
|
246
252
|
openSearch: (searchValue?: string) => {
|
|
247
253
|
actor.send({ type: 'open.search', ...(searchValue && { search: searchValue }) })
|
|
248
254
|
},
|
|
255
|
+
|
|
256
|
+
switchDynamicViewVariant: (variant: DynamicViewDisplayVariant) => {
|
|
257
|
+
actor.send({ type: 'switch.dynamicViewVariant', variant })
|
|
258
|
+
},
|
|
249
259
|
}), [actor])
|
|
250
260
|
}
|
|
251
261
|
|
|
@@ -32,7 +32,7 @@ export const DiagramUI = memo(() => {
|
|
|
32
32
|
: <Controls />}
|
|
33
33
|
{overlaysActorRef && <Overlays overlaysActorRef={overlaysActorRef} />}
|
|
34
34
|
{enableNotations && <NotationPanel />}
|
|
35
|
-
{enableControls
|
|
35
|
+
{enableControls === true && (
|
|
36
36
|
<>
|
|
37
37
|
{enableViewTitle && <DiagramTitlePanel />}
|
|
38
38
|
{enableDynamicViewWalkthrough && <DynamicViewWalkthrough />}
|
|
@@ -3,7 +3,7 @@ import { cx } from '@likec4/styles/css'
|
|
|
3
3
|
import { useCallbackRef, useDebouncedCallback, useTimeout } from '@mantine/hooks'
|
|
4
4
|
import { useCustomCompareMemo } from '@react-hookz/web'
|
|
5
5
|
import type { OnMove, OnMoveEnd } from '@xyflow/system'
|
|
6
|
-
import { shallowEqual } from 'fast-equals'
|
|
6
|
+
import { deepEqual, shallowEqual } from 'fast-equals'
|
|
7
7
|
import { type PropsWithChildren } from 'react'
|
|
8
8
|
import type { Simplify } from 'type-fest'
|
|
9
9
|
import { BaseXYFlow } from '../base/BaseXYFlow'
|
|
@@ -13,7 +13,7 @@ import { useUpdateEffect } from '../hooks'
|
|
|
13
13
|
import { useDiagram, useDiagramContext } from '../hooks/useDiagram'
|
|
14
14
|
import type { LikeC4DiagramProperties } from '../LikeC4Diagram.props'
|
|
15
15
|
import type { DiagramContext } from '../state/types'
|
|
16
|
-
import { BuiltinNodes as defaultNodeTypes, edgeTypes } from './custom'
|
|
16
|
+
import { BuiltinNodes as defaultNodeTypes, edgeTypes, SequenceParallelArea } from './custom'
|
|
17
17
|
import { DiagramUI } from './DiagramUI'
|
|
18
18
|
import type { Types } from './types'
|
|
19
19
|
import { useLayoutConstraints } from './useLayoutConstraints'
|
|
@@ -26,7 +26,9 @@ const selectXYProps = (ctx: DiagramContext) => ({
|
|
|
26
26
|
zoomable: ctx.zoomable,
|
|
27
27
|
fitViewPadding: ctx.fitViewPadding,
|
|
28
28
|
enableFitView: ctx.features.enableFitView,
|
|
29
|
-
enableReadOnly: ctx.features.enableReadOnly || ctx.toggledFeatures.enableReadOnly
|
|
29
|
+
enableReadOnly: ctx.features.enableReadOnly || ctx.toggledFeatures.enableReadOnly
|
|
30
|
+
// if dynamic view display mode is sequence, enable readonly
|
|
31
|
+
|| (ctx.dynamicViewVariant === 'sequence' && ctx.view._type === 'dynamic'),
|
|
30
32
|
...(!ctx.features.enableFitView && {
|
|
31
33
|
viewport: {
|
|
32
34
|
x: -Math.min(ctx.view.bounds.x, 0),
|
|
@@ -41,7 +43,7 @@ const equalsXYProps = (a: ReturnType<typeof selectXYProps>, b: ReturnType<typeof
|
|
|
41
43
|
a.zoomable === b.zoomable &&
|
|
42
44
|
a.enableFitView === b.enableFitView &&
|
|
43
45
|
a.enableReadOnly === b.enableReadOnly &&
|
|
44
|
-
|
|
46
|
+
deepEqual(a.fitViewPadding, b.fitViewPadding) &&
|
|
45
47
|
shallowEqual(a.nodes, b.nodes) &&
|
|
46
48
|
shallowEqual(a.edges, b.edges) &&
|
|
47
49
|
shallowEqual(a.viewport ?? null, b.viewport ?? null)
|
|
@@ -123,7 +125,9 @@ export function LikeC4DiagramXYFlow({
|
|
|
123
125
|
'compound-element': renderNodes?.compoundElement ?? defaultNodeTypes.compoundElement,
|
|
124
126
|
'compound-deployment': renderNodes?.compoundDeployment ?? defaultNodeTypes.compoundDeployment,
|
|
125
127
|
'view-group': renderNodes?.viewGroup ?? defaultNodeTypes.viewGroup,
|
|
126
|
-
|
|
128
|
+
'seq-actor': renderNodes?.sequenceActor ?? defaultNodeTypes.sequenceActor,
|
|
129
|
+
'seq-parallel': SequenceParallelArea,
|
|
130
|
+
} satisfies Record<Types.Node['type'], any>
|
|
127
131
|
},
|
|
128
132
|
[renderNodes],
|
|
129
133
|
shallowEqual,
|
|
@@ -224,6 +228,7 @@ export function LikeC4DiagramXYFlow({
|
|
|
224
228
|
}}
|
|
225
229
|
nodesDraggable={notReadOnly && nodesDraggable}
|
|
226
230
|
nodesSelectable={nodesSelectable}
|
|
231
|
+
edgesFocusable={false}
|
|
227
232
|
{...(notReadOnly && nodesDraggable && layoutConstraints)}
|
|
228
233
|
{...props}
|
|
229
234
|
{...reactFlowProps}>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { DynamicViewDisplayVariant, LayoutedView, WhereOperator } from '@likec4/core/types'
|
|
2
|
+
import type { Types } from './types'
|
|
3
|
+
import { diagramToXY } from './xyflow-diagram/diagram-view'
|
|
4
|
+
import { sequenceViewToXY } from './xyflow-sequence/sequence-view'
|
|
5
|
+
|
|
6
|
+
type ConvertToXYFlowInput = {
|
|
7
|
+
view: LayoutedView
|
|
8
|
+
where: WhereOperator | null
|
|
9
|
+
nodesSelectable: boolean
|
|
10
|
+
dynamicViewVariant: DynamicViewDisplayVariant
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function convertToXYFlow({ dynamicViewVariant, ...params }: ConvertToXYFlowInput): {
|
|
14
|
+
view: LayoutedView
|
|
15
|
+
xynodes: Types.Node[]
|
|
16
|
+
xyedges: Types.Edge[]
|
|
17
|
+
} {
|
|
18
|
+
const view = params.view
|
|
19
|
+
const isDynamic = view._type === 'dynamic'
|
|
20
|
+
|
|
21
|
+
const { bounds, xynodes, xyedges } = isDynamic && dynamicViewVariant === 'sequence'
|
|
22
|
+
? sequenceViewToXY(view)
|
|
23
|
+
: diagramToXY(params)
|
|
24
|
+
|
|
25
|
+
if (isDynamic && view.variant !== dynamicViewVariant) {
|
|
26
|
+
return {
|
|
27
|
+
view: {
|
|
28
|
+
...view,
|
|
29
|
+
bounds,
|
|
30
|
+
variant: dynamicViewVariant,
|
|
31
|
+
},
|
|
32
|
+
xynodes,
|
|
33
|
+
xyedges,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
view: bounds === view.bounds ? view : {
|
|
39
|
+
...view,
|
|
40
|
+
bounds,
|
|
41
|
+
},
|
|
42
|
+
xynodes,
|
|
43
|
+
xyedges,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { getSmoothStepPath } from '@xyflow/system'
|
|
2
|
+
import type { EdgeProps } from '../../../base'
|
|
3
|
+
import { EdgeActionButton, EdgeContainer, EdgeLabel, EdgeLabelContainer, EdgePath } from '../../../base/primitives'
|
|
4
|
+
import { useDiagram } from '../../../hooks/useDiagram'
|
|
5
|
+
import type { Types } from '../../types'
|
|
6
|
+
|
|
7
|
+
const LABEL_OFFSET = 16
|
|
8
|
+
export function SequenceStepEdge(props: EdgeProps<Types.SequenceStepEdgeData>) {
|
|
9
|
+
const diagram = useDiagram()
|
|
10
|
+
const { navigateTo } = props.data
|
|
11
|
+
const isSelfLoop = props.source === props.target
|
|
12
|
+
const isBack = props.sourceX > props.targetX
|
|
13
|
+
const [path] = getSmoothStepPath({
|
|
14
|
+
sourceX: props.sourceX,
|
|
15
|
+
sourceY: props.sourceY,
|
|
16
|
+
sourcePosition: props.sourcePosition,
|
|
17
|
+
targetX: props.targetX,
|
|
18
|
+
targetY: props.targetY,
|
|
19
|
+
targetPosition: props.targetPosition,
|
|
20
|
+
...(isSelfLoop && {
|
|
21
|
+
offset: 30,
|
|
22
|
+
borderRadius: 16,
|
|
23
|
+
}),
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
let labelX = props.sourceX
|
|
27
|
+
switch (true) {
|
|
28
|
+
case isSelfLoop:
|
|
29
|
+
labelX = props.sourceX + 24 + LABEL_OFFSET
|
|
30
|
+
break
|
|
31
|
+
case isBack:
|
|
32
|
+
labelX = props.sourceX - LABEL_OFFSET
|
|
33
|
+
break
|
|
34
|
+
default:
|
|
35
|
+
labelX = props.sourceX + LABEL_OFFSET
|
|
36
|
+
break
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<EdgeContainer {...props}>
|
|
41
|
+
<EdgePath
|
|
42
|
+
edgeProps={props}
|
|
43
|
+
svgPath={path}
|
|
44
|
+
/>
|
|
45
|
+
<EdgeLabelContainer
|
|
46
|
+
edgeProps={props}
|
|
47
|
+
labelPosition={{
|
|
48
|
+
x: labelX,
|
|
49
|
+
y: props.sourceY + (!isSelfLoop ? LABEL_OFFSET : 0),
|
|
50
|
+
translate: isBack ? 'translate(-100%, 0)' : undefined,
|
|
51
|
+
}}
|
|
52
|
+
>
|
|
53
|
+
<EdgeLabel edgeProps={props}>
|
|
54
|
+
{navigateTo && (
|
|
55
|
+
<EdgeActionButton
|
|
56
|
+
onClick={e => {
|
|
57
|
+
e.stopPropagation()
|
|
58
|
+
diagram.navigateTo(navigateTo)
|
|
59
|
+
}} />
|
|
60
|
+
)}
|
|
61
|
+
</EdgeLabel>
|
|
62
|
+
</EdgeLabelContainer>
|
|
63
|
+
</EdgeContainer>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import type { CustomNodes } from '../../custom/customNodes'
|
|
2
2
|
import type { Types } from '../types'
|
|
3
3
|
import { RelationshipEdge } from './edges/RelationshipEdge'
|
|
4
|
+
import { SequenceStepEdge } from './edges/SequenceStepEdge'
|
|
4
5
|
import {
|
|
5
6
|
CompoundDeploymentNode,
|
|
6
7
|
CompoundElementNode,
|
|
7
8
|
DeploymentNode,
|
|
8
9
|
ElementNode,
|
|
10
|
+
SequenceActorNode,
|
|
9
11
|
ViewGroupNode,
|
|
10
|
-
} from './nodes
|
|
12
|
+
} from './nodes'
|
|
11
13
|
|
|
12
14
|
export const BuiltinNodes = {
|
|
13
15
|
element: ElementNode,
|
|
@@ -15,8 +17,12 @@ export const BuiltinNodes = {
|
|
|
15
17
|
compoundElement: CompoundElementNode,
|
|
16
18
|
compoundDeployment: CompoundDeploymentNode,
|
|
17
19
|
viewGroup: ViewGroupNode,
|
|
20
|
+
sequenceActor: SequenceActorNode,
|
|
18
21
|
} satisfies Required<CustomNodes>
|
|
19
22
|
|
|
23
|
+
export { SequenceParallelArea } from './nodes/SequenceActorNode'
|
|
24
|
+
|
|
20
25
|
export const edgeTypes = {
|
|
21
26
|
relationship: RelationshipEdge,
|
|
27
|
+
'seq-step': SequenceStepEdge,
|
|
22
28
|
} satisfies { [key in Types.Edge['type']]: any }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { NodeId } from '@likec4/core'
|
|
1
|
+
import type { NodeId } from '@likec4/core/types'
|
|
2
2
|
import { IconTransform, IconZoomScan } from '@tabler/icons-react'
|
|
3
3
|
import { useMemo } from 'react'
|
|
4
4
|
import { hasAtLeast } from 'remeda'
|
|
@@ -8,6 +8,8 @@ import { useEnabledFeatures } from '../../../context/DiagramFeatures'
|
|
|
8
8
|
import { useDiagram } from '../../../hooks/useDiagram'
|
|
9
9
|
import type { Types } from '../../types'
|
|
10
10
|
|
|
11
|
+
type RequiredData = Pick<Types.ElementNodeData, 'modelFqn' | 'navigateTo'>
|
|
12
|
+
|
|
11
13
|
type WithExtraButtons = {
|
|
12
14
|
/**
|
|
13
15
|
* Add extra action buttons
|
|
@@ -31,7 +33,7 @@ type WithExtraButtons = {
|
|
|
31
33
|
extraButtons?: ElementActionButtons.Item[]
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
export type ElementActionsProps = NodeProps<
|
|
36
|
+
export type ElementActionsProps = NodeProps<RequiredData> & WithExtraButtons
|
|
35
37
|
|
|
36
38
|
export const ElementActions = ({
|
|
37
39
|
extraButtons,
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { defaultTheme } from '@likec4/core'
|
|
2
|
+
import { css } from '@likec4/styles/css'
|
|
3
|
+
import { Box } from '@likec4/styles/jsx'
|
|
4
|
+
import type { NodeProps } from '@xyflow/react'
|
|
5
|
+
import { Handle } from '@xyflow/react'
|
|
6
|
+
import { Position } from '@xyflow/system'
|
|
7
|
+
import { ElementNodeContainer, ElementShape, ElementTitle } from '../../../custom'
|
|
8
|
+
import { type Types } from '../../types'
|
|
9
|
+
import { ElementActions } from './ElementActions'
|
|
10
|
+
import { ElementDetailsButtonWithHandler } from './nodes'
|
|
11
|
+
|
|
12
|
+
const positionMap: Record<Types.SequenceActorNodePort['position'], Position> = {
|
|
13
|
+
left: Position.Left,
|
|
14
|
+
right: Position.Right,
|
|
15
|
+
top: Position.Top,
|
|
16
|
+
bottom: Position.Bottom,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const ActorStepPort = ({
|
|
20
|
+
data,
|
|
21
|
+
port: p,
|
|
22
|
+
}: {
|
|
23
|
+
data: Types.SequenceActorNodeData
|
|
24
|
+
port: Types.SequenceActorNodePort
|
|
25
|
+
}) => {
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
<Box
|
|
29
|
+
data-likec4-color={data.color}
|
|
30
|
+
className={css({
|
|
31
|
+
position: 'absolute',
|
|
32
|
+
backgroundColor: 'var(--likec4-palette-fill)',
|
|
33
|
+
rounded: 'xs',
|
|
34
|
+
width: {
|
|
35
|
+
base: '5px',
|
|
36
|
+
_whenHovered: '7px',
|
|
37
|
+
_whenSelected: '7px',
|
|
38
|
+
},
|
|
39
|
+
// pointerEvents: 'none',
|
|
40
|
+
transition: 'fast',
|
|
41
|
+
translateX: '-1/2',
|
|
42
|
+
translateY: '-1/2',
|
|
43
|
+
translate: 'auto',
|
|
44
|
+
// transform: 'translate',
|
|
45
|
+
})}
|
|
46
|
+
style={{
|
|
47
|
+
top: p.cy,
|
|
48
|
+
left: p.cx,
|
|
49
|
+
height: p.height,
|
|
50
|
+
// transform: p.type === 'source' ? 'translate(-50%, -16px)' : 'translate(-50%, -50%)',
|
|
51
|
+
// transform: 'translate(-50%, -50%)',
|
|
52
|
+
// zIndex: p.type === 'source' ? 1 : 0,
|
|
53
|
+
}}
|
|
54
|
+
/>
|
|
55
|
+
<Handle
|
|
56
|
+
id={p.id}
|
|
57
|
+
type={p.type}
|
|
58
|
+
position={positionMap[p.position]}
|
|
59
|
+
style={{
|
|
60
|
+
top: p.cy - 3,
|
|
61
|
+
left: p.cx - 3,
|
|
62
|
+
width: 6,
|
|
63
|
+
height: 6,
|
|
64
|
+
right: 'unset',
|
|
65
|
+
bottom: 'unset',
|
|
66
|
+
visibility: 'hidden',
|
|
67
|
+
transform: p.position === 'left' ? 'translate(-150%, 0)' : 'translate(100%, 0)',
|
|
68
|
+
}} />
|
|
69
|
+
</>
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function SequenceActorNode(props: NodeProps<Types.SequenceActorNode>) {
|
|
74
|
+
const data = props.data
|
|
75
|
+
const {
|
|
76
|
+
positionAbsoluteY,
|
|
77
|
+
data: {
|
|
78
|
+
viewHeight,
|
|
79
|
+
hovered: isHovered = false,
|
|
80
|
+
ports,
|
|
81
|
+
},
|
|
82
|
+
} = props
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<>
|
|
86
|
+
<Box
|
|
87
|
+
className={css({
|
|
88
|
+
position: 'absolute',
|
|
89
|
+
rounded: 'xs',
|
|
90
|
+
top: '1',
|
|
91
|
+
pointerEvents: 'none',
|
|
92
|
+
transition: 'fast',
|
|
93
|
+
translateX: '-1/2',
|
|
94
|
+
translate: 'auto',
|
|
95
|
+
// transform: 'translate',
|
|
96
|
+
})}
|
|
97
|
+
style={{
|
|
98
|
+
// position: 'absolute',
|
|
99
|
+
backgroundColor: defaultTheme.elements.gray.fill,
|
|
100
|
+
opacity: isHovered ? 0.5 : 0.4,
|
|
101
|
+
left: '50%',
|
|
102
|
+
width: isHovered ? 3 : 2,
|
|
103
|
+
height: viewHeight - positionAbsoluteY,
|
|
104
|
+
zIndex: -1,
|
|
105
|
+
pointerEvents: 'none',
|
|
106
|
+
// top: p.y,
|
|
107
|
+
// left: p.width / 2,
|
|
108
|
+
// height: p.type === 'source' ? 48 : 32,
|
|
109
|
+
// transform: p.type === 'source' ? 'translate(-50%, -16px)' : 'translate(-50%, -50%)',
|
|
110
|
+
// transform: 'translate(-50%, -50%)',
|
|
111
|
+
// zIndex: p.type === 'source' ? 1 : 0,
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
{
|
|
115
|
+
/* <div
|
|
116
|
+
// css={{
|
|
117
|
+
// backgroundColor: 'var(--likec4-palette-fill)',
|
|
118
|
+
// }}
|
|
119
|
+
style={{
|
|
120
|
+
position: 'absolute',
|
|
121
|
+
backgroundColor: defaultTheme.elements.gray.fill,
|
|
122
|
+
opacity: 0.5,
|
|
123
|
+
top: 8,
|
|
124
|
+
left: 'calc(50% - 1px)',
|
|
125
|
+
width: 2,
|
|
126
|
+
height: viewHeight - positionAbsoluteY,
|
|
127
|
+
zIndex: -1,
|
|
128
|
+
pointerEvents: 'none',
|
|
129
|
+
}}>
|
|
130
|
+
</div> */
|
|
131
|
+
}
|
|
132
|
+
<ElementNodeContainer nodeProps={props}>
|
|
133
|
+
<ElementShape {...props} />
|
|
134
|
+
<ElementTitle {...props} />
|
|
135
|
+
{data.modelFqn && (
|
|
136
|
+
<>
|
|
137
|
+
<ElementActions {...props} data={data as Types.ElementNodeData} />
|
|
138
|
+
<ElementDetailsButtonWithHandler {...props} data={data as Types.ElementNodeData} />
|
|
139
|
+
</>
|
|
140
|
+
)}
|
|
141
|
+
</ElementNodeContainer>
|
|
142
|
+
{ports.map(p => <ActorStepPort key={p.id} port={p} data={props.data} />)}
|
|
143
|
+
</>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function SequenceParallelArea(props: NodeProps<Types.SequenceActorNode>) {
|
|
148
|
+
return (
|
|
149
|
+
<Box
|
|
150
|
+
data-likec4-color={props.data.color}
|
|
151
|
+
css={{
|
|
152
|
+
width: '100%',
|
|
153
|
+
height: '100%',
|
|
154
|
+
border: 'default',
|
|
155
|
+
rounded: 'sm',
|
|
156
|
+
borderWidth: 1,
|
|
157
|
+
'--_color': {
|
|
158
|
+
base: 'var(--likec4-palette-stroke)',
|
|
159
|
+
_dark: '[color-mix(in srgb, var(--likec4-palette-hiContrast) 40%, var(--likec4-palette-fill))]',
|
|
160
|
+
},
|
|
161
|
+
borderColor: '[var(--_color)/30]',
|
|
162
|
+
backgroundColor: 'var(--likec4-palette-fill)/15',
|
|
163
|
+
pointerEvents: 'none',
|
|
164
|
+
paddingLeft: '2',
|
|
165
|
+
paddingTop: '0.5',
|
|
166
|
+
fontSize: 'xs',
|
|
167
|
+
fontWeight: 'bold',
|
|
168
|
+
letterSpacing: '.75px',
|
|
169
|
+
color: '[var(--_color)/75]',
|
|
170
|
+
}}
|
|
171
|
+
>
|
|
172
|
+
PARALLEL
|
|
173
|
+
</Box>
|
|
174
|
+
)
|
|
175
|
+
}
|