@likec4/diagram 1.7.2 → 1.7.4

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 (70) hide show
  1. package/dist/LikeC4Diagram.d.ts +1 -1
  2. package/dist/LikeC4Diagram.props.d.ts +38 -22
  3. package/dist/StaticLikeC4Diagram.d.ts +1 -1
  4. package/dist/hooks/index.d.ts +2 -0
  5. package/dist/{state/useDiagramStore.d.ts → hooks/useDiagramState.d.ts} +2 -3
  6. package/dist/{xyflow/hooks → hooks}/useXYFlow.d.ts +10 -10
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.mjs +818 -448
  9. package/dist/state/DiagramContext.d.ts +74 -30
  10. package/dist/state/diagram-to-xyflow.d.ts +2 -0
  11. package/dist/state/diagramStore.d.ts +71 -22
  12. package/dist/style.css +58 -37
  13. package/dist/ui/top-left/ChangeAutoLayoutButton.d.ts +3 -0
  14. package/dist/ui/top-left/TopLeftPanel.d.ts +4 -0
  15. package/dist/ui/top-left/_shared.d.ts +5 -0
  16. package/dist/ui/top-left/styles.css.d.ts +3 -0
  17. package/dist/xyflow/XYFlowInner.d.ts +0 -1
  18. package/dist/xyflow/const.d.ts +1 -0
  19. package/dist/xyflow/edges/edges.css.d.ts +1 -1
  20. package/dist/xyflow/{hooks/useLayoutConstraints.d.ts → useLayoutConstraints.d.ts} +1 -1
  21. package/dist/xyflow/utils.d.ts +11 -1
  22. package/package.json +6 -6
  23. package/src/LikeC4Diagram.props.ts +66 -32
  24. package/src/LikeC4Diagram.tsx +19 -12
  25. package/src/StaticLikeC4Diagram.tsx +2 -0
  26. package/src/hooks/index.ts +2 -0
  27. package/src/{state/useDiagramStore.ts → hooks/useDiagramState.ts} +3 -4
  28. package/src/{xyflow/hooks → hooks}/useXYFlow.ts +1 -1
  29. package/src/index.ts +2 -2
  30. package/src/state/DiagramContext.tsx +15 -7
  31. package/src/state/diagram-to-xyflow.ts +17 -3
  32. package/src/state/diagramStore.ts +73 -38
  33. package/src/ui/DiagramTitlePanel.css.ts +2 -2
  34. package/src/ui/DiagramTitlePanel.tsx +62 -44
  35. package/src/ui/DynamicViewWalkthrough.tsx +1 -2
  36. package/src/ui/OptionsPanel.tsx +1 -1
  37. package/src/ui/options/EdgeOptions.tsx +1 -16
  38. package/src/ui/options/NodeOptions.tsx +38 -13
  39. package/src/ui/top-left/ChangeAutoLayoutButton.tsx +131 -0
  40. package/src/ui/top-left/TopLeftPanel.tsx +213 -0
  41. package/src/ui/top-left/_shared.ts +19 -0
  42. package/src/ui/top-left/styles.css.ts +38 -0
  43. package/src/xyflow/FitviewOnDiagramChange.tsx +2 -2
  44. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +87 -59
  45. package/src/xyflow/XYFlow.tsx +11 -10
  46. package/src/xyflow/XYFlowEvents.tsx +44 -18
  47. package/src/xyflow/XYFlowInner.tsx +5 -7
  48. package/src/xyflow/const.ts +1 -0
  49. package/src/xyflow/edges/RelationshipEdge.tsx +60 -27
  50. package/src/xyflow/edges/edges.css.ts +29 -25
  51. package/src/xyflow/nodes/compound/CompoundNode.tsx +1 -1
  52. package/src/xyflow/nodes/element/ElementLink.tsx +1 -2
  53. package/src/xyflow/nodes/element/ElementNode.tsx +7 -5
  54. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +1 -1
  55. package/src/xyflow/{hooks/useLayoutConstraints.ts → useLayoutConstraints.ts} +3 -3
  56. package/src/xyflow/utils.ts +25 -1
  57. package/dist/state/hooks.d.ts +0 -4
  58. package/dist/state/index.d.ts +0 -2
  59. package/dist/state/useNavigationHistory.d.ts +0 -5
  60. package/dist/types.d.ts +0 -20
  61. package/dist/ui/BackwardForwardPanel.css.d.ts +0 -1
  62. package/dist/ui/BackwardForwardPanel.d.ts +0 -1
  63. package/dist/xyflow/hooks/index.d.ts +0 -2
  64. package/src/state/hooks.ts +0 -5
  65. package/src/state/index.ts +0 -2
  66. package/src/state/useNavigationHistory.ts +0 -39
  67. package/src/types.ts +0 -22
  68. package/src/ui/BackwardForwardPanel.css.ts +0 -22
  69. package/src/ui/BackwardForwardPanel.tsx +0 -76
  70. package/src/xyflow/hooks/index.ts +0 -3
