@likec4/diagram 1.21.1 → 1.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/LikeC4Diagram.js +9 -13
  2. package/dist/base/index.d.ts +0 -1
  3. package/dist/base/primitives/element/styles.css.js +1 -1
  4. package/dist/{base → components}/Link.css.js +3 -3
  5. package/dist/components/SearchControl.css.d.ts +2 -0
  6. package/dist/components/SearchControl.css.js +7 -0
  7. package/dist/components/SearchControl.d.ts +5 -0
  8. package/dist/components/SearchControl.js +17 -0
  9. package/dist/context/DiagramFeatures.d.ts +1 -1
  10. package/dist/context/IconRenderer.d.ts +10 -0
  11. package/dist/context/IconRenderer.js +34 -0
  12. package/dist/hooks/useCurrentViewId.js +8 -0
  13. package/dist/hooks/useDiagram.d.ts +108 -72
  14. package/dist/hooks/useDiagram.js +3 -0
  15. package/dist/likec4diagram/DiagramActor.js +13 -2
  16. package/dist/likec4diagram/DiagramUI.js +0 -2
  17. package/dist/likec4diagram/XYFlow.d.ts +6 -1
  18. package/dist/likec4diagram/XYFlow.js +37 -31
  19. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +2 -1
  20. package/dist/likec4diagram/state/actorContext.d.ts +620 -468
  21. package/dist/likec4diagram/state/assign.js +1 -1
  22. package/dist/likec4diagram/state/machine.d.ts +120 -74
  23. package/dist/likec4diagram/state/machine.js +32 -12
  24. package/dist/likec4diagram/state/syncManualLayoutActor.js +4 -8
  25. package/dist/likec4diagram/ui/controls/Controls.js +65 -48
  26. package/dist/likec4diagram/ui/controls/NavigationButtons.js +44 -69
  27. package/dist/likec4diagram/ui/controls/ToggleReadonly.d.ts +1 -0
  28. package/dist/likec4diagram/ui/controls/ToggleReadonly.js +29 -0
  29. package/dist/likec4diagram/ui/controls/_shared.js +1 -1
  30. package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +1 -1
  31. package/dist/likec4diagram/ui/search/ElementsColumn.css.d.ts +15 -0
  32. package/dist/likec4diagram/ui/search/ElementsColumn.css.js +30 -0
  33. package/dist/likec4diagram/ui/search/ElementsColumn.d.ts +1 -0
  34. package/dist/likec4diagram/ui/search/ElementsColumn.js +243 -0
  35. package/dist/likec4diagram/ui/search/LikeC4Search.css.d.ts +8 -0
  36. package/dist/likec4diagram/ui/search/LikeC4Search.css.js +20 -0
  37. package/dist/likec4diagram/ui/search/LikeC4Search.d.ts +1 -0
  38. package/dist/likec4diagram/ui/search/LikeC4Search.js +265 -0
  39. package/dist/likec4diagram/ui/search/SearchInput.d.ts +1 -0
  40. package/dist/likec4diagram/ui/search/SearchInput.js +196 -0
  41. package/dist/likec4diagram/ui/search/ViewsColum.d.ts +9 -0
  42. package/dist/likec4diagram/ui/search/ViewsColum.js +130 -0
  43. package/dist/likec4diagram/ui/search/ViewsColumn.css.d.ts +5 -0
  44. package/dist/likec4diagram/ui/search/ViewsColumn.css.js +12 -0
  45. package/dist/likec4diagram/ui/search/_shared.css.d.ts +16 -0
  46. package/dist/likec4diagram/ui/search/_shared.css.js +5 -0
  47. package/dist/likec4diagram/ui/search/state.d.ts +19 -0
  48. package/dist/likec4diagram/ui/search/state.js +72 -0
  49. package/dist/likec4diagram/ui/search/utils.d.ts +3 -0
  50. package/dist/likec4diagram/ui/search/utils.js +23 -0
  51. package/dist/likec4diagram/useLayoutConstraints.js +4 -5
  52. package/dist/likec4model/useLikeC4ElementsTree.d.ts +1 -0
  53. package/dist/likec4model/useLikeC4ElementsTree.js +1 -0
  54. package/dist/overlays/Overlays.js +9 -9
  55. package/dist/overlays/element-details/ElementDetailsCard.js +20 -13
  56. package/dist/overlays/overlay/Overlay.d.ts +6 -2
  57. package/dist/overlays/overlay/Overlay.js +18 -29
  58. package/dist/overlays/relationship-details/SelectEdge.js +1 -3
  59. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +6 -5
  60. package/dist/overlays/relationships-browser/SelectElement.js +10 -6
  61. package/dist/overlays/relationships-browser/actor.d.ts +2 -2
  62. package/dist/overlays/relationships-browser/actor.js +8 -8
  63. package/dist/overlays/relationships-browser/custom/nodeTypes.js +2 -2
  64. package/dist/style.css +1 -1
  65. package/package.json +13 -13
  66. package/src/LikeC4Diagram.tsx +0 -1
  67. package/src/base/index.ts +0 -2
  68. package/src/base/primitives/element/styles.css.ts +2 -2
  69. package/src/{base → components}/Link.css.ts +3 -3
  70. package/src/components/SearchControl.css.ts +69 -0
  71. package/src/components/SearchControl.tsx +33 -0
  72. package/src/context/DiagramFeatures.tsx +1 -1
  73. package/src/context/IconRenderer.tsx +54 -1
  74. package/src/globals.css.ts +0 -2
  75. package/src/hooks/useDiagram.ts +5 -0
  76. package/src/likec4diagram/DiagramActor.tsx +15 -2
  77. package/src/likec4diagram/DiagramUI.tsx +0 -4
  78. package/src/likec4diagram/XYFlow.tsx +39 -31
  79. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +2 -1
  80. package/src/likec4diagram/state/assign.ts +1 -1
  81. package/src/likec4diagram/state/machine.ts +40 -14
  82. package/src/likec4diagram/state/syncManualLayoutActor.ts +6 -9
  83. package/src/likec4diagram/ui/controls/Controls.tsx +37 -25
  84. package/src/likec4diagram/ui/controls/NavigationButtons.tsx +36 -58
  85. package/src/likec4diagram/ui/controls/ToggleReadonly.tsx +31 -0
  86. package/src/likec4diagram/ui/controls/styles.css.ts +3 -1
  87. package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +1 -1
  88. package/src/likec4diagram/ui/search/ElementsColumn.css.ts +119 -0
  89. package/src/likec4diagram/ui/search/ElementsColumn.tsx +291 -0
  90. package/src/likec4diagram/ui/search/LikeC4Search.css.ts +117 -0
  91. package/src/likec4diagram/ui/search/LikeC4Search.tsx +312 -0
  92. package/src/likec4diagram/ui/search/SearchInput.tsx +235 -0
  93. package/src/likec4diagram/ui/search/ViewsColum.tsx +158 -0
  94. package/src/likec4diagram/ui/search/ViewsColumn.css.ts +37 -0
  95. package/src/likec4diagram/ui/search/_shared.css.ts +104 -0
  96. package/src/likec4diagram/ui/search/state.ts +76 -0
  97. package/src/likec4diagram/ui/search/utils.ts +20 -0
  98. package/src/likec4diagram/useLayoutConstraints.ts +4 -5
  99. package/src/likec4model/useLikeC4ElementsTree.ts +4 -4
  100. package/src/overlays/Overlays.tsx +31 -25
  101. package/src/overlays/element-details/ElementDetailsCard.css.ts +4 -4
  102. package/src/overlays/element-details/ElementDetailsCard.tsx +245 -240
  103. package/src/overlays/overlay/Overlay.css.ts +10 -9
  104. package/src/overlays/overlay/Overlay.tsx +38 -26
  105. package/src/overlays/relationship-details/SelectEdge.css.ts +1 -0
  106. package/src/overlays/relationship-details/SelectEdge.tsx +2 -4
  107. package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +10 -5
  108. package/src/overlays/relationships-browser/SelectElement.tsx +88 -82
  109. package/src/overlays/relationships-browser/actor.ts +10 -10
  110. package/src/overlays/relationships-browser/custom/nodeTypes.tsx +2 -2
  111. package/dist/LikeC4Search.css.d.ts +0 -1
  112. package/dist/LikeC4Search.css.js +0 -5
  113. package/dist/LikeC4Search.d.ts +0 -2
  114. package/dist/LikeC4Search.js +0 -88
  115. package/src/LikeC4Search.css.ts +0 -12
  116. package/src/LikeC4Search.tsx +0 -91
  117. /package/dist/{base → components}/Link.css.d.ts +0 -0
  118. /package/dist/{base → components}/Link.d.ts +0 -0
  119. /package/dist/{base → components}/Link.js +0 -0
  120. /package/src/{base → components}/Link.tsx +0 -0
