@likec4/diagram 1.56.0 → 1.58.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.
Files changed (208) hide show
  1. package/dist/LikeC4Diagram.js +3 -1
  2. package/dist/LikeC4View.js +47 -55
  3. package/dist/adhoc-editor/EditorPanel.d.ts +1 -1
  4. package/dist/adhoc-editor/ElementsTree.d.ts +1 -1
  5. package/dist/adhoc-editor/ElementsTree.js +2 -6
  6. package/dist/adhoc-editor/LikeC4AdHocViewEditor.d.ts +1 -1
  7. package/dist/adhoc-editor/components/Tree.d.ts +5 -5
  8. package/dist/adhoc-editor/state/ActorProvider.d.ts +1 -1
  9. package/dist/adhoc-editor/state/panel.d.ts +1 -1
  10. package/dist/adhoc-editor/viewrules/ViewRulesPanel.d.ts +1 -1
  11. package/dist/base/BaseXYFlow.d.ts +1 -1
  12. package/dist/base-primitives/Markdown.d.ts +1 -1
  13. package/dist/base-primitives/NodeHandles.d.ts +1 -1
  14. package/dist/base-primitives/compound/CompoundActionButton.d.ts +1 -1
  15. package/dist/base-primitives/compound/CompoundDetailsButton.d.ts +1 -1
  16. package/dist/base-primitives/compound/CompoundNodeContainer.d.ts +1 -1
  17. package/dist/base-primitives/compound/CompoundTitle.d.ts +1 -1
  18. package/dist/base-primitives/compound/actionbtns.css.d.ts +1 -1
  19. package/dist/base-primitives/edge/EdgeActionButton.d.ts +1 -1
  20. package/dist/base-primitives/edge/EdgeContainer.d.ts +1 -1
  21. package/dist/base-primitives/edge/EdgeLabelContainer.d.ts +1 -1
  22. package/dist/base-primitives/edge/EdgeMarkers.d.ts +8 -8
  23. package/dist/base-primitives/element/ElementActionButtons.d.ts +1 -1
  24. package/dist/base-primitives/element/ElementData.d.ts +2 -2
  25. package/dist/base-primitives/element/ElementDetailsButton.d.ts +1 -1
  26. package/dist/base-primitives/element/ElementShape.d.ts +1 -1
  27. package/dist/base-primitives/element/ElementTags.d.ts +1 -1
  28. package/dist/base-primitives/element/ElementTags.js +1 -3
  29. package/dist/components/ErrorFallback.d.ts +2 -2
  30. package/dist/components/NavigationPanel.d.ts +2 -2
  31. package/dist/components/PortalToContainer.d.ts +1 -1
  32. package/dist/components/RootContainer.d.ts +1 -1
  33. package/dist/components/RootContainer.js +19 -18
  34. package/dist/components/SearchControl.d.ts +2 -2
  35. package/dist/components/ViewNotFound.d.ts +2 -2
  36. package/dist/context/CurrentViewModelProvider.d.ts +1 -1
  37. package/dist/context/DefaultMantineProvider.d.ts +1 -1
  38. package/dist/context/DiagramEventHandlers.d.ts +1 -1
  39. package/dist/context/DiagramFeatures.d.ts +1 -1
  40. package/dist/context/DiagramFeatures.js +5 -0
  41. package/dist/context/EnsureMantine.d.ts +1 -1
  42. package/dist/context/FramerMotionConfig.d.ts +3 -3
  43. package/dist/context/FramerMotionConfig.js +2 -2
  44. package/dist/context/IconRenderer.d.ts +2 -2
  45. package/dist/context/IconRenderer.js +32 -12
  46. package/dist/context/LikeC4ModelContext.d.ts +1 -1
  47. package/dist/context/RootContainerContext.d.ts +10 -17
  48. package/dist/context/RootContainerContext.js +1 -13
  49. package/dist/context/ShadowRootContext.d.ts +3 -0
  50. package/dist/context/ShadowRootContext.js +5 -0
  51. package/dist/context/TagStylesContext.d.ts +2 -1
  52. package/dist/context/TagStylesContext.js +5 -7
  53. package/dist/custom/index.d.ts +1 -1
  54. package/dist/custom/index.js +1 -2
  55. package/dist/editor/LikeC4EditorCallbacks.d.ts +5 -0
  56. package/dist/editor/LikeC4EditorProvider.d.ts +2 -2
  57. package/dist/editor/actor/actions.d.ts +174 -0
  58. package/dist/editor/actor/actions.js +188 -0
  59. package/dist/editor/{hotkeyActor.d.ts → actor/hotkey.d.ts} +2 -2
  60. package/dist/editor/{hotkeyActor.js → actor/hotkey.js} +11 -4
  61. package/dist/editor/{editorActor.states.d.ts → actor/machine.d.ts} +5 -3
  62. package/dist/editor/actor/machine.js +23 -0
  63. package/dist/editor/actor/setup.d.ts +55 -0
  64. package/dist/editor/{editorActor.setup.js → actor/setup.js} +14 -10
  65. package/dist/editor/actor/state.editor.d.ts +147 -0
  66. package/dist/editor/actor/state.editor.js +56 -0
  67. package/dist/editor/actor/state.sync-queue.d.ts +612 -0
  68. package/dist/editor/actor/state.sync-queue.js +272 -0
  69. package/dist/editor/actor/types.d.ts +64 -0
  70. package/dist/editor/actor/types.js +5 -0
  71. package/dist/editor/applyChangesToManualLayout.js +1 -1
  72. package/dist/editor/index.d.ts +2 -1
  73. package/dist/editor/useEditorActorLogic.d.ts +8 -2
  74. package/dist/editor/useEditorActorLogic.js +39 -7
  75. package/dist/hooks/useDiagram.js +6 -1
  76. package/dist/hooks/useDiagramCompareLayout.js +1 -1
  77. package/dist/hooks/useEditorActor.d.ts +9 -0
  78. package/dist/hooks/useEditorActor.js +27 -0
  79. package/dist/hooks/useLikeC4ElementsTree.d.ts +3 -2
  80. package/dist/hooks/useLikeC4ElementsTree.js +3 -1
  81. package/dist/index.d.ts +2 -0
  82. package/dist/index.js +3 -1
  83. package/dist/likec4diagram/DiagramUI.d.ts +1 -1
  84. package/dist/likec4diagram/DiagramUI.js +8 -4
  85. package/dist/likec4diagram/DiagramXYFlow.js +26 -14
  86. package/dist/likec4diagram/custom/edges/EdgeDrifts.d.ts +1 -1
  87. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +127 -14
  88. package/dist/likec4diagram/custom/edges/SequenceStepEdge.d.ts +1 -1
  89. package/dist/likec4diagram/custom/edges/edges.css.d.ts +1 -0
  90. package/dist/likec4diagram/custom/edges/edges.css.js +5 -1
  91. package/dist/likec4diagram/custom/nodes/CompoundActions.d.ts +1 -1
  92. package/dist/likec4diagram/custom/nodes/ElementActions.d.ts +2 -2
  93. package/dist/likec4diagram/custom/nodes/NodeDrifts.d.ts +1 -1
  94. package/dist/likec4diagram/custom/nodes/NodeNotes.d.ts +1 -1
  95. package/dist/likec4diagram/custom/nodes/SequenceActorNode.d.ts +2 -2
  96. package/dist/likec4diagram/custom/nodes/nodes.d.ts +7 -7
  97. package/dist/likec4diagram/custom/nodes/toolbar/ColorButton.d.ts +3 -3
  98. package/dist/likec4diagram/custom/nodes/toolbar/CompoundToolbar.d.ts +2 -2
  99. package/dist/likec4diagram/custom/nodes/toolbar/ElementToolbar.d.ts +2 -2
  100. package/dist/likec4diagram/custom/nodes/toolbar/Toolbar.d.ts +1 -1
  101. package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +3 -3
  102. package/dist/likec4diagram/relationship-popover/RelationshipPopover.d.ts +1 -1
  103. package/dist/likec4diagram/relationship-popover/components.d.ts +2 -2
  104. package/dist/likec4diagram/state/DiagramActorProvider.d.ts +1 -1
  105. package/dist/likec4diagram/state/aligners.js +3 -0
  106. package/dist/likec4diagram/state/assign.js +1 -1
  107. package/dist/likec4diagram/state/createViewChange.js +1 -0
  108. package/dist/likec4diagram/state/diagram-api.d.ts +16 -0
  109. package/dist/likec4diagram/state/diagram-api.js +13 -7
  110. package/dist/likec4diagram/state/machine.actions.js +10 -10
  111. package/dist/likec4diagram/state/machine.d.ts +1 -1
  112. package/dist/likec4diagram/state/machine.setup.js +1 -1
  113. package/dist/likec4diagram/state/types.d.ts +1 -1
  114. package/dist/likec4diagram/state/utils.d.ts +1 -1
  115. package/dist/likec4diagram/types.d.ts +2 -0
  116. package/dist/likec4diagram/ui/LayoutDriftFrame.d.ts +1 -1
  117. package/dist/likec4diagram/ui/notation/NotationPanel.d.ts +1 -1
  118. package/dist/likec4diagram/useLayoutConstraints.js +2 -0
  119. package/dist/likec4diagram/xyflow-diagram/diagram-view.js +4 -2
  120. package/dist/likec4diagram/xyflow-sequence/sequence-layout.js +1 -0
  121. package/dist/navigationpanel/NavigationPanel.d.ts +1 -1
  122. package/dist/navigationpanel/NavigationPanelControls.d.ts +1 -1
  123. package/dist/navigationpanel/NavigationPanelDropdown.d.ts +1 -1
  124. package/dist/navigationpanel/NavigationPanelDropdown.js +2 -2
  125. package/dist/navigationpanel/_common.d.ts +2 -2
  126. package/dist/navigationpanel/comparepanel/CompareActionsMenu.d.ts +1 -1
  127. package/dist/navigationpanel/comparepanel/ComparePanel.d.ts +1 -1
  128. package/dist/navigationpanel/comparepanel/ComparePanelControls.d.ts +1 -1
  129. package/dist/navigationpanel/comparepanel/DriftsSummary.d.ts +1 -1
  130. package/dist/navigationpanel/comparepanel/LayoutTypeSwitcher.d.ts +1 -1
  131. package/dist/navigationpanel/controls/DetailsControls.d.ts +1 -1
  132. package/dist/navigationpanel/controls/LayoutWarning.d.ts +1 -1
  133. package/dist/navigationpanel/controls/LogoButton.d.ts +1 -1
  134. package/dist/navigationpanel/controls/NavigationButtons.d.ts +1 -1
  135. package/dist/navigationpanel/controls/OpenSource.d.ts +1 -1
  136. package/dist/navigationpanel/controls/SearchControl.d.ts +1 -1
  137. package/dist/navigationpanel/controls/ToggleReadonly.d.ts +1 -1
  138. package/dist/navigationpanel/controls/ToggleReadonly.js +4 -2
  139. package/dist/navigationpanel/editorpanel/ApplySemanticLayout.d.ts +4 -0
  140. package/dist/navigationpanel/editorpanel/ApplySemanticLayout.js +36 -0
  141. package/dist/navigationpanel/editorpanel/CenterCamera.d.ts +1 -1
  142. package/dist/navigationpanel/editorpanel/ChangeAutoLayoutButton.d.ts +1 -1
  143. package/dist/navigationpanel/editorpanel/EditorPanel.d.ts +1 -1
  144. package/dist/navigationpanel/editorpanel/EditorPanel.js +45 -33
  145. package/dist/navigationpanel/editorpanel/ManualLayoutToolsButton.d.ts +1 -1
  146. package/dist/navigationpanel/editorpanel/ToggleReadonly.d.ts +1 -1
  147. package/dist/navigationpanel/styles.css.d.ts +1 -1
  148. package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.d.ts +1 -1
  149. package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +62 -62
  150. package/dist/navigationpanel/walkthrough/WalkthroughPanel.d.ts +1 -1
  151. package/dist/overlays/Overlays.d.ts +1 -1
  152. package/dist/overlays/element-details/ElementDetails.d.ts +1 -1
  153. package/dist/overlays/element-details/ElementDetailsCard.d.ts +1 -1
  154. package/dist/overlays/element-details/MetadataValue.d.ts +2 -2
  155. package/dist/overlays/element-details/TabPanelRelationships.d.ts +1 -1
  156. package/dist/overlays/element-details/TabPanelStructure.d.ts +2 -2
  157. package/dist/overlays/overlay/Overlay.d.ts +16 -0
  158. package/dist/overlays/overlay/Overlay.js +50 -52
  159. package/dist/overlays/overlaysActor.js +28 -27
  160. package/dist/overlays/relationship-details/RelationshipDetails.d.ts +1 -1
  161. package/dist/overlays/relationship-details/SelectEdge.d.ts +1 -1
  162. package/dist/overlays/relationship-details/custom/ElementActions.d.ts +1 -1
  163. package/dist/overlays/relationship-details/custom/nodeTypes.d.ts +4 -5
  164. package/dist/overlays/relationship-details/custom/nodeTypes.js +25 -24
  165. package/dist/overlays/relationships-browser/RelationshipsBrowser.d.ts +1 -1
  166. package/dist/overlays/relationships-browser/SelectElement.d.ts +1 -1
  167. package/dist/overlays/relationships-browser/SelectElement.js +2 -2
  168. package/dist/overlays/relationships-browser/custom/ElementActions.d.ts +1 -1
  169. package/dist/overlays/relationships-browser/custom/EmptyNode.d.ts +1 -1
  170. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +4 -4
  171. package/dist/projects-overview/ProjectsOverview.d.ts +1 -1
  172. package/dist/projects-overview/custom/nodeTypes.d.ts +1 -1
  173. package/dist/projects-overview/panel/ProjectsOverviewPanel.d.ts +1 -1
  174. package/dist/search/Search.d.ts +6 -3
  175. package/dist/search/Search.js +60 -71
  176. package/dist/search/XStateSearchAdapter.d.ts +1 -1
  177. package/dist/search/components/ElementsColumn.d.ts +1 -1
  178. package/dist/search/components/ElementsColumn.js +12 -8
  179. package/dist/search/components/PickView.d.ts +1 -1
  180. package/dist/search/components/SearchByTags.d.ts +1 -1
  181. package/dist/search/components/SearchInput.d.ts +1 -1
  182. package/dist/search/components/ViewsColum.d.ts +3 -3
  183. package/dist/search/components/_shared.css.d.ts +1 -1
  184. package/dist/search/searchActor.js +30 -26
  185. package/dist/shadowroot/ShadowRoot.d.ts +6 -6
  186. package/dist/shadowroot/ShadowRoot.js +68 -23
  187. package/dist/shadowroot/index.d.ts +1 -0
  188. package/dist/shadowroot/styles.d.ts +13 -0
  189. package/dist/shadowroot/styles.js +60 -0
  190. package/dist/styles2.js +1 -1
  191. package/package.json +33 -40
  192. package/panda.buildinfo.json +19 -22
  193. package/src/styles-font.css +114 -0
  194. package/src/styles-min.css +2 -0
  195. package/src/styles-xyflow.css +1 -0
  196. package/src/styles.css +3 -0
  197. package/styles-min.css +1 -1
  198. package/styles-xyflow.css +1 -1
  199. package/styles.css +1 -1
  200. package/dist/bundle/index.d.ts +0 -1
  201. package/dist/editor/editorActor.actions.d.ts +0 -153
  202. package/dist/editor/editorActor.actions.js +0 -133
  203. package/dist/editor/editorActor.setup.d.ts +0 -84
  204. package/dist/editor/editorActor.states.js +0 -219
  205. package/dist/hooks/useOverlaysActor.js +0 -11
  206. package/dist/hooks/useSearchActor.js +0 -11
  207. package/dist/shadowroot/styles.css.d.ts +0 -4
  208. package/dist/shadowroot/styles.css.js +0 -62
