@likec4/diagram 1.40.0 → 1.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/bundle/{chunk-CDr-4Ymp.js → chunk-FGcODVxo.js} +232 -229
  2. package/bundle/custom.js +59 -59
  3. package/bundle/index.js +140 -100
  4. package/dist/base/primitives/MarkdownBlock.js +2 -0
  5. package/dist/components/Link.js +28 -20
  6. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +1 -1
  7. package/dist/navigationpanel/controls/ViewDetailsCard.js +22 -10
  8. package/dist/overlays/element-details/ElementDetailsCard.css.js +7 -1
  9. package/dist/overlays/element-details/ElementDetailsCard.js +17 -19
  10. package/dist/overlays/relationship-details/layout.d.ts +3 -2
  11. package/dist/overlays/relationship-details/layout.js +1 -2
  12. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -1
  13. package/dist/overlays/relationships-browser/layout.js +1 -1
  14. package/dist/search/components/ElementsColumn.js +1 -1
  15. package/dist/state/DiagramActorProvider.js +23 -32
  16. package/dist/styles-min.css +1 -1
  17. package/dist/styles.css +1 -1
  18. package/dist/styles.css2.js +1 -1
  19. package/package.json +4 -4
  20. package/panda.buildinfo.json +15 -15
  21. package/src/base/primitives/MarkdownBlock.tsx +2 -0
  22. package/src/components/Link.tsx +21 -18
  23. package/src/navigationpanel/controls/ViewDetailsCard.tsx +24 -10
  24. package/src/overlays/element-details/ElementDetailsCard.css.ts +7 -1
  25. package/src/overlays/element-details/ElementDetailsCard.tsx +24 -25
  26. package/src/overlays/relationship-details/layout.ts +4 -3
  27. package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -1
  28. package/src/overlays/relationships-browser/layout.ts +1 -1
  29. package/src/search/components/ElementsColumn.tsx +1 -1
  30. package/src/state/DiagramActorProvider.tsx +29 -45
@@ -12,6 +12,7 @@ const MarkdownBlock = forwardRef(({
12
12
  hideIfEmpty = false,
13
13
  emptyText = "no content",
14
14
  className,
15
+ style,
15
16
  ...props
16
17
  }, ref) => {
17
18
  if (value.isEmpty && hideIfEmpty) {
@@ -31,6 +32,7 @@ const MarkdownBlock = forwardRef(({
31
32
  className
32
33
  ),
33
34
  style: {
35
+ ...style,
34
36
  ...props.fontSize && {
35
37
  "--text-fz": `var(--font-sizes-${props.fontSize}, var(--font-sizes-md))`
36
38
  },
@@ -1,5 +1,6 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { css, cx } from '@likec4/styles/css';
3
+ import { styled } from '@likec4/styles/jsx';
3
4
  import { Badge, CopyButton, ActionIcon } from '@mantine/core';
4
5
  import { forwardRef } from 'react';
5
6
  import { GithubIcon } from './GithubIcon.js';
@@ -66,15 +67,22 @@ const Link = forwardRef(
66
67
  userSelect: "none",
67
68
  pointerEvents: "none",
68
69
  _groupHover: {
69
- color: "[inherit]",
70
+ color: "[var(--badge-color)]",
70
71
  opacity: 0.7
71
72
  }
72
73
  }
73
- }),
74
- label: css({
75
- "& > a": {
76
- color: "[inherit]",
77
- cursor: "pointer",
74
+ })
75
+ },
76
+ children: /* @__PURE__ */ jsxs(
77
+ styled.a,
78
+ {
79
+ href: url,
80
+ target: "_blank",
81
+ style: {
82
+ color: "var(--badge-color)",
83
+ cursor: "pointer"
84
+ },
85
+ css: {
78
86
  transition: "fast",
79
87
  opacity: {
80
88
  base: 0.7,
@@ -84,20 +92,20 @@ const Link = forwardRef(
84
92
  base: "none",
85
93
  _hover: "underline"
86
94
  }
87
- }
88
- })
89
- },
90
- children: /* @__PURE__ */ jsxs("a", { href: url, target: "_blank", children: [
91
- isGithub && /* @__PURE__ */ jsx(
92
- GithubIcon,
93
- {
94
- height: "12",
95
- width: "12",
96
- style: { verticalAlign: "middle", marginRight: "4px" }
97
- }
98
- ),
99
- isGithub ? url.replace(GITHUB_PREFIX, "") : url
100
- ] })
95
+ },
96
+ children: [
97
+ isGithub && /* @__PURE__ */ jsx(
98
+ GithubIcon,
99
+ {
100
+ height: "12",
101
+ width: "12",
102
+ style: { verticalAlign: "middle", marginRight: "4px" }
103
+ }
104
+ ),
105
+ isGithub ? url.replace(GITHUB_PREFIX, "") : url
106
+ ]
107
+ }
108
+ )
101
109
  }