package/dist/index.mjs CHANGED
@@ -6,41 +6,23 @@ import { useReactFlow, useStoreApi, useNodesData, useStore, applyNodeChanges, ap
6
6
  import clsx from "clsx";
7
7
  import { shallowEqual, deepEqual } from "fast-equals";
8
8
  import { m, AnimatePresence, LazyMotion, domAnimation } from "framer-motion";
9
- import { useContext, useState, useCallback, createContext, useRef, useEffect, memo, useMemo, useId } from "react";
10
- import { MantineContext, Box, ActionIcon, Text as Text$1, HoverCard, HoverCardTarget, UnstyledButton, HoverCardDropdown, Stack, Group, Anchor, CopyButton, Button, Card, CardSection, Spoiler, ButtonGroup, rem, Divider, Space, TooltipGroup, Flex, Tooltip, ColorSwatch, CheckIcon, Select, Slider, SegmentedControl } from "@mantine/core";
11
- import { invariant, hasAtLeast, extractStep, nonNullable, StepEdgeId, getBBoxCenter, nonexhaustive, isAncestor, defaultTheme, ElementShapes } from "@likec4/core";
12
- import { getNodeDimensions, getBoundsOfRects, boxToRect, nodeToRect, getViewportForBounds as getViewportForBounds$1 } from "@xyflow/system";
9
+ import { createContext, useRef, useCallback, useContext, useState, memo, useEffect, useId, useMemo } from "react";
10
+ import { createWithEqualityFn, useStoreWithEqualityFn } from "zustand/traditional";
11
+ import { invariant, hasAtLeast, whereOperatorAsPredicate, extractStep, nonNullable, StepEdgeId, getBBoxCenter, nonexhaustive, isAncestor, defaultTheme, ElementShapes } from "@likec4/core";
12
+ import { useFirstMountState, useCustomCompareEffect, useDebouncedEffect } from "@react-hookz/web";
13
+ import { getNodeDimensions, getBoundsOfRects, boxToRect, getViewportForBounds as getViewportForBounds$1 } from "@xyflow/system";
13
14
  import { DEV } from "esm-env";
14
15
  import { isArray, hasAtLeast as hasAtLeast$1, isNullish, entries, reduce, isTruthy, first, last, clamp, isNumber, isNonNullish, keys, takeWhile } from "remeda";
15
16
  import { subscribeWithSelector, devtools } from "zustand/middleware";
16
17
  import { shallow } from "zustand/shallow";
17
- import { createWithEqualityFn, useStoreWithEqualityFn } from "zustand/traditional";
18
18
  import { Bezier } from "bezier-js";
19
- import { useFirstMountState, useCustomCompareEffect, useDebouncedEffect } from "@react-hookz/web";
19
+ import { MantineContext, Box, ActionIcon as ActionIcon$2, Text as Text$1, HoverCard, HoverCardTarget, UnstyledButton, HoverCardDropdown, Stack, Group, Anchor, CopyButton, Button, Card, CardSection, Spoiler, ButtonGroup, rem, Divider, Space, TooltipGroup, Flex, Tooltip as Tooltip$2, ColorSwatch, CheckIcon, Select, Slider, SegmentedControl, Popover, PopoverTarget, PopoverDropdown, FloatingIndicator, Notification, Code } from "@mantine/core";
20
+ import { useHotkeys, useLocalStorage } from "@mantine/hooks";
20
21
  import { assignInlineVars } from "@vanilla-extract/dynamic";
21
22
  import { line, curveCatmullRomOpen } from "d3-shape";
22
23
  import { Solver, Operator, Expression, Strength, Variable } from "@lume/kiwi";
23
- import { IconZoomScan, IconLink, IconChevronLeft, IconChevronRight, IconMenu, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled } from "@tabler/icons-react";
24
- import { useLocalStorage, useHotkeys } from "@mantine/hooks";
25
- var rootClassName = "likec4-diagram-root", cssReactFlow = "_2h8g8h0", cssDisablePan = "_2h8g8h1", cssTransparentBg = "_2h8g8h2", cssNoControls = "_2h8g8h3";
26
- function EnsureMantine({ children }) {
27
- if (!useContext(MantineContext))
28
- throw new Error("LikeC4Diagram must be a child of MantineProvider");
29
- return /* @__PURE__ */ jsx(Fragment, { children });
30
- }
31
- function useSetState(initialState) {
32
- const [state, _setState] = useState(initialState), setState = useCallback(
33
- (statePartial) => _setState((current) => {
34
- const next = {
35
- ...current,
36
- ...typeof statePartial == "function" ? statePartial(current) : statePartial
37
- };
38
- return shallowEqual(current, next) ? current : next;
39
- }),
40
- []
41
- );
42
- return [state, setState];
43
- }
24
+ import { IconZoomScan, IconLink, IconMenu, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled, IconFileSymlink, IconLayoutDashboard, IconArrowBigDownLines, IconFocusCentered, IconMenu2, IconChevronLeft, IconChevronRight, IconAlertTriangle } from "@tabler/icons-react";
25
+ var rootClassName = "likec4-diagram-root";
44
26
  const noop = () => {
45
27
  }, depsShallowEqual = (d1, d2) => {
46
28
  if (d1 === d2)
@@ -73,10 +55,16 @@ const useXYStoreApi = useStoreApi, ZIndexes = {
73
55
  Compound: 2,
74
56
  Edge: 4,
75
57
  Element: 6
76
- }, MinZoom = 0.1;
58
+ }, MinZoom = 0.1, MaxZoom = 2;
77
59
  function toDomPrecision(v) {
78
60
  return v === null ? 0.01 : Math.round(v * 100) / 100;
79
61
  }
62
+ const nodeToRect = (nd) => ({
63
+ x: nd.internals.positionAbsolute.x,
64
+ y: nd.internals.positionAbsolute.y,
65
+ width: nd.width ?? nd.data.element.width,
66
+ height: nd.height ?? nd.data.element.height
67
+ }), isInside = (test, target) => test.x >= target.x && test.y >= target.y && test.x + test.width <= target.x + target.width && test.y + test.height <= target.y + target.height;
80
68
  function bezierControlPoints(diagramEdge) {
81
69
  let [start, ...bezierPoints] = diagramEdge.points;
82
70
  invariant(start, "start should be defined");
@@ -104,7 +92,15 @@ function diagramViewToXYFlowData(view, opts) {
104
92
  const isDynamicView = view.__ === "dynamic", xynodes = [], xyedges = [], nodeLookup = /* @__PURE__ */ new Map(), traverse = view.nodes.reduce(
105
93
  (acc, node) => (nodeLookup.set(node.id, node), node.parent || acc.push({ node, parent: null }), acc),
106
94
  new Array()
107
- ), ns = "", nodeById = (id) => nonNullable(nodeLookup.get(id), `Node not found: ${id}`);
95
+ );
96
+ let visiblePredicate = (_nodeOrEdge) => !0;
97
+ if (opts.where)
98
+ try {
99
+ visiblePredicate = whereOperatorAsPredicate(opts.where);
100
+ } catch (e) {
101
+ console.error("Error in where filter:", e);
102
+ }
103
+ const ns = "", nodeById = (id) => nonNullable(nodeLookup.get(id), `Node not found: ${id}`);
108
104
  let next;
109
105
  for (; next = traverse.shift(); ) {
110
106
  const { node, parent } = next;
@@ -127,9 +123,9 @@ function diagramViewToXYFlowData(view, opts) {
127
123
  deletable: !1,
128
124
  position,
129
125
  zIndex: isCompound ? ZIndexes.Compound : ZIndexes.Element,
130
- hidden: !1,
131
126
  width: node.width,
132
127
  height: node.height,
128
+ hidden: !visiblePredicate(node),
133
129
  // parentId: parent ? ns + parent.id : null,
134
130
  ...parent && {
135
131
  parentId: ns + parent.id
@@ -148,6 +144,7 @@ function diagramViewToXYFlowData(view, opts) {
148
144
  target: ns + target,
149
145
  zIndex: ZIndexes.Edge,
150
146
  selectable: opts.selectable,
147
+ hidden: !visiblePredicate(edge),
151
148
  deletable: !1,
152
149
  data: {
153
150
  edge,
@@ -190,6 +187,7 @@ function createDiagramStore(props) {
190
187
  xynodes,
191
188
  xyedges
192
189
  } = diagramViewToXYFlowData(props.view, {
190
+ where: props.whereFilter,
193
191
  draggable: props.nodesDraggable,
194
192
  selectable: props.nodesSelectable
195
193
  });
@@ -224,6 +222,7 @@ function createDiagramStore(props) {
224
222
  xyflow,
225
223
  xystore,
226
224
  dimmed: dimmed2,
225
+ whereFilter,
227
226
  view: current,
228
227
  lastOnNavigate,
229
228
  navigationHistory,
@@ -239,10 +238,6 @@ function createDiagramStore(props) {
239
238
  xyedges: xyedges2,
240
239
  xynodes: xynodes2
241
240
  } = get();
242
- if (shallowEqual(current, nextView)) {
243
- DEV && console.debug("store: skip updateView");
244
- return;
245
- }
246
241
  viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), viewSyncDebounceTimeout = null);
247
242
  const isSameView = current.id === nextView.id;
248
243
  if (isSameView) {
@@ -289,24 +284,27 @@ function createDiagramStore(props) {
289
284
  lastClickedEdgeId = null, lastClickedNodeId = null, hoveredEdgeId = null, hoveredNodeId = null, focusedNodeId = null, activeDynamicViewStep = null, dimmed2 = EmptyStringSet;
290
285
  }
291
286
  const update = diagramViewToXYFlowData(nextView, {
287
+ where: whereFilter,
292
288
  draggable: nodesDraggable,
293
289
  selectable: nodesSelectable
294
290
  });
295
291
  update.xynodes = update.xynodes.map((update2) => {
296
292
  const existing = xynodes2.find((n) => n.id === update2.id);
297
- return existing && existing.type === update2.type && deepEqual(existing.parentId ?? null, update2.parentId ?? null) ? deepEqual(existing.data.element, update2.data.element) ? existing : {
293
+ return existing && existing.type === update2.type && deepEqual(existing.parentId ?? null, update2.parentId ?? null) ? existing.hidden === update2.hidden && existing.width === update2.width && existing.height === update2.height && deepEqual(existing.position, update2.position) && deepEqual(existing.data.element, update2.data.element) ? existing : {
298
294
  ...existing,
299
295
  ...update2
300
296
  } : update2;
301
297
  }), isSameView && !nextView.hasLayoutDrift && (update.xyedges = update.xyedges.map((update2) => {
302
298
  const existing = xyedges2.find((n) => n.id === update2.id);
303
- return existing ? deepEqual(existing.data, update2.data) ? existing : {
299
+ return existing ? existing.hidden === update2.hidden && deepEqual(existing.data.label, update2.data.label) && deepEqual(existing.data.controlPoints, update2.data.controlPoints) && deepEqual(existing.data.edge, update2.data.edge) ? existing : {
304
300
  ...existing,
305
- ...update2
301
+ ...update2,
302
+ data: {
303
+ ...existing.data,
304
+ ...update2.data
305
+ }
306
306
  } : update2;
307
- }));
308
- const hasChanges = !isSameView || !shallowEqual(update.xynodes, xynodes2) || !shallowEqual(update.xyedges, xyedges2);
309
- set(
307
+ })), set(
310
308
  {
311
309
  isDynamicView: nextView.__ === "dynamic",
312
310
  viewSyncDebounceTimeout,
@@ -321,8 +319,8 @@ function createDiagramStore(props) {
321
319
  navigationHistory,
322
320
  navigationHistoryIndex,
323
321
  dimmed: dimmed2,
324
- xynodes: hasChanges ? update.xynodes : xynodes2,
325
- xyedges: hasChanges ? update.xyedges : xyedges2
322
+ xynodes: !isSameView || !shallowEqual(update.xynodes, xynodes2) ? update.xynodes : xynodes2,
323
+ xyedges: !isSameView || !shallowEqual(update.xyedges, xyedges2) ? update.xyedges : xyedges2
326
324
  },
327
325
  noReplace,
328
326
  isSameView ? "update-view [same]" : "update-view [another]"
@@ -439,10 +437,7 @@ function createDiagramStore(props) {
439
437
  },
440
438
  triggerSaveManualLayout: () => {
441
439
  const { xyflow, view, onChange, xystore, viewSyncDebounceTimeout } = get();
442
- if (viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), set({ viewSyncDebounceTimeout: null })), !onChange) {
443
- DEV && console.debug("ignore triggerSaveManualLayout, as no onChange handler is set");
444
- return;
445
- }
440
+ viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), set({ viewSyncDebounceTimeout: null }));
446
441
  const { nodeLookup } = xystore.getState(), movedNodes = new StringSet();
447
442
  let bounds = {
448
443
  x: 0,
@@ -471,7 +466,15 @@ function createDiagramStore(props) {
471
466
  points: data.edge.points
472
467
  };
473
468
  (_a = data.label) != null && _a.bbox && (_updated.labelBBox = (_b = data.label) == null ? void 0 : _b.bbox), data.edge.labelBBox && (_updated.labelBBox ?? (_updated.labelBBox = data.edge.labelBBox)), controlPoints && hasAtLeast$1(controlPoints, 1) && (_updated.controlPoints = controlPoints), !sourceOrTargetMoved && data.edge.dotpos && (_updated.dotpos = data.edge.dotpos);
474
- const allX = [...data.edge.points.map((p) => p[0]), ...(controlPoints ?? []).map((p) => p.x)], allY = [...data.edge.points.map((p) => p[1]), ...(controlPoints ?? []).map((p) => p.y)], rect = boxToRect({
469
+ const allX = [
470
+ ...data.edge.points.map((p) => p[0]),
471
+ ...(controlPoints ?? []).map((p) => p.x),
472
+ ..._updated.labelBBox ? [_updated.labelBBox.x, _updated.labelBBox.x + _updated.labelBBox.width] : []
473
+ ], allY = [
474
+ ...data.edge.points.map((p) => p[1]),
475
+ ...(controlPoints ?? []).map((p) => p.y),
476
+ ..._updated.labelBBox ? [_updated.labelBBox.y, _updated.labelBBox.y + _updated.labelBBox.height] : []
477
+ ], rect = boxToRect({
475
478
  x: Math.floor(Math.min(...allX)),
476
479
  y: Math.floor(Math.min(...allY)),
477
480
  x2: Math.ceil(Math.max(...allX)),
@@ -488,14 +491,19 @@ function createDiagramStore(props) {
488
491
  ...bounds
489
492
  }
490
493
  };
491
- DEV && console.debug("triggerSaveManualLayout", change), onChange({ change });
494
+ DEV && console.debug("triggerSaveManualLayout", change), isInside(bounds, view.bounds) || set(
495
+ {
496
+ view: {
497
+ ...view,
498
+ bounds
499
+ }
500
+ },
501
+ noReplace,
502
+ "update view bounds"
503
+ ), onChange == null || onChange({ change });
492
504
  },
493
505
  scheduleSaveManualLayout: () => {
494
- let { viewSyncDebounceTimeout, onChange } = get();
495
- if (!onChange) {
496
- DEV && console.debug("ignore triggerSaveManualLayout, as no onChange handler is set");
497
- return;
498
- }
506
+ let { viewSyncDebounceTimeout } = get();
499
507
  viewSyncDebounceTimeout && clearTimeout(viewSyncDebounceTimeout), set(
500
508
  {
501
509
  viewSyncDebounceTimeout: setTimeout(() => {
@@ -508,13 +516,13 @@ function createDiagramStore(props) {
508
516
  );
509
517
  },
510
518
  triggerOnNavigateTo: (xynodeId, event) => {
511
- const { view, xynodes: xynodes2, onNavigateTo } = get();
519
+ const { view, xynodes: xynodes2, onNavigateTo, cancelSaveManualLayout } = get();
512
520
  if (!onNavigateTo)
513
521
  return;
514
522
  const xynode = xynodes2.find(({ id }) => id === xynodeId);
515
523
  invariant(xynode, `xynode not found: ${xynodeId}`);
516
524
  const element = view.nodes.find(({ id }) => id === xynodeId);
517
- invariant(element == null ? void 0 : element.navigateTo, `node is not navigable: ${xynodeId}`), set(
525
+ invariant(element == null ? void 0 : element.navigateTo, `node is not navigable: ${xynodeId}`), cancelSaveManualLayout(), set(
518
526
  {
519
527
  lastClickedNodeId: xynodeId,
520
528
  lastOnNavigate: {
@@ -659,6 +667,7 @@ function DiagramContextProvider({
659
667
  view,
660
668
  className,
661
669
  keepAspectRatio,
670
+ whereFilter,
662
671
  ...props
663
672
  }) {
664
673
  const containerRef = useRef(null), xystore = useXYStoreApi(), xyflow = useXYFlow(), store = useRef(), getContainer = useCallback(() => containerRef.current, [containerRef]);
@@ -667,6 +676,7 @@ function DiagramContextProvider({
667
676
  xyflow,
668
677
  view,
669
678
  getContainer,
679
+ whereFilter: structuredClone(whereFilter),
670
680
  ...props
671
681
  })), useUpdateEffect(
672
682
  () => {
@@ -682,10 +692,11 @@ function DiagramContextProvider({
682
692
  [props]
683
693
  ), useUpdateEffect(
684
694
  () => {
685
- var _a;
686
- (_a = store.current) == null || _a.getState().updateView(view);
695
+ const current = store.current;
696
+ invariant(current, "DiagramContext.store.current is not defined"), deepEqual(whereFilter, current.getState().whereFilter) || current.setState({ whereFilter: structuredClone(whereFilter) }, !1, "update where filter"), current.getState().updateView(view);
687
697
  },
688
- [view]
698
+ [view, whereFilter],
699
+ (a, b) => shallowEqual(a[0], b[0]) && deepEqual(a[1], b[1])
689
700
  ), /* @__PURE__ */ jsx(
690
701
  "div",
691
702
  {
@@ -713,6 +724,12 @@ function useDiagramStoreApi() {
713
724
  throw new Error("useDiagramStoreApi could be used only inside DiagramContext");
714
725
  return store;
715
726
  }
727
+ var cssReactFlow = "_2h8g8h0", cssDisablePan = "_2h8g8h1", cssTransparentBg = "_2h8g8h2", cssNoControls = "_2h8g8h3";
728
+ function EnsureMantine({ children }) {
729
+ if (!useContext(MantineContext))
730
+ throw new Error("LikeC4Diagram must be a child of MantineProvider");
731
+ return /* @__PURE__ */ jsx(Fragment, { children });
732
+ }
716
733
  function selectXYFlowSize(state) {
717
734
  return `${Math.round(state.width)}:${Math.round(state.height)}`;
718
735
  }
@@ -756,51 +773,84 @@ function FitViewOnDiagramChange() {
756
773
  50
757
774
  ), viewportNotMoved && !requiresFit ? /* @__PURE__ */ jsx(FitViewOnViewportResize, { diagramApi }) : null;
758
775
  }
776
+ function useSetState(initialState) {
777
+ const [state, _setState] = useState(initialState), setState = useCallback(
778
+ (statePartial) => _setState((current) => {
779
+ const next = {
780
+ ...current,
781
+ ...typeof statePartial == "function" ? statePartial(current) : statePartial
782
+ };
783
+ return shallowEqual(current, next) ? current : next;
784
+ }),
785
+ []
786
+ );
787
+ return [state, setState];
788
+ }
759
789
  function SelectEdgesOnNodeFocus() {
760
- const diagramStore = useDiagramStoreApi();
761
- return useEffect(
762
- () => diagramStore.subscribe((s) => s.focusedNodeId, (focusedNodeId) => {
763
- if (!focusedNodeId)
764
- return;
765
- const edgeChanges = [], nodeChanges = [], {
766
- edgeLookup,
767
- nodeLookup,
768
- width,
769
- height,
770
- panZoom,
771
- transform,
772
- triggerNodeChanges,
773
- triggerEdgeChanges
774
- } = diagramStore.getState().xystore.getState();
775
- let focusBounds = nodeToRect(nonNullable(nodeLookup.get(focusedNodeId)));
776
- for (const [, edge] of edgeLookup) {
777
- if (edge.source === focusedNodeId || edge.target === focusedNodeId) {
778
- const anotherNodeId = edge.source === focusedNodeId ? edge.target : edge.source, nd = nodeToRect(nonNullable(nodeLookup.get(anotherNodeId)));
779
- focusBounds = getBoundsOfRects(focusBounds, nd);
780
- }
781
- edge.selected && edgeChanges.push({
782
- id: edge.id,
783
- type: "select",
784
- selected: !1
785
- });
790
+ const diagramStore = useDiagramStoreApi(), focusedNodeId = useDiagramState((s) => s.focusedNodeId);
791
+ return useUpdateEffect(() => {
792
+ if (!focusedNodeId) {
793
+ diagramStore.getState().xystore.getState().resetSelectedElements();
794
+ return;
795
+ }
796
+ const container2 = diagramStore.getState().getContainer();
797
+ if (!container2)
798
+ return;
799
+ const { width, height } = container2.getBoundingClientRect(), edgeChanges = [], nodeChanges = [], {
800
+ edgeLookup,
801
+ nodeLookup,
802
+ panZoom,
803
+ transform,
804
+ triggerNodeChanges,
805
+ triggerEdgeChanges
806
+ } = diagramStore.getState().xystore.getState();
807
+ let focusBounds = nodeToRect(nonNullable(nodeLookup.get(focusedNodeId)));
808
+ for (const [, edge] of edgeLookup) {
809
+ if (edge.source === focusedNodeId || edge.target === focusedNodeId) {
810
+ const anotherNodeId = edge.source === focusedNodeId ? edge.target : edge.source, nd = nonNullable(nodeLookup.get(anotherNodeId));
811
+ focusBounds = getBoundsOfRects(focusBounds, nodeToRect(nd));
786
812
  }
787
- for (const [, node] of nodeLookup)
788
- node.selected && node.id !== focusedNodeId && nodeChanges.push({
789
- id: node.id,
790
- type: "select",
791
- selected: !1
792
- });
793
- nodeChanges.push({
794
- id: focusedNodeId,
813
+ edge.selected && edgeChanges.push({
814
+ id: edge.id,
795
815
  type: "select",
796
- selected: !0
797
- }), edgeChanges.length > 0 && triggerEdgeChanges(edgeChanges), triggerNodeChanges(nodeChanges);
798
- const maxZoom = Math.max(1, transform[2]), viewport = getViewportForBounds$1(focusBounds, width, height, MinZoom, maxZoom, 0.2);
799
- panZoom == null || panZoom.setViewport(viewport, {
800
- duration: 350
816
+ selected: !1
801
817
  });
802
- }),
803
- [diagramStore]
818
+ }
819
+ for (const [, node] of nodeLookup)
820
+ node.selected && node.id !== focusedNodeId && nodeChanges.push({
821
+ id: node.id,
822
+ type: "select",
823
+ selected: !1
824
+ });
825
+ nodeChanges.push({
826
+ id: focusedNodeId,
827
+ type: "select",
828
+ selected: !0
829
+ }), edgeChanges.length > 0 && triggerEdgeChanges(edgeChanges), triggerNodeChanges(nodeChanges);
830
+ const maxZoom = Math.max(1, transform[2]), viewport = getViewportForBounds$1(
831
+ {
832
+ x: focusBounds.x - 16,
833
+ y: focusBounds.y - 16,
834
+ width: focusBounds.width + 32,
835
+ height: focusBounds.height + 32
836
+ },
837
+ width,
838
+ height,
839
+ 0.1,
840
+ maxZoom,
841
+ 0
842
+ );
843
+ panZoom == null || panZoom.setViewport(viewport, {
844
+ duration: 350
845
+ });
846
+ }, [focusedNodeId]), useHotkeys(
847
+ focusedNodeId !== null ? [
848
+ ["Escape", (e) => {
849
+ e.stopImmediatePropagation();
850
+ const { xystore, fitDiagram } = diagramStore.getState();
851
+ fitDiagram(), xystore.getState().resetSelectedElements();
852
+ }, { preventDefault: !0 }]
853
+ ] : []
804
854
  ), null;
805
855
  }
806
856
  const Open = (props) => /* @__PURE__ */ jsx(
@@ -962,7 +1012,7 @@ const Open = (props) => /* @__PURE__ */ jsx(
962
1012
  Dot,
963
1013
  ODot
964
1014
  };
965
- var container$4 = "bexn7q1", dimmed$2 = "bexn7q2", edgePathBg = "bexn7q3", markerContext = "bexn7q4", controlPoint = "bexn7q5", controlDragging = "bexn7q6", cssEdgePath = "bexn7q8", varLabelX = "var(--bexn7q9)", varLabelY = "var(--bexn7qa)", edgeLabel = "bexn7qc", stepEdgeNumber = "bexn7qd", edgeLabelText = "bexn7qe";
1015
+ var container$4 = "bexn7q1", dimmed$2 = "bexn7q2", edgePathBg = "bexn7q3", markerContext = "bexn7q4", controlPoint = "bexn7q5", controlDragging = "bexn7q6", cssEdgePath = "bexn7q8", stepEdgeNumber = "bexn7q9", varLabelX = "var(--bexn7qa)", varLabelY = "var(--bexn7qb)", edgeLabel = "bexn7qd", edgeLabelText = "bexn7qe";
966
1016
  function getNodeIntersectionFromCenterToPoint(intersectionNode, { x: x1, y: y1 }) {
967
1017
  const {
968
1018
  width: intersectionNodeWidth,
@@ -1003,7 +1053,7 @@ function bezierPath(bezierSpline) {
1003
1053
  }
1004
1054
  return invariant(points.length === 0, "all points should be consumed"), path;
1005
1055
  }
1006
- const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1056
+ const isSame = (a, b) => Math.abs(a - b) < 2.5, isSamePoint = (a, b) => {
1007
1057
  const [ax, ay] = isArray(a) ? a : [a.x, a.y], [bx, by] = isArray(b) ? b : [b.x, b.y];
1008
1058
  return isSame(ax, bx) && isSame(ay, by);
1009
1059
  }, sameControlPoints = (a, b) => a === b ? !0 : !a || !b || a.length !== b.length ? !1 : a.every((ap, i) => isSamePoint(ap, b[i])), isEqualProps$2 = (prev, next) => prev.id === next.id && deepEqual(prev.source, next.source) && deepEqual(prev.target, next.target) && deepEqual(prev.selected ?? !1, next.selected ?? !1) && isSame(prev.sourceX, next.sourceX) && isSame(prev.sourceY, next.sourceY) && isSame(prev.targetX, next.targetX) && isSame(prev.targetY, next.targetY) && deepEqual(prev.data.stepNum, next.data.stepNum) && deepEqual(prev.data.label, next.data.label) && sameControlPoints(prev.data.controlPoints, next.data.controlPoints) && deepEqual(prev.data.edge, next.data.edge), curve = line().curve(curveCatmullRomOpen).x((d) => d.x).y((d) => d.y), RelationshipEdge = /* @__PURE__ */ memo(function({
@@ -1019,11 +1069,12 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1019
1069
  target,
1020
1070
  interactionWidth
1021
1071
  }) {
1022
- const [isControlPointDragging, setIsControlPointDragging] = useState(!1), diagramStore = useDiagramStoreApi(), xyflowStore = useXYStoreApi(), { isActive, isEdgePathEditable, isHovered, isDimmed } = useDiagramState((s) => ({
1023
- isEdgePathEditable: s.readonly !== !0 && s.experimentalEdgeEditing === !0,
1072
+ const [isControlPointDragging, setIsControlPointDragging] = useState(!1), diagramStore = useDiagramStoreApi(), xyflowStore = useXYStoreApi(), { isActive, isEdgePathEditable, isHovered, isDimmed, hasOpenSourceRelation } = useDiagramState((s) => ({
1073
+ isEdgePathEditable: s.readonly !== !0 && s.experimentalEdgeEditing === !0 && s.focusedNodeId === null && s.activeDynamicViewStep === null,
1024
1074
  isActive: s.focusedNodeId === source || s.focusedNodeId === target || s.activeDynamicViewStep !== null && s.activeDynamicViewStep === data.stepNum,
1025
1075
  isHovered: s.hoveredEdgeId === id,
1026
- isDimmed: s.dimmed.has(id)
1076
+ isDimmed: s.dimmed.has(id),
1077
+ hasOpenSourceRelation: !!s.onOpenSourceRelation
1027
1078
  })), { nodeLookup, edgeLookup } = xyflowStore.getState(), sourceNode = nonNullable(nodeLookup.get(source), `source node ${source} not found`), targetNode = nonNullable(nodeLookup.get(target), `target node ${target} not found`), isModified = isTruthy(data.controlPoints) || !isSamePoint(sourceNode.internals.positionAbsolute, sourceNode.data.element.position) || !isSamePoint(targetNode.internals.positionAbsolute, targetNode.data.element.position), {
1028
1079
  label,
1029
1080
  edge: {
@@ -1045,7 +1096,6 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1045
1096
  });
1046
1097
  let edgePath;
1047
1098
  if (isModified) {
1048
- labelX = labelPos.x, labelY = labelPos.y;
1049
1099
  const sourceCenterPos = { x: sourceX, y: sourceY }, targetCenterPos = { x: targetX, y: targetY }, points = diagramEdge.dir === "back" ? [
1050
1100
  targetCenterPos,
1051
1101
  getNodeIntersectionFromCenterToPoint(targetNode, first(controlPoints) ?? sourceCenterPos),
@@ -1084,9 +1134,9 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1084
1134
  });
1085
1135
  },
1086
1136
  [labelPos],
1087
- 100,
1137
+ 50,
1088
1138
  300
1089
- );
1139
+ ), (isModified || isControlPointDragging) && (labelX = labelPos.x, labelY = labelPos.y);
1090
1140
  const onControlPointerDown = (index, e) => {
1091
1141
  const { domNode } = xyflowStore.getState();
1092
1142
  if (!domNode || e.pointerType !== "mouse")
@@ -1105,22 +1155,35 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1105
1155
  e.stopPropagation();
1106
1156
  let hasMoved = !1, pointer = { x: e.clientX, y: e.clientY };
1107
1157
  const onPointerMove = (e2) => {
1108
- if (!isSamePoint(pointer, [e2.clientX, e2.clientY])) {
1158
+ if (hasMoved || !isSamePoint(pointer, [e2.clientX, e2.clientY])) {
1109
1159
  setIsControlPointDragging(!0), hasMoved = !0, pointer = { x: e2.clientX, y: e2.clientY };
1110
- const { x, y } = xyflow.screenToFlowPosition(pointer, { snapToGrid: !1 }), newControlPoints = controlPoints.slice();
1111
- newControlPoints[index] = {
1112
- x: Math.round(x),
1113
- y: Math.round(y)
1114
- }, xyflow.updateEdgeData(id, { controlPoints: newControlPoints });
1160
+ const { x, y } = xyflow.screenToFlowPosition(pointer, { snapToGrid: !1 });
1161
+ xyflow.updateEdgeData(id, (xyedge) => {
1162
+ const cp = (xyedge.data.controlPoints ?? controlPoints).slice();
1163
+ return cp[index] = {
1164
+ x: Math.round(x),
1165
+ y: Math.round(y)
1166
+ }, {
1167
+ controlPoints: cp
1168
+ };
1169
+ });
1115
1170
  }
1116
- }, onPointerUp = () => {
1117
- domNode.removeEventListener("pointermove", onPointerMove), domNode.removeEventListener("pointerup", onPointerUp), (hasMoved || wasCanceled) && diagramStore.getState().scheduleSaveManualLayout(), setIsControlPointDragging(!1);
1171
+ e2.stopPropagation();
1172
+ }, onPointerUp = (e2) => {
1173
+ domNode.removeEventListener("pointermove", onPointerMove, {
1174
+ capture: !0
1175
+ }), hasMoved && e2.stopPropagation(), (hasMoved || wasCanceled) && diagramStore.getState().scheduleSaveManualLayout(), setIsControlPointDragging(!1);
1118
1176
  };
1119
- domNode.addEventListener("pointermove", onPointerMove), domNode.addEventListener("pointerup", onPointerUp, { once: !0 });
1177
+ domNode.addEventListener("pointermove", onPointerMove, {
1178
+ capture: !0
1179
+ }), domNode.addEventListener("pointerup", onPointerUp, {
1180
+ once: !0,
1181
+ capture: !0
1182
+ });
1120
1183
  };
1121
1184
  let markerStartName = toMarker(diagramEdge.tail), markerEndName = toMarker(diagramEdge.head ?? "normal");
1122
1185
  diagramEdge.dir === "back" && ([markerStartName, markerEndName] = [markerEndName, markerStartName]);
1123
- const MarkerStart = markerStartName ? EdgeMarkers[markerStartName] : null, MarkerEnd = markerEndName ? EdgeMarkers[markerEndName] : null, labelZIndex = 1 + (isHovered ? ZIndexes.Element : edgeLookup.get(id).zIndex ?? ZIndexes.Edge);
1186
+ const MarkerStart = markerStartName ? EdgeMarkers[markerStartName] : null, MarkerEnd = markerEndName ? EdgeMarkers[markerEndName] : null, labelZIndex = 1 + (isHovered ? ZIndexes.Element : edgeLookup.get(id).zIndex ?? ZIndexes.Edge), relationId = first(data.edge.relations), showOpenSourceRelation = hasOpenSourceRelation && relationId !== void 0;
1124
1187
  return /* @__PURE__ */ jsxs(
1125
1188
  "g",
1126
1189
  {
@@ -1206,13 +1269,17 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1206
1269
  zIndex: labelZIndex,
1207
1270
  isHovered,
1208
1271
  isActive,
1209
- isStepEdge
1272
+ isStepEdge,
1273
+ onClick: showOpenSourceRelation && ((e) => {
1274
+ var _a, _b;
1275
+ e.stopPropagation(), (_b = (_a = diagramStore.getState()).onOpenSourceRelation) == null || _b.call(_a, relationId);
1276
+ })
1210
1277
  }
1211
1278
  )
1212
1279
  ]
1213
1280
  }
1214
1281
  );
1215
- }, isEqualProps$2), EdgeLabel = memo(({
1282
+ }, isEqualProps$2), EdgeLabel = ({
1216
1283
  isDimmed,
1217
1284
  color,
1218
1285
  isModified,
@@ -1224,7 +1291,8 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1224
1291
  stepNum,
1225
1292
  isHovered,
1226
1293
  isActive,
1227
- zIndex
1294
+ zIndex,
1295
+ onClick
1228
1296
  }) => /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsxs(
1229
1297
  Box,
1230
1298
  {
@@ -1252,162 +1320,17 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
1252
1320
  "data-edge-hovered": isHovered,
1253
1321
  "data-edge-active": isActive
1254
1322
  },
1323
+ onClick: onClick || void 0,
1255
1324
  children: [
1256
1325
  stepNum !== null && /* @__PURE__ */ jsx(Box, { className: stepEdgeNumber, children: stepNum }),
1257
1326
  isTruthy(label == null ? void 0 : label.text) && /* @__PURE__ */ jsx(Box, { className: edgeLabelText, children: label.text })
1258
1327
  ]
1259
1328
  }
1260
- ) }), deepEqual);
1261
- class Rect {
1262
- constructor() {
1263
- __publicField(this, "id");
1264
- __publicField(this, "minX", new Variable());
1265
- __publicField(this, "minY", new Variable());
1266
- __publicField(this, "maxX", new Variable());
1267
- __publicField(this, "maxY", new Variable());
1268
- }
1269
- get x() {
1270
- return this.minX;
1271
- }
1272
- get y() {
1273
- return this.minY;
1274
- }
1275
- get positionAbsolute() {
1276
- return {
1277
- x: this.x.value(),
1278
- y: this.y.value()
1279
- };
1280
- }
1281
- get dimensions() {
1282
- return {
1283
- width: this.maxX.value() - this.minX.value(),
1284
- height: this.maxY.value() - this.minY.value()
1285
- };
1286
- }
1287
- // Position relative to parent
1288
- get position() {
1289
- const positionAbsolute = this.positionAbsolute;
1290
- if (!this.parent)
1291
- return positionAbsolute;
1292
- const parentPosition = this.parent.positionAbsolute;
1293
- return {
1294
- x: positionAbsolute.x - parentPosition.x,
1295
- y: positionAbsolute.y - parentPosition.y
1296
- };
1297
- }
1298
- }
1299
- class Compound extends Rect {
1300
- constructor(solver, xynode, parent = null) {
1301
- super();
1302
- __publicField(this, "children", []);
1303
- this.solver = solver, this.parent = parent, this.id = xynode.id, solver.createConstraint(this.maxX, Operator.Ge, this.minX), solver.createConstraint(this.maxY, Operator.Ge, this.minY), parent && parent.addChild(this);
1304
- }
1305
- addChild(rect) {
1306
- this.children.push(rect);
1307
- const leftPadding = new Expression(
1308
- rect.minX,
1309
- [-1, this.minX]
1310
- ), { weak } = Strength;
1311
- this.solver.createConstraint(leftPadding, Operator.Ge, 40), this.solver.createConstraint(leftPadding, Operator.Eq, 41, weak);
1312
- const topPadding = new Expression(
1313
- rect.minY,
1314
- [-1, this.minY]
1315
- );
1316
- this.solver.createConstraint(topPadding, Operator.Ge, 54), this.solver.createConstraint(topPadding, Operator.Eq, 55, weak);
1317
- const rightPadding = new Expression(
1318
- this.maxX,
1319
- [-1, rect.maxX]
1320
- );
1321
- this.solver.createConstraint(rightPadding, Operator.Ge, 40), this.solver.createConstraint(rightPadding, Operator.Eq, 41, weak);
1322
- const bottomPadding = new Expression(
1323
- this.maxY,
1324
- [-1, rect.maxY]
1325
- );
1326
- this.solver.createConstraint(bottomPadding, Operator.Ge, 40), this.solver.createConstraint(bottomPadding, Operator.Eq, 41, weak);
1327
- }
1328
- }
1329
- class Leaf extends Rect {
1330
- constructor(solver, xynode, parent = null, isEditing = !1) {
1331
- super(), this.parent = parent, this.isEditing = isEditing, this.id = xynode.id;
1332
- const x = Math.ceil(xynode.internals.positionAbsolute.x), y = Math.ceil(xynode.internals.positionAbsolute.y), { width, height } = getNodeDimensions(xynode);
1333
- if (this.maxX = new Expression(this.minX, Math.ceil(width)), this.maxY = new Expression(this.minY, Math.ceil(height)), isEditing) {
1334
- const superStrong = Strength.create(100, 0, 0);
1335
- solver.addEditVariable(this.minX, superStrong), solver.addEditVariable(this.minY, superStrong), solver.suggestValue(this.minX, x), solver.suggestValue(this.minY, y);
1336
- } else {
1337
- const halfMedium = Strength.create(0, 1, 0, 0.5);
1338
- solver.createConstraint(this.minX, Operator.Eq, x, halfMedium), solver.createConstraint(this.minY, Operator.Eq, y, halfMedium);
1339
- }
1340
- parent && parent.addChild(this);
1341
- }
1342
- }
1343
- function createLayoutConstraints(xyflowApi, draggingNodeId) {
1344
- var _a;
1345
- const { parentLookup, nodeLookup } = xyflowApi.getState(), solver = new Solver(), rects = /* @__PURE__ */ new Map(), traverse = new Array();
1346
- for (const [, xynode] of nodeLookup)
1347
- isNullish(xynode.parentId) && traverse.push({
1348
- xynode,
1349
- parent: null
1350
- });
1351
- for (; traverse.length > 0; ) {
1352
- const { xynode, parent } = traverse.shift(), isDragging = xynode.dragging === !0 || xynode.id === draggingNodeId, shouldTraverse = !isDragging && xynode.type === "compound" && isAncestor(xynode.id, draggingNodeId), rect = shouldTraverse ? new Compound(solver, xynode, parent) : new Leaf(solver, xynode, parent, isDragging);
1353
- rects.set(xynode.id, rect), shouldTraverse && ((_a = parentLookup.get(xynode.id)) == null || _a.forEach((child) => {
1354
- traverse.push({
1355
- xynode: child,
1356
- parent: rect
1357
- });
1358
- }));
1359
- }
1360
- solver.updateVariables(), solver.maxIterations = 1e3;
1361
- const rectsToUpdate = [...rects.values()].filter((r) => r.id !== draggingNodeId);
1362
- function updateXYFlowNodes() {
1363
- solver.updateVariables(), xyflowApi.getState().triggerNodeChanges(
1364
- rectsToUpdate.reduce((acc, r) => (acc.push({
1365
- id: r.id,
1366
- type: "position",
1367
- dragging: !1,
1368
- position: r.position,
1369
- positionAbsolute: r.positionAbsolute
1370
- }), r instanceof Compound && acc.push({
1371
- id: r.id,
1372
- type: "dimensions",
1373
- setAttributes: !0,
1374
- dimensions: r.dimensions
1375
- }), acc), [])
1376
- );
1377
- }
1378
- let animationFrameId = null;
1379
- function onNodeDrag(xynode) {
1380
- rectsToUpdate.length !== 0 && (animationFrameId ?? (animationFrameId = requestAnimationFrame(() => {
1381
- animationFrameId = null;
1382
- const pos = nodeLookup.get(xynode.id).internals.positionAbsolute, rect = nonNullable(rects.get(xynode.id));
1383
- solver.suggestValue(rect.minX, Math.ceil(pos.x)), solver.suggestValue(rect.minY, Math.ceil(pos.y)), updateXYFlowNodes();
1384
- })));
1385
- }
1386
- return {
1387
- onNodeDrag,
1388
- updateXYFlowNodes
1389
- };
1390
- }
1391
- function useLayoutConstraints() {
1392
- const diagramApi = useDiagramStoreApi(), solverRef = useRef();
1393
- return useMemo(() => ({
1394
- onNodeDragStart: (_event, xynode) => {
1395
- const { cancelSaveManualLayout, xystore } = diagramApi.getState();
1396
- cancelSaveManualLayout(), solverRef.current = createLayoutConstraints(xystore, xynode.id);
1397
- },
1398
- onNodeDrag: (_event, xynode) => {
1399
- var _a;
1400
- invariant(solverRef.current, "solverRef.current should be defined"), (_a = solverRef.current) == null || _a.onNodeDrag(xynode);
1401
- },
1402
- onNodeDragStop: (_event, _xynode) => {
1403
- diagramApi.getState().scheduleSaveManualLayout(), solverRef.current = void 0;
1404
- }
1405
- }), [diagramApi]);
1406
- }
1329
+ ) });
1407
1330
  function NavigateToBtn({ xynodeId, className }) {
1408
1331
  const diagramApi = useDiagramStoreApi();
1409
1332
  return /* @__PURE__ */ jsx(
1410
- ActionIcon,
1333
+ ActionIcon$2,
1411
1334
  {
1412
1335
  className: clsx("nodrag nopan", className),
1413
1336
  radius: "md",
@@ -1797,12 +1720,13 @@ const Text = Text$1.withProps({
1797
1720
  width,
1798
1721
  height
1799
1722
  }) {
1800
- const store = useDiagramStoreApi(), { isHovered, isDimmed, hasOnNavigateTo, isHovercards, isInteractive } = useDiagramState((s) => ({
1723
+ const store = useDiagramStoreApi(), { isHovered, isDimmed, hasOnNavigateTo, isHovercards, isInteractive, hasGoToSource } = useDiagramState((s) => ({
1801
1724
  isHovered: s.hoveredNodeId === id,
1802
1725
  isDimmed: s.dimmed.has(id),
1803
1726
  isInteractive: s.nodesDraggable || s.nodesSelectable || !!s.onNavigateTo,
1804
1727
  isHovercards: s.showElementLinks,
1805
- hasOnNavigateTo: !!s.onNavigateTo
1728
+ hasOnNavigateTo: !!s.onNavigateTo,
1729
+ hasGoToSource: !!s.onOpenSourceElement
1806
1730
  })), isNavigable = hasOnNavigateTo && !!element.navigateTo, w = toDomPrecision(width ?? element.width), h = toDomPrecision(height ?? element.height);
1807
1731
  let animate = "idle";
1808
1732
  switch (!0) {
@@ -1936,33 +1860,182 @@ const Text = Text$1.withProps({
1936
1860
  const RenderIcon = store.getState().renderIcon, icon = RenderIcon ? /* @__PURE__ */ jsx(RenderIcon, { node }) : null;
1937
1861
  return icon ? /* @__PURE__ */ jsx("div", { className: clsx(elementIcon, "likec4-element-icon"), children: icon }) : null;
1938
1862
  };
1939
- function useXYFlowEvents() {
1940
- const diagramApi = useDiagramStoreApi(), lastClickTimestamp = useRef(), dblclickTimeout = useRef(), hoveredNodeFromOnEdgeEnterRef = useRef("");
1941
- return useMemo(() => {
1942
- const dbclickLock = () => dblclickTimeout.current !== void 0 ? !0 : (dblclickTimeout.current = window.setTimeout(() => {
1943
- dblclickTimeout.current = void 0;
1944
- }, 250), !1), lastClickWasRecent = (ms = 1500) => lastClickTimestamp.current && Date.now() - lastClickTimestamp.current < ms;
1863
+ class Rect {
1864
+ constructor() {
1865
+ __publicField(this, "id");
1866
+ __publicField(this, "minX", new Variable());
1867
+ __publicField(this, "minY", new Variable());
1868
+ __publicField(this, "maxX", new Variable());
1869
+ __publicField(this, "maxY", new Variable());
1870
+ }
1871
+ get x() {
1872
+ return this.minX;
1873
+ }
1874
+ get y() {
1875
+ return this.minY;
1876
+ }
1877
+ get positionAbsolute() {
1945
1878
  return {
1946
- onDoubleClick: (event) => {
1947
- const {
1948
- fitViewEnabled,
1949
- onCanvasDblClick,
1950
- resetLastClicked,
1951
- fitDiagram
1952
- } = diagramApi.getState();
1953
- fitViewEnabled && (fitDiagram(), onCanvasDblClick || event.stopPropagation()), resetLastClicked(), onCanvasDblClick == null || onCanvasDblClick(event);
1954
- },
1955
- onPaneClick: (event) => {
1956
- if (dbclickLock())
1957
- return;
1958
- const {
1959
- focusedNodeId,
1879
+ x: this.x.value(),
1880
+ y: this.y.value()
1881
+ };
1882
+ }
1883
+ get dimensions() {
1884
+ return {
1885
+ width: this.maxX.value() - this.minX.value(),
1886
+ height: this.maxY.value() - this.minY.value()
1887
+ };
1888
+ }
1889
+ // Position relative to parent
1890
+ get position() {
1891
+ const positionAbsolute = this.positionAbsolute;
1892
+ if (!this.parent)
1893
+ return positionAbsolute;
1894
+ const parentPosition = this.parent.positionAbsolute;
1895
+ return {
1896
+ x: positionAbsolute.x - parentPosition.x,
1897
+ y: positionAbsolute.y - parentPosition.y
1898
+ };
1899
+ }
1900
+ }
1901
+ class Compound extends Rect {
1902
+ constructor(solver, xynode, parent = null) {
1903
+ super();
1904
+ __publicField(this, "children", []);
1905
+ this.solver = solver, this.parent = parent, this.id = xynode.id, solver.createConstraint(this.maxX, Operator.Ge, this.minX), solver.createConstraint(this.maxY, Operator.Ge, this.minY), parent && parent.addChild(this);
1906
+ }
1907
+ addChild(rect) {
1908
+ this.children.push(rect);
1909
+ const leftPadding = new Expression(
1910
+ rect.minX,
1911
+ [-1, this.minX]
1912
+ ), { weak } = Strength;
1913
+ this.solver.createConstraint(leftPadding, Operator.Ge, 40), this.solver.createConstraint(leftPadding, Operator.Eq, 41, weak);
1914
+ const topPadding = new Expression(
1915
+ rect.minY,
1916
+ [-1, this.minY]
1917
+ );
1918
+ this.solver.createConstraint(topPadding, Operator.Ge, 54), this.solver.createConstraint(topPadding, Operator.Eq, 55, weak);
1919
+ const rightPadding = new Expression(
1920
+ this.maxX,
1921
+ [-1, rect.maxX]
1922
+ );
1923
+ this.solver.createConstraint(rightPadding, Operator.Ge, 40), this.solver.createConstraint(rightPadding, Operator.Eq, 41, weak);
1924
+ const bottomPadding = new Expression(
1925
+ this.maxY,
1926
+ [-1, rect.maxY]
1927
+ );
1928
+ this.solver.createConstraint(bottomPadding, Operator.Ge, 40), this.solver.createConstraint(bottomPadding, Operator.Eq, 41, weak);
1929
+ }
1930
+ }
1931
+ class Leaf extends Rect {
1932
+ constructor(solver, xynode, parent = null, isEditing = !1) {
1933
+ super(), this.parent = parent, this.isEditing = isEditing, this.id = xynode.id;
1934
+ const x = Math.ceil(xynode.internals.positionAbsolute.x), y = Math.ceil(xynode.internals.positionAbsolute.y), { width, height } = getNodeDimensions(xynode);
1935
+ if (this.maxX = new Expression(this.minX, Math.ceil(width)), this.maxY = new Expression(this.minY, Math.ceil(height)), isEditing) {
1936
+ const superStrong = Strength.create(100, 0, 0);
1937
+ solver.addEditVariable(this.minX, superStrong), solver.addEditVariable(this.minY, superStrong), solver.suggestValue(this.minX, x), solver.suggestValue(this.minY, y);
1938
+ } else {
1939
+ const halfMedium = Strength.create(0, 1, 0, 0.5);
1940
+ solver.createConstraint(this.minX, Operator.Eq, x, halfMedium), solver.createConstraint(this.minY, Operator.Eq, y, halfMedium);
1941
+ }
1942
+ parent && parent.addChild(this);
1943
+ }
1944
+ }
1945
+ function createLayoutConstraints(xyflowApi, draggingNodeId) {
1946
+ var _a;
1947
+ const { parentLookup, nodeLookup } = xyflowApi.getState(), solver = new Solver(), rects = /* @__PURE__ */ new Map(), traverse = new Array();
1948
+ for (const [, xynode] of nodeLookup)
1949
+ isNullish(xynode.parentId) && traverse.push({
1950
+ xynode,
1951
+ parent: null
1952
+ });
1953
+ for (; traverse.length > 0; ) {
1954
+ const { xynode, parent } = traverse.shift(), isDragging = xynode.dragging === !0 || xynode.id === draggingNodeId, shouldTraverse = !isDragging && xynode.type === "compound" && isAncestor(xynode.id, draggingNodeId), rect = shouldTraverse ? new Compound(solver, xynode, parent) : new Leaf(solver, xynode, parent, isDragging);
1955
+ rects.set(xynode.id, rect), shouldTraverse && ((_a = parentLookup.get(xynode.id)) == null || _a.forEach((child) => {
1956
+ traverse.push({
1957
+ xynode: child,
1958
+ parent: rect
1959
+ });
1960
+ }));
1961
+ }
1962
+ solver.updateVariables(), solver.maxIterations = 1e3;
1963
+ const rectsToUpdate = [...rects.values()].filter((r) => r.id !== draggingNodeId);
1964
+ function updateXYFlowNodes() {
1965
+ solver.updateVariables(), xyflowApi.getState().triggerNodeChanges(
1966
+ rectsToUpdate.reduce((acc, r) => (acc.push({
1967
+ id: r.id,
1968
+ type: "position",
1969
+ dragging: !1,
1970
+ position: r.position,
1971
+ positionAbsolute: r.positionAbsolute
1972
+ }), r instanceof Compound && acc.push({
1973
+ id: r.id,
1974
+ type: "dimensions",
1975
+ setAttributes: !0,
1976
+ dimensions: r.dimensions
1977
+ }), acc), [])
1978
+ );
1979
+ }
1980
+ let animationFrameId = null;
1981
+ function onNodeDrag(xynode) {
1982
+ rectsToUpdate.length !== 0 && (animationFrameId ?? (animationFrameId = requestAnimationFrame(() => {
1983
+ animationFrameId = null;
1984
+ const pos = nodeLookup.get(xynode.id).internals.positionAbsolute, rect = nonNullable(rects.get(xynode.id));
1985
+ solver.suggestValue(rect.minX, Math.ceil(pos.x)), solver.suggestValue(rect.minY, Math.ceil(pos.y)), updateXYFlowNodes();
1986
+ })));
1987
+ }
1988
+ return {
1989
+ onNodeDrag,
1990
+ updateXYFlowNodes
1991
+ };
1992
+ }
1993
+ function useLayoutConstraints() {
1994
+ const diagramApi = useDiagramStoreApi(), solverRef = useRef();
1995
+ return useMemo(() => ({
1996
+ onNodeDragStart: (_event, xynode) => {
1997
+ const { cancelSaveManualLayout, xystore } = diagramApi.getState();
1998
+ cancelSaveManualLayout(), solverRef.current = createLayoutConstraints(xystore, xynode.id);
1999
+ },
2000
+ onNodeDrag: (_event, xynode) => {
2001
+ var _a;
2002
+ invariant(solverRef.current, "solverRef.current should be defined"), (_a = solverRef.current) == null || _a.onNodeDrag(xynode);
2003
+ },
2004
+ onNodeDragStop: (_event, _xynode) => {
2005
+ diagramApi.getState().scheduleSaveManualLayout(), solverRef.current = void 0;
2006
+ }
2007
+ }), [diagramApi]);
2008
+ }
2009
+ function useXYFlowEvents() {
2010
+ const diagramApi = useDiagramStoreApi(), lastClickTimestamp = useRef(), dblclickTimeout = useRef(), hoveredNodeFromOnEdgeEnterRef = useRef("");
2011
+ return useMemo(() => {
2012
+ const dbclickLock = () => dblclickTimeout.current !== void 0 ? !0 : (dblclickTimeout.current = window.setTimeout(() => {
2013
+ dblclickTimeout.current = void 0;
2014
+ }, 250), !1), lastClickWasRecent = (ms = 1500) => lastClickTimestamp.current && Date.now() - lastClickTimestamp.current < ms;
2015
+ return {
2016
+ onDoubleClick: (event) => {
2017
+ const {
2018
+ onCanvasDblClick,
2019
+ zoomable,
2020
+ xystore,
2021
+ viewportChanged,
2022
+ fitDiagram,
2023
+ resetLastClicked
2024
+ } = diagramApi.getState();
2025
+ resetLastClicked(), xystore.getState().resetSelectedElements(), onCanvasDblClick || event.stopPropagation(), zoomable && viewportChanged && fitDiagram(), onCanvasDblClick == null || onCanvasDblClick(event);
2026
+ },
2027
+ onPaneClick: (event) => {
2028
+ if (dbclickLock())
2029
+ return;
2030
+ const {
2031
+ focusedNodeId,
1960
2032
  activeDynamicViewStep,
1961
2033
  fitDiagram,
1962
2034
  onCanvasClick,
2035
+ xystore,
1963
2036
  resetLastClicked
1964
2037
  } = diagramApi.getState();
1965
- (focusedNodeId ?? activeDynamicViewStep) !== null && (fitDiagram(), onCanvasClick || event.stopPropagation()), resetLastClicked(), onCanvasClick == null || onCanvasClick(event);
2038
+ (focusedNodeId ?? activeDynamicViewStep) !== null && (fitDiagram(), onCanvasClick || event.stopPropagation()), resetLastClicked(), xystore.getState().resetSelectedElements(), onCanvasClick == null || onCanvasClick(event);
1966
2039
  },
1967
2040
  onNodeContextMenu: (event, xynode) => {
1968
2041
  var _a, _b;
@@ -1990,22 +2063,33 @@ function useXYFlowEvents() {
1990
2063
  fitDiagram,
1991
2064
  focusOnNode,
1992
2065
  onNodeClick,
2066
+ xystore,
1993
2067
  enableFocusMode,
1994
2068
  lastClickedNodeId,
1995
- setLastClickedNode
2069
+ nodesSelectable,
2070
+ setLastClickedNode,
2071
+ onOpenSourceElement
1996
2072
  } = diagramApi.getState();
1997
2073
  setLastClickedNode(xynode.id);
1998
2074
  const shallChangeFocus = !!focusedNodeId && focusedNodeId !== xynode.id, clickedRecently = lastClickedNodeId === xynode.id && lastClickWasRecent();
1999
- if (enableFocusMode) {
2000
- let stopPropagation = !1;
2075
+ if (clickedRecently && onOpenSourceElement && onOpenSourceElement(xynode.data.element.id), enableFocusMode || nodesSelectable) {
2076
+ let stopPropagation = !0;
2001
2077
  switch (!0) {
2002
- case (!focusedNodeId && clickedRecently):
2003
- case shallChangeFocus:
2004
- stopPropagation = !0, focusOnNode(xynode.id);
2078
+ case (enableFocusMode && !focusedNodeId && clickedRecently):
2079
+ case (enableFocusMode && shallChangeFocus): {
2080
+ focusOnNode(xynode.id);
2005
2081
  break;
2006
- case (focusedNodeId === xynode.id && clickedRecently):
2007
- stopPropagation = !0, fitDiagram();
2082
+ }
2083
+ case (enableFocusMode && focusedNodeId === xynode.id && clickedRecently): {
2084
+ fitDiagram();
2085
+ break;
2086
+ }
2087
+ case nodesSelectable: {
2088
+ xystore.getState().addSelectedNodes([xynode.id]);
2008
2089
  break;
2090
+ }
2091
+ default:
2092
+ stopPropagation = !1;
2009
2093
  }
2010
2094
  !onNodeClick && stopPropagation && event.stopPropagation();
2011
2095
  }
@@ -2033,6 +2117,8 @@ function useXYFlowEvents() {
2033
2117
  activateDynamicStep,
2034
2118
  activeDynamicViewStep,
2035
2119
  focusedNodeId,
2120
+ xystore,
2121
+ nodesSelectable,
2036
2122
  focusOnNode,
2037
2123
  onEdgeClick,
2038
2124
  setLastClickedEdge
@@ -2046,7 +2132,7 @@ function useXYFlowEvents() {
2046
2132
  return;
2047
2133
  }
2048
2134
  }
2049
- isEdgeOfFocusedNode && (focusOnNode(focusedNodeId === xyedge.source ? xyedge.target : xyedge.source), onEdgeClick || event.stopPropagation()), onEdgeClick == null || onEdgeClick({
2135
+ isEdgeOfFocusedNode ? (focusOnNode(focusedNodeId === xyedge.source ? xyedge.target : xyedge.source), onEdgeClick || event.stopPropagation()) : nodesSelectable && (xystore.getState().addSelectedEdges([xyedge.id]), onEdgeClick || event.stopPropagation()), onEdgeClick == null || onEdgeClick({
2050
2136
  edge: xyedge.data.edge,
2051
2137
  xyedge,
2052
2138
  event
@@ -2150,11 +2236,11 @@ function XYFlow({
2150
2236
  hasOnEdgeContextMenu,
2151
2237
  translateX,
2152
2238
  translateY
2153
- } = useDiagramState(selector$1, shallowEqual), layoutConstraints = useLayoutConstraints(), handlers = useXYFlowEvents();
2239
+ } = useDiagramState(selector$1, shallowEqual), [zoomOnDoubleClick, setZoomOnDoubleClick] = useState(zoomable), layoutConstraints = useLayoutConstraints(), handlers = useXYFlowEvents();
2154
2240
  return useOnViewportChange({
2155
2241
  onEnd: ({ x, y, zoom }) => {
2156
2242
  const roundedX = Math.round(x), roundedY = Math.round(y);
2157
- (x !== roundedX || y !== roundedY) && xyflowApi.setState({ transform: [roundedX, roundedY, zoom] });
2243
+ (x !== roundedX || y !== roundedY) && xyflowApi.setState({ transform: [roundedX, roundedY, zoom] }), setZoomOnDoubleClick(zoomable && zoom < 1.1);
2158
2244
  }
2159
2245
  }), /* @__PURE__ */ jsx(
2160
2246
  ReactFlow,
@@ -2171,7 +2257,7 @@ function XYFlow({
2171
2257
  ...!zoomable && {
2172
2258
  zoomActivationKeyCode: null
2173
2259
  },
2174
- maxZoom: zoomable ? 1.9 : 1,
2260
+ maxZoom: zoomable ? MaxZoom : 1,
2175
2261
  minZoom: zoomable ? MinZoom : 1,
2176
2262
  fitView,
2177
2263
  fitViewOptions: useMemo(() => ({
@@ -2206,7 +2292,7 @@ function XYFlow({
2206
2292
  onNodeDragStop: layoutConstraints.onNodeDragStop
2207
2293
  },
2208
2294
  nodeDragThreshold: 3,
2209
- zoomOnDoubleClick: !1,
2295
+ zoomOnDoubleClick,
2210
2296
  elevateNodesOnSelect: !1,
2211
2297
  selectNodesOnDrag: !1,
2212
2298
  onNodesChange,
@@ -2236,82 +2322,6 @@ function XYFlow({
2236
2322
  }
2237
2323
  );
2238
2324
  }
2239
- var panel$1 = "_19mimxc0";
2240
- const historySelector = (s) => ({
2241
- hasStepBack: s.navigationHistoryIndex > 0,
2242
- hasStepForward: s.navigationHistoryIndex < s.navigationHistory.length - 1,
2243
- goBack: s.goBack,
2244
- goForward: s.goForward
2245
- });
2246
- function BackwardForwardPanel() {
2247
- const {
2248
- hasStepBack,
2249
- hasStepForward,
2250
- goBack,
2251
- goForward
2252
- } = useDiagramState(historySelector);
2253
- return /* @__PURE__ */ jsx(
2254
- Group,
2255
- {
2256
- className: clsx(
2257
- "react-flow__panel",
2258
- panel$1,
2259
- "likec4-navigation-panel"
2260
- ),
2261
- gap: "xs",
2262
- children: /* @__PURE__ */ jsxs(AnimatePresence, { children: [
2263
- hasStepBack && /* @__PURE__ */ jsx(
2264
- m.div,
2265
- {
2266
- layout: !0,
2267
- initial: { opacity: 0.05, transform: "translateX(-10px)" },
2268
- animate: { opacity: 1, transform: "translateX(0)" },
2269
- exit: {
2270
- opacity: 0.05,
2271
- transform: "translateX(-10px)"
2272
- },
2273
- children: /* @__PURE__ */ jsx(
2274
- ActionIcon,
2275
- {
2276
- variant: "light",
2277
- color: "gray",
2278
- onClick: (e) => {
2279
- e.stopPropagation(), goBack();
2280
- },
2281
- children: /* @__PURE__ */ jsx(IconChevronLeft, {})
2282
- }
2283
- )
2284
- },
2285
- "back"
2286
- ),
2287
- hasStepForward && /* @__PURE__ */ jsx(
2288
- m.div,
2289
- {
2290
- layout: !0,
2291
- initial: { opacity: 0.05, transform: "translateX(10px)" },
2292
- animate: { opacity: 1, transform: "translateX(0)" },
2293
- exit: {
2294
- opacity: 0,
2295
- transform: "translateX(10px)"
2296
- },
2297
- children: /* @__PURE__ */ jsx(
2298
- ActionIcon,
2299
- {
2300
- variant: "light",
2301
- color: "gray",
2302
- onClick: (e) => {
2303
- e.stopPropagation(), goForward();
2304
- },
2305
- children: /* @__PURE__ */ jsx(IconChevronRight, {})
2306
- }
2307
- )
2308
- },
2309
- "forward"
2310
- )
2311
- ] })
2312
- }
2313
- );
2314
- }
2315
2325
  var container$1 = "hbkbtj0", card = "hbkbtj1", title = "hbkbtj2", description = "hbkbtj3";
2316
2326
  const selector = (s) => ({
2317
2327
  id: s.view.id,
@@ -2343,62 +2353,75 @@ function DiagramTitlePanel() {
2343
2353
  radius: "sm",
2344
2354
  className: card,
2345
2355
  withBorder: !0,
2346
- p: "md",
2347
- pb: isCollapsed ? "sm" : "md",
2356
+ p: isCollapsed ? "sm" : "md",
2348
2357
  onDoubleClick: (e) => e.stopPropagation(),
2349
2358
  children: [
2350
- /* @__PURE__ */ jsx(CardSection, { mb: isCollapsed ? 10 : "sm", children: /* @__PURE__ */ jsx(
2359
+ isCollapsed && /* @__PURE__ */ jsx(CardSection, { children: /* @__PURE__ */ jsx(
2351
2360
  Button,
2352
2361
  {
2353
2362
  fullWidth: !0,
2354
- size: "xs",
2355
- h: "sm",
2363
+ justify: "stretch",
2364
+ size: "sm",
2356
2365
  py: 2,
2357
2366
  radius: "0",
2358
- variant: isCollapsed ? "light" : "subtle",
2359
- color: "gray",
2367
+ variant: "subtle",
2368
+ color: "dark",
2360
2369
  onClick: toggle,
2361
- children: /* @__PURE__ */ jsx(IconMenu, { size: 11, opacity: 0.7 })
2370
+ children: /* @__PURE__ */ jsx(Text$1, { inline: !0, fw: 500, fz: "xs", c: "gray", children: title$12 })
2362
2371
  }
2363
2372
  ) }),
2364
- /* @__PURE__ */ jsxs(Group, { justify: "stretch", wrap: "nowrap", mb: isCollapsed ? 0 : "sm", children: [
2365
- /* @__PURE__ */ jsx(
2366
- Text$1,
2367
- {
2368
- component: "div",
2369
- flex: "1",
2370
- size: isCollapsed ? "sm" : "lg",
2371
- fw: 500,
2372
- lh: 1.1,
2373
- className: title,
2374
- children: title$12
2375
- }
2376
- ),
2377
- /* @__PURE__ */ jsxs(
2378
- Text$1,
2373
+ !isCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
2374
+ /* @__PURE__ */ jsx(CardSection, { mb: "sm", children: /* @__PURE__ */ jsx(
2375
+ Button,
2379
2376
  {
2380
- hidden: isCollapsed,
2381
- component: "div",
2382
- flex: "0 0 auto",
2383
- inline: !0,
2377
+ fullWidth: !0,
2384
2378
  size: "xs",
2385
- fz: 9,
2386
- fw: 500,
2387
- c: "dimmed",
2388
- style: {
2389
- userSelect: "all"
2390
- },
2391
- children: [
2392
- /* @__PURE__ */ jsxs("span", { style: { userSelect: "none" }, children: [
2393
- "id:",
2394
- " "
2395
- ] }),
2396
- id
2397
- ]
2379
+ h: "sm",
2380
+ py: 2,
2381
+ radius: "0",
2382
+ variant: "subtle",
2383
+ color: "gray",
2384
+ onClick: toggle,
2385
+ children: /* @__PURE__ */ jsx(IconMenu, { size: 11, opacity: 0.7 })
2398
2386
  }
2399
- )
2400
- ] }),
2401
- !isCollapsed && /* @__PURE__ */ jsxs(Fragment, { children: [
2387
+ ) }),
2388
+ /* @__PURE__ */ jsxs(Group, { justify: "stretch", wrap: "nowrap", mb: "sm", children: [
2389
+ /* @__PURE__ */ jsx(
2390
+ Text$1,
2391
+ {
2392
+ component: "div",
2393
+ flex: "1",
2394
+ size: "md",
2395
+ fw: 500,
2396
+ lh: 1.1,
2397
+ className: title,
2398
+ children: title$12
2399
+ }
2400
+ ),
2401
+ /* @__PURE__ */ jsxs(
2402
+ Text$1,
2403
+ {
2404
+ hidden: isCollapsed,
2405
+ component: "div",
2406
+ flex: "0 0 auto",
2407
+ inline: !0,
2408
+ size: "xs",
2409
+ fz: 9,
2410
+ fw: 500,
2411
+ c: "dimmed",
2412
+ style: {
2413
+ userSelect: "all"
2414
+ },
2415
+ children: [
2416
+ /* @__PURE__ */ jsxs("span", { style: { userSelect: "none" }, children: [
2417
+ "id:",
2418
+ " "
2419
+ ] }),
2420
+ id
2421
+ ]
2422
+ }
2423
+ )
2424
+ ] }),
2402
2425
  description$12 && /* @__PURE__ */ jsx(
2403
2426
  Spoiler,
2404
2427
  {
@@ -2573,7 +2596,7 @@ const {
2573
2596
  return null;
2574
2597
  if (nodes.length !== selectedNodeIds.length)
2575
2598
  throw new Error("NodeOptions: nodes and props.nodes should have the same length");
2576
- const showShapeOption = nodes.some((node) => node.type === "element"), [firstNode, ...rest] = nodes, showOpacityOption = firstNode.type === "compound" && (rest.length === 0 || rest.every((node) => node.type === "compound")), triggerChange = (style) => {
2599
+ const showShapeOption = nodes.some((node) => node.type === "element"), [firstNode, ...rest] = nodes, showGoToSource = rest.length === 0 && diagramApi.getState().onOpenSourceElement, showOpacityOption = firstNode.type === "compound" && (rest.length === 0 || rest.every((node) => node.type === "compound")), triggerChange = (style) => {
2577
2600
  const targets = nodes.map((node) => node.data.element.id);
2578
2601
  invariant(hasAtLeast$1(targets, 1), "At least one target is required"), diagramApi.getState().triggerChangeElementStyle({
2579
2602
  op: "change-element-style",
@@ -2582,12 +2605,36 @@ const {
2582
2605
  });
2583
2606
  };
2584
2607
  return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2585
- /* @__PURE__ */ jsxs("div", { children: [
2586
- /* @__PURE__ */ jsxs(Text$1, { fz: rem(9), fw: "500", c: "dimmed", children: [
2587
- "ELEMENT",
2588
- rest.length > 0 ? "S" : ""
2608
+ /* @__PURE__ */ jsxs(Group, { wrap: "nowrap", align: "flex-start", children: [
2609
+ /* @__PURE__ */ jsxs(Box, { flex: 1, children: [
2610
+ /* @__PURE__ */ jsxs(Text$1, { fz: rem(9), fw: "500", c: "dimmed", children: [
2611
+ "ELEMENT",
2612
+ rest.length > 0 ? "S" : ""
2613
+ ] }),
2614
+ /* @__PURE__ */ jsx(Text$1, { size: "xs", c: rest.length > 0 ? "dimmed" : "", truncate: !0, children: rest.length === 0 ? firstNode.data.element.title : "[ multiple ]" })
2589
2615
  ] }),
2590
- /* @__PURE__ */ jsx(Text$1, { size: "xs", c: rest.length > 0 ? "dimmed" : "", truncate: !0, children: rest.length === 0 ? firstNode.data.element.title : "[ multiple ]" })
2616
+ showGoToSource && /* @__PURE__ */ jsx(Box, { flex: 0, children: /* @__PURE__ */ jsx(
2617
+ ActionIcon$2,
2618
+ {
2619
+ size: "sm",
2620
+ variant: "light",
2621
+ color: "gray",
2622
+ onClick: (e) => {
2623
+ var _a, _b;
2624
+ e.stopPropagation(), (_b = (_a = diagramApi.getState()).onOpenSourceElement) == null || _b.call(_a, firstNode.data.element.id);
2625
+ },
2626
+ children: /* @__PURE__ */ jsx(
2627
+ IconFileSymlink,
2628
+ {
2629
+ stroke: 1.2,
2630
+ style: {
2631
+ width: "70%",
2632
+ height: "70%"
2633
+ }
2634
+ }
2635
+ )
2636
+ }
2637
+ ) })
2591
2638
  ] }),
2592
2639
  showShapeOption && /* @__PURE__ */ jsx(
2593
2640
  ShapeOption,
@@ -2645,7 +2692,7 @@ function Colors({
2645
2692
  return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsxs(TooltipGroup, { openDelay: 400, closeDelay: 300, children: [
2646
2693
  /* @__PURE__ */ jsx(Divider, { label: "color", labelPosition: "left" }),
2647
2694
  /* @__PURE__ */ jsx(Flex, { mt: "xs", maw: 150, gap: "xs", justify: "flex-start", align: "flex-start", direction: "row", wrap: "wrap", children: themedColors.map(({ key, value }) => /* @__PURE__ */ jsx(
2648
- Tooltip,
2695
+ Tooltip$2,
2649
2696
  {
2650
2697
  label: key,
2651
2698
  fz: "xs",
@@ -2667,7 +2714,7 @@ function Colors({
2667
2714
  key
2668
2715
  )) }),
2669
2716
  /* @__PURE__ */ jsx(Flex, { mt: "sm", maw: 150, gap: "xs", justify: "flex-start", align: "flex-start", direction: "row", wrap: "wrap", children: colors.map(({ key, value }) => /* @__PURE__ */ jsx(
2670
- Tooltip,
2717
+ Tooltip$2,
2671
2718
  {
2672
2719
  label: key,
2673
2720
  fz: "xs",
@@ -2784,7 +2831,7 @@ function BorderStyleOption({
2784
2831
  }
2785
2832
  ) });
2786
2833
  }
2787
- var panel = "_1lmzt1h0";
2834
+ var panel$1 = "_1lmzt1h0";
2788
2835
  function OptionsPanel() {
2789
2836
  const { isFocused, viewId } = useDiagramState((s) => ({
2790
2837
  viewId: s.view.id,
@@ -2813,7 +2860,7 @@ function OptionsPanel() {
2813
2860
  scale: 0.85
2814
2861
  },
2815
2862
  transition: { duration: 0.14 },
2816
- className: clsx("react-flow__panel", panel),
2863
+ className: clsx("react-flow__panel", panel$1),
2817
2864
  style: {
2818
2865
  transformOrigin: "center right",
2819
2866
  maxWidth: "320px"
@@ -2823,6 +2870,323 @@ function OptionsPanel() {
2823
2870
  viewId
2824
2871
  ) });
2825
2872
  }
2873
+ const Tooltip$1 = Tooltip$2.withProps({
2874
+ color: "gray",
2875
+ fz: "xs",
2876
+ position: "right",
2877
+ openDelay: 400,
2878
+ closeDelay: 100,
2879
+ label: "",
2880
+ children: null,
2881
+ offset: 8,
2882
+ transitionProps: { transition: "fade-right", duration: 200 }
2883
+ }), ActionIcon$1 = ActionIcon$2.withProps({
2884
+ className: "action-icon",
2885
+ variant: "light",
2886
+ color: "gray"
2887
+ });
2888
+ var panel = "_1snasyb0", autolayoutIcon = "_1snasyb1", autolayoutIndicator = "_1snasyb2";
2889
+ const ActionIcon = ActionIcon$2.withProps({
2890
+ size: "md",
2891
+ variant: "subtle",
2892
+ color: "gray"
2893
+ }), Tooltip = Tooltip$2.withProps({
2894
+ color: "gray",
2895
+ fz: "xs",
2896
+ position: "right",
2897
+ openDelay: 300,
2898
+ label: "",
2899
+ children: null,
2900
+ offset: 5,
2901
+ transitionProps: { transition: "fade", duration: 200 }
2902
+ }), ChangeAutoLayoutButton = (props) => {
2903
+ const store = useDiagramStoreApi(), [rootRef, setRootRef] = useState(null), [controlsRefs, setControlsRefs] = useState({}), autoLayout = useDiagramState((s) => s.view.autoLayout), setControlRef = (name) => (node) => {
2904
+ controlsRefs[name] = node, setControlsRefs(controlsRefs);
2905
+ }, setAutoLayout = (layout) => (event) => {
2906
+ var _a, _b;
2907
+ event.stopPropagation(), (_b = (_a = store.getState()).onChange) == null || _b.call(_a, {
2908
+ change: {
2909
+ op: "change-autolayout",
2910
+ layout
2911
+ }
2912
+ });
2913
+ };
2914
+ return /* @__PURE__ */ jsxs(
2915
+ Popover,
2916
+ {
2917
+ position: "right-start",
2918
+ clickOutsideEvents: [
2919
+ "pointerdown"
2920
+ ],
2921
+ radius: "xs",
2922
+ shadow: "lg",
2923
+ offset: {
2924
+ mainAxis: 10
2925
+ },
2926
+ ...props,
2927
+ children: [
2928
+ /* @__PURE__ */ jsx(PopoverTarget, { children: /* @__PURE__ */ jsx(
2929
+ ActionIcon$2,
2930
+ {
2931
+ className: "action-icon",
2932
+ variant: "light",
2933
+ color: "gray",
2934
+ children: /* @__PURE__ */ jsx(IconLayoutDashboard, { stroke: 1.3 })
2935
+ }
2936
+ ) }),
2937
+ /* @__PURE__ */ jsx(PopoverDropdown, { className: "likec4-top-left-panel", p: 8, pt: 4, children: /* @__PURE__ */ jsxs(Box, { pos: "relative", ref: setRootRef, children: [
2938
+ /* @__PURE__ */ jsx(
2939
+ FloatingIndicator,
2940
+ {
2941
+ target: controlsRefs[autoLayout],
2942
+ parent: rootRef,
2943
+ className: autolayoutIndicator
2944
+ }
2945
+ ),
2946
+ /* @__PURE__ */ jsx(Box, { mb: 10, children: /* @__PURE__ */ jsx(Text$1, { inline: !0, fz: "xs", c: "dimmed", fw: 500, children: "Auto layout:" }) }),
2947
+ /* @__PURE__ */ jsx(TooltipGroup, { openDelay: 100, children: /* @__PURE__ */ jsxs(Stack, { align: "center", gap: 1, children: [
2948
+ /* @__PURE__ */ jsx(Tooltip, { label: "Top to Bottom", children: /* @__PURE__ */ jsx(
2949
+ ActionIcon,
2950
+ {
2951
+ className: autolayoutIcon,
2952
+ ref: setControlRef("TB"),
2953
+ onClick: setAutoLayout("TB"),
2954
+ children: /* @__PURE__ */ jsx(IconArrowBigDownLines, { stroke: 1.3 })
2955
+ }
2956
+ ) }),
2957
+ /* @__PURE__ */ jsxs(Group, { gap: 30, children: [
2958
+ /* @__PURE__ */ jsx(Tooltip, { label: "Left to Right", children: /* @__PURE__ */ jsx(
2959
+ ActionIcon,
2960
+ {
2961
+ className: autolayoutIcon,
2962
+ ref: setControlRef("LR"),
2963
+ onClick: setAutoLayout("LR"),
2964
+ children: /* @__PURE__ */ jsx(IconArrowBigDownLines, { stroke: 1.3, style: { rotate: "270deg" } })
2965
+ }
2966
+ ) }),
2967
+ /* @__PURE__ */ jsx(Tooltip, { label: "Right to Left", children: /* @__PURE__ */ jsx(
2968
+ ActionIcon,
2969
+ {
2970
+ className: autolayoutIcon,
2971
+ ref: setControlRef("RL"),
2972
+ onClick: setAutoLayout("RL"),
2973
+ children: /* @__PURE__ */ jsx(IconArrowBigDownLines, { stroke: 1.3, style: { rotate: "90deg" } })
2974
+ }
2975
+ ) })
2976
+ ] }),
2977
+ /* @__PURE__ */ jsx(Tooltip, { label: "Bottom to Top", children: /* @__PURE__ */ jsx(
2978
+ ActionIcon,
2979
+ {
2980
+ className: autolayoutIcon,
2981
+ ref: setControlRef("BT"),
2982
+ onClick: setAutoLayout("BT"),
2983
+ children: /* @__PURE__ */ jsx(IconArrowBigDownLines, { stroke: 1.3, style: { rotate: "180deg" } })
2984
+ }
2985
+ ) })
2986
+ ] }) })
2987
+ ] }) })
2988
+ ]
2989
+ }
2990
+ );
2991
+ }, historySelector = (s) => ({
2992
+ showBurgerMenu: !!s.onBurgerMenuClick,
2993
+ hasStepBack: s.navigationHistoryIndex > 0,
2994
+ hasStepForward: s.navigationHistoryIndex < s.navigationHistory.length - 1
2995
+ }), BackwardForwardButtons = () => {
2996
+ const store = useDiagramStoreApi(), {
2997
+ showBurgerMenu,
2998
+ hasStepBack,
2999
+ hasStepForward
3000
+ } = useDiagramState(historySelector);
3001
+ return /* @__PURE__ */ jsxs(
3002
+ Group,
3003
+ {
3004
+ className: "likec4-navigation-panel",
3005
+ gap: "xs",
3006
+ children: [
3007
+ showBurgerMenu && /* @__PURE__ */ jsx(
3008
+ ActionIcon$1,
3009
+ {
3010
+ onClick: (e) => {
3011
+ var _a, _b;
3012
+ e.stopPropagation(), (_b = (_a = store.getState()).onBurgerMenuClick) == null || _b.call(_a);
3013
+ },
3014
+ children: /* @__PURE__ */ jsx(IconMenu2, {})
3015
+ }
3016
+ ),
3017
+ /* @__PURE__ */ jsxs(AnimatePresence, { children: [
3018
+ hasStepBack && /* @__PURE__ */ jsx(
3019
+ m.div,
3020
+ {
3021
+ layout: !0,
3022
+ initial: { opacity: 0.05, transform: "translateX(-10px)" },
3023
+ animate: { opacity: 1, transform: "translateX(0)" },
3024
+ exit: {
3025
+ opacity: 0.05,
3026
+ transform: "translateX(-10px)"
3027
+ },
3028
+ children: /* @__PURE__ */ jsx(
3029
+ ActionIcon$1,
3030
+ {
3031
+ onClick: (e) => {
3032
+ e.stopPropagation(), store.getState().goBack();
3033
+ },
3034
+ children: /* @__PURE__ */ jsx(IconChevronLeft, {})
3035
+ }
3036
+ )
3037
+ },
3038
+ "back"
3039
+ ),
3040
+ hasStepForward && /* @__PURE__ */ jsx(
3041
+ m.div,
3042
+ {
3043
+ layout: !0,
3044
+ initial: { opacity: 0.05, transform: "translateX(10px)" },
3045
+ animate: { opacity: 1, transform: "translateX(0)" },
3046
+ exit: {
3047
+ opacity: 0,
3048
+ transform: "translateX(10px)"
3049
+ },
3050
+ children: /* @__PURE__ */ jsx(
3051
+ ActionIcon$1,
3052
+ {
3053
+ onClick: (e) => {
3054
+ e.stopPropagation(), store.getState().goForward();
3055
+ },
3056
+ children: /* @__PURE__ */ jsx(IconChevronRight, {})
3057
+ }
3058
+ )
3059
+ },
3060
+ "forward"
3061
+ )
3062
+ ] })
3063
+ ]
3064
+ }
3065
+ );
3066
+ }, LayoutDriftNotification = (props) => /* @__PURE__ */ jsxs(
3067
+ HoverCard,
3068
+ {
3069
+ position: "right-start",
3070
+ openDelay: 200,
3071
+ closeDelay: 100,
3072
+ ...props,
3073
+ children: [
3074
+ /* @__PURE__ */ jsx(HoverCardTarget, { children: /* @__PURE__ */ jsx(
3075
+ ActionIcon$1,
3076
+ {
3077
+ className: "action-icon",
3078
+ variant: "light",
3079
+ color: "orange",
3080
+ children: /* @__PURE__ */ jsx(IconAlertTriangle, {})
3081
+ }
3082
+ ) }),
3083
+ /* @__PURE__ */ jsx(HoverCardDropdown, { p: "0", children: /* @__PURE__ */ jsxs(
3084
+ Notification,
3085
+ {
3086
+ color: "orange",
3087
+ withBorder: !1,
3088
+ withCloseButton: !1,
3089
+ title: "Manual layout issues",
3090
+ children: [
3091
+ /* @__PURE__ */ jsxs(Text$1, { mt: 2, size: "sm", lh: "xs", children: [
3092
+ "View contains new elements or their sizes have changed,",
3093
+ /* @__PURE__ */ jsx("br", {}),
3094
+ "last manual layout can not be applied."
3095
+ ] }),
3096
+ /* @__PURE__ */ jsxs(Text$1, { mt: "xs", size: "sm", lh: "xs", children: [
3097
+ "Update view predicates or remove ",
3098
+ /* @__PURE__ */ jsx(Code, { children: "@likec4-generated" })
3099
+ ] })
3100
+ ]
3101
+ }
3102
+ ) })
3103
+ ]
3104
+ }
3105
+ ), TopLeftPanel = () => {
3106
+ const store = useDiagramStoreApi(), {
3107
+ showNavigationButtons,
3108
+ showFitDiagram,
3109
+ showLayoutDriftWarning,
3110
+ showChangeAutoLayout,
3111
+ portalProps: _portalProps,
3112
+ showGoToSource
3113
+ } = useDiagramState((s) => {
3114
+ const isNotActive = s.activeDynamicViewStep === null && s.focusedNodeId === null, target = s.getContainer();
3115
+ return {
3116
+ showNavigationButtons: !!s.onBurgerMenuClick || s.showNavigationButtons && !!s.onNavigateTo,
3117
+ showFitDiagram: s.fitViewEnabled && s.zoomable && s.viewportChanged,
3118
+ showLayoutDriftWarning: s.readonly !== !0 && s.view.hasLayoutDrift === !0 && isNotActive,
3119
+ showChangeAutoLayout: s.readonly !== !0 && !!s.onChange && isNotActive,
3120
+ showGoToSource: !!s.onOpenSourceView,
3121
+ portalProps: target ? { target } : void 0
3122
+ };
3123
+ }), portalProps = _portalProps ? { portalProps: _portalProps } : void 0;
3124
+ return /* @__PURE__ */ jsxs(
3125
+ Stack,
3126
+ {
3127
+ className: clsx(
3128
+ "react-flow__panel",
3129
+ panel,
3130
+ "likec4-top-left-panel"
3131
+ ),
3132
+ onClick: (e) => e.stopPropagation(),
3133
+ gap: "xs",
3134
+ children: [
3135
+ showNavigationButtons && /* @__PURE__ */ jsx(BackwardForwardButtons, {}),
3136
+ showGoToSource && /* @__PURE__ */ jsx(Tooltip$1, { label: "Go to source", ...portalProps, children: /* @__PURE__ */ jsx(
3137
+ ActionIcon$1,
3138
+ {
3139
+ className: "action-icon",
3140
+ onClick: (e) => {
3141
+ var _a, _b;
3142
+ e.stopPropagation(), (_b = (_a = store.getState()).onOpenSourceView) == null || _b.call(_a);
3143
+ },
3144
+ children: /* @__PURE__ */ jsx(IconFileSymlink, { stroke: 1.5 })
3145
+ }
3146
+ ) }),
3147
+ showChangeAutoLayout && /* @__PURE__ */ jsx(ChangeAutoLayoutButton, { ...portalProps }),
3148
+ /* @__PURE__ */ jsxs(AnimatePresence, { children: [
3149
+ showLayoutDriftWarning && /* @__PURE__ */ jsx(
3150
+ m.div,
3151
+ {
3152
+ initial: { opacity: 0.05, transform: "translateX(-40%)" },
3153
+ animate: { opacity: 1, transform: "translateX(0)" },
3154
+ exit: {
3155
+ opacity: 0,
3156
+ transform: "translateX(-40%)"
3157
+ },
3158
+ children: /* @__PURE__ */ jsx(LayoutDriftNotification, { ...portalProps })
3159
+ },
3160
+ "layout"
3161
+ ),
3162
+ showFitDiagram && /* @__PURE__ */ jsx(
3163
+ m.div,
3164
+ {
3165
+ initial: { opacity: 0.05, transform: "translateX(-20%)" },
3166
+ animate: { opacity: 1, transform: "translateX(0)" },
3167
+ exit: {
3168
+ opacity: 0,
3169
+ transform: "translateX(-30%)"
3170
+ },
3171
+ children: /* @__PURE__ */ jsx(Tooltip$1, { label: "Center diagram", ...portalProps, children: /* @__PURE__ */ jsx(
3172
+ ActionIcon$1,
3173
+ {
3174
+ className: "action-icon",
3175
+ onClick: (e) => {
3176
+ e.stopPropagation(), store.getState().fitDiagram();
3177
+ },
3178
+ children: /* @__PURE__ */ jsx(IconFocusCentered, {})
3179
+ }
3180
+ ) })
3181
+ },
3182
+ "fit-view"
3183
+ )
3184
+ ] })
3185
+ ]
3186
+ }
3187
+ );
3188
+ };
3189
+ TopLeftPanel.displayName = "TopLeftPanel";
2826
3190
  function literalToEnum(value) {
2827
3191
  switch (value) {
2828
3192
  case "dots":
@@ -2845,8 +3209,7 @@ const XYFlowInner = memo(function({
2845
3209
  children,
2846
3210
  background,
2847
3211
  controls,
2848
- showDiagramTitle,
2849
- showNavigationButtons
3212
+ showDiagramTitle
2850
3213
  }) {
2851
3214
  const {
2852
3215
  isDynamicView,
@@ -2862,10 +3225,10 @@ const XYFlowInner = memo(function({
2862
3225
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2863
3226
  background !== "transparent" && background !== "solid" && /* @__PURE__ */ jsx(XYFlowBackground, { background }),
2864
3227
  controls && /* @__PURE__ */ jsx(Controls, { position: "bottom-right" }),
2865
- readonly === !1 && /* @__PURE__ */ jsx(OptionsPanel, {}),
3228
+ /* @__PURE__ */ jsx(TopLeftPanel, {}),
3229
+ readonly !== !0 && /* @__PURE__ */ jsx(OptionsPanel, {}),
2866
3230
  showDiagramTitle === !0 && !isDynamicViewActive && /* @__PURE__ */ jsx(DiagramTitlePanel, {}),
2867
3231
  isDynamicView && enableDynamicViewWalkthrough && /* @__PURE__ */ jsx(DynamicViewWalkthrough, {}),
2868
- showNavigationButtons && /* @__PURE__ */ jsx(BackwardForwardPanel, {}),
2869
3232
  children
2870
3233
  ] });
2871
3234
  }, shallowEqual);
@@ -2884,9 +3247,8 @@ function LikeC4Diagram({
2884
3247
  controls = !1,
2885
3248
  showElementLinks = !0,
2886
3249
  showDiagramTitle = !0,
2887
- showNavigationButtons = !1,
2888
3250
  enableDynamicViewWalkthrough = !1,
2889
- enableFocusMode = readonly,
3251
+ enableFocusMode = !1,
2890
3252
  initialWidth,
2891
3253
  initialHeight,
2892
3254
  keepAspectRatio = !1,
@@ -2900,8 +3262,13 @@ function LikeC4Diagram({
2900
3262
  onNavigateTo,
2901
3263
  onNodeClick,
2902
3264
  onNodeContextMenu,
2903
- onEditorCommand,
2904
- renderIcon
3265
+ onOpenSourceElement,
3266
+ onOpenSourceView,
3267
+ onOpenSourceRelation,
3268
+ onBurgerMenuClick,
3269
+ renderIcon,
3270
+ where,
3271
+ showNavigationButtons = !!onNavigateTo
2905
3272
  }) {
2906
3273
  const initialRef = useRef({
2907
3274
  defaultNodes: [],
@@ -2909,7 +3276,7 @@ function LikeC4Diagram({
2909
3276
  initialWidth: initialWidth ?? view.bounds.width,
2910
3277
  initialHeight: initialHeight ?? view.bounds.height
2911
3278
  });
2912
- return /* @__PURE__ */ jsx(EnsureMantine, { children: /* @__PURE__ */ jsx(LazyMotion, { features: domAnimation, strict: !0, children: /* @__PURE__ */ jsx(
3279
+ return readonly !== !0 && where && console.warn("where filter is only supported in readonly mode"), /* @__PURE__ */ jsx(EnsureMantine, { children: /* @__PURE__ */ jsx(LazyMotion, { features: domAnimation, strict: !0, children: /* @__PURE__ */ jsx(
2913
3280
  ReactFlowProvider,
2914
3281
  {
2915
3282
  fitView,
@@ -2926,11 +3293,13 @@ function LikeC4Diagram({
2926
3293
  fitViewEnabled: fitView,
2927
3294
  fitViewPadding,
2928
3295
  showElementLinks,
3296
+ showNavigationButtons,
2929
3297
  nodesDraggable,
2930
3298
  nodesSelectable,
2931
3299
  experimentalEdgeEditing,
2932
3300
  enableDynamicViewWalkthrough,
2933
3301
  enableFocusMode,
3302
+ whereFilter: where ?? null,
2934
3303
  renderIcon: renderIcon ?? null,
2935
3304
  onCanvasClick: onCanvasClick ?? null,
2936
3305
  onCanvasContextMenu: onCanvasContextMenu ?? null,
@@ -2941,14 +3310,16 @@ function LikeC4Diagram({
2941
3310
  onChange: onChange ?? null,
2942
3311
  onNavigateTo: onNavigateTo ?? null,
2943
3312
  onCanvasDblClick: onCanvasDblClick ?? null,
2944
- onEditorCommand: onEditorCommand ?? null,
3313
+ onOpenSourceView: onOpenSourceView ?? null,
3314
+ onOpenSourceElement: onOpenSourceElement ?? null,
3315
+ onOpenSourceRelation: onOpenSourceRelation ?? null,
3316
+ onBurgerMenuClick: onBurgerMenuClick ?? null,
2945
3317
  children: /* @__PURE__ */ jsx(
2946
3318
  LikeC4DiagramInnerMemo,
2947
3319
  {
2948
3320
  controls,
2949
3321
  background,
2950
- showDiagramTitle,
2951
- showNavigationButtons
3322
+ showDiagramTitle
2952
3323
  }
2953
3324
  )
2954
3325
  }
@@ -2959,8 +3330,7 @@ function LikeC4Diagram({
2959
3330
  const LikeC4DiagramInnerMemo = memo(function({
2960
3331
  background,
2961
3332
  controls,
2962
- showDiagramTitle,
2963
- showNavigationButtons
3333
+ showDiagramTitle
2964
3334
  }) {
2965
3335
  const {
2966
3336
  isInitialized,
@@ -2988,7 +3358,6 @@ const LikeC4DiagramInnerMemo = memo(function({
2988
3358
  children: /* @__PURE__ */ jsx(
2989
3359
  XYFlowInner,
2990
3360
  {
2991
- showNavigationButtons,
2992
3361
  showDiagramTitle,
2993
3362
  background,
2994
3363
  controls
@@ -3023,6 +3392,7 @@ function StaticLikeC4Diagram({
3023
3392
  showElementLinks: !0,
3024
3393
  showDiagramTitle: !1,
3025
3394
  enableDynamicViewWalkthrough: !1,
3395
+ enableFocusMode: !1,
3026
3396
  nodesSelectable: !1,
3027
3397
  nodesDraggable: !1,
3028
3398
  ...rest