@likec4/diagram 1.23.1 → 1.24.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.css.d.ts +5 -0
- package/dist/LikeC4Diagram.css.js +1 -0
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.js +6 -2
- package/dist/LikeC4Diagram.props.d.ts +6 -0
- package/dist/StaticLikeC4Diagram.js +2 -1
- package/dist/base/BaseXYFlow.d.ts +1 -1
- package/dist/base/BaseXYFlow.js +12 -3
- package/dist/base/const.d.ts +1 -1
- package/dist/base/const.js +1 -1
- package/dist/base/primitives/compound/CompoundActionButton.css.js +2 -0
- package/dist/base/primitives/compound/CompoundDetailsButton.css.js +2 -0
- package/dist/base/primitives/compound/CompoundNodeContainer.css.d.ts +0 -1
- package/dist/base/primitives/compound/CompoundNodeContainer.css.js +4 -4
- package/dist/base/primitives/compound/CompoundNodeContainer.js +35 -22
- package/dist/base/primitives/compound/CompoundTitle.css.js +3 -1
- package/dist/base/primitives/customNode.js +1 -1
- package/dist/base/primitives/edge/EdgeContainer.js +5 -4
- package/dist/base/primitives/edge/EdgeLabel.css.d.ts +0 -1
- package/dist/base/primitives/edge/EdgeLabel.css.js +2 -5
- package/dist/base/primitives/edge/EdgeLabel.js +5 -5
- package/dist/base/primitives/edge/edge.css.d.ts +1 -1
- package/dist/base/primitives/edge/edge.css.js +4 -5
- package/dist/base/primitives/element/ElementActionButtons.css.js +2 -0
- package/dist/base/primitives/element/ElementActionButtons.js +4 -3
- package/dist/base/primitives/element/ElementDetailsButton.css.js +2 -0
- package/dist/base/primitives/element/ElementNodeContainer.css.js +2 -0
- package/dist/base/primitives/element/ElementNodeContainer.js +3 -1
- package/dist/base/primitives/element/ElementShape.css.js +4 -2
- package/dist/base/primitives/element/ElementShape.js +2 -3
- package/dist/base/primitives/element/ElementTitle.css.js +2 -0
- package/dist/base/primitives/element/styles.css.js +2 -0
- package/dist/components/SearchControl.css.js +2 -0
- package/dist/context/FramerMotionConfig.d.ts +9 -1
- package/dist/context/FramerMotionConfig.js +5 -2
- package/dist/context/RootContainer.js +13 -1
- package/dist/diagram.css +1 -1
- package/dist/globals.css.d.ts +2 -0
- package/dist/hooks/safeContext.js +1 -0
- package/dist/hooks/useDiagram.d.ts +415 -693
- package/dist/hooks/useDiagram.js +1 -0
- package/dist/hooks/useIsReducedGraphics.d.ts +4 -0
- package/dist/hooks/useIsReducedGraphics.js +8 -0
- package/dist/hooks/useXYFlow.js +1 -1
- package/dist/likec4diagram/DiagramUI.d.ts +2 -1
- package/dist/likec4diagram/DiagramUI.js +5 -3
- package/dist/likec4diagram/custom/nodes/nodeTypes.js +2 -2
- package/dist/likec4diagram/ui/controls/styles.css.js +2 -0
- package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.css.js +2 -0
- package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +3 -4
- package/dist/likec4diagram/ui/search/LikeC4Search.css.js +2 -0
- package/dist/overlays/element-details/ElementDetailsCard.js +12 -8
- package/dist/overlays/element-details/actor.d.ts +9084 -2569
- package/dist/overlays/overlay/Overlay.js +6 -3
- package/dist/overlays/relationship-details/RelationshipDetails.js +31 -17
- package/dist/overlays/relationship-details/actor.d.ts +228 -3
- package/dist/overlays/relationship-details/actor.js +86 -14
- package/dist/overlays/relationship-details/hooks.d.ts +3 -0
- package/dist/overlays/relationship-details/hooks.js +6 -2
- package/dist/overlays/relationships-browser/-useRelationshipsView.js +12 -3
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +12 -3
- package/dist/overlays/relationships-browser/actor.d.ts +271 -54
- package/dist/overlays/relationships-browser/actor.js +86 -23
- package/dist/state/DiagramActorProvider.js +12 -2
- package/dist/state/diagram-machine.d.ts +426 -694
- package/dist/state/diagram-machine.js +89 -68
- package/dist/state/persistence.d.ts +5 -0
- package/dist/state/persistence.js +23 -0
- package/package.json +9 -9
- package/src/LikeC4Diagram.css.ts +13 -5
- package/src/LikeC4Diagram.props.ts +7 -0
- package/src/LikeC4Diagram.tsx +33 -24
- package/src/StaticLikeC4Diagram.tsx +2 -1
- package/src/base/BaseXYFlow.tsx +14 -9
- package/src/base/const.ts +1 -1
- package/src/base/primitives/compound/CompoundActionButton.css.ts +6 -0
- package/src/base/primitives/compound/CompoundDetailsButton.css.ts +4 -0
- package/src/base/primitives/compound/CompoundNodeContainer.css.ts +41 -59
- package/src/base/primitives/compound/CompoundNodeContainer.tsx +42 -22
- package/src/base/primitives/compound/CompoundTitle.css.ts +14 -13
- package/src/base/primitives/customNode.ts +3 -2
- package/src/base/primitives/edge/EdgeContainer.tsx +4 -3
- package/src/base/primitives/edge/EdgeLabel.css.ts +17 -11
- package/src/base/primitives/edge/EdgeLabel.tsx +4 -4
- package/src/base/primitives/edge/edge.css.ts +47 -27
- package/src/base/primitives/element/ElementActionButtons.css.ts +4 -0
- package/src/base/primitives/element/ElementActionButtons.tsx +4 -2
- package/src/base/primitives/element/ElementDetailsButton.css.ts +6 -8
- package/src/base/primitives/element/ElementNodeContainer.css.ts +18 -21
- package/src/base/primitives/element/ElementNodeContainer.tsx +3 -1
- package/src/base/primitives/element/ElementShape.css.ts +10 -6
- package/src/base/primitives/element/ElementShape.tsx +2 -2
- package/src/components/SearchControl.css.ts +11 -4
- package/src/context/FramerMotionConfig.tsx +13 -2
- package/src/context/RootContainer.tsx +9 -2
- package/src/globals.css.ts +3 -0
- package/src/hooks/safeContext.tsx +2 -1
- package/src/hooks/useDiagram.ts +1 -0
- package/src/hooks/useIsReducedGraphics.ts +5 -0
- package/src/hooks/useXYFlow.ts +1 -1
- package/src/likec4diagram/DiagramUI.tsx +5 -3
- package/src/likec4diagram/custom/nodes/nodeTypes.tsx +2 -2
- package/src/likec4diagram/ui/controls/styles.css.ts +11 -1
- package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.css.ts +10 -3
- package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +6 -3
- package/src/likec4diagram/ui/search/LikeC4Search.css.ts +1 -0
- package/src/overlays/element-details/ElementDetailsCard.tsx +238 -231
- package/src/overlays/overlay/Overlay.css.ts +1 -9
- package/src/overlays/overlay/Overlay.tsx +6 -3
- package/src/overlays/relationship-details/RelationshipDetails.tsx +83 -66
- package/src/overlays/relationship-details/actor.ts +106 -13
- package/src/overlays/relationship-details/hooks.ts +6 -2
- package/src/overlays/relationships-browser/-useRelationshipsView.ts +10 -0
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +16 -8
- package/src/overlays/relationships-browser/actor.ts +92 -22
- package/src/state/DiagramActorProvider.tsx +13 -2
- package/src/state/diagram-machine.ts +88 -65
- package/src/state/persistence.ts +22 -0
|
@@ -62,8 +62,9 @@ import {
|
|
|
62
62
|
updateNodeData,
|
|
63
63
|
} from './assign'
|
|
64
64
|
import { type HotKeyEvent, hotkeyActorLogic } from './hotkeyActor'
|
|
65
|
+
import { DiagramToggledFeaturesPersistence } from './persistence'
|
|
65
66
|
import { type Events as SyncLayoutEvents, syncManualLayoutActorLogic } from './syncManualLayoutActor'
|
|
66
|
-
import { focusedBounds, typedSystem } from './utils'
|
|
67
|
+
import { findDiagramNode, focusedBounds, typedSystem } from './utils'
|
|
67
68
|
|
|
68
69
|
type XYStoreApi = ReturnType<typeof useStoreApi<Types.Node, Types.Edge>>
|
|
69
70
|
|
|
@@ -197,7 +198,7 @@ export const diagramMachine = setup({
|
|
|
197
198
|
}
|
|
198
199
|
nonexhaustive(event.type)
|
|
199
200
|
},
|
|
200
|
-
'click: selected node
|
|
201
|
+
'click: selected node': ({ event }) => {
|
|
201
202
|
assertEvent(event, 'xyflow.nodeClick')
|
|
202
203
|
return event.node.selected === true
|
|
203
204
|
},
|
|
@@ -209,6 +210,10 @@ export const diagramMachine = setup({
|
|
|
209
210
|
assertEvent(event, 'xyflow.nodeClick')
|
|
210
211
|
return context.focusedNode === event.node.id
|
|
211
212
|
},
|
|
213
|
+
'click: node has connections': ({ context, event }) => {
|
|
214
|
+
assertEvent(event, 'xyflow.nodeClick')
|
|
215
|
+
return context.xyedges.some(e => e.source === event.node.id || e.target === event.node.id)
|
|
216
|
+
},
|
|
212
217
|
},
|
|
213
218
|
actions: {
|
|
214
219
|
'trigger:NavigateTo': (_, _params: { viewId: ViewId }) => {
|
|
@@ -220,6 +225,26 @@ export const diagramMachine = setup({
|
|
|
220
225
|
'trigger:OpenSource': (_, _params: OpenSourceParams) => {
|
|
221
226
|
},
|
|
222
227
|
|
|
228
|
+
'assign lastClickedNode': assign(({ context, event }) => {
|
|
229
|
+
assertEvent(event, 'xyflow.nodeClick')
|
|
230
|
+
return {
|
|
231
|
+
lastClickedNode: lastClickedNode({ context, event }),
|
|
232
|
+
}
|
|
233
|
+
}),
|
|
234
|
+
|
|
235
|
+
'open source of focused or last clicked node': enqueueActions(({ context, enqueue }) => {
|
|
236
|
+
const nodeId = context.focusedNode ?? context.lastClickedNode?.id
|
|
237
|
+
if (!nodeId || !context.features.enableVscode) return
|
|
238
|
+
const diagramNode = findDiagramNode(context, nodeId)
|
|
239
|
+
if (!diagramNode) return
|
|
240
|
+
|
|
241
|
+
if (DiagramNode.deploymentRef(diagramNode)) {
|
|
242
|
+
enqueue.raise({ type: 'open.source', deployment: DiagramNode.deploymentRef(diagramNode)! })
|
|
243
|
+
} else if (DiagramNode.modelRef(diagramNode)) {
|
|
244
|
+
enqueue.raise({ type: 'open.source', element: DiagramNode.modelRef(diagramNode)! })
|
|
245
|
+
}
|
|
246
|
+
}),
|
|
247
|
+
|
|
223
248
|
'xyflow:fitDiagram': ({ context }, params?: { duration?: number; bounds?: BBox }) => {
|
|
224
249
|
const {
|
|
225
250
|
bounds = context.view.bounds,
|
|
@@ -340,7 +365,7 @@ export const diagramMachine = setup({
|
|
|
340
365
|
context: ({ input, self, spawn }) => ({
|
|
341
366
|
...input,
|
|
342
367
|
features: { ...AllDisabled },
|
|
343
|
-
toggledFeatures: {
|
|
368
|
+
toggledFeatures: DiagramToggledFeaturesPersistence.read() ?? {
|
|
344
369
|
enableReadOnly: true,
|
|
345
370
|
},
|
|
346
371
|
initialized: false,
|
|
@@ -398,10 +423,11 @@ export const diagramMachine = setup({
|
|
|
398
423
|
{
|
|
399
424
|
// TODO: xstate fails to infer the type of the guard
|
|
400
425
|
guard: and([
|
|
401
|
-
'enabled: FocusMode'
|
|
426
|
+
'enabled: FocusMode',
|
|
427
|
+
'click: node has connections',
|
|
402
428
|
or([
|
|
403
|
-
'click: same node'
|
|
404
|
-
'click: selected node
|
|
429
|
+
'click: same node',
|
|
430
|
+
'click: selected node',
|
|
405
431
|
]),
|
|
406
432
|
]) as any,
|
|
407
433
|
actions: [
|
|
@@ -413,9 +439,10 @@ export const diagramMachine = setup({
|
|
|
413
439
|
target: 'focused',
|
|
414
440
|
},
|
|
415
441
|
{
|
|
416
|
-
actions:
|
|
417
|
-
lastClickedNode,
|
|
418
|
-
|
|
442
|
+
actions: [
|
|
443
|
+
'assign lastClickedNode',
|
|
444
|
+
'open source of focused or last clicked node',
|
|
445
|
+
],
|
|
419
446
|
},
|
|
420
447
|
],
|
|
421
448
|
'xyflow.paneClick': {
|
|
@@ -458,6 +485,7 @@ export const diagramMachine = setup({
|
|
|
458
485
|
...focusNodesEdges(s),
|
|
459
486
|
viewportBeforeFocus: { ...s.context.viewport },
|
|
460
487
|
})),
|
|
488
|
+
'open source of focused or last clicked node',
|
|
461
489
|
spawnChild('hotkeyActorLogic', { id: 'hotkey' }),
|
|
462
490
|
{
|
|
463
491
|
type: 'xyflow:fitDiagram',
|
|
@@ -490,6 +518,7 @@ export const diagramMachine = setup({
|
|
|
490
518
|
focusedNode: ({ event }) => event.node.id as NodeId,
|
|
491
519
|
}),
|
|
492
520
|
assign(focusNodesEdges),
|
|
521
|
+
'open source of focused or last clicked node',
|
|
493
522
|
{
|
|
494
523
|
type: 'xyflow:fitDiagram',
|
|
495
524
|
params: focusedBounds,
|
|
@@ -503,6 +532,7 @@ export const diagramMachine = setup({
|
|
|
503
532
|
focusedNode: ({ event }) => event.nodeId,
|
|
504
533
|
}),
|
|
505
534
|
assign(focusNodesEdges),
|
|
535
|
+
'open source of focused or last clicked node',
|
|
506
536
|
{
|
|
507
537
|
type: 'xyflow:fitDiagram',
|
|
508
538
|
params: focusedBounds,
|
|
@@ -534,57 +564,16 @@ export const diagramMachine = setup({
|
|
|
534
564
|
},
|
|
535
565
|
// Navigating to another view (after `navigateTo` event)
|
|
536
566
|
navigating: {
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
enqueue({
|
|
545
|
-
type: 'trigger:NavigateTo',
|
|
546
|
-
params: ({ context }) => ({
|
|
547
|
-
viewId: nonNullable(context.lastOnNavigate, 'Invalid state, lastOnNavigate is null').toView,
|
|
548
|
-
}),
|
|
549
|
-
})
|
|
567
|
+
entry: [
|
|
568
|
+
'closeAllOverlays',
|
|
569
|
+
'stopSyncLayout',
|
|
570
|
+
{
|
|
571
|
+
type: 'trigger:NavigateTo',
|
|
572
|
+
params: ({ context }) => ({
|
|
573
|
+
viewId: nonNullable(context.lastOnNavigate, 'Invalid state, lastOnNavigate is null').toView,
|
|
550
574
|
}),
|
|
551
|
-
on: {
|
|
552
|
-
'update.view': {
|
|
553
|
-
actions: enqueueActions(({ enqueue, context, event }) => {
|
|
554
|
-
const { fromNode, toNode } = findCorrespondingNode(context, event)
|
|
555
|
-
if (fromNode && toNode) {
|
|
556
|
-
enqueue({
|
|
557
|
-
type: 'xyflow:alignNodeFromToAfterNavigate',
|
|
558
|
-
params: {
|
|
559
|
-
fromNode: fromNode.id,
|
|
560
|
-
toPosition: {
|
|
561
|
-
x: toNode.position[0],
|
|
562
|
-
y: toNode.position[1],
|
|
563
|
-
},
|
|
564
|
-
},
|
|
565
|
-
})
|
|
566
|
-
enqueue.raise({ type: 'fitDiagram' }, { id: 'fitDiagram', delay: 80 })
|
|
567
|
-
} else {
|
|
568
|
-
enqueue({
|
|
569
|
-
type: 'xyflow:setViewportCenter',
|
|
570
|
-
params: getBBoxCenter(event.view.bounds),
|
|
571
|
-
})
|
|
572
|
-
enqueue.raise({ type: 'fitDiagram', duration: 200 }, { id: 'fitDiagram', delay: 25 })
|
|
573
|
-
}
|
|
574
|
-
enqueue.assign(updateNavigationHistory)
|
|
575
|
-
enqueue.assign(mergeXYNodesEdges)
|
|
576
|
-
}),
|
|
577
|
-
target: 'done',
|
|
578
|
-
},
|
|
579
|
-
},
|
|
580
575
|
},
|
|
581
|
-
|
|
582
|
-
type: 'final',
|
|
583
|
-
},
|
|
584
|
-
},
|
|
585
|
-
onDone: {
|
|
586
|
-
target: 'idle',
|
|
587
|
-
},
|
|
576
|
+
],
|
|
588
577
|
exit: assign({
|
|
589
578
|
syncLayoutActorRef: ({ self, context, spawn }) =>
|
|
590
579
|
spawn('syncManualLayoutActorLogic', {
|
|
@@ -592,12 +581,44 @@ export const diagramMachine = setup({
|
|
|
592
581
|
systemId: 'syncLayout',
|
|
593
582
|
input: { parent: self, viewId: context.view.id },
|
|
594
583
|
}),
|
|
595
|
-
lastOnNavigate: null,
|
|
584
|
+
// lastOnNavigate: null,
|
|
596
585
|
}),
|
|
586
|
+
on: {
|
|
587
|
+
'update.view': {
|
|
588
|
+
actions: enqueueActions(({ enqueue, context, event }) => {
|
|
589
|
+
const { fromNode, toNode } = findCorrespondingNode(context, event)
|
|
590
|
+
if (fromNode && toNode) {
|
|
591
|
+
enqueue({
|
|
592
|
+
type: 'xyflow:alignNodeFromToAfterNavigate',
|
|
593
|
+
params: {
|
|
594
|
+
fromNode: fromNode.id,
|
|
595
|
+
toPosition: {
|
|
596
|
+
x: toNode.position[0],
|
|
597
|
+
y: toNode.position[1],
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
})
|
|
601
|
+
enqueue.raise({ type: 'fitDiagram' }, { id: 'fitDiagram', delay: 80 })
|
|
602
|
+
} else {
|
|
603
|
+
enqueue({
|
|
604
|
+
type: 'xyflow:setViewportCenter',
|
|
605
|
+
params: getBBoxCenter(event.view.bounds),
|
|
606
|
+
})
|
|
607
|
+
enqueue.raise({ type: 'fitDiagram', duration: 200 }, { id: 'fitDiagram', delay: 25 })
|
|
608
|
+
}
|
|
609
|
+
enqueue.assign(updateNavigationHistory)
|
|
610
|
+
enqueue.assign(mergeXYNodesEdges)
|
|
611
|
+
enqueue.assign({
|
|
612
|
+
lastOnNavigate: null,
|
|
613
|
+
})
|
|
614
|
+
}),
|
|
615
|
+
target: '#idle',
|
|
616
|
+
},
|
|
617
|
+
},
|
|
597
618
|
},
|
|
598
619
|
walkthrough: {
|
|
599
620
|
entry: [
|
|
600
|
-
|
|
621
|
+
spawnChild('hotkeyActorLogic', { id: 'hotkey' }),
|
|
601
622
|
assign({
|
|
602
623
|
viewportBeforeFocus: ({ context }) => context.viewport,
|
|
603
624
|
activeWalkthrough: ({ context, event }) => {
|
|
@@ -863,11 +884,13 @@ export const diagramMachine = setup({
|
|
|
863
884
|
},
|
|
864
885
|
'toggle.feature': {
|
|
865
886
|
actions: assign({
|
|
866
|
-
toggledFeatures: ({ context, event }) =>
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
887
|
+
toggledFeatures: ({ context, event }) => {
|
|
888
|
+
return DiagramToggledFeaturesPersistence.write({
|
|
889
|
+
...context.toggledFeatures,
|
|
890
|
+
[`enable${event.feature}`]: event.forceValue ??
|
|
891
|
+
!(context.toggledFeatures[`enable${event.feature}`] ?? context.features[`enable${event.feature}`]),
|
|
892
|
+
})
|
|
893
|
+
},
|
|
871
894
|
}),
|
|
872
895
|
},
|
|
873
896
|
},
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { isBoolean, pickBy } from 'remeda'
|
|
2
|
+
import type { EnabledFeatures } from '../context/DiagramFeatures'
|
|
3
|
+
|
|
4
|
+
const key = `likec4:diagram:toggledFeatures`
|
|
5
|
+
export const DiagramToggledFeaturesPersistence = {
|
|
6
|
+
read() {
|
|
7
|
+
try {
|
|
8
|
+
let fromStorage = sessionStorage.getItem(key)
|
|
9
|
+
if (fromStorage) {
|
|
10
|
+
return JSON.parse(fromStorage) as Partial<EnabledFeatures>
|
|
11
|
+
}
|
|
12
|
+
throw new Error(`Workspace ${key} not found`)
|
|
13
|
+
} catch (e) {
|
|
14
|
+
console.error(`Error reading fromStorage ${key}:`, e)
|
|
15
|
+
return null
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
write<F extends Partial<EnabledFeatures>>(toggledFeatures: F): F {
|
|
19
|
+
sessionStorage.setItem(key, JSON.stringify(pickBy(toggledFeatures, isBoolean)))
|
|
20
|
+
return toggledFeatures
|
|
21
|
+
},
|
|
22
|
+
}
|