likec4 1.42.1 → 1.44.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.
@@ -1,11 +1,15 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, lazy, Suspense, createContext, useContext, useState, useMemo, memo, useRef, StrictMode } from "react";
3
3
  import { createRoot } from "react-dom/client";
4
- import { cN as useRouter, cO as isNotFound, cP as Container, bk as Alert, as as Text, aa as Code, ac as Button, ab as Group, a_ as rem, b_ as Title, cQ as Link, cR as useNavigate, d as useCallbackRef, cS as createRootRouteWithContext, cT as stripSearchParams, aI as e, cU as Outlet, O as useMantineColorScheme, cV as createFileRoute, cW as useDocumentTitle, aY as Stack, cX as Loader, cY as useStore, a7 as ErrorBoundary, cZ as Navigate, c_ as t, s as shallowEqual, c$ as useParams, S as useIsomorphicLayoutEffect, d0 as SimpleGrid, d1 as useInViewport, j as e$1, ch as Card, aq as Box, d2 as notFound, bv as r, bj as useTree, d3 as useComputedColorScheme, bl as Tree, aA as HoverCard, aB as HoverCardTarget, aC as HoverCardDropdown, aj as ThemeIcon, d4 as onMount, R as atom, cg as useLocalStorage, d5 as Drawer, bT as ScrollArea, aR as SegmentedControl, ah as ActionIcon, b2 as Menu, b3 as MenuTarget, b4 as MenuDropdown, b5 as MenuItem, aQ as CopyButton$1, d6 as Select, d7 as ModalRoot, d8 as ModalOverlay, d9 as ModalContent, da as ModalBody, bP as Tabs, bQ as TabsList, bR as TabsTab, bS as TabsPanel, db as useMatches, dc as useMantineTheme, dd as useMediaQuery, de as useDisclosure, b1 as Paper, aX as Divider, aW as Space, df as useParentMatches, dg as MenuLabel, a2 as t$1, bo as t$2, br as t$3, bq as e$2, bp as t$4, bs as t$5, V as t$6, bt as n, k as t$7, by as dagre, bn as DefaultMap, bz as t$8, bA as t$9, dh as useSearch, av as useDebouncedCallback, di as LoadingOverlay, dj as toBlob, ak as Tooltip, dk as useAsync, dl as PanelGroup, dm as Panel, dn as PanelResizeHandle, dp as Burger, dq as RouterProvider, dr as createRouter$1, ds as createHashHistory, dt as createBrowserHistory, du as createTheme, aT as Portal, X as MantineProvider } from "./vendors.js";
4
+ import { cB as useRouter, cC as isNotFound, cD as Container, a_ as Alert, O as Text, cE as Code, P as Button, aH as Group, aD as rem, bE as Title, cF as Link, cG as useNavigate, bx as useCallbackRef, cH as createRootRouteWithContext, cI as stripSearchParams, al as e, cJ as Outlet, l as useMantineColorScheme, cK as createFileRoute, cL as useDocumentTitle, aB as Stack, cM as Loader, cN as useStore, N as ErrorBoundary, cO as Navigate, d as deepEqual, s as shallowEqual, cP as useParams, v as useIsomorphicLayoutEffect, cQ as SimpleGrid, cR as useInViewport, cS as e$1, bZ as Card, ab as Box, cT as notFound, b7 as r, aZ as useTree, cU as useComputedColorScheme, a$ as Tree, as as HoverCard, at as HoverCardTarget, au as HoverCardDropdown, T as ThemeIcon, cV as onMount, r as atom, bY as useLocalStorage, cW as Drawer, bv as ScrollArea, a4 as SegmentedControl, Y as ActionIcon, a1 as Menu, aI as MenuTarget, aJ as MenuDropdown, aK as MenuItem, ar as CopyButton$1, cX as Select, cY as ModalRoot, cZ as ModalOverlay, c_ as ModalContent, c$ as ModalBody, br as Tabs, bs as TabsList, bt as TabsTab, bu as TabsPanel, d0 as useMatches, d1 as useMantineTheme, d2 as useMediaQuery, d3 as useDisclosure, aG as Paper, a5 as Divider, aA as Space, d4 as useParentMatches, d5 as MenuLabel, G as t, b1 as t$1, b4 as t$2, b3 as e$2, b2 as t$3, b5 as t$4, z as t$5, b6 as n, g as t$6, ba as dagre, bb as t$7, bc as t$8, d6 as useSearch, ae as useDebouncedCallback, d7 as LoadingOverlay, d8 as toBlob, $ as Tooltip, d9 as useAsync, da as PanelGroup, db as Panel, dc as PanelResizeHandle, dd as Burger, de as RouterProvider, df as createRouter$1, dg as createHashHistory, dh as createBrowserHistory, di as createTheme, ax as Portal, A as MantineProvider } from "./vendors.js";
5
5
  import { projects } from "likec4:projects";