@@ -0,0 +1,72 @@
1
+ import { DiagramNode } from "@likec4/core";
2
+ import { createSafeContext } from "@mantine/core";
3
+ import { useCallbackRef } from "@mantine/hooks";
4
+ import { useStore } from "@nanostores/react";
5
+ import { atom, computed, onMount } from "nanostores";
6
+ import { useDeferredValue } from "react";
7
+ import { useDiagram } from "../../../hooks/useDiagram.js";
8
+ const $search = atom("");
9
+ function setSearch(term) {
10
+ $search.set(term);
11
+ }
12
+ function useSearch() {
13
+ return useStore($search);
14
+ }
15
+ const $normalizedSearch = computed($search, (search) => {
16
+ const v = search.trim().toLowerCase();
17
+ return v.length > 1 ? v : "";
18
+ });
19
+ function useNormalizedSearch() {
20
+ return useDeferredValue(useStore($normalizedSearch));
21
+ }
22
+ const [LikeC4SearchContext, useCloseSearch] = createSafeContext("LikeC4Search");
23
+ const $pickView = atom(null);
24
+ onMount($search, () => {
25
+ $pickView.set(null);
26
+ });
27
+ function usePickView() {
28
+ return useStore($pickView);
29
+ }
30
+ function setPickView(data) {
31
+ $pickView.set(data);
32
+ }
33
+ function wasResetPickView() {
34
+ if ($pickView.get() !== null) {
35
+ $pickView.set(null);
36
+ return true;
37
+ }
38
+ return false;
39
+ }
40
+ const $pickViewActive = computed($pickView, (pickView) => pickView !== null);
41
+ function useIsPickViewActive() {
42
+ return useStore($pickViewActive);
43
+ }
44
+ function useCloseSearchAndNavigateTo() {
45
+ const diagram = useDiagram();
46
+ const close = useCloseSearch();
47
+ return useCallbackRef((viewId, fromElementFqn) => {
48
+ close(() => {
49
+ var _a, _b;
50
+ fromElementFqn ?? (fromElementFqn = (_a = $pickView.get()) == null ? void 0 : _a.elementFqn);
51
+ setPickView(null);
52
+ const fromNode = fromElementFqn ? (_b = diagram.getContext().view.nodes.find((n) => DiagramNode.modelRef(n) === fromElementFqn)) == null ? void 0 : _b.id : void 0;
53
+ if (diagram.currentView().id === viewId && fromNode) {
54
+ diagram.focusNode(fromNode);
55
+ return;
56
+ }
57
+ diagram.navigateTo(viewId, fromNode);
58
+ });
59
+ });
60
+ }
61
+ export {
62
+ LikeC4SearchContext,
63
+ setPickView,
64
+ setSearch,
65
+ useCloseSearch,
66
+ useCloseSearchAndNavigateTo,
67
+ useIsPickViewActive,
68
+ useNormalizedSearch,
69
+ usePickView,
70
+ useSearch,
71
+ wasResetPickView
72
+ };
@@ -0,0 +1,3 @@
1
+ export declare function stopAndPrevent(e: React.KeyboardEvent | KeyboardEvent): void;
2
+ export declare function centerY(element: HTMLElement): number;
3
+ export declare function moveFocusToSearchInput(): void;
@@ -0,0 +1,23 @@
1
+ function stopAndPrevent(e) {
2
+ e.stopPropagation();
3
+ e.preventDefault();
4
+ return;
5
+ }
6
+ function centerY(element) {
7
+ const rect = element.getBoundingClientRect();
8
+ const y = rect.y + Math.floor(rect.height / 2);
9
+ return y;
10
+ }
11
+ function moveFocusToSearchInput() {
12
+ const input = document.getElementById("likec4searchinput");
13
+ if (input) {
14
+ const length = input.value.length;
15
+ input.focus();
16
+ input.setSelectionRange(length, length);
17
+ }
18
+ }
19
+ export {
20
+ centerY,
21
+ moveFocusToSearchInput,
22
+ stopAndPrevent
23
+ };
@@ -6,7 +6,6 @@ import "@xyflow/react";
6
6
  import { getNodeDimensions } from "@xyflow/system";