102
110
  );
103
111
  }
@@ -38,7 +38,7 @@ export declare const RelationshipEdge: FunctionComponent<{
38
38
  points: NonEmptyArray<Point>;
39
39
  color: Color | undefined;
40
40
  dir: "forward" | "back" | "both" | undefined;
41
- technology: string | undefined;
41
+ technology: string | null | undefined;
42
42
  labelBBox: BBox | null | undefined;
43
43
  line: RelationshipLineType | undefined;
44
44
  head: RelationshipArrowType | undefined;
@@ -4,8 +4,9 @@ import { HStack, Box, styled } from '@likec4/styles/jsx';
4
4
  import { hstack, vstack } from '@likec4/styles/patterns';
5
5
  import { Popover, UnstyledButton, Text, Badge } from '@mantine/core';
6
6
  import * as m from 'motion/react-m';
7
+ import { useState } from 'react';
7
8
  import { Link } from '../../components/Link.js';
8
- import { useDiagram } from '../../hooks/useDiagram.js';
9
+ import { useDiagram, useOnDiagramEvent } from '../../hooks/useDiagram.js';
9
10
  import { useMantinePortalProps } from '../../hooks/useMantinePortalProps.js';
10
11
  import { useNavigationActorSnapshot } from '../hooks.js';
11
12
  import IconId from '../../node_modules/.pnpm/@tabler_icons-react@3.34.1_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconId.js';
@@ -25,6 +26,7 @@ const selector = ({ context }) => {
25
26
  };
26
27
  };
27
28
  const ViewDetailsCard = (props) => {
29
+ const [opened, setOpened] = useState(false);
28
30
  const data = useNavigationActorSnapshot(selector);
29
31
  const portalProps = useMantinePortalProps();
30
32
  return /* @__PURE__ */ jsxs(
@@ -33,20 +35,21 @@ const ViewDetailsCard = (props) => {
33
35
  position: "bottom-end",
34
36
  shadow: "xl",
35
37
  clickOutsideEvents: ["pointerdown", "mousedown", "click"],
36
- trapFocus: true,
37
38
  offset: {
38
39
  mainAxis: 4
39
40
  },
41
+ opened,
42
+ onChange: setOpened,
40
43
  ...portalProps,
41
44
  ...props,
42
45
  children: [
43
- /* @__PURE__ */ jsx(ViewDetailsCardTrigger, { linksCount: data.links.length }),
44
- /* @__PURE__ */ jsx(ViewDetailsCardDropdown, { data })
46
+ /* @__PURE__ */ jsx(ViewDetailsCardTrigger, { linksCount: data.links.length, onOpen: () => setOpened(true) }),
47
+ opened && /* @__PURE__ */ jsx(ViewDetailsCardDropdown, { data, onClose: () => setOpened(false) })
45
48
  ]
46
49
  }
47
50
  );
48
51
  };
