@likec4/diagram 1.46.3 → 1.47.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 (68) hide show
  1. package/bundle/index.js +1548 -595
  2. package/dist/LikeC4Diagram.d.ts +1 -1
  3. package/dist/LikeC4Diagram.js +2 -2
  4. package/dist/LikeC4Diagram.props.d.ts +1 -1
  5. package/dist/LikeC4ProjectsOverview.d.ts +7 -0
  6. package/dist/LikeC4ProjectsOverview.js +32 -0
  7. package/dist/base-primitives/Markdown.d.ts +1 -1
  8. package/dist/base-primitives/compound/CompoundNodeContainer.d.ts +4 -3
  9. package/dist/base-primitives/compound/actionbtns.css.d.ts +1 -1
  10. package/dist/base-primitives/element/ElementNodeContainer.js +2 -3
  11. package/dist/base-primitives/element/ElementShape.js +109 -20
  12. package/dist/components/NavigationPanel.d.ts +11 -0
  13. package/dist/components/NavigationPanel.js +69 -0
  14. package/dist/context/DiagramEventHandlers.js +1 -1
  15. package/dist/context/IconRenderer.js +4 -1
  16. package/dist/hooks/useLikeC4Project.js +10 -2
  17. package/dist/hooks/useLikeC4Styles.js +0 -3
  18. package/dist/index.d.ts +2 -1
  19. package/dist/index.js +2 -1
  20. package/dist/likec4diagram/DiagramXYFlow.js +1 -0
  21. package/dist/likec4diagram/custom/nodes/toolbar/ColorButton.js +3 -3
  22. package/dist/likec4diagram/custom/nodes/toolbar/CompoundToolbar.js +1 -38
  23. package/dist/likec4diagram/custom/nodes/toolbar/ElementToolbar.js +29 -14
  24. package/dist/likec4diagram/custom/nodes/toolbar/Toolbar.js +9 -5
  25. package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +6 -1
  26. package/dist/likec4diagram/custom/nodes/toolbar/_shared.js +44 -8
  27. package/dist/likec4diagram/xyflow-sequence/utils.d.ts +1 -1
  28. package/dist/navigationpanel/NavigationPanelControls.js +2 -2
  29. package/dist/navigationpanel/_common.d.ts +1 -1
  30. package/dist/navigationpanel/controls/LogoButton.d.ts +1 -0
  31. package/dist/navigationpanel/controls/{BurgerButton.js → LogoButton.js} +5 -5
  32. package/dist/navigationpanel/controls/index.d.ts +1 -1
  33. package/dist/navigationpanel/styles.css.d.ts +1 -1
  34. package/dist/node_modules/.pnpm/@tabler_icons-react@3.36.0_react@19.2.3/node_modules/@tabler/icons-react/dist/esm/icons/IconFileText.js +14 -0
  35. package/dist/overlays/relationships-browser/custom/edgeTypes.js +0 -1
  36. package/dist/projects-overview/ProjectsOverview.d.ts +13 -0
  37. package/dist/projects-overview/ProjectsOverview.js +57 -0
  38. package/dist/projects-overview/ProjectsOverviewXY.d.ts +17 -0
  39. package/dist/projects-overview/ProjectsOverviewXY.js +98 -0
  40. package/dist/projects-overview/_types.d.ts +34 -0
  41. package/dist/projects-overview/actor.d.ts +121 -0
  42. package/dist/projects-overview/actor.js +382 -0
  43. package/dist/projects-overview/context.d.ts +4 -0
  44. package/dist/projects-overview/context.js +9 -0
  45. package/dist/projects-overview/custom/edgeTypes.d.ts +3 -0
  46. package/dist/projects-overview/custom/edgeTypes.js +23 -0
  47. package/dist/projects-overview/custom/index.d.ts +2 -0
  48. package/dist/projects-overview/custom/nodeTypes.d.ts +2 -0
  49. package/dist/projects-overview/custom/nodeTypes.js +45 -0
  50. package/dist/projects-overview/custom/styles.css.d.ts +1 -0
  51. package/dist/projects-overview/hooks.d.ts +5 -0
  52. package/dist/projects-overview/hooks.js +14 -0
  53. package/dist/projects-overview/index.d.ts +1 -0
  54. package/dist/projects-overview/layouted-to-xyflow.d.ts +6 -0
  55. package/dist/projects-overview/layouted-to-xyflow.js +49 -0
  56. package/dist/projects-overview/panel/ProjectsOverviewPanel.d.ts +1 -0
  57. package/dist/projects-overview/panel/ProjectsOverviewPanel.js +11 -0
  58. package/dist/projects-overview/persistence.d.ts +5 -0
  59. package/dist/projects-overview/persistence.js +24 -0
  60. package/dist/search/components/_shared.css.d.ts +1 -1
  61. package/dist/styles.css2.js +1 -1
  62. package/package.json +10 -10
  63. package/panda.buildinfo.json +62 -29
  64. package/styles-min.css +1 -1
  65. package/styles.css +1 -1
  66. package/dist/base-primitives/element/ElementNodeContainer.css.d.ts +0 -1
  67. package/dist/base-primitives/element/ElementNodeContainer.css.js +0 -39
  68. package/dist/navigationpanel/controls/BurgerButton.d.ts +0 -1