6
- import { c as css, L as LikeC4ProjectsProvider, u as useLikeC4Projects, I as IconRendererProvider, a as LikeC4ModelProvider, S as StaticLikeC4Diagram, M as Markdown, R as RichText, B as Box$1, b as useLikeC4Model$1, n as nonexhaustive, d as compareNatural, e as useUpdateEffect, f as IconStarFilled, g as IconStack2, h as IconLayoutDashboard, i as IconFileCode, j as IconFolderOpen, k as IconFolderFilled, l as IconArrowLeft, m as IconMoonStars, o as IconSun, p as IconChevronDown, q as IconAlertTriangle, r as IconCheck, s as IconCopy, t as IconExternalLink, v as IconShare, w as computeRelationshipsView, x as toArray, y as sortParentsFirst, z as exact, A as invariant, C as isDescendantOf, D as isAncestor, E as nonNullable, F as getViewBounds, G as LikeC4Diagram, H as useDiagramContext } from "./likec4.js";
6
+ import { c as css, L as LikeC4ProjectsProvider, u as useLikeC4Projects, I as IconRendererProvider, a as LikeC4ModelProvider, b as useUpdateEffect, S as StaticLikeC4Diagram, M as Markdown, B as Box$1, d as useLikeC4Model$1, e as IconStarFilled, f as IconStack2, g as IconLayoutDashboard, h as IconFileCode, i as IconFolderOpen, j as IconFolderFilled, k as IconArrowLeft, l as IconMoonStars, m as IconSun, n as IconChevronDown, o as IconAlertTriangle, p as IconCheck, q as IconCopy, r as IconExternalLink, s as IconShare, t as pickViewBounds, v as LikeC4Diagram, w as useDiagramContext } from "./likec4.js";
7
7
  import { pageTitle, ComponentName, useHashHistory, withOverviewGraph, krokiPumlSvgUrl, isDevelopment, krokiD2SvgUrl, basepath } from "./const.js";
8
8
  import { loadModel } from "likec4:model";
