@likec4/diagram 1.22.0 → 1.22.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/context/DiagramFeatures.d.ts +1 -1
- package/dist/hooks/useDiagram.d.ts +104 -68
- package/dist/hooks/useDiagram.js +3 -0
- package/dist/likec4diagram/DiagramActor.js +13 -2
- package/dist/likec4diagram/XYFlow.js +9 -2
- package/dist/likec4diagram/state/actorContext.d.ts +604 -452
- package/dist/likec4diagram/state/machine.d.ts +113 -67
- package/dist/likec4diagram/state/machine.js +22 -5
- package/dist/likec4diagram/state/syncManualLayoutActor.js +4 -8
- package/dist/likec4diagram/ui/controls/Controls.js +2 -0
- package/dist/likec4diagram/ui/controls/ToggleReadonly.d.ts +1 -0
- package/dist/likec4diagram/ui/controls/ToggleReadonly.js +29 -0
- package/package.json +3 -4
- package/src/context/DiagramFeatures.tsx +1 -1
- package/src/hooks/useDiagram.ts +5 -0
- package/src/likec4diagram/DiagramActor.tsx +15 -2
- package/src/likec4diagram/XYFlow.tsx +9 -1
- package/src/likec4diagram/state/machine.ts +28 -4
- package/src/likec4diagram/state/syncManualLayoutActor.ts +6 -9
- package/src/likec4diagram/ui/controls/Controls.tsx +2 -0
- package/src/likec4diagram/ui/controls/ToggleReadonly.tsx +31 -0
|
@@ -3,6 +3,7 @@ import { ReactFlowInstance, useStoreApi, GeneralHelpers, ViewportHelperFunctions
|
|
|
3
3
|
import { EdgeChange, NodeChange, Rect, Viewport, EdgeMarkerType, HandleType } from '@xyflow/system';
|
|
4
4
|
import { ActorRefFromLogic, SnapshotFrom, StateMachine, CallbackActorLogic, AnyEventObject, NonReducibleUnknown, EventObject, MetaObject, AnyActorLogic, ConditionalRequired, InputFrom, RequiredLogicInput, IsNotNever, ActorRef, MachineSnapshot, AnyActorRef, StateValue, ActionFunction, ActorLogic, Values, RequiredActorOptions, GetConcreteByKey, StopAction, CancelAction } from 'xstate';
|
|
5
5
|
import { EnabledFeatures } from '../../context';
|
|
6
|
+
import { FeatureName } from '../../context/DiagramFeatures';
|
|
6
7
|
import { OpenSourceParams } from '../../LikeC4Diagram.props';
|
|
7
8
|
import { Types } from '../types';
|
|
8
9
|
import { AlignmentMode } from './aligners';
|
|
@@ -31,8 +32,10 @@ export interface Input {
|
|
|
31
32
|
pannable: boolean;
|
|
32
33
|
fitViewPadding: number;
|
|
33
34
|
}
|
|
35
|
+
type ToggledFeatures = Partial<EnabledFeatures>;
|
|
34
36
|
export interface DiagramContext extends Input {
|
|
35
37
|
features: EnabledFeatures;
|
|
38
|
+
toggledFeatures: ToggledFeatures;
|
|
36
39
|
initialized: boolean;
|
|
37
40
|
viewport: Viewport;
|
|
38
41
|
viewportChangedManually: boolean;
|
|
@@ -156,6 +159,10 @@ export type Events = HotKeyEvent | {
|
|
|
156
159
|
direction: 'next' | 'previous';
|
|
157
160
|
} | {
|
|
158
161
|
type: 'walkthrough.end';
|
|
162
|
+
} | {
|
|
163
|
+
type: 'toggle.feature';
|
|
164
|
+
feature: FeatureName;
|
|
165
|
+
forceValue?: boolean;
|
|
159
166
|
};
|
|
160
167
|
export type ActionArg = {
|
|
161
168
|
context: DiagramContext;
|
|
@@ -614,6 +621,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
614
621
|
toPosition: XYPoint;
|
|
615
622
|
};
|
|
616
623
|
};
|
|
624
|
+
updateFeatures: {
|
|
625
|
+
type: "updateFeatures";
|
|
626
|
+
params: NonReducibleUnknown;
|
|
627
|
+
};
|
|
617
628
|
}>, Values<{
|
|
618
629
|
"enabled: FitView": {
|
|
619
630
|
type: "enabled: FitView";
|
|
@@ -1444,6 +1455,9 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
1444
1455
|
enableLikeC4Model: boolean;
|
|
1445
1456
|
enableVscode: boolean;
|
|
1446
1457
|
};
|
|
1458
|
+
toggledFeatures: {
|
|
1459
|
+
enableReadOnly: true;
|
|
1460
|
+
};
|
|
1447
1461
|
initialized: false;
|
|
1448
1462
|
viewportChangedManually: false;
|
|
1449
1463
|
lastOnNavigate: null;
|
|
@@ -1831,6 +1845,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
1831
1845
|
toPosition: XYPoint;
|
|
1832
1846
|
};
|
|
1833
1847
|
};
|
|
1848
|
+
updateFeatures: {
|
|
1849
|
+
type: "updateFeatures";
|
|
1850
|
+
params: NonReducibleUnknown;
|
|
1851
|
+
};
|
|
1834
1852
|
}>, Values<{
|
|
1835
1853
|
"enabled: FitView": {
|
|
1836
1854
|
type: "enabled: FitView";
|
|
@@ -4531,6 +4549,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
4531
4549
|
toPosition: XYPoint;
|
|
4532
4550
|
};
|
|
4533
4551
|
};
|
|
4552
|
+
updateFeatures: {
|
|
4553
|
+
type: "updateFeatures";
|
|
4554
|
+
params: NonReducibleUnknown;
|
|
4555
|
+
};
|
|
4534
4556
|
}>, Values<{
|
|
4535
4557
|
"enabled: FitView": {
|
|
4536
4558
|
type: "enabled: FitView";
|
|
@@ -5775,6 +5797,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
5775
5797
|
toPosition: XYPoint;
|
|
5776
5798
|
};
|
|
5777
5799
|
};
|
|
5800
|
+
updateFeatures: {
|
|
5801
|
+
type: "updateFeatures";
|
|
5802
|
+
params: NonReducibleUnknown;
|
|
5803
|
+
};
|
|
5778
5804
|
}>, Values<{
|
|
5779
5805
|
"enabled: FitView": {
|
|
5780
5806
|
type: "enabled: FitView";
|
|
@@ -6080,6 +6106,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
6080
6106
|
toPosition: XYPoint;
|
|
6081
6107
|
};
|
|
6082
6108
|
};
|
|
6109
|
+
updateFeatures: {
|
|
6110
|
+
type: "updateFeatures";
|
|
6111
|
+
params: NonReducibleUnknown;
|
|
6112
|
+
};
|
|
6083
6113
|
}>, Values<{
|
|
6084
6114
|
"enabled: FitView": {
|
|
6085
6115
|
type: "enabled: FitView";
|
|
@@ -7246,6 +7276,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
7246
7276
|
toPosition: XYPoint;
|
|
7247
7277
|
};
|
|
7248
7278
|
};
|
|
7279
|
+
updateFeatures: {
|
|
7280
|
+
type: "updateFeatures";
|
|
7281
|
+
params: NonReducibleUnknown;
|
|
7282
|
+
};
|
|
7249
7283
|
}>, Values<{
|
|
7250
7284
|
"enabled: FitView": {
|
|
7251
7285
|
type: "enabled: FitView";
|
|
@@ -7559,6 +7593,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
7559
7593
|
toPosition: XYPoint;
|
|
7560
7594
|
};
|
|
7561
7595
|
};
|
|
7596
|
+
updateFeatures: {
|
|
7597
|
+
type: "updateFeatures";
|
|
7598
|
+
params: NonReducibleUnknown;
|
|
7599
|
+
};
|
|
7562
7600
|
}>, Values<{
|
|
7563
7601
|
"enabled: FitView": {
|
|
7564
7602
|
type: "enabled: FitView";
|
|
@@ -9385,6 +9423,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
9385
9423
|
toPosition: XYPoint;
|
|
9386
9424
|
};
|
|
9387
9425
|
};
|
|
9426
|
+
updateFeatures: {
|
|
9427
|
+
type: "updateFeatures";
|
|
9428
|
+
params: NonReducibleUnknown;
|
|
9429
|
+
};
|
|
9388
9430
|
}>, Values<{
|
|
9389
9431
|
"enabled: FitView": {
|
|
9390
9432
|
type: "enabled: FitView";
|
|
@@ -9640,10 +9682,10 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
9640
9682
|
}>, never, never, never, never>;
|
|
9641
9683
|
};
|
|
9642
9684
|
readonly 'update.features': {
|
|
9643
|
-
readonly actions:
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9685
|
+
readonly actions: "updateFeatures";
|
|
9686
|
+
};
|
|
9687
|
+
readonly 'update.nodeData': {
|
|
9688
|
+
readonly actions: ActionFunction<DiagramContext, Events, Events, undefined, Values<{
|
|
9647
9689
|
hotkeyActor: {
|
|
9648
9690
|
src: "hotkeyActor";
|
|
9649
9691
|
logic: CallbackActorLogic<AnyEventObject, NonReducibleUnknown, HotKeyEvent>;
|
|
@@ -9854,7 +9896,7 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
9854
9896
|
};
|
|
9855
9897
|
}>, never, never, never, never>;
|
|
9856
9898
|
};
|
|
9857
|
-
readonly 'update.
|
|
9899
|
+
readonly 'update.edgeData': {
|
|
9858
9900
|
readonly actions: ActionFunction<DiagramContext, Events, Events, undefined, Values<{
|
|
9859
9901
|
hotkeyActor: {
|
|
9860
9902
|
src: "hotkeyActor";
|
|
@@ -10066,8 +10108,27 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
10066
10108
|
};
|
|
10067
10109
|
}>, never, never, never, never>;
|
|
10068
10110
|
};
|
|
10069
|
-
readonly '
|
|
10070
|
-
readonly
|
|
10111
|
+
readonly 'layout.align': {
|
|
10112
|
+
readonly guard: "not readonly";
|
|
10113
|
+
readonly actions: readonly [{
|
|
10114
|
+
readonly type: "layout.align";
|
|
10115
|
+
readonly params: ({ event }: {
|
|
10116
|
+
context: DiagramContext;
|
|
10117
|
+
event: {
|
|
10118
|
+
type: "layout.align";
|
|
10119
|
+
mode: AlignmentMode;
|
|
10120
|
+
};
|
|
10121
|
+
}) => {
|
|
10122
|
+
mode: AlignmentMode;
|
|
10123
|
+
};
|
|
10124
|
+
}, ActionFunction<DiagramContext, {
|
|
10125
|
+
type: "layout.align";
|
|
10126
|
+
mode: AlignmentMode;
|
|
10127
|
+
}, Events, undefined, never, never, never, never, never>];
|
|
10128
|
+
};
|
|
10129
|
+
readonly 'layout.resetEdgeControlPoints': {
|
|
10130
|
+
readonly guard: "not readonly";
|
|
10131
|
+
readonly actions: readonly [ ActionFunction<DiagramContext, Events, Events, undefined, Values<{
|
|
10071
10132
|
hotkeyActor: {
|
|
10072
10133
|
src: "hotkeyActor";
|
|
10073
10134
|
logic: CallbackActorLogic<AnyEventObject, NonReducibleUnknown, HotKeyEvent>;
|
|
@@ -10276,29 +10337,26 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
10276
10337
|
}, "active", any, any, any>, Events, Input, any, any>;
|
|
10277
10338
|
id: "relationshipsBrowser";
|
|
10278
10339
|
};
|
|
10279
|
-
}>, never, never, never, never
|
|
10340
|
+
}>, never, never, never, never>, ActionFunction<DiagramContext, {
|
|
10341
|
+
type: "layout.resetEdgeControlPoints";
|
|
10342
|
+
}, Events, undefined, never, never, never, never, never>];
|
|
10280
10343
|
};
|
|
10281
|
-
readonly '
|
|
10282
|
-
readonly guard:
|
|
10283
|
-
|
|
10284
|
-
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10288
|
-
|
|
10289
|
-
mode: AlignmentMode;
|
|
10290
|
-
};
|
|
10291
|
-
}) => {
|
|
10292
|
-
mode: AlignmentMode;
|
|
10293
|
-
};
|
|
10294
|
-
}, ActionFunction<DiagramContext, {
|
|
10295
|
-
type: "layout.align";
|
|
10296
|
-
mode: AlignmentMode;
|
|
10344
|
+
readonly 'xyflow.resized': {
|
|
10345
|
+
readonly guard: ({ context }: {
|
|
10346
|
+
context: DiagramContext;
|
|
10347
|
+
}) => boolean;
|
|
10348
|
+
readonly actions: readonly [ CancelAction<DiagramContext, {
|
|
10349
|
+
type: "xyflow.resized";
|
|
10350
|
+
}, undefined, Events>, ActionFunction<DiagramContext, {
|
|
10351
|
+
type: "xyflow.resized";
|
|
10297
10352
|
}, Events, undefined, never, never, never, never, never>];
|
|
10298
10353
|
};
|
|
10299
|
-
readonly '
|
|
10300
|
-
readonly
|
|
10301
|
-
|
|
10354
|
+
readonly 'open.elementDetails': {
|
|
10355
|
+
readonly actions: ActionFunction<DiagramContext, {
|
|
10356
|
+
type: "open.elementDetails";
|
|
10357
|
+
fqn: Fqn;
|
|
10358
|
+
fromNode?: NodeId | undefined;
|
|
10359
|
+
}, Events, undefined, Values<{
|
|
10302
10360
|
hotkeyActor: {
|
|
10303
10361
|
src: "hotkeyActor";
|
|
10304
10362
|
logic: CallbackActorLogic<AnyEventObject, NonReducibleUnknown, HotKeyEvent>;
|
|
@@ -10507,25 +10565,37 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
10507
10565
|
}, "active", any, any, any>, Events, Input, any, any>;
|
|
10508
10566
|
id: "relationshipsBrowser";
|
|
10509
10567
|
};
|
|
10510
|
-
}>, never, never, never, never
|
|
10511
|
-
|
|
10512
|
-
}, Events, undefined, never, never, never, never, never>];
|
|
10568
|
+
}>, never, never, never, never>;
|
|
10569
|
+
readonly target: ".overlay.elementDetails";
|
|
10513
10570
|
};
|
|
10514
|
-
readonly '
|
|
10515
|
-
readonly
|
|
10516
|
-
context: DiagramContext;
|
|
10517
|
-
}) => boolean;
|
|
10518
|
-
readonly actions: readonly [ CancelAction<DiagramContext, {
|
|
10519
|
-
type: "xyflow.resized";
|
|
10520
|
-
}, undefined, Events>, ActionFunction<DiagramContext, {
|
|
10521
|
-
type: "xyflow.resized";
|
|
10522
|
-
}, Events, undefined, never, never, never, never, never>];
|
|
10571
|
+
readonly 'open.relationshipDetails': {
|
|
10572
|
+
readonly target: ".overlay.relationshipDetails";
|
|
10523
10573
|
};
|
|
10524
|
-
readonly 'open.
|
|
10574
|
+
readonly 'open.relationshipsBrowser': {
|
|
10575
|
+
readonly target: ".overlay.relationshipsBrowser";
|
|
10576
|
+
};
|
|
10577
|
+
readonly 'open.source': {
|
|
10578
|
+
readonly actions: {
|
|
10579
|
+
readonly type: "trigger:OpenSource";
|
|
10580
|
+
readonly params: (data: {
|
|
10581
|
+
context: DiagramContext;
|
|
10582
|
+
event: {
|
|
10583
|
+
type: "open.source";
|
|
10584
|
+
} & OpenSourceParams;
|
|
10585
|
+
}) => {
|
|
10586
|
+
type: "open.source";
|
|
10587
|
+
} & OpenSourceParams;
|
|
10588
|
+
};
|
|
10589
|
+
};
|
|
10590
|
+
readonly 'walkthrough.start': {
|
|
10591
|
+
readonly guard: "is dynamic view";
|
|
10592
|
+
readonly target: ".walkthrough";
|
|
10593
|
+
};
|
|
10594
|
+
readonly 'toggle.feature': {
|
|
10525
10595
|
readonly actions: ActionFunction<DiagramContext, {
|
|
10526
|
-
type: "
|
|
10527
|
-
|
|
10528
|
-
|
|
10596
|
+
type: "toggle.feature";
|
|
10597
|
+
feature: FeatureName;
|
|
10598
|
+
forceValue?: boolean;
|
|
10529
10599
|
}, Events, undefined, Values<{
|
|
10530
10600
|
hotkeyActor: {
|
|
10531
10601
|
src: "hotkeyActor";
|
|
@@ -10736,30 +10806,6 @@ export declare const diagramMachine: StateMachine<DiagramContext, Events, {
|
|
|
10736
10806
|
id: "relationshipsBrowser";
|
|
10737
10807
|
};
|
|
10738
10808
|
}>, never, never, never, never>;
|
|
10739
|
-
readonly target: ".overlay.elementDetails";
|
|
10740
|
-
};
|
|
10741
|
-
readonly 'open.relationshipDetails': {
|
|
10742
|
-
readonly target: ".overlay.relationshipDetails";
|
|
10743
|
-
};
|
|
10744
|
-
readonly 'open.relationshipsBrowser': {
|
|
10745
|
-
readonly target: ".overlay.relationshipsBrowser";
|
|
10746
|
-
};
|
|
10747
|
-
readonly 'open.source': {
|
|
10748
|
-
readonly actions: {
|
|
10749
|
-
readonly type: "trigger:OpenSource";
|
|
10750
|
-
readonly params: (data: {
|
|
10751
|
-
context: DiagramContext;
|
|
10752
|
-
event: {
|
|
10753
|
-
type: "open.source";
|
|
10754
|
-
} & OpenSourceParams;
|
|
10755
|
-
}) => {
|
|
10756
|
-
type: "open.source";
|
|
10757
|
-
} & OpenSourceParams;
|
|
10758
|
-
};
|
|
10759
|
-
};
|
|
10760
|
-
readonly 'walkthrough.start': {
|
|
10761
|
-
readonly guard: "is dynamic view";
|
|
10762
|
-
readonly target: ".walkthrough";
|
|
10763
10809
|
};
|
|
10764
10810
|
};
|
|
10765
10811
|
readonly exit: readonly [ StopAction<DiagramContext, Events, undefined, Events>, StopAction<DiagramContext, Events, undefined, Events>, ActionFunction<DiagramContext, Events, Events, undefined, Values<{
|
|
@@ -2,7 +2,7 @@ import { nonNullable, invariant, nonexhaustive, getBBoxCenter, getParallelStepsP
|
|
|
2
2
|
import { getViewportForBounds, applyEdgeChanges, applyNodeChanges } from "@xyflow/react";
|
|
3
3
|
import { nodeToRect } from "@xyflow/system";
|
|
4
4
|
import { hasAtLeast, prop, clamp, first } from "remeda";
|
|
5
|
-
import { setup, assertEvent, stopChild,
|
|
5
|
+
import { setup, assign, assertEvent, stopChild, cancel, raise, enqueueActions, spawnChild, sendTo, and, or } from "xstate";
|
|
6
6
|
import { MinZoom } from "../../base/const.js";
|
|
7
7
|
import { AllDisabled } from "../../context/DiagramFeatures.js";
|
|
8
8
|
import { relationshipDetailsActor } from "../../overlays/relationship-details/actor.js";
|
|
@@ -143,13 +143,24 @@ const diagramMachine = setup({
|
|
|
143
143
|
};
|
|
144
144
|
});
|
|
145
145
|
});
|
|
146
|
-
}
|
|
146
|
+
},
|
|
147
|
+
"updateFeatures": assign(({ event }) => {
|
|
148
|
+
assertEvent(event, "update.features");
|
|
149
|
+
return {
|
|
150
|
+
features: {
|
|
151
|
+
...event.features
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
})
|
|
147
155
|
}
|
|
148
156
|
}).createMachine({
|
|
149
157
|
initial: "initializing",
|
|
150
158
|
context: ({ input, self, spawn }) => ({
|
|
151
159
|
...input,
|
|
152
160
|
features: { ...AllDisabled },
|
|
161
|
+
toggledFeatures: {
|
|
162
|
+
enableReadOnly: true
|
|
163
|
+
},
|
|
153
164
|
initialized: false,
|
|
154
165
|
viewportChangedManually: false,
|
|
155
166
|
lastOnNavigate: null,
|
|
@@ -699,9 +710,7 @@ const diagramMachine = setup({
|
|
|
699
710
|
actions: assign(({ event }) => ({ ...event.inputs }))
|
|
700
711
|
},
|
|
701
712
|
"update.features": {
|
|
702
|
-
actions:
|
|
703
|
-
features: ({ event }) => event.features
|
|
704
|
-
})
|
|
713
|
+
actions: "updateFeatures"
|
|
705
714
|
},
|
|
706
715
|
"update.nodeData": {
|
|
707
716
|
actions: assign(updateNodeData)
|
|
@@ -758,6 +767,14 @@ const diagramMachine = setup({
|
|
|
758
767
|
"walkthrough.start": {
|
|
759
768
|
guard: "is dynamic view",
|
|
760
769
|
target: ".walkthrough"
|
|
770
|
+
},
|
|
771
|
+
"toggle.feature": {
|
|
772
|
+
actions: assign({
|
|
773
|
+
toggledFeatures: ({ context, event }) => ({
|
|
774
|
+
...context.toggledFeatures,
|
|
775
|
+
[`enable${event.feature}`]: event.forceValue ?? !(context.toggledFeatures[`enable${event.feature}`] ?? context.features[`enable${event.feature}`])
|
|
776
|
+
})
|
|
777
|
+
})
|
|
761
778
|
}
|
|
762
779
|
},
|
|
763
780
|
exit: [
|
|
@@ -98,12 +98,7 @@ function createViewChange(parentContext) {
|
|
|
98
98
|
const { view, xystore, xyflow } = parentContext;
|
|
99
99
|
const { nodeLookup } = xystore.getState();
|
|
100
100
|
const movedNodes = /* @__PURE__ */ new Set();
|
|
101
|
-
let bounds
|
|
102
|
-
x: 0,
|
|
103
|
-
y: 0,
|
|
104
|
-
width: 1,
|
|
105
|
-
height: 1
|
|
106
|
-
};
|
|
101
|
+
let bounds;
|
|
107
102
|
const nodes = reduce([...nodeLookup.values()], (acc, node) => {
|
|
108
103
|
const dimensions = getNodeDimensions(node);
|
|
109
104
|
if (!isSamePoint(node.internals.positionAbsolute, node.data.position) || node.initialWidth !== dimensions.width || node.initialHeight !== dimensions.height) {
|
|
@@ -116,7 +111,7 @@ function createViewChange(parentContext) {
|
|
|
116
111
|
width: Math.ceil(dimensions.width),
|
|
117
112
|
height: Math.ceil(dimensions.height)
|
|
118
113
|
};
|
|
119
|
-
bounds = getBoundsOfRects(bounds, rect);
|
|
114
|
+
bounds = bounds ? getBoundsOfRects(bounds, rect) : rect;
|
|
120
115
|
return acc;
|
|
121
116
|
}, {});
|
|
122
117
|
const edges = reduce((xyflow == null ? void 0 : xyflow.getEdges()) ?? [], (acc, { source, target, data }) => {
|
|
@@ -159,9 +154,10 @@ function createViewChange(parentContext) {
|
|
|
159
154
|
x2: Math.ceil(Math.max(...allX)),
|
|
160
155
|
y2: Math.ceil(Math.max(...allY))
|
|
161
156
|
});
|
|
162
|
-
bounds = getBoundsOfRects(bounds, rect);
|
|
157
|
+
bounds = bounds ? getBoundsOfRects(bounds, rect) : rect;
|
|
163
158
|
return acc;
|
|
164
159
|
}, {});
|
|
160
|
+
bounds ?? (bounds = view.bounds);
|
|
165
161
|
return {
|
|
166
162
|
op: "save-manual-layout",
|
|
167
163
|
layout: {
|
|
@@ -14,6 +14,7 @@ import { LayoutDriftNotification } from "./LayoutDriftNotification.js";
|
|
|
14
14
|
import { ManualLayoutToolsButton } from "./ManualLayoutToolsButton.js";
|
|
15
15
|
import { NavigationButtons } from "./NavigationButtons.js";
|
|
16
16
|
import { navigationButtons, actionIconGroup, panel } from "./styles.css.js";
|
|
17
|
+
import { ToggleReadonly } from "./ToggleReadonly.js";
|
|
17
18
|
import { useDiagramEventHandlers } from "../../../context/DiagramEventHandlers.js";
|
|
18
19
|
import { useEnabledFeatures } from "../../../context/DiagramFeatures.js";
|
|
19
20
|
import { useMantinePortalProps } from "../../../hooks/useMantinePortalProps.js";
|
|
@@ -82,6 +83,7 @@ const Controls = memo(() => {
|
|
|
82
83
|
children: /* @__PURE__ */ jsx(IconFileSymlink, { stroke: 1.5 })
|
|
83
84
|
}
|
|
84
85
|
) }),
|
|
86
|
+
enableControls && /* @__PURE__ */ jsx(ToggleReadonly, {}),
|
|
85
87
|
enableControls && hasLayoutDrift && /* @__PURE__ */ jsx(LayoutDriftNotification, { ...portalProps }),
|
|
86
88
|
enableControls && notReadOnly && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
87
89
|
/* @__PURE__ */ jsx(ChangeAutoLayoutButton, { ...portalProps }),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ToggleReadonly: () => import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { IconLock, IconLockOpen2 } from "@tabler/icons-react";
|
|
3
|
+
import { useDiagram } from "../../../hooks/useDiagram.js";
|
|
4
|
+
import { useDiagramContext } from "../../../hooks/useDiagramContext.js";
|
|
5
|
+
import { Tooltip, ActionIcon } from "./_shared.js";
|
|
6
|
+
const selector = (state) => ({
|
|
7
|
+
visible: state.features.enableReadOnly !== true,
|
|
8
|
+
isReadOnly: state.toggledFeatures.enableReadOnly ?? state.features.enableReadOnly
|
|
9
|
+
});
|
|
10
|
+
const ToggleReadonly = () => {
|
|
11
|
+
const { visible, isReadOnly } = useDiagramContext(selector);
|
|
12
|
+
const diagram = useDiagram();
|
|
13
|
+
if (!visible) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return /* @__PURE__ */ jsx(Tooltip, { label: isReadOnly ? "Enable editing" : "Disable editing", children: /* @__PURE__ */ jsx(
|
|
17
|
+
ActionIcon,
|
|
18
|
+
{
|
|
19
|
+
onClick: (e) => {
|
|
20
|
+
e.stopPropagation();
|
|
21
|
+
diagram.toggleFeature("ReadOnly");
|
|
22
|
+
},
|
|
23
|
+
children: isReadOnly ? /* @__PURE__ */ jsx(IconLock, {}) : /* @__PURE__ */ jsx(IconLockOpen2, {})
|
|
24
|
+
}
|
|
25
|
+
) });
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
ToggleReadonly
|
|
29
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/diagram",
|
|
3
|
-
"version": "1.22.
|
|
3
|
+
"version": "1.22.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -39,14 +39,13 @@
|
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"@dagrejs/dagre": "1.1.4",
|
|
42
|
-
"@likec4/core": "1.22.
|
|
42
|
+
"@likec4/core": "1.22.1",
|
|
43
43
|
"@mantine/vanilla-extract": "7.16.3",
|
|
44
44
|
"@nanostores/react": "0.8.4",
|
|
45
45
|
"@react-hookz/web": "^25.0.1",
|
|
46
46
|
"@tabler/icons-react": "3.29.0",
|
|
47
47
|
"@vanilla-extract/dynamic": "^2.1.2",
|
|
48
48
|
"@xstate/react": "^5.0.2",
|
|
49
|
-
"@xstate/store": "^2.6.2",
|
|
50
49
|
"@xyflow/react": "12.4.2",
|
|
51
50
|
"@xyflow/system": "0.0.50",
|
|
52
51
|
"bezier-js": "^6.1.4",
|
|
@@ -69,7 +68,7 @@
|
|
|
69
68
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
70
69
|
},
|
|
71
70
|
"devDependencies": {
|
|
72
|
-
"@likec4/tsconfig": "1.22.
|
|
71
|
+
"@likec4/tsconfig": "1.22.1",
|
|
73
72
|
"@mantine/core": "7.16.3",
|
|
74
73
|
"@mantine/hooks": "7.16.3",
|
|
75
74
|
"@statelyai/inspect": "^0.4.0",
|
package/src/hooks/useDiagram.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { EdgeId, Fqn, NodeId, ViewId } from '@likec4/core'
|
|
2
2
|
import { useMemo, useTransition } from 'react'
|
|
3
3
|
import type { PartialDeep } from 'type-fest'
|
|
4
|
+
import type { FeatureName } from '../context/DiagramFeatures'
|
|
4
5
|
import { useDiagramActor } from '../hooks/useDiagramActor'
|
|
5
6
|
import type { OpenSourceParams } from '../LikeC4Diagram.props'
|
|
6
7
|
import type { AlignmentMode } from '../likec4diagram/state/aligners'
|
|
@@ -125,5 +126,9 @@ export function useDiagram() {
|
|
|
125
126
|
stopWalkthrough: () => {
|
|
126
127
|
actor.send({ type: 'walkthrough.end' })
|
|
127
128
|
},
|
|
129
|
+
|
|
130
|
+
toggleFeature: (feature: FeatureName, forceValue?: boolean) => {
|
|
131
|
+
actor.send({ type: 'toggle.feature', feature, ...(forceValue !== undefined && { forceValue }) })
|
|
132
|
+
},
|
|
128
133
|
}), [actor])
|
|
129
134
|
}
|
|
@@ -2,11 +2,12 @@ import type { ViewId } from '@likec4/core'
|
|
|
2
2
|
import { useCallbackRef } from '@mantine/hooks'
|
|
3
3
|
import { useStoreApi } from '@xyflow/react'
|
|
4
4
|
import { type PropsWithChildren, useEffect } from 'react'
|
|
5
|
-
import { useDiagramEventHandlers, useEnabledFeatures } from '../context'
|
|
5
|
+
import { DiagramFeatures, useDiagramEventHandlers, useEnabledFeatures } from '../context'
|
|
6
6
|
import { useDiagramActor } from '../hooks/useDiagramActor'
|
|
7
7
|
import { useUpdateEffect } from '../hooks/useUpdateEffect'
|
|
8
8
|
import { LikeC4ViewMachineContextProvider } from './state/actorContext'
|
|
9
9
|
// import { useInspector } from './state/inspector'
|
|
10
|
+
import { useDiagramContext } from '../hooks/useDiagramContext'
|
|
10
11
|
import { type Input, diagramMachine } from './state/machine'
|
|
11
12
|
import { syncManualLayoutActor } from './state/syncManualLayoutActor'
|
|
12
13
|
import type { Types } from './types'
|
|
@@ -54,7 +55,9 @@ export function DiagramActor({ input, children }: PropsWithChildren<{ input: Act
|
|
|
54
55
|
}}
|
|
55
56
|
>
|
|
56
57
|
<SyncStore input={input} />
|
|
57
|
-
|
|
58
|
+
<DiagramActorToggledFeatures>
|
|
59
|
+
{children}
|
|
60
|
+
</DiagramActorToggledFeatures>
|
|
58
61
|
</LikeC4ViewMachineContextProvider>
|
|
59
62
|
)
|
|
60
63
|
)
|
|
@@ -77,3 +80,13 @@ const SyncStore = ({ input: { view, xyedges, xynodes, ...inputs } }: { input: Ac
|
|
|
77
80
|
|
|
78
81
|
return null
|
|
79
82
|
}
|
|
83
|
+
|
|
84
|
+
function DiagramActorToggledFeatures({ children }: PropsWithChildren) {
|
|
85
|
+
const toggledFeatures = useDiagramContext(s => s.toggledFeatures)
|
|
86
|
+
return (
|
|
87
|
+
<DiagramFeatures
|
|
88
|
+
overrides={toggledFeatures}>
|
|
89
|
+
{children}
|
|
90
|
+
</DiagramFeatures>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
@@ -24,6 +24,13 @@ const selectXYProps = (ctx: DiagramContext) => ({
|
|
|
24
24
|
fitViewPadding: ctx.fitViewPadding,
|
|
25
25
|
enableFitView: ctx.features.enableFitView,
|
|
26
26
|
enableReadOnly: ctx.features.enableReadOnly,
|
|
27
|
+
...(!ctx.features.enableFitView && {
|
|
28
|
+
viewport: {
|
|
29
|
+
x: -Math.min(ctx.view.bounds.x, 0),
|
|
30
|
+
y: -Math.min(ctx.view.bounds.y, 0),
|
|
31
|
+
zoom: 1,
|
|
32
|
+
},
|
|
33
|
+
}),
|
|
27
34
|
})
|
|
28
35
|
const equalsXYProps = (a: ReturnType<typeof selectXYProps>, b: ReturnType<typeof selectXYProps>): boolean =>
|
|
29
36
|
a.initialized === b.initialized &&
|
|
@@ -33,7 +40,8 @@ const equalsXYProps = (a: ReturnType<typeof selectXYProps>, b: ReturnType<typeof
|
|
|
33
40
|
a.enableFitView === b.enableFitView &&
|
|
34
41
|
a.enableReadOnly === b.enableReadOnly &&
|
|
35
42
|
shallowEqual(a.nodes, b.nodes) &&
|
|
36
|
-
shallowEqual(a.edges, b.edges)
|
|
43
|
+
shallowEqual(a.edges, b.edges) &&
|
|
44
|
+
shallowEqual(a.viewport, b.viewport)
|
|
37
45
|
|
|
38
46
|
type Picked = EnforceOptional<
|
|
39
47
|
Pick<
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
} from 'xstate'
|
|
42
42
|
import { MinZoom } from '../../base/const'
|
|
43
43
|
import type { EnabledFeatures } from '../../context'
|
|
44
|
-
import { AllDisabled } from '../../context/DiagramFeatures'
|
|
44
|
+
import { type FeatureName, AllDisabled } from '../../context/DiagramFeatures'
|
|
45
45
|
import type { OpenSourceParams } from '../../LikeC4Diagram.props'
|
|
46
46
|
import { relationshipDetailsActor } from '../../overlays/relationship-details/actor'
|
|
47
47
|
import { relationshipsBrowserActor } from '../../overlays/relationships-browser/actor'
|
|
@@ -86,8 +86,12 @@ export interface Input {
|
|
|
86
86
|
fitViewPadding: number
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
type ToggledFeatures = Partial<EnabledFeatures>
|
|
90
|
+
|
|
89
91
|
export interface DiagramContext extends Input {
|
|
90
92
|
features: EnabledFeatures
|
|
93
|
+
// This is used to override features from props
|
|
94
|
+
toggledFeatures: ToggledFeatures
|
|
91
95
|
initialized: boolean
|
|
92
96
|
viewport: Viewport
|
|
93
97
|
viewportChangedManually: boolean
|
|
@@ -165,6 +169,7 @@ export type Events =
|
|
|
165
169
|
| { type: 'walkthrough.start'; stepId?: StepEdgeId }
|
|
166
170
|
| { type: 'walkthrough.step'; direction: 'next' | 'previous' }
|
|
167
171
|
| { type: 'walkthrough.end' }
|
|
172
|
+
| { type: 'toggle.feature'; feature: FeatureName; forceValue?: boolean }
|
|
168
173
|
|
|
169
174
|
export type ActionArg = { context: DiagramContext; event: Events }
|
|
170
175
|
|
|
@@ -306,12 +311,24 @@ export const diagramMachine = setup({
|
|
|
306
311
|
})
|
|
307
312
|
})
|
|
308
313
|
},
|
|
314
|
+
|
|
315
|
+
'updateFeatures': assign(({ event }) => {
|
|
316
|
+
assertEvent(event, 'update.features')
|
|
317
|
+
return {
|
|
318
|
+
features: {
|
|
319
|
+
...event.features,
|
|
320
|
+
},
|
|
321
|
+
}
|
|
322
|
+
}),
|
|
309
323
|
},
|
|
310
324
|
}).createMachine({
|
|
311
325
|
initial: 'initializing',
|
|
312
326
|
context: ({ input, self, spawn }) => ({
|
|
313
327
|
...input,
|
|
314
328
|
features: { ...AllDisabled },
|
|
329
|
+
toggledFeatures: {
|
|
330
|
+
enableReadOnly: true,
|
|
331
|
+
},
|
|
315
332
|
initialized: false,
|
|
316
333
|
viewportChangedManually: false,
|
|
317
334
|
lastOnNavigate: null,
|
|
@@ -863,9 +880,7 @@ export const diagramMachine = setup({
|
|
|
863
880
|
actions: assign(({ event }) => ({ ...event.inputs })),
|
|
864
881
|
},
|
|
865
882
|
'update.features': {
|
|
866
|
-
actions:
|
|
867
|
-
features: ({ event }) => event.features,
|
|
868
|
-
}),
|
|
883
|
+
actions: 'updateFeatures',
|
|
869
884
|
},
|
|
870
885
|
'update.nodeData': {
|
|
871
886
|
actions: assign(updateNodeData),
|
|
@@ -921,6 +936,15 @@ export const diagramMachine = setup({
|
|
|
921
936
|
guard: 'is dynamic view',
|
|
922
937
|
target: '.walkthrough',
|
|
923
938
|
},
|
|
939
|
+
'toggle.feature': {
|
|
940
|
+
actions: assign({
|
|
941
|
+
toggledFeatures: ({ context, event }) => ({
|
|
942
|
+
...context.toggledFeatures,
|
|
943
|
+
[`enable${event.feature}`]: event.forceValue ??
|
|
944
|
+
!(context.toggledFeatures[`enable${event.feature}`] ?? context.features[`enable${event.feature}`]),
|
|
945
|
+
}),
|
|
946
|
+
}),
|
|
947
|
+
},
|
|
924
948
|
},
|
|
925
949
|
exit: [
|
|
926
950
|
stopChild('layout'),
|