@@ -0,0 +1,121 @@
1
+ import { NodeId, ProjectId, BBox } from '@likec4/core';
2
+ import { LayoutedProjectsView } from '@likec4/core/compute-view';
3
+ import { EdgeChange, NodeChange } from '@xyflow/system';
4
+ import { MouseEvent } from 'react';
5
+ import { Simplify } from 'type-fest';
6
+ import { ActorRef, SnapshotFrom, StateMachine, ActionFunction, Values } from 'xstate';
7
+ import { ViewPadding } from '../custom';
8
+ import { ProjectsOverviewTypes, ProjectsOverviewXYFLowInstance, ProjectsOverviewXYStoreApi } from './_types';
9
+ export type Input = {
10
+ view: LayoutedProjectsView;
11
+ fitViewPadding: ViewPadding;
12
+ };
13
+ export interface Context {
14
+ initialized: {
15
+ xydata: boolean;
16
+ xyflow: boolean;
17
+ };
18
+ xystore: ProjectsOverviewXYStoreApi | null;
19
+ xyflow: ProjectsOverviewXYFLowInstance | null;
20
+ view: LayoutedProjectsView;
21
+ fitViewPadding: ViewPadding;
22
+ xynodes: ProjectsOverviewTypes.Node[];
23
+ xyedges: ProjectsOverviewTypes.Edge[];
24
+ navigateTo?: ProjectsOverviewTypes.Node;
25
+ }
26
+ export type EmittedEvents = {
27
+ type: 'navigate.to';
28
+ projectId: ProjectId;
29
+ };
30
+ /**
31
+ * Converts a union of events to a union of events with a prefix.
32
+ */
33
+ type EmitEach<T extends {
34
+ type: string;
35
+ }> = {
36
+ [Key in T['type']]: Simplify<{
37
+ type: `emit.${Key}`;
38
+ } & Omit<Extract<T, {
39
+ type: Key;
40
+ }>, 'type'>>;
41
+ }[T['type']];
42
+ export type Events = {
43
+ type: 'navigate.to';
44
+ projectId: ProjectId;
45
+ fromNode: NodeId;
46
+ } | {
47
+ type: 'xyflow.init';
48
+ xyflow: ProjectsOverviewXYFLowInstance;
49
+ xystore: ProjectsOverviewXYStoreApi;
50
+ } | {
51
+ type: 'xyflow.click.node';
52
+ node: ProjectsOverviewTypes.Node;
53
+ } | {
54
+ type: 'xyflow.click.edge';
55
+ edge: ProjectsOverviewTypes.Edge;
56
+ } | {
57
+ type: 'xyflow.click.pane';
58
+ } | {
59
+ type: 'xyflow.click.double';
60
+ } | {
61
+ type: 'xyflow.mouse.enter.node';
62
+ node: ProjectsOverviewTypes.Node;
63
+ } | {
64
+ type: 'xyflow.mouse.leave.node';
65
+ node: ProjectsOverviewTypes.Node;
66
+ } | {
67
+ type: 'xyflow.mouse.enter.edge';
68
+ edge: ProjectsOverviewTypes.Edge;
69
+ event: MouseEvent;
70
+ } | {
71
+ type: 'xyflow.mouse.leave.edge';
72
+ edge: ProjectsOverviewTypes.Edge;
73
+ event: MouseEvent;
74
+ } | {
75
+ type: 'xyflow.applyNodeChanges';
76
+ changes: NodeChange<ProjectsOverviewTypes.Node>[];
77
+ } | {
78
+ type: 'xyflow.applyEdgeChanges';
79
+ changes: EdgeChange<ProjectsOverviewTypes.Edge>[];
80
+ } | {
81
+ type: 'xyflow.fitDiagram';
82
+ bounds?: BBox;
83
+ duration?: number;
84
+ } | {
85
+ type: 'update.view';
86
+ view: LayoutedProjectsView;
87
+ } | EmitEach<EmittedEvents> | {
88
+ type: 'close';
89
+ };
90
+ type Tags = 'active';
91
+ export declare const onMouseEnterOrLeave: () => ActionFunction<Context, Events, Events, undefined, never, never, never, never, never>;
92
+ export declare const fitDiagram: (params?: {
93
+ duration?: number;
94
+ bounds?: BBox;
95
+ }) => ActionFunction<Context, Events, Events, undefined, never, never, Values<{
96
+ isReady: {
97
+ type: "isReady";
98
+ params: unknown;
99
+ };
100
+ "click: selected node": {
101
+ type: "click: selected node";
102
+ params: unknown;
103
+ };
104
+ }>, never, EmittedEvents>;
105
+ export declare const restoreViewport: () => ActionFunction<Context, Events, Events, undefined, never, never, Values<{
106
+ isReady: {
107
+ type: "isReady";
108
+ params: unknown;
109
+ };
110
+ "click: selected node": {
111
+ type: "click: selected node";
112
+ params: unknown;
113
+ };
114
+ }>, never, EmittedEvents>;
115
+ export interface ProjectsOverviewLogic extends StateMachine<Context, Events, {}, any, any, any, any, any, Tags, Input, any, EmittedEvents, any, any> {
116
+ }
117
+ export declare const projectOverviewLogic: ProjectsOverviewLogic;
118
+ export type ProjectsOverviewSnapshot = SnapshotFrom<ProjectsOverviewLogic>;
119
+ export interface ProjectsOverviewActorRef extends ActorRef<ProjectsOverviewSnapshot, Events, EmittedEvents> {
120
+ }
121
+ export type { Input as ProjectsOverviewInput, };
@@ -0,0 +1,382 @@
1
+ import { invariant, nonNullable, nonexhaustive } from '@likec4/core';
2
+ import { getViewportForBounds, applyEdgeChanges, applyNodeChanges } from '@xyflow/react';
3
+ import { animate, stagger, motionValue, mapValue, styleEffect } from 'motion';
4
+ import { clamp } from 'remeda';
5
+ import { setup, assertEvent } from 'xstate';
6
+ import { Base } from '../base/Base.js';
7
+ import { layoutedProjectsViewToXYFlow } from './layouted-to-xyflow.js';
8
+ import { ProjectsOverviewViewportPersistence } from './persistence.js';
9
+ import { x as xstateActions_cjsExports } from '../_virtual/xstate-actions.cjs.js';
10
+ import { MinZoom } from '../base/const.js';
11
+
12
+ const machine = setup({
13
+ types: {
14
+ context: {},
15
+ tags: "",
16
+ input: {},
17
+ events: {},
18
+ emitted: {}
19
+ },
20
+ guards: {
21
+ isReady: ({ context }) => context.initialized.xydata && context.initialized.xyflow && !!context.xystore && !!context.xyflow,
22
+ "click: selected node": ({ event }) => {
23
+ assertEvent(event, ["xyflow.click.node"]);
24
+ return event.node.selected === true;
25
+ }
26
+ }
27
+ });
28
+ const updateView = () => machine.assign(({ event }) => {
29
+ assertEvent(event, "update.view");
30
+ const { xynodes, xyedges } = layoutedProjectsViewToXYFlow(event.view);
31
+ return {
32
+ view: event.view,
33
+ xynodes,
34
+ xyedges
35
+ };
36
+ });
37
+ const xyflowApplyNodeChanges = () => machine.assign(({ context, event }) => {
38
+ assertEvent(event, "xyflow.applyNodeChanges");
39
+ return {
40
+ xynodes: applyNodeChanges(event.changes, context.xynodes)
41
+ };
42
+ });
43
+ const xyflowApplyEdgeChanges = () => machine.assign(({ context, event }) => {
44
+ assertEvent(event, "xyflow.applyEdgeChanges");
45
+ return {
46
+ xyedges: applyEdgeChanges(event.changes, context.xyedges)
47
+ };
48
+ });
49
+ const onMouseEnterOrLeave = () => machine.assign(({ context, event }) => {
50
+ assertEvent(event, [
51
+ "xyflow.mouse.enter.edge",
52
+ "xyflow.mouse.leave.edge",
53
+ "xyflow.mouse.enter.node",
54
+ "xyflow.mouse.leave.node"
55
+ ]);
56
+ const isEnter = event.type.startsWith("xyflow.mouse.enter");
57
+ switch (event.type) {
58
+ case "xyflow.mouse.enter.edge":
59
+ case "xyflow.mouse.leave.edge": {
60
+ const edgeId = event.edge.id;
61
+ return {
62
+ xyedges: context.xyedges.map((e) => {
63
+ if (e.id === edgeId) {
64
+ return Base.setHovered(e, isEnter);
65
+ }
66
+ return e;
67
+ })
68
+ };
69
+ }
70
+ case "xyflow.mouse.enter.node":
71
+ case "xyflow.mouse.leave.node": {
72
+ const nodeId = event.node.id;
73
+ return {
74
+ xynodes: context.xynodes.map((n) => {
75
+ if (n.id === nodeId) {
76
+ return Base.setHovered(n, isEnter);
77
+ }
78
+ return n;
79
+ })
80
+ };
81
+ }
82
+ default:
83
+ nonexhaustive(event);
84
+ }
85
+ });
86
+ const saveViewport = () => machine.createAction(({ context }) => {
87
+ const xyflow = context.xyflow;
88
+ if (xyflow) {
89
+ ProjectsOverviewViewportPersistence.write(xyflow.getViewport());
90
+ }
91
+ });
92
+ const handleClick = () => machine.enqueueActions(({ event, enqueue }) => {
93
+ if (event.type === "xyflow.click.double") {
94
+ enqueue(cancelFitDiagram());
95
+ enqueue(raiseFitDiagram());
96
+ return;
97
+ }
98
+ if (event.type === "xyflow.click.pane") {
99
+ enqueue(cancelFitDiagram());
100
+ return;
101
+ }
102
+ console.warn("Unknown event", event);
103
+ });
104
+ const cancelFitDiagram = () => machine.cancel("fitDiagram");
105
+ const raiseFitDiagram = (params) => {
106
+ const { delay = 30, ...rest } = {};
107
+ return machine.raise(
108
+ {
109
+ type: "xyflow.fitDiagram",
110
+ ...rest
111
+ },
112
+ {
113
+ id: "fitDiagram",
114
+ delay
115
+ }
116
+ );
117
+ };
118
+ const fitDiagram = (params) => machine.enqueueActions(({ context, event, enqueue }) => {
119
+ enqueue(cancelFitDiagram());
120
+ let bounds = context.view.bounds, duration;
121
+ if (params) {
122
+ bounds = params.bounds ?? context.view.bounds;
123
+ duration = params.duration;
124
+ } else if (event.type === "xyflow.fitDiagram") {
125
+ bounds = event.bounds ?? context.view.bounds;
126
+ duration = event.duration;
127
+ }
128
+ duration ??= 450;
129
+ const { width, height, panZoom, transform } = nonNullable(context.xystore).getState();
130
+ const maxZoom = Math.max(1, transform[2]);
131
+ const viewport = getViewportForBounds(
132
+ bounds,
133
+ width,
134
+ height,
135
+ MinZoom,
136
+ maxZoom,
137
+ context.fitViewPadding
138
+ );
139
+ viewport.x = Math.round(viewport.x);
140
+ viewport.y = Math.round(viewport.y);
141
+ const animationProps = duration > 0 ? { duration, interpolate: "smooth" } : void 0;
142
+ panZoom?.setViewport(viewport, animationProps).catch((err) => {
143
+ console.error("Error during fitDiagram panZoom setViewport", { err });
144
+ });
145
+ ProjectsOverviewViewportPersistence.write(null);
146
+ });
147
+ const restoreViewport = () => machine.enqueueActions(({ context, enqueue }) => {
148
+ const viewport = ProjectsOverviewViewportPersistence.read();
149
+ if (viewport) {
150
+ const xyflow = nonNullable(context.xyflow);
151
+ xyflow.setViewport(viewport, {
152
+ duration: 0
153
+ });
154
+ return;
155
+ }
156
+ enqueue(fitDiagram({ duration: 0 }));
157
+ });
158
+ const dispose = () => machine.assign({
159
+ xyflow: null,
160
+ xystore: null,
161
+ initialized: {
162
+ xyflow: false,
163
+ xydata: false
164
+ },
165
+ xyedges: [],
166
+ xynodes: []
167
+ });
168
+ const assignNavigateTo = () => machine.assign(({ event, context }) => {
169
+ let navigateTo;
170
+ switch (event.type) {
171
+ case "xyflow.click.node": {
172
+ navigateTo = event.node;
173
+ break;
174
+ }
175
+ case "navigate.to": {
176
+ navigateTo = nonNullable(context.xynodes.find((n) => n.id === event.fromNode), `Node ${event.fromNode} not found`);
177
+ break;
178
+ }
179
+ default: {
180
+ console.warn(`Unexpected event ${event.type} in assignNavigateTo`);
181
+ return {};
182
+ }
183
+ }
184
+ return {
185
+ navigateTo
186
+ };
187
+ });
188
+ const _projectOverviewLogic = machine.createMachine({
189
+ id: "projects-overview",
190
+ context: ({ input }) => ({
191
+ ...input,
192
+ initialized: {
193
+ xydata: false,
194
+ xyflow: false
195
+ },
196
+ xyflow: null,
197
+ xystore: null,
198
+ xynodes: [],
199
+ xyedges: []
200
+ }),
201
+ initial: "init",
202
+ on: {
203
+ "close": {
204
+ target: ".closed"
205
+ }
206
+ },
207
+ states: {
208
+ init: {
209
+ on: {
210
+ "update.view": {
211
+ actions: [
212
+ updateView(),
213
+ xstateActions_cjsExports.assign(({ context }) => ({
214
+ initialized: {
215
+ ...context.initialized,
216
+ xydata: true
217
+ }
218
+ }))
219
+ ],
220
+ target: "isReady"
221
+ },
222
+ "xyflow.init": {
223
+ actions: [
224
+ xstateActions_cjsExports.assign(({ context, event }) => ({
225
+ initialized: {
226
+ ...context.initialized,
227
+ xyflow: true
228
+ },
229
+ xyflow: event.xyflow,
230
+ xystore: event.xystore
231
+ }))
232
+ ],
233
+ target: "isReady"
234
+ }
235
+ }
236
+ },
237
+ isReady: {
238
+ always: [{
239
+ guard: "isReady",
240
+ target: "active"
241
+ }, {
242
+ target: "init"
243
+ }]
244
+ },
245
+ active: {
246
+ tags: "active",
247
+ entry: [
248
+ restoreViewport()
249
+ ],
250
+ on: {
251
+ "navigate.to": {
252
+ actions: assignNavigateTo(),
253
+ target: "navigate"
254
+ },
255
+ "xyflow.applyNodeChanges": {
256
+ actions: xyflowApplyNodeChanges()
257
+ },
258
+ "xyflow.applyEdgeChanges": {
259
+ actions: xyflowApplyEdgeChanges()
260
+ },
261
+ "xyflow.mouse.*": {
262
+ actions: onMouseEnterOrLeave()
263
+ },
264
+ "xyflow.click.node": [
265
+ {
266
+ guard: "click: selected node",
267
+ actions: assignNavigateTo(),
268
+ target: "navigate"
269
+ }
270
+ ],
271
+ "xyflow.click.*": {
272
+ actions: handleClick()
273
+ },
274
+ "xyflow.fitDiagram": {
275
+ actions: fitDiagram()
276
+ },
277
+ "update.view": {
278
+ actions: updateView()
279
+ }
280
+ }
281
+ },
282
+ navigate: {
283
+ tags: "active",
284
+ entry: [
285
+ cancelFitDiagram(),
286
+ saveViewport(),
287
+ xstateActions_cjsExports.assign({
288
+ xyedges: []
289
+ }),
290
+ ({ context: { navigateTo, xyflow, xystore }, self }) => {
291
+ invariant(xyflow && navigateTo, "Invalid state, xyflow is undefined");
292
+ const { width, domNode } = nonNullable(xystore).getState();
293
+ const nextZoom = clamp(
294
+ Math.min(
295
+ width * 2 / 3 / navigateTo.data.width
296
+ // (height - 200) / (navigateTo.data.height),
297
+ ),
298
+ { min: MinZoom, max: 2.5 }
299
+ );
300
+ const next = {
301
+ x: Math.round(
302
+ -nextZoom * navigateTo.position.x + (width - nextZoom * navigateTo.data.width) / 2
303
+ ),
304
+ y: Math.round(-nextZoom * navigateTo.position.y) + 50
305
+ };
306
+ const current = xyflow.getViewport();
307
+ const otherNodes = domNode.querySelectorAll(
308
+ `.react-flow__node-project:not([data-id="${navigateTo.id}"]) > *`
309
+ );
310
+ const otherNodesAnimation = animate(otherNodes, {
311
+ opacity: 0,
312
+ scale: 0.9
313
+ }, {
314
+ visualDuration: 0.25,
315
+ delay: stagger(0.08, { from: "center" })
316
+ });
317
+ const v = motionValue(1);
318
+ const transform = mapValue(
319
+ v,
320
+ [1, 0],
321
+ [
322
+ `translate(${current.x}px, ${current.y}px) scale(${current.zoom})`,
323
+ `translate(${next.x}px, ${next.y}px) scale(${nextZoom})`
324
+ ]
325
+ );
326
+ const cancelViewportAnimation = styleEffect(
327
+ domNode.querySelector(".xyflow__viewport"),
328
+ { transform }
329
+ );
330
+ const cancelOpacityAnimation = styleEffect(
331
+ domNode.querySelector(`.react-flow__node-project:is([data-id="${navigateTo.id}"]) > *`),
332
+ { opacity: v }
333
+ );
334
+ const targetAnimation = animate(
335
+ v,
336
+ 0,
337
+ {
338
+ delay: otherNodes.length > 3 ? 0.25 : 0,
339
+ type: "spring",
340
+ stiffness: 350,
341
+ damping: 40,
342
+ mass: 1.5,
343
+ visualDuration: 0.55
344
+ }
345
+ );
346
+ Promise.race([
347
+ targetAnimation.finished,
348
+ sleep(750)
349
+ ]).then(() => {
350
+ cancelViewportAnimation();
351
+ cancelOpacityAnimation();
352
+ targetAnimation.stop();
353
+ otherNodesAnimation.stop();
354
+ self.send({
355
+ type: "emit.navigate.to",
356
+ projectId: navigateTo.data.projectId
357
+ });
358
+ });
359
+ }
360
+ ],
361
+ on: {
362
+ "emit.navigate.to": {
363
+ actions: xstateActions_cjsExports.emit(({ event }) => ({
364
+ ...event,
365
+ type: "navigate.to"
366
+ }))
367
+ }
368
+ }
369
+ },
370
+ closed: {
371
+ id: "closed",
372
+ type: "final",
373
+ entry: dispose()
374
+ }
375
+ }
376
+ });
377
+ const projectOverviewLogic = _projectOverviewLogic;
378
+ function sleep(ms) {
379
+ return new Promise((resolve) => setTimeout(resolve, ms));
380
+ }
381
+
382
+ export { fitDiagram, onMouseEnterOrLeave, projectOverviewLogic, restoreViewport };
@@ -0,0 +1,4 @@
1
+ import { ProjectsOverviewActorRef } from './actor';
2
+ import { Context } from 'react';
3
+ export declare const ProjectsOverviewActorContext: Context<ProjectsOverviewActorRef | null>;
4
+ export declare function useProjectsOverviewActor(): ProjectsOverviewActorRef;
@@ -0,0 +1,9 @@
1
+ import { nonNullable } from '@likec4/core';
2
+ import { createContext, useContext } from 'react';
3
+
4
+ const ProjectsOverviewActorContext = createContext(null);
5
+ function useProjectsOverviewActor() {
6
+ return nonNullable(useContext(ProjectsOverviewActorContext), "No ProjectsOverviewActorContext");
7
+ }
8
+
9
+ export { ProjectsOverviewActorContext, useProjectsOverviewActor };
@@ -0,0 +1,3 @@
1
+ import { ProjectsOverviewTypes } from '../_types';
2
+ import { FunctionComponent } from 'react';
3
+ export declare const RelationshipEdge: FunctionComponent<ProjectsOverviewTypes.EdgeProps>;
@@ -0,0 +1,23 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { bezierPath } from '../../utils/xyflow.js';
3
+ import { memoEdge } from '../../base-primitives/memoEdge.js';
4
+ import { EdgeContainer } from '../../base-primitives/edge/EdgeContainer.js';
5
+ import { EdgePath } from '../../base-primitives/edge/EdgePath.js';
6
+ import { EdgeLabelContainer } from '../../base-primitives/edge/EdgeLabelContainer.js';
7
+ import { EdgeLabel } from '../../base-primitives/edge/EdgeLabel.js';
8
+
9
+ const RelationshipEdge = memoEdge((edgeProps) => {
10
+ const path = bezierPath(edgeProps.data.points);
11
+ return /* @__PURE__ */ jsxs(EdgeContainer, { ...edgeProps, children: [
12
+ /* @__PURE__ */ jsx(
13
+ EdgePath,
14
+ {
15
+ edgeProps,
16
+ svgPath: path
17
+ }
18
+ ),
19
+ /* @__PURE__ */ jsx(EdgeLabelContainer, { edgeProps, children: /* @__PURE__ */ jsx(EdgeLabel, { edgeProps }) })
20
+ ] });
21
+ });
22
+
23
+ export { RelationshipEdge };
@@ -0,0 +1,2 @@
1
+ export { RelationshipEdge } from './edgeTypes';
2
+ export { ProjectNode } from './nodeTypes';
@@ -0,0 +1,2 @@
1
+ import { ProjectsOverviewTypes } from '../_types';
2
+ export declare function ProjectNode(props: ProjectsOverviewTypes.NodeProps<'project'>): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,45 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useCallbackRef } from '@mantine/hooks';
3
+ import { useProjectsOverviewActor } from '../context.js';
4
+ import { ElementNodeContainer } from '../../base-primitives/element/ElementNodeContainer.js';
5
+ import { ElementShape } from '../../base-primitives/element/ElementShape.js';
6
+ import { ElementData } from '../../base-primitives/element/ElementData.js';
7
+ import { ElementActionButtons } from '../../base-primitives/element/ElementActionButtons.js';
8
+ import IconZoomScan from '../../node_modules/.pnpm/@tabler_icons-react@3.36.0_react@19.2.3/node_modules/@tabler/icons-react/dist/esm/icons/IconZoomScan.js';
9
+ import { DefaultHandles } from '../../base-primitives/NodeHandles.js';
10
+
11
+ function ProjectNode(props) {
12
+ const actor = useProjectsOverviewActor();
13
+ const navigateTo = useCallbackRef((e) => {
14
+ e.stopPropagation();
15
+ actor.send({ type: "navigate.to", fromNode: props.data.id, projectId: props.data.projectId });
16
+ });
17
+ return /* @__PURE__ */ jsxs(
18
+ ElementNodeContainer,
19
+ {
20
+ layout: true,
21
+ nodeProps: props,
22
+ children: [
23
+ /* @__PURE__ */ jsx(ElementShape, { ...props }),
24
+ /* @__PURE__ */ jsx(ElementData, { ...props }),
25
+ /* @__PURE__ */ jsx(
26
+ ElementActionButtons,
27
+ {
28
+ ...props,
29
+ buttons: [
30
+ {
31
+ key: "navigate",
32
+ icon: /* @__PURE__ */ jsx(IconZoomScan, {}),
33
+ onClick: navigateTo
34
+ }
35
+ ]
36
+ }
37
+ ),
38
+ /* @__PURE__ */ jsx(DefaultHandles, {})
39
+ ]
40
+ },
41
+ props.id
42
+ );
43
+ }
44
+
45
+ export { ProjectNode };
@@ -0,0 +1 @@
1
+ export declare const emptyNode: string;
@@ -0,0 +1,5 @@
1
+ import { ProjectsOverviewXYFLowInstance, ProjectsOverviewXYStoreApi } from './_types';
2
+ import { ProjectsOverviewSnapshot } from './actor';
3
+ export declare function useProjectsOverviewState<T>(selector: (state: ProjectsOverviewSnapshot) => T, compare?: (a: T, b: T) => boolean): T;
4
+ export declare function useProjectsOverviewXYFlow(): ProjectsOverviewXYFLowInstance;
5
+ export declare function useProjectsOverviewXYStoreApi(): ProjectsOverviewXYStoreApi;
@@ -0,0 +1,14 @@
1
+ import { useSelector } from '@xstate/react';
2
+ import { useStoreApi } from '@xyflow/react';
3
+ import { shallowEqual } from 'fast-equals';
4
+ import { useProjectsOverviewActor } from './context.js';
5
+
6
+ function useProjectsOverviewState(selector, compare = shallowEqual) {
7
+ const actor = useProjectsOverviewActor();
8
+ return useSelector(actor, selector, compare);
9
+ }
10
+ function useProjectsOverviewXYStoreApi() {
11
+ return useStoreApi();
12
+ }
13
+
14
+ export { useProjectsOverviewState, useProjectsOverviewXYStoreApi };
@@ -0,0 +1 @@
1
+ export { ProjectsOverview, type ProjectsOverviewProps, } from './ProjectsOverview';
@@ -0,0 +1,6 @@
1
+ import { LayoutedProjectsView } from '@likec4/core/compute-view';
2
+ import { ProjectsOverviewTypes } from './_types';
3
+ export declare function layoutedProjectsViewToXYFlow(view: LayoutedProjectsView): {
4
+ xynodes: ProjectsOverviewTypes.Node[];
5
+ xyedges: ProjectsOverviewTypes.Edge[];
6
+ };
@@ -0,0 +1,49 @@
1
+ import { map } from 'remeda';
2
+ import { ZIndexes } from '../base/const.js';
3
+
4
+ function layoutedProjectsViewToXYFlow(view) {
5
+ return {
6
+ xynodes: map(view.nodes, projectNodeToXY),
7
+ xyedges: map(view.edges, projectEdgeToXY)
8
+ };
9
+ }
10
+ function projectNodeToXY({ id, x, y, width, height, ...node }) {
11
+ return {
12
+ id,
13
+ position: { x, y },
14
+ type: "project",
15
+ initialWidth: width,
16
+ initialHeight: height,
17
+ draggable: false,
18
+ deletable: false,
19
+ zIndex: ZIndexes.Element,
20
+ style: {
21
+ width,
22
+ height
23
+ },
24
+ data: {
25
+ id,
26
+ width,
27
+ height,
28
+ ...node
29
+ }
30
+ };
31
+ }
32
+ function projectEdgeToXY({ id, source, target, ...edge }) {
33
+ return {
34
+ id,
35
+ source,
36
+ target,
37
+ type: "relationship",
38
+ zIndex: ZIndexes.Edge,
39
+ deletable: false,
40
+ data: {
41
+ id,
42
+ technology: null,
43
+ labelBBox: null,
44
+ ...edge
45
+ }
46
+ };
47
+ }
48
+
49
+ export { layoutedProjectsViewToXYFlow };
@@ -0,0 +1 @@
1
+ export declare const ProjectsOverviewPanel: () => import("react/jsx-runtime").JSX.Element;