7
7
  import { useRef, useMemo } from "react";
8
8
  import { pipe, filter, map, hasAtLeast, isNullish } from "remeda";
9
- import { useSyncedRef } from "@react-hookz/web";
10
9
  import { useDiagram } from "../hooks/useDiagram.js";
11
10
  import { useXYStoreApi } from "../hooks/useXYFlow.js";
12
11
  class Rect {
@@ -192,11 +191,11 @@ function createLayoutConstraints(xyflowApi, editingNodeIds) {
192
191
  }
193
192
  function useLayoutConstraints() {
194
193
  const xystore = useXYStoreApi();
195
- const diagram = useSyncedRef(useDiagram());
194
+ const diagram = useDiagram();
196
195
  const solverRef = useRef(void 0);
197
196
  return useMemo(() => ({
198
197
  onNodeDragStart: (_event, xynode) => {
199
- diagram.current.cancelSaveManualLayout();
198
+ diagram.cancelSaveManualLayout();
200
199
  const { nodeLookup } = xystore.getState();
201
200
  const draggingNodes = pipe(
202
201
  Array.from(nodeLookup.values()),
@@ -219,10 +218,10 @@ function useLayoutConstraints() {
219
218
  onNodeDragStop: () => {
220
219
  var _a;
221
220
  (_a = solverRef.current) == null ? void 0 : _a.updateXYFlowNodes();
222
- diagram.current.scheduleSaveManualLayout();
221
+ diagram.scheduleSaveManualLayout();
223
222
  solverRef.current = void 0;
224
223
  }
225
- }), [xystore]);
224
+ }), [xystore, diagram]);
226
225
  }
227
226
  export {
228
227
  createLayoutConstraints,
@@ -4,6 +4,7 @@ interface LikeC4ModelTreeNodeData {
4
4
  value: Fqn;
5
5
  children: LikeC4ModelTreeNodeData[];
6
6
  }
7
+ export declare const sortByLabel: (a: LikeC4ModelTreeNodeData, b: LikeC4ModelTreeNodeData) => 0 | 1 | -1;
7
8
  /**
8
9
  * Returns a tree of elements in the model.
9
10
  * If `viewId` is provided, returns the tree of elements in the view.
@@ -21,5 +21,6 @@ function useLikeC4ElementsTree(viewId) {
21
21
  }, [model, viewId ?? null]);
22
22
  }
23
23
  export {
24
+ sortByLabel,
24
25
  useLikeC4ElementsTree
25
26
  };
@@ -3,7 +3,7 @@ import { Box, Notification, Code, Group, Button } from "@mantine/core";
3
3
  import { useCallbackRef } from "@mantine/hooks";
4
4
  import { IconX } from "@tabler/icons-react";
5
5
  import { deepEqual } from "fast-equals";
6
- import { useReducedMotion } from "framer-motion";
6
+ import { useReducedMotion, AnimatePresence } from "framer-motion";
7
7
  import { animate } from "framer-motion/dom";
8
8
  import { memo, useMemo, useEffect } from "react";
9
9
  import { ErrorBoundary } from "react-error-boundary";
@@ -79,23 +79,23 @@ const Overlays = memo(() => {
79
79
  diagram.closeOverlay();
80
80
  });
81
81
  return /* @__PURE__ */ jsx(DiagramFeatures.Overlays, { children: /* @__PURE__ */ jsxs(ErrorBoundary, { FallbackComponent: Fallback, onReset: onClose, children: [
82
- relationshipsBrowserActor && /* @__PURE__ */ jsx(
82
+ /* @__PURE__ */ jsx(AnimatePresence, { onExitComplete: onClose, children: relationshipsBrowserActor && /* @__PURE__ */ jsx(
83
83
  Overlay,
84
84
  {
85
- onClose,
85
+ onClose: () => relationshipsBrowserActor.send({ type: "close" }),
86
86
  children: /* @__PURE__ */ jsx(RelationshipsBrowser, { actorRef: relationshipsBrowserActor })
87
87
  },
88
88
  "relationships-browser"
89
- ),
90
- relationshipDetailsActor && /* @__PURE__ */ jsx(
89
+ ) }),
90
+ /* @__PURE__ */ jsx(AnimatePresence, { onExitComplete: onClose, children: relationshipDetailsActor && /* @__PURE__ */ jsx(
91
91
  Overlay,
92
92
  {
93
- onClose,
93
+ onClose: () => relationshipDetailsActor.send({ type: "close" }),
94
94
  children: /* @__PURE__ */ jsx(RelationshipDetails, { actorRef: relationshipDetailsActor })
95
95
  },
96
96
  "relationship-details"
97
- ),
98
- !!activeElementDetailsOf && /* @__PURE__ */ jsx(
97
+ ) }),
98
+ /* @__PURE__ */ jsx(AnimatePresence, { children: !!activeElementDetailsOf && /* @__PURE__ */ jsx(
99
99
  ElementDetailsCard,
100
100
  {
101
101
  fqn: activeElementDetailsOf,
@@ -105,7 +105,7 @@ const Overlays = memo(() => {
105
105
  onClose
106
106
  },
107
107
  "element-details"
108
- )
108
+ ) })
109
109
  ] }) });
110
110
  });
111
111
  Overlays.displayName = "Overlays";
@@ -1,12 +1,13 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { isScopedElementView, isDeploymentView } from "@likec4/core";
3
- import { RemoveScroll, Card, Box, Group, Text, CloseButton, Badge, Flex, ActionIconGroup, ActionIcon, Tooltip as Tooltip$1, Tabs, TabsList, TabsTab, TabsPanel, ScrollArea, Stack, Divider as Divider$1, Code, UnstyledButton, ThemeIcon } from "@mantine/core";
3
+ import { Card, Box, Group, Text, CloseButton, Badge, Flex, ActionIconGroup, ActionIcon, Tooltip as Tooltip$1, Tabs, TabsList, TabsTab, TabsPanel, ScrollArea, Stack, Divider as Divider$1, Code, UnstyledButton, ThemeIcon } from "@mantine/core";
4
4
  import { useViewportSize, useSessionStorage } from "@mantine/hooks";
5
- import { useSyncedRef, useDebouncedCallback } from "@react-hookz/web";
5
+ import { useSyncedRef, useDebouncedCallback, useTimeoutEffect } from "@react-hookz/web";
6
6
  import { IconExternalLink, IconFileSymlink, IconZoomScan, IconStack2 } from "@tabler/icons-react";
7
7
  import { useDragControls, useMotionValue, m } from "framer-motion";
8
- import { useCallback, useRef } from "react";
8
+ import { useState, useCallback, useRef } from "react";
9
9
  import { pipe, map, partition, only, clamp, isNullish } from "remeda";
10
+ import { Link } from "../../components/Link.js";
10
11
  import { useDiagram } from "../../hooks/useDiagram.js";
11
12
  import { dialog, card, cardHeader, title, tabsPanel, tabsTab, tabsList, tabsRoot, propertiesGrid, resizeHandle, elementIcon, propertyLabel, viewButton, viewButtonTitle } from "./ElementDetailsCard.css.js";
12
13
  import { TabPanelDeployments } from "./TabPanelDeployments.js";
@@ -16,7 +17,6 @@ import { useLikeC4Model } from "../../likec4model/useLikeC4Model.js";
16
17
  import { useUpdateEffect } from "../../hooks/useUpdateEffect.js";
17
18
  import { IconRenderer } from "../../context/IconRenderer.js";
18
19
  import { IfEnabled, DiagramFeatures } from "../../context/DiagramFeatures.js";
19
- import { Link } from "../../base/Link.js";
20
20
  const Divider = Divider$1.withProps({
21
21
  mb: 8,
22
22
  labelPosition: "left",
@@ -54,6 +54,7 @@ function ElementDetailsCard({
54
54
  onClose
55
55
  }) {
56
56
  var _a, _b, _c;
57
+ const [opened, setOpened] = useState(false);
57
58
  const windowSize = useViewportSize();
58
59
  const windowWidth = windowSize.width || window.innerWidth || 1200, windowHeight = windowSize.height || window.innerHeight || 800;
59
60
  const [activeTab, setActiveTab] = useSessionStorage({
@@ -138,11 +139,21 @@ function ElementDetailsCard({
138
139
  },
139
140
  className: elementIcon
140
141
  });
142
+ useTimeoutEffect(() => {
143
+ var _a2, _b2;
144
+ if (!((_a2 = ref.current) == null ? void 0 : _a2.open)) {
145
+ (_b2 = ref.current) == null ? void 0 : _b2.showModal();
146
+ }
147
+ }, 30);
148
+ useTimeoutEffect(() => {
149
+ setOpened(true);
150
+ }, 120);
141
151
  return /* @__PURE__ */ jsx(
142
152
  m.dialog,
143
153
  {
144
154
  ref,
145
155
  className: dialog,
156
+ layout: true,
146
157
  initial: {
147
158
  "--backdrop-blur": "0px",
148
159
  "--backdrop-opacity": "10%"
@@ -158,22 +169,18 @@ function ElementDetailsCard({
158
169
  duration: 0.1
159
170
  }
160
171
  },
161
- onAnimationStart: () => {
162
- var _a2;
163
- (_a2 = ref.current) == null ? void 0 : _a2.showModal();
164
- },
165
172
  onClick: (e) => {
166
- var _a2, _b2;
173
+ var _a2, _b2, _c2;
167
174
  if (((_b2 = (_a2 = e.target) == null ? void 0 : _a2.nodeName) == null ? void 0 : _b2.toUpperCase()) === "DIALOG") {
168
175
  e.stopPropagation();
169
- close();
176
+ (_c2 = ref.current) == null ? void 0 : _c2.close();
170
177
  }
171
178
  },
172
179
  onClose: (e) => {
173
180
  e.stopPropagation();
174
181
  close();
175
182
  },
176
- children: /* @__PURE__ */ jsx(RemoveScroll, { forwardProps: true, children: /* @__PURE__ */ jsxs(
183
+ children: /* @__PURE__ */ jsxs(
177
184
  Card,
178
185
  {
179
186
  drag: true,
@@ -347,7 +354,7 @@ function ElementDetailsCard({
347
354
  enableRelationshipBrowser: false,
348
355
  enableNavigateTo: false
349
356
  },
350
- children: !!nodeModel && activeTab === "Relationships" && /* @__PURE__ */ jsx(
357
+ children: opened && !!nodeModel && activeTab === "Relationships" && /* @__PURE__ */ jsx(
351
358
  TabPanelRelationships,
352
359
  {
353
360
  element: elementModel,
@@ -399,7 +406,7 @@ function ElementDetailsCard({
399
406
  )
400
407
  ]
401
408
  }
402
- ) })
409
+ )
403
410
  }
404
411
  );
405
412
  }
@@ -1,8 +1,12 @@
1
1
  import { HTMLMotionProps } from 'framer-motion';
2
- import { PropsWithChildren, ForwardRefExoticComponent, RefAttributes } from 'react';
2
+ import { PropsWithChildren } from 'react';
3
3
  type OverlayProps = PropsWithChildren<HTMLMotionProps<'dialog'> & {
4
+ classes?: {
5
+ dialog?: string;
6
+ body?: string;
7
+ };
4
8
  onClose: () => void;
5
9
  onClick?: never;
6
10
  }>;
7
- export declare const Overlay: ForwardRefExoticComponent<Omit<OverlayProps, "ref"> & RefAttributes<HTMLDialogElement>>;
11
+ export declare function Overlay({ children, onClose, className, classes, ...rest }: OverlayProps): import("react/jsx-runtime").JSX.Element;
8
12
  export {};
@@ -1,12 +1,11 @@
1
1
  import { jsx, Fragment } from "react/jsx-runtime";
2
2
  import { RemoveScroll, Box } from "@mantine/core";
3
- import { useMergedRef } from "@mantine/hooks";
4
- import { useSyncedRef, useDebouncedCallback } from "@react-hookz/web";
3
+ import { useSyncedRef, useDebouncedCallback, useTimeoutEffect } from "@react-hookz/web";
5
4
  import clsx from "clsx";
6
5
  import { m } from "framer-motion";
7
- import { forwardRef, useState, useRef, useLayoutEffect } from "react";
6
+ import { useState, useRef } from "react";
8
7
  import { body, dialog } from "./Overlay.css.js";
9
- const Overlay = forwardRef(({ children, onClose, className, ...rest }, ref) => {
8
+ function Overlay({ children, onClose, className, classes, ...rest }) {
10
9
  const [opened, setOpened] = useState(false);
11
10
  const dialogRef = useRef(null);
12
11
  const onCloseRef = useSyncedRef(onClose);
@@ -17,23 +16,18 @@ const Overlay = forwardRef(({ children, onClose, className, ...rest }, ref) => {
17
16
  [],
18
17
  50
19
18
  );
20
- useLayoutEffect(() => {
21
- var _a;
22
- const cancel = (e) => {
23
- e.preventDefault();
24
- onCloseRef.current();
25
- };
26
- (_a = dialogRef.current) == null ? void 0 : _a.addEventListener("cancel", cancel, { capture: true });
27
- return () => {
28
- var _a2;
29
- (_a2 = dialogRef.current) == null ? void 0 : _a2.removeEventListener("cancel", cancel, { capture: true });
30
- };
31
- }, []);
19
+ useTimeoutEffect(() => {
20
+ var _a, _b;
21
+ if (!((_a = dialogRef.current) == null ? void 0 : _a.open)) {
22
+ (_b = dialogRef.current) == null ? void 0 : _b.showModal();
23
+ }
24
+ setOpened(true);
25
+ }, 30);
32
26
  return /* @__PURE__ */ jsx(
33
27
  m.dialog,
34
28
  {
35
- ref: useMergedRef(ref, dialogRef),
36
- className: clsx(dialog, className),
29
+ ref: dialogRef,
30
+ className: clsx(dialog, classes == null ? void 0 : classes.dialog, className),
37
31
  initial: {
38
32
  "--backdrop-blur": "0px",
39
33
  "--backdrop-opacity": "5%",
@@ -50,13 +44,8 @@ const Overlay = forwardRef(({ children, onClose, className, ...rest }, ref) => {
50
44
  // delay: 0.25,
51
45
  // }
52
46
  },
53
- onAnimationStart: () => {
54
- var _a;
55
- (_a = dialogRef.current) == null ? void 0 : _a.showModal();
56
- setOpened(true);
57
- },
58
47
  exit: {
59
- opacity: 0.1,
48
+ opacity: 0,
60
49
  translateY: -10,
61
50
  "--backdrop-blur": "0px",
62
51
  "--backdrop-opacity": "0%",
@@ -65,22 +54,22 @@ const Overlay = forwardRef(({ children, onClose, className, ...rest }, ref) => {
65
54
  }
66
55
  },
67
56
  onClick: (e) => {
68
- var _a, _b;
57
+ var _a, _b, _c;
69
58
  if (((_b = (_a = e.target) == null ? void 0 : _a.nodeName) == null ? void 0 : _b.toUpperCase()) === "DIALOG") {
70
59
  e.stopPropagation();
71
- close();
60
+ (_c = dialogRef.current) == null ? void 0 : _c.close();
61
+ return;
72
62
  }
73
63
  },
74
64
  onClose: (e) => {
75
- e.preventDefault();
76
65
  e.stopPropagation();
77
66
  close();
78
67
  },
79
68
  ...rest,
80
- children: /* @__PURE__ */ jsx(RemoveScroll, { forwardProps: true, children: /* @__PURE__ */ jsx(Box, { className: body, children: opened && /* @__PURE__ */ jsx(Fragment, { children }) }) })
69
+ children: /* @__PURE__ */ jsx(RemoveScroll, { forwardProps: true, children: /* @__PURE__ */ jsx(Box, { className: clsx(body, classes == null ? void 0 : classes.body), children: opened && /* @__PURE__ */ jsx(Fragment, { children }) }) })
81
70
  }
82
71
  );
83
- });
72
+ }
84
73
  export {
85
74
  Overlay
86
75
  };
@@ -81,7 +81,7 @@ const SelectEdge = ({
81
81
  ]
82
82
  }
83
83
  ) }),
84
- /* @__PURE__ */ jsx(PopoverDropdown, { p: 0, miw: 250, maw: 420, children: /* @__PURE__ */ jsx(ScrollAreaAutosize, { className: scrollArea, scrollbars: "y", type: "never", viewportRef: viewport, children: /* @__PURE__ */ jsx(Box, { className: edgeGrid, p: "xs", children: edges.map((e) => /* @__PURE__ */ jsxs(
84
+ /* @__PURE__ */ jsx(PopoverDropdown, { p: 0, miw: 250, maw: 400, children: /* @__PURE__ */ jsx(ScrollAreaAutosize, { className: scrollArea, scrollbars: "y", type: "never", viewportRef: viewport, children: /* @__PURE__ */ jsx(Box, { className: edgeGrid, p: "xs", maw: 400, children: edges.map((e) => /* @__PURE__ */ jsxs(
85
85
  "div",
86
86
  {
87
87
  className: edgeRow,
@@ -95,7 +95,6 @@ const SelectEdge = ({
95
95
  Box,
96
96
  {
97
97
  className: edgeSource,
98
- maw: 160,
99
98
  mod: {
100
99
  "edge-id": e.id,
101
100
  "likec4-color": e.source.color
@@ -108,7 +107,6 @@ const SelectEdge = ({
108
107
  Box,
109
108
  {
110
109
  className: edgeTarget,
111
- maw: 160,
112
110
  mod: {
113
111
  "likec4-color": e.target.color
114
112
  },
@@ -5,8 +5,8 @@ import { IconX, IconChevronLeft, IconChevronRight } from "@tabler/icons-react";
5
5
  import { ReactFlowProvider, useStoreApi, Panel } from "@xyflow/react";
6
6
  import clsx from "clsx";
7
7
  import { shallowEqual } from "fast-equals";
8
- import { AnimatePresence, m } from "framer-motion";
9
- import { useRef, memo, useEffect } from "react";
8
+ import { AnimatePresence, LayoutGroup, m } from "framer-motion";
9
+ import { useId, useRef, memo, useEffect } from "react";
10
10
  import { BaseXYFlow } from "../../base/BaseXYFlow.js";
11
11
  import { useRelationshipsView } from "./-useRelationshipsView.js";
12
12
  import { ViewPadding } from "./const.js";
@@ -15,6 +15,7 @@ import { nodeTypes } from "./custom/nodeTypes.js";
15
15
  import { RelationshipsBrowserActorContext, useRelationshipsBrowser, useRelationshipsBrowserState } from "./hooks.js";
16
16
  import { SelectElement } from "./SelectElement.js";
17
17
  function RelationshipsBrowser({ actorRef }) {
18
+ const id = useId();
18
19
  const initialRef = useRef(null);
19
20
  if (initialRef.current == null) {
20
21
  initialRef.current = {
@@ -22,7 +23,7 @@ function RelationshipsBrowser({ actorRef }) {
22
23
  initialEdges: []
23
24
  };
24
25
  }
25
- return /* @__PURE__ */ jsx(RelationshipsBrowserActorContext.Provider, { value: actorRef, children: /* @__PURE__ */ jsx(ReactFlowProvider, { ...initialRef.current, children: /* @__PURE__ */ jsx(RelationshipsBrowserXYFlow, {}) }) });
26
+ return /* @__PURE__ */ jsx(RelationshipsBrowserActorContext.Provider, { value: actorRef, children: /* @__PURE__ */ jsx(ReactFlowProvider, { ...initialRef.current, children: /* @__PURE__ */ jsx(AnimatePresence, { children: /* @__PURE__ */ jsx(LayoutGroup, { id, children: /* @__PURE__ */ jsx(RelationshipsBrowserXYFlow, {}) }) }) }) });
26
27
  }
27
28
  const selector = (state) => ({
28
29
  initialized: state.context.initialized,
@@ -76,10 +77,10 @@ const RelationshipsBrowserXYFlow = memo(() => {
76
77
  browser.send({ type: "xyflow.resized" });
77
78
  }),
78
79
  onNodesChange: useCallbackRef((changes) => {
79
- browser.send({ type: "xyflow.applyNodeChages", changes });
80
+ browser.send({ type: "xyflow.applyNodeChanges", changes });
80
81
  }),
81
82
  onEdgesChange: useCallbackRef((changes) => {
82
- browser.send({ type: "xyflow.applyEdgeChages", changes });
83
+ browser.send({ type: "xyflow.applyEdgeChanges", changes });
83
84
  }),
84
85
  nodesDraggable: false,
85
86
  fitView: false,
@@ -1,6 +1,6 @@
1
- import { jsxs, jsx } from "react/jsx-runtime";
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { ancestorsFqn } from "@likec4/core";
3
- import { useTree, useComputedColorScheme, Popover, PopoverTarget, Button, PopoverDropdown, ScrollAreaAutosize, Tree, Group, ActionIcon, Box, Text } from "@mantine/core";
3
+ import { useTree, useComputedColorScheme, Box, Popover, PopoverTarget, Button, PopoverDropdown, ScrollAreaAutosize, Tree, Group, ActionIcon, Text } from "@mantine/core";
4
4
  import { IconSelector, IconChevronRight } from "@tabler/icons-react";
5
5
  import { useRef, useEffect } from "react";
6
6
  import * as SelectElement_css from "./SelectElement.css.js";
@@ -27,12 +27,12 @@ const SelectElement = ({
27
27
  tree.select(subjectId);
28
28
  }, [subjectId]);
29
29
  const theme = useComputedColorScheme();
30
- return /* @__PURE__ */ jsxs(
30
+ return /* @__PURE__ */ jsx(Box, { pos: "relative", children: /* @__PURE__ */ jsxs(
31
31
  Popover,
32
32
  {
33
- position: "bottom",
33
+ position: "bottom-start",
34
34
  shadow: "md",
35
- keepMounted: true,
35
+ keepMounted: false,
36
36
  withinPortal: false,
37
37
  closeOnClickOutside: true,
38
38
  clickOutsideEvents: ["pointerdown", "mousedown", "click"],
@@ -67,6 +67,10 @@ const SelectElement = ({
67
67
  classNames: SelectElement_css,
68
68
  levelOffset: 8,
69
69
  styles: {
70
+ root: {
71
+ maxWidth: 400,
72
+ overflow: "hidden"
73
+ },
70
74
  label: {
71
75
  paddingTop: 5,
72
76
  paddingBottom: 6
@@ -122,7 +126,7 @@ const SelectElement = ({
122
126
  ) }) })
123
127
  ]
124
128
  }
125
- );
129
+ ) });
126
130
  };
127
131
  export {
128
132
  SelectElement
@@ -33,10 +33,10 @@ export type Events = {
33
33
  type: 'xyflow.edgeClick';
34
34
  edge: RelationshipsBrowserTypes.Edge;
35
35
  } | {
36
- type: 'xyflow.applyNodeChages';
36
+ type: 'xyflow.applyNodeChanges';
37
37
  changes: NodeChange<RelationshipsBrowserTypes.Node>[];
38
38
  } | {
39
- type: 'xyflow.applyEdgeChages';
39
+ type: 'xyflow.applyEdgeChanges';
40
40
  changes: EdgeChange<RelationshipsBrowserTypes.Edge>[];
41
41
  } | {
42
42
  type: 'xyflow.paneClick';
@@ -99,7 +99,7 @@ const relationshipsBrowserActor = setup({
99
99
  const currentSubjectNode = findRootSubject(currentNodes);
100
100
  const existingNode = navigateFromNode ? currentNodes.find((n) => n.id === navigateFromNode) : currentNodes.find((n) => n.type !== "empty" && n.data.column !== "subjects" && n.data.fqn === subjectId);
101
101
  if (!nextSubjectNode || !existingNode || nextSubjectNode.type === "empty" || !currentSubjectNode || nextSubjectNode.data.fqn === currentSubjectNode.data.fqn) {
102
- xyflow.setViewport(nextviewport);
102
+ await xyflow.setViewport(nextviewport);
103
103
  return updateXYData();
104
104
  }
105
105
  const nextSubjectCenter = {
@@ -168,7 +168,7 @@ const relationshipsBrowserActor = setup({
168
168
  return updateXYData();
169
169
  }
170
170
  await xyflow.setCenter(currentSubjectCenter.x, currentSubjectCenter.y, { zoom, duration: 350 });
171
- xyflow.setCenter(nextSubjectCenter.x, nextSubjectCenter.y, { zoom });
171
+ await xyflow.setCenter(nextSubjectCenter.x, nextSubjectCenter.y, { zoom });
172
172
  return updateXYData();
173
173
  })
174
174
  }
@@ -260,11 +260,11 @@ const relationshipsBrowserActor = setup({
260
260
  xyedges: ({ event }) => event.xyedges
261
261
  })
262
262
  },
263
- "xyflow.applyEdgeChages": {
264
- // actions: log('layouting: ignore xyflow.applyEdgeChages'),
263
+ "xyflow.applyEdgeChanges": {
264
+ // actions: log('layouting: ignore xyflow.applyEdgeChanges'),
265
265
  },
266
- "xyflow.applyNodeChages": {
267
- // actions: log('layouting: ignore xyflow.applyNodeChages'),
266
+ "xyflow.applyNodeChanges": {
267
+ // actions: log('layouting: ignore xyflow.applyNodeChanges'),
268
268
  }
269
269
  }
270
270
  }
@@ -335,14 +335,14 @@ const relationshipsBrowserActor = setup({
335
335
  }
336
336
  },
337
337
  on: {
338
- "xyflow.applyNodeChages": {
338
+ "xyflow.applyNodeChanges": {
339
339
  actions: assign({
340
340
  xynodes: ({ context, event }) => {
341
341
  return applyNodeChanges(event.changes, context.xynodes);
342
342
  }
343
343
  })
344
344
  },
345
- "xyflow.applyEdgeChages": {
345
+ "xyflow.applyEdgeChanges": {
346
346
  actions: assign({
347
347
  xyedges: ({ context, event }) => {
348
348
  return applyEdgeChanges(event.changes, context.xyedges);
@@ -17,13 +17,13 @@ const nodeTypes = {
17
17
  /* @__PURE__ */ jsx(ElementTitle, { ...props, iconSize: 40 }),
18
18
  /* @__PURE__ */ jsx(ElementActions, { ...props }),
19
19
  /* @__PURE__ */ jsx(ElementPorts, { ...props })
20
- ] });
20
+ ] }, props.id);
21
21
  }),
22
22
  compound: customNode((props) => {
23
23
  return /* @__PURE__ */ jsxs(CompoundNodeContainer, { component: m.div, layoutId: props.id, nodeProps: props, children: [
24
24
  /* @__PURE__ */ jsx(CompoundTitle, { ...props }),
25
25
  /* @__PURE__ */ jsx(CompoundPorts, { ...props })
26
- ] });
26
+ ] }, props.id);
27
27
  }),
28
28
  empty: customNode((props) => {
29
29
  return /* @__PURE__ */ jsx(EmptyNode, { ...props });