@@ -0,0 +1,272 @@
1
+ import "../../_virtual/_rolldown/runtime.js";
2
+ import { machine } from "./setup.js";
3
+ import { typedSystem } from "../../likec4diagram/state/utils.js";
4
+ import { cancelSync, clearQueue, deleteNodesAndEdges, makeSnapshot, pushToSyncQueue, redo, scheduleSync, undo } from "./actions.js";
5
+ import { isViewChange } from "./types.js";
6
+ import { findLast } from "remeda";
7
+ import { invariant } from "@likec4/core";
8
+ import { assign, enqueueActions, log, sendTo } from "xstate";
9
+ //#region src/editor/actor/state.sync-queue.ts
10
+ var to = {
11
+ idle: { target: "#queue-idle" },
12
+ pending: { target: "#queue-pending" },
13
+ suspended: { target: "#queue-suspended" },
14
+ process: { target: "#queue-process" }
15
+ };
16
+ var idOf = (t) => ({ id: t.target.substring(1) });
17
+ /**
18
+ * Idle state, no pending operations
19
+ */
20
+ var idle = machine.createStateConfig({
21
+ ...idOf(to.idle),
22
+ always: {
23
+ guard: "has pending",
24
+ ...to.pending
25
+ },
26
+ on: {
27
+ "delete.nodes-edges": { actions: deleteNodesAndEdges() },
28
+ "change.sync-snapshot": {
29
+ actions: pushToSyncQueue(),
30
+ ...to.pending
31
+ },
32
+ "change.*": {
33
+ actions: pushToSyncQueue(),
34
+ ...to.process
35
+ },
36
+ "undo": { actions: undo() },
37
+ "redo": { actions: redo() },
38
+ "cancel": {
39
+ actions: cancelSync(),
40
+ ...to.idle
41
+ },
42
+ "view.synched": { actions: log("in idle got view.synched") }
43
+ }
44
+ });
45
+ /**
46
+ * Has pending operations
47
+ */
48
+ var pending = machine.createStateConfig({
49
+ ...idOf(to.pending),
50
+ on: {
51
+ "change.sync-snapshot": {
52
+ reenter: true,
53
+ actions: pushToSyncQueue(),
54
+ ...to.pending
55
+ },
56
+ "change.*": {
57
+ actions: pushToSyncQueue(),
58
+ ...to.process
59
+ },
60
+ "delete.nodes-edges": {
61
+ actions: deleteNodesAndEdges(),
62
+ reenter: true,
63
+ ...to.pending
64
+ },
65
+ "edit.move.start": { ...to.suspended },
66
+ "undo": {
67
+ reenter: true,
68
+ actions: undo(),
69
+ ...to.pending
70
+ },
71
+ "redo": {
72
+ reenter: true,
73
+ actions: redo(),
74
+ ...to.pending
75
+ },
76
+ "cancel": {
77
+ actions: clearQueue(),
78
+ ...to.idle
79
+ },
80
+ "view.synched": { actions: log("in pending got view.synched") }
81
+ },
82
+ after: { "wait-after-edit": [{
83
+ guard: "has pending",
84
+ ...to.process
85
+ }, to.idle] }
86
+ });
87
+ /**
88
+ * When editing starts, we suspend the queue
89
+ */
90
+ var suspended = machine.createStateConfig({
91
+ ...idOf(to.suspended),
92
+ on: {
93
+ "edit.*": to.idle,
94
+ "cancel": {
95
+ actions: [clearQueue(), cancelSync()],
96
+ ...to.idle
97
+ }
98
+ }
99
+ });
100
+ var peekFromQueue = () => machine.assign(({ system, context: { syncQueue } }) => {
101
+ let [head, ...tail] = syncQueue;
102
+ if (head === "sync-snapshot") head = makeSnapshot(system).change;
103
+ return {
104
+ processing: head ?? null,
105
+ syncQueue: tail
106
+ };
107
+ });
108
+ var clearProcessing = () => ({ processing: null });
109
+ /**
110
+ * Processing pending operation
111
+ */
112
+ var process = machine.createStateConfig({
113
+ ...idOf(to.process),
114
+ initial: "peekFromQueue",
115
+ tags: ["busy"],
116
+ states: {
117
+ peekFromQueue: {
118
+ entry: peekFromQueue(),
119
+ always: [
120
+ {
121
+ guard: ({ context: { processing } }) => processing === "apply-latest-to-manual",
122
+ target: "applyLatestToManual"
123
+ },
124
+ {
125
+ guard: ({ context: { processing } }) => processing === "apply-semantic-layout",
126
+ target: "applySemanticLayout"
127
+ },
128
+ {
129
+ guard: ({ context: { processing } }) => isViewChange(processing),
130
+ target: "executeChanges"
131
+ },
132
+ {
133
+ guard: "has pending",
134
+ reenter: true,
135
+ ...to.process
136
+ },
137
+ {
138
+ actions: clearQueue(),
139
+ ...to.idle
140
+ }
141
+ ]
142
+ },
143
+ /**
144
+ * Syncing state, some edits are not yet synced
145
+ */
146
+ applyLatestToManual: machine.createStateConfig({
147
+ initial: "call",
148
+ entry: assign(({ system }) => ({ processing: makeSnapshot(system).change })),
149
+ states: {
150
+ call: { invoke: {
151
+ src: "applyLatest",
152
+ input: ({ context }) => {
153
+ const current = context.processing;
154
+ invariant(isViewChange(current) && current.op === "save-view-snapshot");
155
+ return {
156
+ current: current.layout,
157
+ viewId: context.viewId
158
+ };
159
+ },
160
+ onDone: {
161
+ actions: sendTo(typedSystem.diagramActor, ({ event }) => ({
162
+ type: "update.view",
163
+ view: event.output.updated
164
+ }), { delay: 20 }),
165
+ target: "wait"
166
+ },
167
+ onError: {
168
+ actions: assign(({ event }) => {
169
+ console.error("applyLatestToManual onError", { error: event.error });
170
+ return {
171
+ processing: null,
172
+ syncQueue: []
173
+ };
174
+ }),
175
+ ...to.idle
176
+ }
177
+ } },
178
+ wait: {
179
+ on: { "*": { actions: log(({ event }) => `wait: ignoring event ${event.type}`) } },
180
+ after: { "500ms": {
181
+ actions: [
182
+ clearQueue(),
183
+ assign({ redo: null }),
184
+ scheduleSync()
185
+ ],
186
+ ...to.idle
187
+ } }
188
+ }
189
+ }
190
+ }),
191
+ /**
192
+ * User requested semantic layout, we will call the AI
193
+ */
194
+ applySemanticLayout: machine.createStateConfig({
195
+ tags: ["ai-semantic-layout"],
196
+ invoke: {
197
+ src: "applySemanticLayout",
198
+ input: ({ context }) => ({ viewId: context.viewId }),
199
+ onDone: { target: "decideNext" },
200
+ onError: {
201
+ actions: ({ event }) => {
202
+ console.error("applySemanticLayout onError", { error: event.error });
203
+ },
204
+ target: "failure"
205
+ }
206
+ }
207
+ }),
208
+ /**
209
+ * Calls `executeChange` to save the snapshot
210
+ */
211
+ executeChanges: machine.createStateConfig({ invoke: {
212
+ src: "executeChange",
213
+ input: ({ context: { processing, syncQueue, viewId } }) => {
214
+ invariant(processing && isViewChange(processing));
215
+ return {
216
+ changes: [processing, ...syncQueue.filter(isViewChange)],
217
+ viewId
218
+ };
219
+ },
220
+ onDone: {
221
+ actions: enqueueActions(({ context, event, enqueue }) => {
222
+ const requested = event.output.requested;
223
+ enqueue.assign({
224
+ processing: null,
225
+ syncQueue: context.syncQueue.filter((change) => !isViewChange(change) || !requested.includes(change))
226
+ });
227
+ const lastSyncSnapshot = findLast(event.output.applied, (c) => c.op === "save-view-snapshot");
228
+ if (lastSyncSnapshot) enqueue.sendTo(typedSystem.diagramActor, {
229
+ type: "update.view-bounds",
230
+ bounds: lastSyncSnapshot.layout.bounds
231
+ });
232
+ }),
233
+ target: "waitViewSynced"
234
+ },
235
+ onError: {
236
+ actions: ({ event }) => {
237
+ console.error("executeChanges onError", { error: event.error });
238
+ },
239
+ target: "failure"
240
+ }
241
+ } }),
242
+ waitViewSynced: {
243
+ on: { "view.synched": { target: "decideNext" } },
244
+ after: { 2e3: "decideNext" }
245
+ },
246
+ decideNext: {
247
+ entry: assign(clearProcessing),
248
+ always: [{
249
+ guard: "has pending",
250
+ reenter: true,
251
+ ...to.process
252
+ }, to.idle]
253
+ },
254
+ failure: { always: {
255
+ actions: clearQueue(),
256
+ ...to.idle
257
+ } }
258
+ },
259
+ on: {}
260
+ });
261
+ var syncQueue = machine.createStateConfig({
262
+ initial: "idle",
263
+ states: {
264
+ idle,
265
+ pending,
266
+ suspended,
267
+ process
268
+ },
269
+ on: {}
270
+ });
271
+ //#endregion
272
+ export { syncQueue };
@@ -0,0 +1,64 @@
1
+ import { Types } from '../../likec4diagram/types';
2
+ import { HotKeyEvent } from './hotkey';
3
+ import type * as t from '@likec4/core/types';
4
+ export type EditorActorEvent = {
5
+ type: 'change.view';
6
+ change: t.ViewChange;
7
+ } | {
8
+ type: 'change.semantic-layout';
9
+ } | {
10
+ type: 'change.latest-to-manual';
11
+ } | {
12
+ type: 'change.sync-snapshot';
13
+ } | {
14
+ type: 'delete.nodes-edges';
15
+ nodeIds: t.NodeId[];
16
+ edgeIds: t.EdgeId[];
17
+ } | {
18
+ type: 'view.synched';
19
+ } | {
20
+ type: 'cancel';
21
+ } | {
22
+ type: 'edit.move.start';
23
+ subject: 'node' | 'edge';
24
+ } | {
25
+ type: 'edit.move.end';
26
+ } | {
27
+ type: 'edit.move.cancel';
28
+ } | HotKeyEvent;
29
+ export type Snapshot = {
30
+ view: t.LayoutedView;
31
+ change: t.ViewChange.SaveViewSnapshot;
32
+ xynodes: Types.Node[];
33
+ xyedges: Types.Edge[];
34
+ };
35
+ export type LinkedSnapshot = {
36
+ head: Snapshot;
37
+ tail: LinkedSnapshot | null;
38
+ };
39
+ export interface EditorActorInput {
40
+ viewId: t.ViewId;
41
+ }
42
+ export type SyncOp = t.ViewChange | 'sync-snapshot' | 'apply-semantic-layout' | 'apply-latest-to-manual';
43
+ export declare const isViewChange: (change: SyncOp | null) => change is t.ViewChange;
44
+ export interface EditorActorContext {
45
+ viewId: t.ViewId;
46
+ history: LinkedSnapshot | null;
47
+ redo: LinkedSnapshot | null;
48
+ editing: null | {
49
+ /**
50
+ * The subject of the edit
51
+ */
52
+ subject: 'node' | 'edge';
53
+ /**
54
+ * The state before editing started
55
+ */
56
+ before: Snapshot;
57
+ };
58
+ syncQueue: Array<SyncOp>;
59
+ processing: Exclude<SyncOp, 'sync-snapshot'> | null;
60
+ }
61
+ export type EditorActorEmitedEvent = {
62
+ type: 'idle';
63
+ };
64
+ export type EditorActorStateTag = 'pending' | 'busy' | 'ai-semantic-layout';
@@ -0,0 +1,5 @@
1
+ import "../../_virtual/_rolldown/runtime.js";
2
+ //#region src/editor/actor/types.ts
3
+ var isViewChange = (change) => change !== null && typeof change !== "string";
4
+ //#endregion
5
+ export { isViewChange };
@@ -153,7 +153,7 @@ function edgeControlPoints(source, target) {
153
153
  if (source === target) {
154
154
  const loopSize = 80;
155
155
  const centerOfTopBoundary = vector(0, source.height || 0).multiply(-.5).add(sourceCenter);
156
- return [centerOfTopBoundary.add(vector(-loopSize / 2.5, -loopSize)).trunc().toObject(), centerOfTopBoundary.add(vector(loopSize / 2.5, -loopSize)).trunc().toObject()];
156
+ return [centerOfTopBoundary.add(vector(-80 / 2.5, -80)).trunc().toObject(), centerOfTopBoundary.add(vector(loopSize / 2.5, -80)).trunc().toObject()];
157
157
  }
158
158
  const sourceToTargetVector = targetCenter.subtract(sourceCenter);
159
159
  const sourceBorderPoint = getBorderPointOnVector(source, sourceCenter, sourceToTargetVector);
@@ -1,4 +1,5 @@
1
- export type * from './editorActor.states';
1
+ export type * from './actor/machine';
2
+ export type * from './actor/types';
2
3
  export { createLikeC4Editor } from './LikeC4EditorCallbacks';
3
4
  export type { LikeC4EditorCallbacks } from './LikeC4EditorCallbacks';
4
5
  export { EnsureEditorContext, LikeC4EditorProvider, useOptionalLikeC4Editor, } from './LikeC4EditorProvider';
@@ -1,2 +1,8 @@
1
- import { EditorActorLogic } from './editorActor.states';
2
- export declare function useEditorActorLogic(): EditorActorLogic;
1
+ import { EditorActorLogic } from './actor/machine';
2
+ export declare function useEditorActorLogic(): EditorActorLogic & {
3
+ /**
4
+ * True if the editor is running in stub mode (no actual editor port available)
5
+ * This happens when the diagram is rendered outside of vscode extension / vite- plugin
6
+ */
7
+ readonly isStub: boolean;
8
+ };
@@ -1,9 +1,10 @@
1
1
  import "../_virtual/_rolldown/runtime.js";
2
2
  import { useCallbackRef } from "../hooks/useCallbackRef.js";
3
3
  import { useOptionalLikeC4Editor } from "./LikeC4EditorProvider.js";
4
- import { editorActorLogic } from "./editorActor.states.js";
4
+ import { editorActorLogic } from "./actor/machine.js";
5
5
  import { applyChangesToManualLayout } from "./applyChangesToManualLayout.js";
6
6
  import { useMemo } from "react";
7
+ import { isNullish } from "remeda";
7
8
  import { fromPromise } from "xstate";
8
9
  //#region src/editor/useEditorActorLogic.ts
9
10
  var promisify = (fn) => {
@@ -11,25 +12,56 @@ var promisify = (fn) => {
11
12
  };
12
13
  function useEditorActorLogic() {
13
14
  const port = useOptionalLikeC4Editor();
15
+ const isStub = isNullish(port);
14
16
  const applyLatest = useCallbackRef(async ({ input: { viewId, current } }) => {
15
17
  if (!port) {
16
18
  console.error("No editor port available for applying latest to manual layout");
17
- return Promise.reject(/* @__PURE__ */ new Error("No editor port"));
19
+ throw new Error("No editor port");
18
20
  }
19
21
  return { updated: applyChangesToManualLayout(await promisify(() => current ?? port.fetchView(viewId, "manual")), await promisify(() => port.fetchView(viewId, "auto"))) };
20
22
  });
21
23
  const executeChange = useCallbackRef(async ({ input }) => {
22
24
  if (!port) {
23
25
  console.error("No editor port available for executing change");
24
- return Promise.reject(/* @__PURE__ */ new Error("No editor port"));
26
+ throw new Error("No editor port");
25
27
  }
26
- for (const change of input.changes) await promisify(() => port.handleChange(input.viewId, change));
28
+ const applied = [];
29
+ for (const change of input.changes) try {
30
+ await promisify(() => port.handleChange(input.viewId, change));
31
+ applied.push(change);
32
+ } catch (error) {
33
+ console.error("Failed to execute change", {
34
+ change,
35
+ error
36
+ });
37
+ }
38
+ return {
39
+ requested: input.changes,
40
+ applied
41
+ };
42
+ });
43
+ const applySemanticLayout = useCallbackRef(async ({ input }) => {
44
+ if (!port) {
45
+ console.error("No editor port available for applying semantic layout");
46
+ throw new Error("No editor port");
47
+ }
48
+ if (!port.applySemanticLayout) {
49
+ console.error("No applySemanticLayout method available on editor port");
50
+ throw new Error("No applySemanticLayout method");
51
+ }
52
+ await port.applySemanticLayout(input.viewId);
27
53
  return {};
28
54
  });
29
- return useMemo(() => editorActorLogic.provide({ actors: {
55
+ return useMemo(() => Object.assign(editorActorLogic.provide({ actors: {
30
56
  applyLatest: fromPromise(applyLatest),
31
- executeChange: fromPromise(executeChange)
32
- } }), [applyLatest, executeChange]);
57
+ executeChange: fromPromise(executeChange),
58
+ applySemanticLayout: fromPromise(applySemanticLayout)
59
+ } }), { isStub }), [
60
+ applyLatest,
61
+ executeChange,
62
+ applySemanticLayout,
63
+ isStub
64
+ ]);
33
65
  }
34
66
  //#endregion
35
67
  export { useEditorActorLogic };
@@ -45,7 +45,11 @@ function useOnDiagramEvent(event, callback, options) {
45
45
  useEffect(() => {
46
46
  if (once && wasCalled.current) return;
47
47
  let subscription = actorRef.on(event, (payload) => {
48
- callbackRef(payload);
48
+ if (!once || !wasCalled.current) try {
49
+ callbackRef(payload);
50
+ } catch (error) {
51
+ console.error(error);
52
+ }
49
53
  wasCalled.current = true;
50
54
  if (once) {
51
55
  subscription?.unsubscribe();
@@ -56,6 +60,7 @@ function useOnDiagramEvent(event, callback, options) {
56
60
  subscription?.unsubscribe();
57
61
  };
58
62
  }, [
63
+ callbackRef,
59
64
  actorRef,
60
65
  event,
61
66
  once
@@ -68,7 +68,7 @@ function useDiagramCompareLayout() {
68
68
  console.warn("Compare with latest feature is not enabled");
69
69
  return;
70
70
  }
71
- nonNullable(actorRef.system?.get("editor"), "editor actor not found").send({ type: "applyLatestToManual" });
71
+ nonNullable(actorRef.system?.get("editor"), "editor actor not found").send({ type: "change.latest-to-manual" });
72
72
  if (state.isActive) actorRef.send({
73
73
  type: "toggle.feature",
74
74
  feature: "CompareWithLatest",
@@ -0,0 +1,9 @@
1
+ import { EditorActorRef } from '../editor/actor/machine';
2
+ import { EditorActorStateTag } from '../editor/actor/types';
3
+ export declare function useEditorActorRef(): EditorActorRef | null;
4
+ export declare function useEditorActorStateHasTag(tag: EditorActorStateTag): boolean;
5
+ /**
6
+ * Check if the editor actor is in the 'busy' state
7
+ * (i.e. syncing with the backend)
8
+ */
9
+ export declare function useEditorIsBusy(): boolean;
@@ -0,0 +1,27 @@
1
+ import "../_virtual/_rolldown/runtime.js";
2
+ import { selectDiagramActor, useDiagramSnapshot } from "./useDiagram.js";
3
+ import { useEffect, useState } from "react";
4
+ import "@mantine/hooks";
5
+ //#region src/hooks/useEditorActor.ts
6
+ var select = selectDiagramActor((s) => {
7
+ return s.children.editor ?? null;
8
+ });
9
+ function useEditorActorRef() {
10
+ return useDiagramSnapshot(select, Object.is);
11
+ }
12
+ function useEditorActorStateHasTag(tag) {
13
+ const editorActor = useEditorActorRef();
14
+ const [hasTag, setHasTag] = useState(() => editorActor?.getSnapshot().hasTag(tag) ?? false);
15
+ useEffect(() => {
16
+ const subscription = editorActor?.select((s) => s.hasTag(tag)).subscribe((hasTag) => {
17
+ setHasTag(hasTag);
18
+ });
19
+ return () => {
20
+ subscription?.unsubscribe();
21
+ setHasTag(false);
22
+ };
23
+ }, [editorActor, tag]);
24
+ return hasTag;
25
+ }
26
+ //#endregion
27
+ export { useEditorActorStateHasTag };
@@ -1,8 +1,10 @@
1
1
  import { Fqn, ViewId } from '@likec4/core/types';
2
- interface LikeC4ModelTreeNodeData {
2
+ import { TreeNodeData } from '@mantine/core';
3
+ export interface LikeC4ModelTreeNodeData extends TreeNodeData {
3
4
  label: string;
4
5
  value: Fqn;
5
6
  children: LikeC4ModelTreeNodeData[];
7
+ hasChildren: boolean;
6
8
  }
7
9
  export declare const sortByLabel: (a: LikeC4ModelTreeNodeData, b: LikeC4ModelTreeNodeData) => number;
8
10
  /**
@@ -10,4 +12,3 @@ export declare const sortByLabel: (a: LikeC4ModelTreeNodeData, b: LikeC4ModelTre
10
12
  * If `viewId` is provided, returns the tree of elements in the view.
11
13
  */
12
14
  export declare function useLikeC4ElementsTree(viewId?: ViewId): LikeC4ModelTreeNodeData[];
13
- export {};
@@ -5,10 +5,12 @@ import { compareNatural } from "@likec4/core/utils";
5
5
  //#region src/hooks/useLikeC4ElementsTree.ts
6
6
  var sortByLabel = (a, b) => compareNatural(a.label, b.label);
7
7
  function buildNode(element) {
8
+ const children = [...element.children()].map(buildNode).sort(sortByLabel);
8
9
  return {
9
10
  label: element.title || element.id,
10
11
  value: element.id,
11
- children: [...element.children()].map(buildNode).sort(sortByLabel)
12
+ children,
13
+ hasChildren: children.length > 0
12
14
  };
13
15
  }
14
16
  /**
package/dist/index.d.ts CHANGED
@@ -22,3 +22,5 @@ export { LikeC4ProjectsOverview, type LikeC4ProjectsOverviewProps, } from './Lik
22
22
  export { normalizeSearch, SearchContext, type SearchContextValue, useSearchContext, } from './search/SearchContext';
23
23
  export { bodyCss as searchBodyCss, dialogCss as searchDialogCss, SearchPanelContent, } from './search/Search';
24
24
  export { SearchControl } from './components/SearchControl';
25
+ export { DefaultMantineProvider } from './context/DefaultMantineProvider';
26
+ export { FramerMotionConfig } from './context/FramerMotionConfig';
package/dist/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { IconRendererProvider } from "./context/IconRenderer.js";
2
2
  import { useUpdateEffect } from "./hooks/useUpdateEffect.js";
3
+ import { DefaultMantineProvider } from "./context/DefaultMantineProvider.js";
4
+ import { FramerMotionConfig } from "./context/FramerMotionConfig.js";
3
5
  import { useDiagram } from "./hooks/safeContext.js";
4
6
  import { useDiagramContext, useOnDiagramEvent } from "./hooks/useDiagram.js";
5
7
  import { useCurrentView, useCurrentViewId } from "./hooks/useCurrentView.js";
@@ -21,4 +23,4 @@ import { LikeC4View } from "./LikeC4View.js";
21
23
  import { ReactLikeC4 } from "./ReactLikeC4.js";
22
24
  import { LikeC4ProjectsOverview } from "./LikeC4ProjectsOverview.js";
23
25
  import { SearchControl } from "./components/SearchControl.js";
24
- export { IconRendererProvider, LikeC4Diagram, LikeC4EditorProvider, LikeC4ModelProvider, LikeC4ProjectsOverview, LikeC4ProjectsProvider, LikeC4View, ReactLikeC4, SearchContext, SearchControl, SearchPanelContent, StaticLikeC4Diagram, createLikeC4Editor, normalizeSearch, pickViewBounds, bodyCss as searchBodyCss, dialogCss as searchDialogCss, useChangeLikeC4Project, useCurrentView, useCurrentViewId, useCurrentViewModel, useDiagram, useDiagramContext, useHasProjects, useLikeC4Model, useLikeC4Project, useLikeC4ProjectId, useLikeC4Projects, useLikeC4ProjectsContext, useLikeC4Specification, useLikeC4Styles, useLikeC4ViewModel, useOnDiagramEvent, useOptionalCurrentViewModel, useSearchContext, useUpdateEffect };
26
+ export { DefaultMantineProvider, FramerMotionConfig, IconRendererProvider, LikeC4Diagram, LikeC4EditorProvider, LikeC4ModelProvider, LikeC4ProjectsOverview, LikeC4ProjectsProvider, LikeC4View, ReactLikeC4, SearchContext, SearchControl, SearchPanelContent, StaticLikeC4Diagram, createLikeC4Editor, normalizeSearch, pickViewBounds, bodyCss as searchBodyCss, dialogCss as searchDialogCss, useChangeLikeC4Project, useCurrentView, useCurrentViewId, useCurrentViewModel, useDiagram, useDiagramContext, useHasProjects, useLikeC4Model, useLikeC4Project, useLikeC4ProjectId, useLikeC4Projects, useLikeC4ProjectsContext, useLikeC4Specification, useLikeC4Styles, useLikeC4ViewModel, useOnDiagramEvent, useOptionalCurrentViewModel, useSearchContext, useUpdateEffect };
@@ -1,2 +1,2 @@
1
1
  import { MemoExoticComponent } from 'react';
2
- export declare const LikeC4DiagramUI: MemoExoticComponent<() => import("react/jsx-runtime").JSX.Element>;
2
+ export declare const LikeC4DiagramUI: MemoExoticComponent<() => import("react").JSX.Element>;
@@ -1,7 +1,7 @@
1
1
  import "../_virtual/_rolldown/runtime.js";
2
2
  import { useEnabledFeatures } from "../context/DiagramFeatures.js";
3
+ import { selectDiagramActor, useDiagramSnapshot } from "../hooks/useDiagram.js";
3
4
  import { ErrorBoundary } from "../components/ErrorFallback.js";
4
- import { useOverlaysActorRef } from "../hooks/useOverlaysActor.js";
5
5
  import { NavigationPanel } from "../navigationpanel/NavigationPanel.js";
6
6
  import { Overlays } from "../overlays/Overlays.js";
7
7
  import { Search } from "../search/Search.js";
@@ -12,10 +12,14 @@ import { memo, useCallback } from "react";
12
12
  import { jsx, jsxs } from "react/jsx-runtime";
13
13
  import { useRerender } from "@react-hookz/web";
14
14
  //#region src/likec4diagram/DiagramUI.tsx
15
+ var selectChildren = selectDiagramActor((s) => ({
16
+ overlays: s.children.overlays ?? null,
17
+ search: s.children.search ?? null
18
+ }));
15
19
  var LikeC4DiagramUI = memo(() => {
16
20
  const { enableControls, enableNotations, enableSearch, enableRelationshipDetails, enableReadOnly, enableCompareWithLatest } = useEnabledFeatures();
17
21
  const rerender = useRerender();
18
- const overlaysActorRef = useOverlaysActorRef();
22
+ const actors = useDiagramSnapshot(selectChildren);
19
23
  return /* @__PURE__ */ jsxs(ErrorBoundary, {
20
24
  onReset: useCallback(() => {
21
25
  console.warn("DiagramUI: resetting error boundary and rerendering...");
@@ -23,9 +27,9 @@ var LikeC4DiagramUI = memo(() => {
23
27
  }, []),
24
28
  children: [
25
29
  enableControls && /* @__PURE__ */ jsx(NavigationPanel, {}),
26
- overlaysActorRef && /* @__PURE__ */ jsx(Overlays, { overlaysActorRef }),
30
+ actors.overlays && /* @__PURE__ */ jsx(Overlays, { overlaysActorRef: actors.overlays }),
27
31
  enableNotations && /* @__PURE__ */ jsx(NotationPanel, {}),
28
- enableSearch && /* @__PURE__ */ jsx(Search, {}),
32
+ enableSearch && actors.search && /* @__PURE__ */ jsx(Search, { searchActorRef: actors.search }),
29
33
  enableRelationshipDetails && enableReadOnly && /* @__PURE__ */ jsx(RelationshipPopover, {}),
30
34
  enableCompareWithLatest && /* @__PURE__ */ jsx(LayoutDriftFrame, {})
31
35
  ]