49
- const ViewDetailsCardTrigger = ({ linksCount }) => /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsxs(
52
+ const ViewDetailsCardTrigger = ({ linksCount, onOpen }) => /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsxs(
50
53
  UnstyledButton,
51
54
  {
52
55
  component: m.button,
@@ -55,6 +58,10 @@ const ViewDetailsCardTrigger = ({ linksCount }) => /* @__PURE__ */ jsx(Popover.T
55
58
  scale: 0.95,
56
59
  translateY: 1
57
60
  },
61
+ onClick: (e) => {
62
+ e.stopPropagation();
63
+ onOpen();
64
+ },
58
65
  className: cx(
59
66
  "group",
60
67
  hstack({
@@ -115,9 +122,12 @@ const ViewDetailsCardDropdown = ({
115
122
  tags,
116
123
  links,
117
124
  relativePath
118
- }
125
+ },
126
+ onClose
119
127
  }) => {
120
128
  const diagram = useDiagram();
129
+ useOnDiagramEvent("paneClick", onClose);
130
+ useOnDiagramEvent("nodeClick", onClose);
121
131
  return /* @__PURE__ */ jsxs(
122
132
  Popover.Dropdown,
123
133
  {
@@ -128,9 +138,10 @@ const ViewDetailsCardDropdown = ({
128
138
  layerStyle: "likec4.dropdown",
129
139
  gap: "md",
130
140
  padding: "md",
141
+ paddingBottom: "lg",
131
142
  pointerEvents: "all",
132
- maxWidth: "calc(100cqw - 32px)",
133
- minWidth: "calc(100cqw - 50px)",
143
+ maxWidth: "calc(100cqw - 52px)",
144
+ minWidth: "200px",
134
145
  maxHeight: "calc(100cqh - 100px)",
135
146
  width: "max-content",
136
147
  cursor: "default",
@@ -147,7 +158,7 @@ const ViewDetailsCardDropdown = ({
147
158
  ),
148
159
  children: [
149
160
  /* @__PURE__ */ jsxs("section", { children: [
150
- /* @__PURE__ */ jsx(Text, { component: "div", fw: 500, size: "xl", children: title }),
161
+ /* @__PURE__ */ jsx(Text, { component: "div", fw: 500, size: "xl", lh: "sm", children: title }),
151
162
  /* @__PURE__ */ jsxs(HStack, { alignItems: "flex-start", mt: "1", children: [
152
163
  /* @__PURE__ */ jsx(ViewBadge, { label: "id", value: id }),
153
164
  /* @__PURE__ */ jsx(HStack, { gap: "xs", flexWrap: "wrap", children: tags.map((tag, i) => /* @__PURE__ */ jsx(
@@ -168,7 +179,7 @@ const ViewDetailsCardDropdown = ({
168
179
  /* @__PURE__ */ jsx(SectionHeader, { children: "Links" }),
169
180
  /* @__PURE__ */ jsx(HStack, { gap: "xs", flexWrap: "wrap", children: links.map((link, i) => /* @__PURE__ */ jsx(Link, { value: link }, `${i}-${link.url}`)) })
170
181
  ] }),
171
- description.isEmpty && /* @__PURE__ */ jsx(Text, { component: "div", fw: 500, size: "xs", c: "dimmed", my: "md", style: { userSelect: "none" }, children: "No description" }),
182
+ description.isEmpty && /* @__PURE__ */ jsx(Text, { component: "div", fw: 500, size: "xs", c: "dimmed", style: { userSelect: "none" }, children: "No description" }),
172
183
  description.nonEmpty && /* @__PURE__ */ jsxs("section", { children: [
173
184
  /* @__PURE__ */ jsx(SectionHeader, { children: "Description" }),
174
185
  /* @__PURE__ */ jsx(
@@ -208,6 +219,7 @@ const ViewBadge = ({
208
219
  overflow: "visible",
209
220
  px: "1",
210
221
  color: {
222
+ _dark: "mantine.colors.gray[4]",
211
223
  _light: "mantine.colors.gray[8]"
212
224
  }
213
225
  }),
@@ -24,13 +24,19 @@ const dialog = css({
24
24
  const card = css({
25
25
  position: "absolute",
26
26
  pointerEvents: "all",
27
+ display: "flex",
28
+ flexDirection: "column",
29
+ padding: "4",
27
30
  gap: "lg",
28
31
  justifyContent: "stretch",
32
+ color: "mantine.colors.text",
29
33
  backgroundColor: {
30
34
  base: "mantine.colors.body",
31
35
  _dark: "mantine.colors.dark[6]"
32
36
  },
33
- border: `none`,
37
+ boxShadow: "md",
38
+ overflow: "hidden",
39
+ border: "none",
34
40
  backgroundImage: `
35
41
  linear-gradient(180deg,
36
42
  color-mix(in srgb, var(--likec4-palette-fill) 60%, transparent),
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { cx, css } from '@likec4/styles/css';
3
3
  import { HStack } from '@likec4/styles/jsx';
4
- import { RemoveScroll, Card, Group, Text, CloseButton, Badge, Flex, ActionIconGroup, ActionIcon, Tooltip as Tooltip$1, Tabs, TabsList, TabsTab, TabsPanel, ScrollArea, Box, Stack, Divider as Divider$1, ScrollAreaAutosize, UnstyledButton, ThemeIcon } from '@mantine/core';
4
+ import { RemoveScroll, Text, CloseButton, Badge, Flex, ActionIconGroup, ActionIcon, Tooltip as Tooltip$1, Tabs, TabsList, TabsTab, TabsPanel, ScrollArea, Box, Stack, Divider as Divider$1, ScrollAreaAutosize, UnstyledButton, Group, ThemeIcon } from '@mantine/core';
5
5
  import { useViewportSize, useSessionStorage } from '@mantine/hooks';
6
6
  import { useSyncedRef, useDebouncedCallback, useTimeoutEffect } from '@react-hookz/web';
7
7
  import { useDragControls, useMotionValue, m } from 'motion/react';
@@ -14,7 +14,7 @@ import { elementIcon, card, cardHeader, title, tabsPanel, tabsTab, tabsList, tab
14
14
  import { TabPanelDeployments } from './TabPanelDeployments.js';
15
15
  import { TabPanelRelationships } from './TabPanelRelationships.js';
16
16
  import { TabPanelStructure } from './TabPanelStructure.js';
17
- import { useLikeC4Model } from '../../likec4model/useLikeC4Model.js';
17
+ import { useCurrentViewModel } from '../../likec4model/useCurrentViewModel.js';
18
18
  import { useUpdateEffect } from '../../hooks/useUpdateEffect.js';
19
19
  import { IconRenderer } from '../../context/IconRenderer.js';
20
20
  import { stopPropagation } from '../../utils/xyflow.js';
@@ -69,8 +69,7 @@ function ElementDetailsCard({
69
69
  defaultValue: "Properties"
70
70
  });
71
71
  const diagram = useDiagram();
72
- const likec4model = useLikeC4Model();
73
- const viewModel = likec4model.view(viewId);
72
+ const viewModel = useCurrentViewModel();
74
73
  const nodeModel = fromNode ? viewModel.findNode(fromNode) : viewModel.findNodeWithElement(fqn);
75
74
  const elementModel = viewModel.$model.element(fqn);
76
75
  const [viewsOf, otherViews] = pipe(
@@ -150,7 +149,7 @@ function ElementDetailsCard({
150
149
  }, 20);
151
150
  useTimeoutEffect(() => {
152
151
  setOpened(true);
153
- }, 200);
152
+ }, 220);
154
153
  return /* @__PURE__ */ jsx(
155
154
  m.dialog,
156
155
  {
@@ -185,10 +184,8 @@ function ElementDetailsCard({
185
184
  close();
186
185
  },
187
186
  children: /* @__PURE__ */ jsx(RemoveScroll, { forwardProps: true, removeScrollBar: false, children: /* @__PURE__ */ jsxs(
188
- Card,
187
+ m.div,
189
188
  {
190
- shadow: "md",
191
- component: m.div,
192
189
  layout: true,
193
190
  layoutRoot: true,
194
191
  drag: true,
@@ -221,14 +218,13 @@ function ElementDetailsCard({
221
218
  }
222
219
  },
223
220
  style: {
224
- // `style` prop in Mantine doesn't accept motion values
225
221
  width,
226
222
  height
227
223
  },
228
224
  children: [
229
225
  /* @__PURE__ */ jsxs("div", { className: cardHeader, onPointerDown: (e) => controls.start(e), children: [
230
- /* @__PURE__ */ jsxs(Group, { align: "start", justify: "space-between", gap: "sm", mb: "sm", wrap: "nowrap", children: [
231
- /* @__PURE__ */ jsxs(Group, { align: "start", gap: "sm", style: { cursor: "default" }, wrap: "nowrap", children: [
226
+ /* @__PURE__ */ jsxs(HStack, { alignItems: "start", justify: "space-between", gap: "sm", mb: "sm", flexWrap: "nowrap", children: [
227
+ /* @__PURE__ */ jsxs(HStack, { alignItems: "start", gap: "sm", style: { cursor: "default" }, flexWrap: "nowrap", children: [
232
228
  elementIcon$1,
233
229
  /* @__PURE__ */ jsxs("div", { children: [
234
230
  /* @__PURE__ */ jsx(
@@ -253,7 +249,7 @@ function ElementDetailsCard({
253
249
  }
254
250
  )
255
251
  ] }),
256
- /* @__PURE__ */ jsxs(Group, { align: "baseline", gap: "sm", wrap: "nowrap", children: [
252
+ /* @__PURE__ */ jsxs(HStack, { alignItems: "baseline", gap: "sm", flexWrap: "nowrap", children: [
257
253
  /* @__PURE__ */ jsxs("div", { children: [
258
254
  /* @__PURE__ */ jsx(SmallLabel, { children: "kind" }),
259
255
  /* @__PURE__ */ jsx(
@@ -359,6 +355,10 @@ function ElementDetailsCard({
359
355
  children: [
360
356
  /* @__PURE__ */ jsx(TabsList, { children: TABS.map((tab) => /* @__PURE__ */ jsx(TabsTab, { value: tab, children: tab }, tab)) }),
361
357
  /* @__PURE__ */ jsx(TabsPanel, { value: "Properties", children: /* @__PURE__ */ jsx(ScrollArea, { scrollbars: "y", type: "scroll", offsetScrollbars: true, children: /* @__PURE__ */ jsxs(Box, { className: propertiesGrid, pt: "xs", children: [
358
+ elementModel.hasSummary && /* @__PURE__ */ jsxs(Fragment, { children: [
359
+ /* @__PURE__ */ jsx(PropertyLabel, { children: "summary" }),
360
+ /* @__PURE__ */ jsx(MarkdownBlock, { value: elementModel.summary })
361
+ ] }),
362
362
  /* @__PURE__ */ jsxs(Fragment, { children: [
363
363
  /* @__PURE__ */ jsx(PropertyLabel, { children: "description" }),
364
364
  /* @__PURE__ */ jsx(
@@ -494,12 +494,10 @@ function ElementMetata({
494
494
  children: entries(metadata).map(([key, value]) => /* @__PURE__ */ jsxs(
495
495
  "div",
496
496
  {
497
- className: cx(
498
- "group",
499
- css({
500
- display: "contents"
501
- })
502
- ),
497
+ style: {
498
+ display: "contents"
499
+ },
500
+ className: "group",
503
501
  children: [
504
502
  /* @__PURE__ */ jsxs(
505
503
  "div",
@@ -548,7 +546,7 @@ function ElementMetata({
548
546
  fontSize: "sm",
549
547
  padding: "xxs",
550
548
  whiteSpace: "pre",
551
- fontFamily: "[var(--mantine-font-family-monospace)]",
549
+ fontFamily: "mono",
552
550
  userSelect: "all"
553
551
  }),
554
552
  children: value
@@ -1,5 +1,6 @@
1
1
  import { DiagramEdge, DiagramNode, DiagramView, Fqn, RelationId, RichTextOrEmpty } from '@likec4/core/types';
2
2
  import { AnyAux, LikeC4ViewModel } from '@likec4/core/model';
3
+ import { Except } from 'type-fest';
3
4
  import { RelationshipDetailsTypes } from './_types';
4
5
  import { RelationshipDetailsViewData } from './compute';
5
6
  export type LayoutResult = {
@@ -8,13 +9,13 @@ export type LayoutResult = {
8
9
  bounds: DiagramView['bounds'];
9
10
  };
10
11
  export declare namespace LayoutResult {
11
- type Node = Omit<DiagramNode, 'modelRef' | 'description' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
12
+ type Node = Except<DiagramNode, 'modelRef' | 'description' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
12
13
  description: RichTextOrEmpty;
13
14
  modelRef: Fqn;
14
15
  column: RelationshipDetailsTypes.Column;
15
16
  ports: RelationshipDetailsTypes.Ports;
16
17
  };
17
- type Edge = Omit<DiagramEdge, 'relations' | 'description'> & {
18
+ type Edge = Except<DiagramEdge, 'relations' | 'description'> & {
18
19
  relationId: RelationId;
19
20
  sourceHandle: string;
20
21
  targetHandle: string;
@@ -1,6 +1,5 @@
1
1
  import { treeFromElements } from '@likec4/core/compute-view/relationships';
2
2
  import dagre from '@dagrejs/dagre';
3
- import { RichText } from '@likec4/core';
4
3
  import { ifind, DefaultMap, invariant } from '@likec4/core/utils';
5
4
  import { pipe, filter, mapToObj, find, map, tap, reduce, sortBy, prop } from 'remeda';
6
5
 
@@ -240,7 +239,7 @@ function layoutRelationshipDetails(data, scope) {
240
239
  y: position.y,
241
240
  position: [position.x, position.y],
242
241
  title: element.title,
243
- description: RichText.from(element.description),
242
+ description: element.summary,
244
243
  technology: element.technology,
245
244
  tags: [...element.tags],
246
245
  links: null,
@@ -2,6 +2,7 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { cx } from '@likec4/styles/css';
3
3
  import { ActionIcon, Group } from '@mantine/core';
4
4
  import { useCallbackRef, useStateHistory } from '@mantine/hooks';
5
+ import { useRafEffect } from '@react-hookz/web';
5
6
  import { ReactFlowProvider, useStoreApi, useReactFlow, Panel } from '@xyflow/react';
6
7
  import { shallowEqual } from 'fast-equals';
7
8
  import { LayoutGroup, AnimatePresence, m } from 'motion/react';
@@ -137,7 +138,7 @@ const RelationshipsBrowserInner = memo(() => {
137
138
  browser.navigateTo(historySubjectId);
138
139
  }
139
140
  }, [historySubjectId, browser]);
140
- useEffect(() => {
141
+ useRafEffect(() => {
141
142
  browser.updateView(layouted);
142
143
  }, [layouted, browser]);
143
144
  const hasStepBack = current > 0;
@@ -374,7 +374,7 @@ function layoutRelationshipsView(data, scope) {
374
374
  y: position.y,
375
375
  position: [position.x, position.y],
376
376
  title: element.title,
377
- description: RichText.from(element.description),
377
+ description: element.summary,
378
378
  technology: element.technology,
379
379
  tags: [...element.tags],
380
380
  links: null,
@@ -224,7 +224,7 @@ function ElementTreeNode({ node, elementProps, hasChildren, expanded }) {
224
224
  }
225
225
  ) })
226
226
  ] }),
227
- /* @__PURE__ */ jsx(Highlight, { component: "div", highlight: searchTerms, className: btn.description, lineClamp: 1, children: element.description.text || "No description" })
227
+ /* @__PURE__ */ jsx(Highlight, { component: "div", highlight: searchTerms, className: btn.description, lineClamp: 1, children: element.summary.text || "No description" })
228
228
  ] }),
229
229
  /* @__PURE__ */ jsx(Text, { component: "div", className: cx(elementViewsCount, btn.descriptionColor), fz: "xs", children: views.length === 0 ? "No views" : /* @__PURE__ */ jsxs(Fragment, { children: [
230
230
  views.length,
@@ -1,14 +1,13 @@
1
1
  import { jsxs, jsx } from 'react/jsx-runtime';
2
- import { useCustomCompareEffect } from '@react-hookz/web';
2
+ import { useCustomCompareEffect, useRafEffect } from '@react-hookz/web';
3
3
  import { useActorRef, useSelector } from '@xstate/react';
4
4
  import { useStoreApi } from '@xyflow/react';
5
5
  import { shallowEqual, deepEqual } from 'fast-equals';
6
- import { useRef, useMemo, useEffect } from 'react';
6
+ import { useRef, useMemo } from 'react';
7
7
  import { ErrorBoundary } from '../components/ErrorFallback.js';
8
8
  import { useDiagramEventHandlers } from '../context/DiagramEventHandlers.js';
9
9
  import { useEnabledFeatures, DiagramFeatures } from '../context/DiagramFeatures.js';
10
10
  import { DiagramActorContextProvider } from '../hooks/safeContext.js';
11
- import { useCurrentViewId } from '../hooks/useCurrentViewId.js';
12
11
  import { convertToXYFlow } from '../likec4diagram/convert-to-xyflow.js';
13
12
  import { CurrentViewModelContext } from '../likec4model/LikeC4ModelContext.js';
14
13
  import { useLikeC4Model } from '../likec4model/useLikeC4Model.js';
@@ -16,15 +15,6 @@ import { diagramMachine } from './diagram-machine.js';
16
15
  import { syncManualLayoutActorLogic } from './syncManualLayoutActor.js';
17
16
  import { useOnDiagramEvent } from '../hooks/useDiagram.js';
18
17
 
19
- const selectToggledFeatures = (state) => {
20
- if (state.context.features.enableReadOnly || state.context.activeWalkthrough) {
21
- return {
22
- ...state.context.toggledFeatures,
23
- enableReadOnly: true
24
- };
25
- }
26
- return state.context.toggledFeatures;
27
- };
28
18
  const selectDynamicViewVariant = (state) => {
29
19
  return state.context.dynamicViewVariant;
30
20
  };
@@ -91,23 +81,37 @@ function DiagramActorProvider({
91
81
  () => convertToXYFlow({ view, where, nodesSelectable, dynamicViewVariant }),
92
82
  [view, where, nodesSelectable, dynamicViewVariant]
93
83
  );
94
- useEffect(() => {
84
+ useRafEffect(() => {
95
85
  actorRef.send({
96
86
  type: "update.view",
97
87
  ...update
98
88
  });
99
89
  }, [actorRef, update]);
100
- const toggledFeatures = useSelector(actorRef, selectToggledFeatures, shallowEqual);
101
90
  return /* @__PURE__ */ jsxs(DiagramActorContextProvider, { value: actorRef, children: [
102
- /* @__PURE__ */ jsx(DiagramFeatures, { overrides: toggledFeatures, children: /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(CurrentViewModelProvider, { children }) }) }),
91
+ /* @__PURE__ */ jsx(ErrorBoundary, { children: /* @__PURE__ */ jsx(CurrentViewModelProvider, { actorRef, children }) }),
103
92
  /* @__PURE__ */ jsx(DiagramActorEventListener, { actorRef })
104
93
  ] });
105
94
  }
106
- function CurrentViewModelProvider({ children }) {
107
- const viewId = useCurrentViewId();
95
+ const selectViewIdAndToggledFeatures = (state) => {
96
+ if (state.context.features.enableReadOnly || state.context.activeWalkthrough) {
97
+ return {
98
+ viewId: state.context.view.id,
99
+ toggledFeatures: {
100
+ ...state.context.toggledFeatures,
101
+ enableReadOnly: true
102
+ }
103
+ };
104
+ }
105
+ return {
106
+ viewId: state.context.view.id,
107
+ toggledFeatures: state.context.toggledFeatures
108
+ };
109
+ };
110
+ function CurrentViewModelProvider({ children, actorRef }) {
111
+ const { viewId, toggledFeatures } = useSelector(actorRef, selectViewIdAndToggledFeatures, deepEqual);
108
112
  const likec4model = useLikeC4Model();
109
113
  const viewmodel = likec4model.findView(viewId);
110
- return /* @__PURE__ */ jsx(CurrentViewModelContext.Provider, { value: viewmodel, children });
114
+ return /* @__PURE__ */ jsx(CurrentViewModelContext.Provider, { value: viewmodel, children: /* @__PURE__ */ jsx(DiagramFeatures, { overrides: toggledFeatures, children }) });
111
115
  }
112
116
  function DiagramActorEventListener({ actorRef }) {
113
117
  const {
@@ -115,20 +119,7 @@ function DiagramActorEventListener({ actorRef }) {
115
119
  onOpenSource
116
120
  } = useDiagramEventHandlers();
117
121
  useOnDiagramEvent("openSource", ({ params }) => onOpenSource?.(params));
118
- useEffect(() => {
119
- if (!onNavigateTo) return;
120
- let frame;
121
- const subscription = actorRef.on("navigateTo", ({ viewId }) => {
122
- cancelAnimationFrame(frame);
123
- frame = requestAnimationFrame(() => {
124
- onNavigateTo(viewId);
125
- });
126
- });
127
- return () => {
128
- cancelAnimationFrame(frame);
129
- subscription.unsubscribe();
130
- };
131
- }, [actorRef, onNavigateTo]);
122
+ useOnDiagramEvent("navigateTo", ({ viewId }) => onNavigateTo?.(viewId));
132
123
  return null;
133
124
  }
134
125