9
+ import { RichText } from "@likec4/core/types";
10
+ import { nonexhaustive, compareNatural, toArray, sortParentsFirst, invariant, DefaultMap, isDescendantOf, isAncestor, nonNullable } from "@likec4/core/utils";
11
+ import { exact } from "@likec4/core";
12
+ import { computeRelationshipsView } from "@likec4/core/compute-view/relationships";
9
13
  function Fallback$1({ error, resetErrorBoundary }) {
10
14
  const router = useRouter();
11
15
  return isNotFound(error) ? /* @__PURE__ */ jsx(Container, { my: "md", children: /* @__PURE__ */ jsxs(Alert, { variant: "light", color: "orange", children: [
@@ -182,15 +186,15 @@ function LikeC4IconRendererContext({ children, projectId }) {
182
186
  const IconRenderer = _renderers[projectId] ??= (props) => /* @__PURE__ */ jsx(ProjectIconRenderer, { ...props, projectId });
183
187
  return /* @__PURE__ */ jsx(IconRendererProvider, { value: IconRenderer, children });
184
188
  }
185
- const LikeC4ModelDataContext = createContext(null), LikeC4ModelDataContextProvider = LikeC4ModelDataContext.Provider, useLikeC4ModelDataAtom = () => {
189
+ const LikeC4ModelDataContext = createContext(null), LikeC4ModelDataContextProvider = LikeC4ModelDataContext.Provider, useLikeC4ModelAtom = () => {
186
190
  const ctx = useContext(LikeC4ModelDataContext);
187
191
  if (ctx === null)
188
- throw new Error("LikeC4ModelDataAtom is not provided");
192
+ throw new Error("LikeC4ModelAtom is not provided");
189
193
  return ctx;
190
194
  };
191
195
  function LikeC4ModelContext({ likec4data, likec4model, children }) {
192
196
  const model = useStore(likec4model);
193
- return /* @__PURE__ */ jsx(LikeC4ModelDataContextProvider, { value: likec4data, children: /* @__PURE__ */ jsx(LikeC4ModelProvider, { likec4model: model, children }) });
197
+ return /* @__PURE__ */ jsx(LikeC4ModelDataContextProvider, { value: likec4model, children: /* @__PURE__ */ jsx(LikeC4ModelProvider, { likec4model: model, children }) });
194
198
  }
195
199
  css({
196
200
  position: "absolute",
@@ -278,13 +282,16 @@ function useTransparentBackground(enabled = !0) {
278
282
  }, [enabled]);
279
283
  }
280
284
  function useLikeC4Views() {
281
- const $likec4data = useLikeC4ModelDataAtom(), [views, setViews] = useState([]);
282
- return useEffect(() => $likec4data.subscribe((next) => {
285
+ const $likec4model = useLikeC4ModelAtom(), [views, setViews] = useState([]);
286
+ return useEffect(() => $likec4model.subscribe((next) => {
283
287
  setViews((prev) => {
284
- const nextViews = t(next.views);
288
+ const nextViews = [...next.views()].map((v) => {
289
+ const n2 = v.$layouted, p = prev.find((_) => _.id === v.id);
290
+ return p && deepEqual(n2, p) ? p : n2;
291
+ });
285
292
  return shallowEqual(prev, nextViews) ? prev : nextViews;
286
293
  });
287
- }), [$likec4data]), views;
294
+ }), [$likec4model]), views;
288
295
  }
289
296
  function useCurrentViewId() {
290
297
  return useParams({
@@ -292,9 +299,18 @@ function useCurrentViewId() {
292
299
  strict: !1
293
300
  });
294
301
  }
295
- function useCurrentDiagram() {
296
- const viewId = useCurrentViewId();
297
- return useLikeC4Views().find((v) => v.id === viewId) ?? null;
302
+ function useCurrentView() {
303
+ const viewId = useCurrentViewId(), $likec4model = useLikeC4ModelAtom(), [layoutType, setLayoutType] = useState("manual");
304
+ useUpdateEffect(() => {
305
+ setLayoutType("manual");
306
+ }, [viewId]);
307
+ const [view, setView] = useState($likec4model.value?.findView(viewId)?.$layouted ?? null);
308
+ return useEffect(() => $likec4model.subscribe((next) => {
309
+ setView((current) => {
310
+ const vm = next.findView(viewId), nextView = (layoutType === "manual" ? vm?.$layouted : vm?.$view) ?? null;
311
+ return deepEqual(current, nextView) ? current : nextView;
312
+ });
313
+ }), [$likec4model, viewId, layoutType]), [view, setLayoutType];
298
314
  }
299
315
  function useCurrentProject() {
300
316
  const projects2 = useLikeC4Projects(), projectId = useParams({
@@ -576,7 +592,7 @@ const isFile = (node) => isTreeNodeData(node) && node.type === "file", FolderIco
576
592
  viewId: viewId2
577
593
  })
578
594
  });
579
- }, diagram = useCurrentDiagram(), viewId = diagram?.id ?? null, tree = useTree({
595
+ }, [diagram] = useCurrentView(), viewId = diagram?.id ?? null, tree = useTree({
580
596
  multiple: !1
581
597
  });
582
598
  tree.setHoveredNode = setHoveredNode;
@@ -967,7 +983,7 @@ function WebcomponentsPanel({ diagram }) {
967
983
  function ShareModal({
968
984
  onClose
969
985
  }) {
970
- const diagram = useCurrentDiagram(), [activeTab, setActiveTab] = useState("webcomponent");
986
+ const [diagram] = useCurrentView(), [activeTab, setActiveTab] = useState("webcomponent");
971
987
  return diagram ? /* @__PURE__ */ jsxs(
972
988
  ModalRoot,
973
989
  {
@@ -1297,11 +1313,11 @@ function applyDagreLayout(g) {
1297
1313
  }
1298
1314
  function layoutRelationshipsView(data) {
1299
1315
  const g = createGraph(), incomers = createNodes("in", data.incomers, g), subjects = createNodes("subject", data.subjects, g), outgoers = createNodes("out", data.outgoers, g), edges = [];
1300
- t$1(
1301
- t$5(
1302
- t$1(
1316
+ t(
1317
+ t$4(
1318
+ t(
1303
1319
  toArray(data.incoming),
1304
- t$3((r2) => ({
1320
+ t$2((r2) => ({
1305
1321
  id: r2.source.id,
1306
1322
  source: incomers.byId(r2.source.id).graph,
1307
1323
  target: subjects.byId(r2.target.id).graph,
@@ -1310,9 +1326,9 @@ function layoutRelationshipsView(data) {
1310
1326
  // Sort by source
1311
1327
  sortParentsFirst
1312
1328
  ),
1313
- t$1(
1329
+ t(
1314
1330
  toArray(data.outgoing),
1315
- t$3((r2) => ({
1331
+ t$2((r2) => ({
1316
1332
  id: r2.target.id,
1317
1333
  source: subjects.byId(r2.source.id).graph,
1318
1334
  target: outgoers.byId(r2.target.id).graph,
@@ -1322,13 +1338,13 @@ function layoutRelationshipsView(data) {
1322
1338
  sortParentsFirst
1323
1339
  )
1324
1340
  ),
1325
- t$3((r2) => ({
1341
+ t$2((r2) => ({
1326
1342
  ...r2,
1327
1343
  expr: `${r2.source.id}->${r2.target.id}`
1328
1344
  })),
1329
1345
  // Group if same source and target
1330
- t$4(e$2("expr")),
1331
- t$2((grouped) => {
1346
+ t$3(e$2("expr")),
1347
+ t$1((grouped) => {
1332
1348
  const source = grouped[0].source, target = grouped[0].target, name = grouped[0].expr;
1333
1349
  g.node(source.id).outPorts.push(target.id), g.node(target.id).inPorts.push(source.id), g.setEdge(source.portId, target.portId, {
1334
1350
  ...Sizes.edgeLabel
@@ -1336,7 +1352,7 @@ function layoutRelationshipsView(data) {
1336
1352
  name,
1337
1353
  source: source.id,
1338
1354
  target: target.id,
1339
- relations: t$3(grouped, e$2("relation"))
1355
+ relations: t$2(grouped, e$2("relation"))
1340
1356
  });
1341
1357
  })
1342
1358
  );
@@ -1351,21 +1367,21 @@ function layoutRelationshipsView(data) {
1351
1367
  ...incomers.graphNodes.values(),
1352
1368
  ...subjects.graphNodes.values(),
1353
1369
  ...outgoers.graphNodes.values()
1354
- ], _calculatedNodeBounds = t$1(
1370
+ ], _calculatedNodeBounds = t(
1355
1371
  nodeIds,
1356
1372
  // Compound nodes have different portId
1357
1373
  n((n2) => n2.id === n2.portId),
1358
- t$6((n2) => [n2.id, dagreBounds(n2.id)])
1374
+ t$5((n2) => [n2.id, dagreBounds(n2.id)])
1359
1375
  );
1360
1376
  function nodeBounds(nodeId) {
1361
- return _calculatedNodeBounds[nodeId] ??= t$1(
1377
+ return _calculatedNodeBounds[nodeId] ??= t(
1362
1378
  g.children(nodeId) ?? [],
1363
1379
  n((id) => !id.endsWith(PortSuffix)),
1364
- t$3((id) => nodeBounds(id)),
1365
- t$9((bounds) => {
1380
+ t$2((id) => nodeBounds(id)),
1381
+ t$8((bounds) => {
1366
1382
  invariant(bounds.length > 0, `Node ${nodeId} has no nested nodes`);
1367
1383
  }),
1368
- t$8((acc, bounds) => ({
1384
+ t$7((acc, bounds) => ({
1369
1385
  minY: Math.min(acc.minY, bounds.position.y),
1370
1386
  maxY: Math.max(acc.maxY, bounds.position.y + bounds.height)
1371
1387
  }), { minY: 1 / 0, maxY: -1 / 0 }),
@@ -1444,7 +1460,7 @@ function layoutRelationshipsView(data) {
1444
1460
  const edge = g.edge(e2), ename = e2.name;
1445
1461
  invariant(ename, "Edge has no name");
1446
1462
  const { name, source, target, relations } = r(edges, (e22) => e22.name === ename), points = edge.points.map((p) => [p.x, p.y]);
1447
- return invariant(t$7(points, 1), `Edge ${name} has less than 2 points`), {
1463
+ return invariant(t$6(points, 1), `Edge ${name} has less than 2 points`), {
1448
1464
  id: name,
1449
1465
  source,
1450
1466
  target,
@@ -1506,7 +1522,7 @@ function ExportPage() {
1506
1522
  dynamic
1507
1523
  } = useSearch({
1508
1524
  strict: !1
1509
- }), diagram = useCurrentDiagram(), viewportRef = useRef(null), loadingOverlayRef = useRef(null), downloadedRef = useRef(!1);
1525
+ }), [diagram] = useCurrentView(), viewportRef = useRef(null), loadingOverlayRef = useRef(null), downloadedRef = useRef(!1);
1510
1526
  useTransparentBackground();
1511
1527
  const downloadDiagram = useDebouncedCallback(
1512
1528
  () => {
@@ -1524,7 +1540,7 @@ function ExportPage() {
1524
1540
  );
1525
1541
  if (!diagram)
1526
1542
  return /* @__PURE__ */ jsx("div", { children: "Loading..." });
1527
- const bounds = getViewBounds(diagram, dynamic), extraPadding = 16, width = bounds.width + padding * 2 + extraPadding, height = bounds.height + padding * 2 + extraPadding;
1543
+ const bounds = pickViewBounds(diagram, dynamic), extraPadding = 16, width = bounds.width + padding * 2 + extraPadding, height = bounds.height + padding * 2 + extraPadding;
1528
1544
  return /* @__PURE__ */ jsxs(
1529
1545
  Box$1,
1530
1546
  {
@@ -1569,7 +1585,7 @@ function ExportPage() {
1569
1585
  pannable: !1,
1570
1586
  zoomable: !1,
1571
1587
  controls: !1,
1572
- showNotations: !1,
1588
+ enableNotations: !1,
1573
1589
  enableElementDetails: !1,
1574
1590
  enableRelationshipDetails: !1,
1575
1591
  enableRelationshipBrowser: !1,
@@ -1611,10 +1627,10 @@ function EmbedPage() {
1611
1627
  dynamic
1612
1628
  } = useSearch({
1613
1629
  strict: !1
1614
- }), diagram = useCurrentDiagram();
1630
+ }), [diagram] = useCurrentView();
1615
1631
  if (useTransparentBackground(!!diagram), !diagram)
1616
1632
  return /* @__PURE__ */ jsx("div", { children: "Loading..." });
1617
- const bounds = getViewBounds(diagram, dynamic);
1633
+ const bounds = pickViewBounds(diagram, dynamic);
1618
1634
  return /* @__PURE__ */ jsx(
1619
1635
  "div",
1620
1636
  {
@@ -1650,7 +1666,7 @@ const Route$b = createFileRoute("/_single/embed/$viewId")({
1650
1666
  component: EmbedPage
1651
1667
  });
1652
1668
  function ViewReact() {
1653
- const navigate = useNavigate(), view = useCurrentDiagram(), model = useLikeC4Model$1(), { dynamic } = useSearch({
1669
+ const navigate = useNavigate(), [view, setLayoutType] = useCurrentView(), model = useLikeC4Model$1(), { dynamic } = useSearch({
1654
1670
  from: "__root__"
1655
1671
  }), onNavigateTo = useCallbackRef((viewId) => {
1656
1672
  navigate({
@@ -1689,11 +1705,12 @@ function ViewReact() {
1689
1705
  enableRelationshipDetails: !0,
1690
1706
  enableRelationshipBrowser: !0,
1691
1707
  enableElementTags: !0,
1692
- experimentalEdgeEditing: !1,
1693
- showNotations: hasNotations,
1708
+ enableCompareWithLatest: !0,
1709
+ enableNotations: hasNotations,
1694
1710
  nodesDraggable: !1,
1695
1711
  nodesSelectable: !0,
1696
1712
  onNavigateTo,
1713
+ onLayoutTypeChange: setLayoutType,
1697
1714
  onBurgerMenuClick: () => {
1698
1715
  navigate({
1699
1716
  to: "/"
@@ -1920,16 +1937,16 @@ function ViewAsMmd() {
1920
1937
  ] });
1921
1938
  }
1922
1939
  function ViewEditor() {
1923
- const router = useRouter(), view = useCurrentDiagram(), onNavigateTo = useCallbackRef((viewId) => {
1924
- const loc = router.buildLocation({
1925
- to: ".",
1940
+ const navigate = useNavigate(), [view, setLayoutType] = useCurrentView(), onNavigateTo = useCallbackRef((viewId) => {
1941
+ navigate({
1942
+ to: "./",
1943
+ viewTransition: !1,
1926
1944
  params: (current) => ({
1927
1945
  ...current,
1928
1946
  viewId
1929
1947
  }),
1930
1948
  search: !0
1931
1949
  });
1932
- router.commitLocation(loc);
1933
1950
  });
1934
1951
  if (!view)
1935
1952
  return /* @__PURE__ */ jsx(NotFound, {});
@@ -1943,7 +1960,6 @@ function ViewEditor() {
1943
1960
  pannable: !0,
1944
1961
  controls: !0,
1945
1962
  nodesDraggable: !0,
1946
- experimentalEdgeEditing: !0,
1947
1963
  fitViewPadding: {
1948
1964
  top: "70px",
1949
1965
  bottom: "32px",
@@ -1951,7 +1967,7 @@ function ViewEditor() {
1951
1967
  right: "32px"
1952
1968
  },
1953
1969
  showNavigationButtons: !0,
1954
- showNotations: isDevelopment || hasNotations,
1970
+ enableNotations: isDevelopment || hasNotations,
1955
1971
  enableSearch: !0,
1956
1972
  enableDynamicViewWalkthrough: !0,
1957
1973
  enableFocusMode: !0,
@@ -1959,10 +1975,12 @@ function ViewEditor() {
1959
1975
  enableRelationshipDetails: !0,
1960
1976
  enableRelationshipBrowser: !0,
1961
1977
  enableElementTags: !0,
1978
+ enableCompareWithLatest: !0,
1962
1979
  onNavigateTo,
1980
+ onLayoutTypeChange: setLayoutType,
1963
1981
  onChange: (e2) => console.log(e2),
1964
1982
  onBurgerMenuClick: () => {
1965
- router.navigate({
1983
+ navigate({
1966
1984
  to: "/"
1967
1985
  });
1968
1986
  }