likec4 1.41.0 → 1.42.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 (42) hide show
  1. package/__app__/src/likec4.js +11659 -12120
  2. package/__app__/src/main.js +185 -129
  3. package/__app__/src/style.css +1 -1
  4. package/__app__/src/vendors.js +38519 -17031
  5. package/__app__/src/webcomponent.js +68 -0
  6. package/config/package.json +2 -2
  7. package/config/schema.json +575 -0
  8. package/dist/cli/index.mjs +557 -553
  9. package/dist/config/index.d.mts +4 -1
  10. package/dist/config/index.mjs +1 -1
  11. package/dist/index.d.mts +4 -4
  12. package/dist/index.mjs +1 -1
  13. package/dist/model/index.d.mts +47 -4
  14. package/dist/model/index.mjs +1 -1
  15. package/dist/shared/likec4.B5Q51Z1F.mjs +543 -0
  16. package/dist/shared/likec4.BCSBNe4z.d.mts +6808 -0
  17. package/dist/shared/likec4.CB2-Uaub.mjs +47 -0
  18. package/dist/shared/likec4.CJVbsoPD.mjs +256 -0
  19. package/dist/shared/{likec4.3AlS7pfZ.d.mts → likec4.CaOUU1HJ.d.mts} +204 -149
  20. package/dist/shared/likec4.DOUP9ptn.mjs +1 -0
  21. package/dist/shared/{likec4.C8C0fF8a.mjs → likec4.DO_7oUns.mjs} +1 -1
  22. package/dist/shared/likec4.DdxVkEIS.mjs +4038 -0
  23. package/dist/vite-plugin/index.d.mts +4 -3
  24. package/dist/vite-plugin/index.mjs +1 -1
  25. package/dist/vite-plugin/internal.mjs +3 -3
  26. package/icons/all/package.json +4 -0
  27. package/model/builder/package.json +4 -0
  28. package/model/package.json +4 -0
  29. package/package.json +42 -42
  30. package/react/index.d.ts +6655 -0
  31. package/react/index.js +48628 -0
  32. package/react/package.json +3 -2
  33. package/vite-plugin/package.json +2 -2
  34. package/vite-plugin-modules.d.ts +5 -5
  35. package/__app__/src/webcomponent.tsx +0 -81
  36. package/dist/shared/likec4.CdNNo2L4.mjs +0 -1
  37. package/dist/shared/likec4.CxmGAh_J.mjs +0 -144
  38. package/dist/shared/likec4.DX1wM3Or.d.mts +0 -1704
  39. package/dist/shared/likec4.Db3cTW-C.mjs +0 -257
  40. package/dist/shared/likec4.bxIrQhth.mjs +0 -4174
  41. package/react/index.d.mts +0 -6578
  42. package/react/index.mjs +0 -185
@@ -1,13 +1,11 @@
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 { cw as useRouter, cx as isNotFound, cy as Container, b2 as Alert, T as Text, aM as Code, aa as Button, ao as Group, aj as rem, bG as Title, cz as Link, cA as useNavigate, f as useCallbackRef, cB as createRootRouteWithContext, cC as stripSearchParams, R as e, cD as Outlet, cE as useMantineColorScheme, cF as createFileRoute, cG as useDocumentTitle, af as Stack, cH as Loader, cI as useStore, b0 as ErrorBoundary, cJ as Navigate, cK as SimpleGrid, cL as useInViewport, cM as e$1, bZ as Card, an as Box, cN as notFound, cO as useParams, cb as t, s as shallowEqual, cP as useIsomorphicLayoutEffect, bb as r, b1 as useTree, cQ as useComputedColorScheme, b3 as Tree, aI as HoverCard, aJ as HoverCardTarget, aK as HoverCardDropdown, aB as ThemeIcon, cR as onMount, x as atom, bY as useLocalStorage, cS as Drawer, bz as ScrollArea, ap as SegmentedControl, P as ActionIcon, aq as Menu, ar as MenuTarget, as as MenuDropdown, at as MenuItem, aQ as CopyButton$1, cT as Select, cU as ModalRoot, cV as ModalOverlay, cW as ModalContent, cX as ModalBody, bv as Tabs, bw as TabsList, bx as TabsTab, by as TabsPanel, cY as useMatches, cZ as useMantineTheme, c_ as useMediaQuery, c$ as useDisclosure, am as Paper, ae as Divider, ad as Space, d0 as useParentMatches, d1 as MenuLabel, C as t$1, b5 as t$2, b8 as t$3, b7 as e$2, b6 as t$4, b9 as t$5, r as t$6, ba as n, i as t$7, be as dagre, bf as t$8, bg as t$9, d2 as useSearch, a4 as useDebouncedEffect, d3 as LoadingOverlay, a6 as Tooltip, d4 as useAsync, d5 as PanelGroup, d6 as Panel, d7 as PanelResizeHandle, d8 as Burger, d9 as RouterProvider, da as createRouter$1, db as createHashHistory, dc as createBrowserHistory, dd as createTheme, aS as Portal, w as MantineProvider } from "./vendors.js";
4
+ import { cL as useRouter, cM as isNotFound, cN as Container, bk as Alert, at as Text, ab as Code, ad as Button, ac as Group, a$ as rem, b_ as Title, cO as Link, cP as useNavigate, d as useCallbackRef, cQ as createRootRouteWithContext, cR as stripSearchParams, aJ as e, cS as Outlet, O as useMantineColorScheme, cT as createFileRoute, cU as useDocumentTitle, aZ as Stack, cV as Loader, cW as useStore, a8 as ErrorBoundary, cX as Navigate, cY as t, s as shallowEqual, cZ as useParams, S as useIsomorphicLayoutEffect, c_ as SimpleGrid, c$ as useInViewport, j as e$1, ch as Card, ar as Box, d0 as notFound, bv as r, bj as useTree, d1 as useComputedColorScheme, bl as Tree, aB as HoverCard, aC as HoverCardTarget, aD as HoverCardDropdown, ak as ThemeIcon, d2 as onMount, Q as atom, cg as useLocalStorage, d3 as Drawer, bT as ScrollArea, aS as SegmentedControl, ai as ActionIcon, b3 as Menu, b4 as MenuTarget, b5 as MenuDropdown, b6 as MenuItem, aR as CopyButton$1, d4 as Select, d5 as ModalRoot, d6 as ModalOverlay, d7 as ModalContent, d8 as ModalBody, bP as Tabs, bQ as TabsList, bR as TabsTab, bS as TabsPanel, d9 as useMatches, da as useMantineTheme, db as useMediaQuery, dc as useDisclosure, b2 as Paper, aY as Divider, aX as Space, dd as useParentMatches, de as MenuLabel, a3 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, df as useSearch, aw as useDebouncedCallback, dg as LoadingOverlay, dh as toBlob, al as Tooltip, di as useAsync, dj as PanelGroup, dk as Panel, dl as PanelResizeHandle, dm as Burger, dn as RouterProvider, dp as createRouter$1, dq as createHashHistory, dr as createBrowserHistory, ds as createTheme, aU as Portal, X 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, b as useLikeC4Model$1, S as StaticLikeC4Diagram, M as MarkdownBlock, B as Box$1, d as useUpdateEffect, 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 LikeC4Diagram } from "./likec4.js";
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";
7
7
  import { pageTitle, ComponentName, useHashHistory, withOverviewGraph, krokiPumlSvgUrl, isDevelopment, krokiD2SvgUrl, basepath } from "./const.js";
8
8
  import { loadModel } from "likec4:model";
9
- import { nonexhaustive, compareNatural, toArray, sortParentsFirst, invariant, DefaultMap, isDescendantOf, isAncestor, nonNullable } from "@likec4/core/utils";
10
- import { computeRelationshipsView } from "@likec4/core/compute-view/relationships";
11
9
  function Fallback$1({ error, resetErrorBoundary }) {
12
10
  const router = useRouter();
13
11
  return isNotFound(error) ? /* @__PURE__ */ jsx(Container, { my: "md", children: /* @__PURE__ */ jsxs(Alert, { variant: "light", color: "orange", children: [
@@ -85,7 +83,7 @@ function NotFound() {
85
83
  }
86
84
  function LikeC4ProjectsContext({ children }) {
87
85
  const navigate = useNavigate(), onProjectChange = useCallbackRef((projectId) => {
88
- navigate({ to: "/project/$projectId/", params: { projectId } });
86
+ navigate({ to: "/project/$projectId/", params: { projectId } }).catch(console.error);
89
87
  });
90
88
  return /* @__PURE__ */ jsx(
91
89
  LikeC4ProjectsProvider,
@@ -109,6 +107,11 @@ const asTheme = (v) => {
109
107
  return Math.round(parseFloat(v));
110
108
  }
111
109
  return 20;
110
+ }, asDynamicVariant = (v) => {
111
+ if (typeof v != "string")
112
+ return "diagram";
113
+ const vlower = v.toLowerCase();
114
+ return vlower === "diagram" || vlower === "sequence" ? vlower : "diagram";
112
115
  }, Route$m = createRootRouteWithContext()({
113
116
  component: RootComponent,
114
117
  validateSearch: (search) => ({
@@ -117,13 +120,17 @@ const asTheme = (v) => {
117
120
  },
118
121
  ...e(search.theme) && {
119
122
  theme: asTheme(search.theme)
123
+ },
124
+ ...e(search.dynamic) && {
125
+ dynamic: asDynamicVariant(search.dynamic)
120
126
  }
121
127
  }),
122
128
  search: {
123
129
  middlewares: [
124
130
  stripSearchParams({
125
131
  padding: 20,
126
- theme: "auto"
132
+ theme: "auto",
133
+ dynamic: "diagram"
127
134
  })
128
135
  ]
129
136
  }
@@ -172,16 +179,18 @@ const ProjectIcons = lazy(async () => {
172
179
  }), ProjectIconRenderer = (props) => /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(Loader, { className: "pending", type: "oval", size: "xs" }), children: /* @__PURE__ */ jsx(ProjectIcons, { ...props }) });
173
180
  let _renderers = {};
174
181
  function LikeC4IconRendererContext({ children, projectId }) {
175
- const IconRenderer = _renderers[projectId] ?? (_renderers[projectId] = (props) => /* @__PURE__ */ jsx(ProjectIconRenderer, { ...props, projectId }));
182
+ const IconRenderer = _renderers[projectId] ??= (props) => /* @__PURE__ */ jsx(ProjectIconRenderer, { ...props, projectId });
176
183
  return /* @__PURE__ */ jsx(IconRendererProvider, { value: IconRenderer, children });
177
184
  }
178
- const LikeC4ModelDataContext = createContext(null);
179
- function useLikeC4ModelDataAtom() {
180
- return useContext(LikeC4ModelDataContext);
181
- }
185
+ const LikeC4ModelDataContext = createContext(null), LikeC4ModelDataContextProvider = LikeC4ModelDataContext.Provider, useLikeC4ModelDataAtom = () => {
186
+ const ctx = useContext(LikeC4ModelDataContext);
187
+ if (ctx === null)
188
+ throw new Error("LikeC4ModelDataAtom is not provided");
189
+ return ctx;
190
+ };
182
191
  function LikeC4ModelContext({ likec4data, likec4model, children }) {
183
192
  const model = useStore(likec4model);
184
- return /* @__PURE__ */ jsx(LikeC4ModelDataContext.Provider, { value: likec4data, children: /* @__PURE__ */ jsx(LikeC4ModelProvider, { likec4model: model, children }) });
193
+ return /* @__PURE__ */ jsx(LikeC4ModelDataContextProvider, { value: likec4data, children: /* @__PURE__ */ jsx(LikeC4ModelProvider, { likec4model: model, children }) });
185
194
  }
186
195
  css({
187
196
  position: "absolute",
@@ -258,6 +267,42 @@ const Route$j = createFileRoute("/")({
258
267
  }
259
268
  )
260
269
  });
270
+ function useTransparentBackground(enabled = !0) {
271
+ useIsomorphicLayoutEffect(() => {
272
+ const htmlEl = document.body.parentElement;
273
+ if (!htmlEl || enabled !== !0) return;
274
+ const classname = "transparent-bg";
275
+ return htmlEl.classList.add(classname), () => {
276
+ htmlEl.classList.remove(classname);
277
+ };
278
+ }, [enabled]);
279
+ }
280
+ function useLikeC4Views() {
281
+ const $likec4data = useLikeC4ModelDataAtom(), [views, setViews] = useState([]);
282
+ return useEffect(() => $likec4data.subscribe((next) => {
283
+ setViews((prev) => {
284
+ const nextViews = t(next.views);
285
+ return shallowEqual(prev, nextViews) ? prev : nextViews;
286
+ });
287
+ }), [$likec4data]), views;
288
+ }
289
+ function useCurrentViewId() {
290
+ return useParams({
291
+ select: (params) => params.viewId ?? "index",
292
+ strict: !1
293
+ });
294
+ }
295
+ function useCurrentDiagram() {
296
+ const viewId = useCurrentViewId();
297
+ return useLikeC4Views().find((v) => v.id === viewId) ?? null;
298
+ }
299
+ function useCurrentProject() {
300
+ const projects2 = useLikeC4Projects(), projectId = useParams({
301
+ select: (params) => params.projectId,
302
+ strict: !1
303
+ });
304
+ return projects2.find((p) => p.id === projectId) ?? projects2[0];
305
+ }
261
306
  css({
262
307
  color: "mantine.colors.dimmed"
263
308
  });
@@ -291,7 +336,7 @@ const previewBg = css({
291
336
  });
292
337
  function RouteComponent$1() {
293
338
  useDocumentTitle(pageTitle);
294
- const views = [...useLikeC4Model$1().views()];
339
+ const views = useLikeC4Views();
295
340
  return /* @__PURE__ */ jsx(Container, { size: "xl", children: /* @__PURE__ */ jsx(
296
341
  SimpleGrid,
297
342
  {
@@ -323,7 +368,7 @@ function ViewCard({ view }) {
323
368
  StaticLikeC4Diagram,
324
369
  {
325
370
  background: "transparent",
326
- view: view.$view,
371
+ view,
327
372
  fitView: !0,
328
373
  fitViewPadding: "4px",
329
374
  reduceGraphics: !0
@@ -331,9 +376,9 @@ function ViewCard({ view }) {
331
376
  ) }) }),
332
377
  /* @__PURE__ */ jsx(Group, { justify: "space-between", mt: "md", children: /* @__PURE__ */ jsx(Text, { fw: 500, children: view.title ?? view.id }) }),
333
378
  /* @__PURE__ */ jsx(
334
- MarkdownBlock,
379
+ Markdown,
335
380
  {
336
- value: view.description,
381
+ value: RichText.from(view.description),
337
382
  textScale: 0.75,
338
383
  emptyText: "No description",
339
384
  lineClamp: 3,
@@ -464,42 +509,6 @@ function WebcomponentPage() {
464
509
  }
465
510
  );
466
511
  }
467
- function useTransparentBackground(enabled = !0) {
468
- useIsomorphicLayoutEffect(() => {
469
- const htmlEl = document.body.parentElement;
470
- if (!htmlEl || enabled !== !0) return;
471
- const classname = "transparent-bg";
472
- return htmlEl.classList.add(classname), () => {
473
- htmlEl.classList.remove(classname);
474
- };
475
- }, [enabled]);
476
- }
477
- function useLikeC4Views() {
478
- const $likec4data = useLikeC4ModelDataAtom(), [views, setViews] = useState([]);
479
- return useEffect(() => $likec4data.subscribe((next) => {
480
- setViews((prev) => {
481
- const nextViews = t(next.views);
482
- return shallowEqual(prev, nextViews) ? prev : nextViews;
483
- });
484
- }), [$likec4data]), views;
485
- }
486
- function useCurrentViewId() {
487
- return useParams({
488
- select: (params) => params.viewId ?? "index",
489
- strict: !1
490
- });
491
- }
492
- function useCurrentDiagram() {
493
- const viewId = useCurrentViewId();
494
- return useLikeC4Views().find((v) => v.id === viewId) ?? null;
495
- }
496
- function useCurrentProject() {
497
- const projects2 = useLikeC4Projects(), projectId = useParams({
498
- select: (params) => params.projectId,
499
- strict: !1
500
- });
501
- return projects2.find((p) => p.id === projectId) ?? projects2[0];
502
- }
503
512
  const isTreeNodeData = (node) => "type" in node && ["file", "folder", "view", "deployment-view"].includes(node.type);
504
513
  function dropFilename(relativePath) {
505
514
  return relativePath === "" ? "" : relativePath.split("/").slice(0, -1).join("/");
@@ -531,10 +540,10 @@ function buildDiagramTreeData(views, groupBy) {
531
540
  let relativePath;
532
541
  switch (groupBy) {
533
542
  case "by-files":
534
- relativePath = view.$view.relativePath ?? "";
543
+ relativePath = view.$view.sourcePath ?? "";
535
544
  break;
536
545
  case "by-folders":
537
- relativePath = dropFilename(view.$view.relativePath ?? "");
546
+ relativePath = dropFilename(view.$view.sourcePath ?? "");
538
547
  break;
539
548
  case "none":
540
549
  relativePath = "";
@@ -567,21 +576,21 @@ const isFile = (node) => isTreeNodeData(node) && node.type === "file", FolderIco
567
576
  viewId: viewId2
568
577
  })
569
578
  });
570
- }, diagram = useCurrentDiagram(), viewId = (diagram == null ? void 0 : diagram.id) ?? null, tree = useTree({
579
+ }, diagram = useCurrentDiagram(), viewId = diagram?.id ?? null, tree = useTree({
571
580
  multiple: !1
572
581
  });
573
582
  tree.setHoveredNode = setHoveredNode;
574
- const relativePath = (diagram == null ? void 0 : diagram.relativePath) ?? null;
583
+ const sourcePath = diagram?.sourcePath ?? null;
575
584
  useUpdateEffect(() => {
576
585
  tree.collapseAllNodes();
577
586
  }, [groupBy]), useEffect(() => {
578
- if (relativePath) {
579
- const segments = relativePath.split("/");
587
+ if (sourcePath) {
588
+ const segments = sourcePath.split("/");
580
589
  let path = "@fs";
581
590
  for (const segment of segments)
582
591
  path += `/${segment}`, tree.expand(path);
583
592
  }
584
- }, [relativePath, groupBy]), useEffect(() => {
593
+ }, [sourcePath, groupBy]), useEffect(() => {
585
594
  viewId && tree.select(viewId);
586
595
  }, [viewId]);
587
596
  const theme2 = useComputedColorScheme();
@@ -892,7 +901,11 @@ function WebcomponentsPanel({ diagram }) {
892
901
  window.location.href
893
902
  ).href}"><\/script>
894
903
  `.trim(), htmlCode = `
895
- <${ComponentName.View} view-id="${encodeURIComponent(diagram.id)}"></${ComponentName.View}>
904
+ <${ComponentName.View}
905
+ view-id="${encodeURIComponent(diagram.id)}"
906
+ browser="true"
907
+ dynamic-variant="sequence">
908
+ </${ComponentName.View}>
896
909
  `.trim(), webcomponentPreview = router.buildLocation(
897
910
  {
898
911
  to: "/webcomponent/$",
@@ -1283,7 +1296,6 @@ function applyDagreLayout(g) {
1283
1296
  };
1284
1297
  }
1285
1298
  function layoutRelationshipsView(data) {
1286
- var _a, _b;
1287
1299
  const g = createGraph(), incomers = createNodes("in", data.incomers, g), subjects = createNodes("subject", data.subjects, g), outgoers = createNodes("out", data.outgoers, g), edges = [];
1288
1300
  t$1(
1289
1301
  t$5(
@@ -1332,7 +1344,7 @@ function layoutRelationshipsView(data) {
1332
1344
  const nodeId = subjectNode.id, node = g.node(nodeId);
1333
1345
  if (node.isCompound)
1334
1346
  continue;
1335
- const edgeCount = Math.max(((_a = g.inEdges(nodeId)) == null ? void 0 : _a.length) ?? 0, ((_b = g.outEdges(nodeId)) == null ? void 0 : _b.length) ?? 0);
1347
+ const edgeCount = Math.max(g.inEdges(nodeId)?.length ?? 0, g.outEdges(nodeId)?.length ?? 0);
1336
1348
  edgeCount > 2 && (node.height = node.height + (edgeCount - 3) * 14);
1337
1349
  }
1338
1350
  const dagreBounds = applyDagreLayout(g), nodeIds = [
@@ -1346,7 +1358,7 @@ function layoutRelationshipsView(data) {
1346
1358
  t$6((n2) => [n2.id, dagreBounds(n2.id)])
1347
1359
  );
1348
1360
  function nodeBounds(nodeId) {
1349
- return _calculatedNodeBounds[nodeId] ?? (_calculatedNodeBounds[nodeId] = t$1(
1361
+ return _calculatedNodeBounds[nodeId] ??= t$1(
1350
1362
  g.children(nodeId) ?? [],
1351
1363
  n((id) => !id.endsWith(PortSuffix)),
1352
1364
  t$3((id) => nodeBounds(id)),
@@ -1371,7 +1383,7 @@ function layoutRelationshipsView(data) {
1371
1383
  height: maxY - minY2
1372
1384
  };
1373
1385
  }
1374
- ));
1386
+ );
1375
1387
  }
1376
1388
  function nodeLevel(nodeId) {
1377
1389
  const parent = g.parent(nodeId);
@@ -1383,16 +1395,14 @@ function layoutRelationshipsView(data) {
1383
1395
  }
1384
1396
  let minX = 0, minY = 0;
1385
1397
  const nodes = nodeIds.map(({ id }) => {
1386
- var _a2;
1387
1398
  const { element } = g.node(id);
1388
1399
  let { position, width, height } = nodeBounds(id);
1389
1400
  const parentId = g.parent(id), children = (g.children(id) ?? []).filter((c) => !c.endsWith(PortSuffix));
1390
1401
  minX = Math.min(minX, position.x), minY = Math.min(minY, position.y);
1391
- const navigateTo = ((_a2 = element.defaultView) == null ? void 0 : _a2.id) ?? null;
1392
- return {
1402
+ const navigateTo = element.defaultView?.id ?? null, { icon, shape, color, ...style } = element.style;
1403
+ return exact({
1393
1404
  id,
1394
1405
  parent: parentId ?? null,
1395
- position: [position.x, position.y],
1396
1406
  x: position.x,
1397
1407
  y: position.y,
1398
1408
  title: element.title,
@@ -1400,8 +1410,9 @@ function layoutRelationshipsView(data) {
1400
1410
  technology: element.technology,
1401
1411
  tags: element.tags,
1402
1412
  links: null,
1403
- color: element.color,
1404
- shape: element.shape,
1413
+ color,
1414
+ shape,
1415
+ icon,
1405
1416
  modelRef: element.id,
1406
1417
  kind: element.kind,
1407
1418
  level: nodeLevel(id),
@@ -1411,9 +1422,7 @@ function layoutRelationshipsView(data) {
1411
1422
  width,
1412
1423
  height
1413
1424
  },
1414
- style: {
1415
- ...element.$element.style
1416
- },
1425
+ style,
1417
1426
  navigateTo,
1418
1427
  inEdges: [],
1419
1428
  outEdges: [],
@@ -1421,7 +1430,7 @@ function layoutRelationshipsView(data) {
1421
1430
  children,
1422
1431
  width,
1423
1432
  height
1424
- };
1433
+ });
1425
1434
  });
1426
1435
  return {
1427
1436
  bounds: {
@@ -1433,7 +1442,7 @@ function layoutRelationshipsView(data) {
1433
1442
  nodes,
1434
1443
  edges: g.edges().map((e2) => {
1435
1444
  const edge = g.edge(e2), ename = e2.name;
1436
- invariant(ename, `Edge ${e2} has no name`);
1445
+ invariant(ename, "Edge has no name");
1437
1446
  const { name, source, target, relations } = r(edges, (e22) => e22.name === ename), points = edge.points.map((p) => [p.x, p.y]);
1438
1447
  return invariant(t$7(points, 1), `Edge ${name} has less than 2 points`), {
1439
1448
  id: name,
@@ -1442,7 +1451,9 @@ function layoutRelationshipsView(data) {
1442
1451
  label: null,
1443
1452
  relations: relations.map((r2) => r2.id),
1444
1453
  parent: null,
1445
- points
1454
+ points,
1455
+ color: "gray",
1456
+ line: "dashed"
1446
1457
  };
1447
1458
  })
1448
1459
  };
@@ -1474,7 +1485,6 @@ async function downloadAsPng({
1474
1485
  pngFilename,
1475
1486
  viewport
1476
1487
  }) {
1477
- const { toBlob } = await import("./vendors.js").then((n2) => n2.de);
1478
1488
  try {
1479
1489
  const blob = await toBlob(viewport, {
1480
1490
  backgroundColor: "transparent",
@@ -1492,44 +1502,43 @@ async function downloadAsPng({
1492
1502
  function ExportPage() {
1493
1503
  const {
1494
1504
  padding = 20,
1495
- download = !1
1505
+ download = !1,
1506
+ dynamic
1496
1507
  } = useSearch({
1497
1508
  strict: !1
1498
1509
  }), diagram = useCurrentDiagram(), viewportRef = useRef(null), loadingOverlayRef = useRef(null), downloadedRef = useRef(!1);
1499
- if (useTransparentBackground(), useEffect(
1500
- () => {
1501
- if (!viewportRef.current)
1502
- return;
1503
- [...viewportRef.current.querySelectorAll(".react-flow__viewport")].forEach((el) => {
1504
- el.style.transform = "translate(" + padding + "px, " + padding + "px)";
1505
- });
1506
- }
1507
- ), useDebouncedEffect(
1510
+ useTransparentBackground();
1511
+ const downloadDiagram = useDebouncedCallback(
1508
1512
  () => {
1509
1513
  const viewport = viewportRef.current;
1510
- if (!download || !viewport || !diagram)
1514
+ if (!download || !viewport || !diagram || downloadedRef.current)
1511
1515
  return;
1512
1516
  const loadingOverlay = loadingOverlayRef.current;
1513
- loadingOverlay && (loadingOverlay.style.display = "none"), !downloadedRef.current && (downloadedRef.current = !0, downloadAsPng({
1517
+ loadingOverlay && (loadingOverlay.style.display = "none"), downloadedRef.current = !0, downloadAsPng({
1514
1518
  pngFilename: diagram.id,
1515
1519
  viewport
1516
- }));
1520
+ });
1517
1521
  },
1518
1522
  [diagram],
1519
1523
  500
1520
- ), !diagram)
1524
+ );
1525
+ if (!diagram)
1521
1526
  return /* @__PURE__ */ jsx("div", { children: "Loading..." });
1522
- const extraPadding = 16, width = diagram.bounds.width + padding * 2 + extraPadding, height = diagram.bounds.height + padding * 2 + extraPadding;
1527
+ const bounds = getViewBounds(diagram, dynamic), extraPadding = 16, width = bounds.width + padding * 2 + extraPadding, height = bounds.height + padding * 2 + extraPadding;
1523
1528
  return /* @__PURE__ */ jsxs(
1524
1529
  Box$1,
1525
1530
  {
1526
1531
  ref: viewportRef,
1527
1532
  "data-testid": "export-page",
1528
1533
  css: {
1534
+ position: "fixed",
1535
+ top: "0",
1536
+ left: "0",
1529
1537
  padding: "0",
1530
1538
  margin: "0",
1531
1539
  background: "transparent",
1532
- overflow: "hidden"
1540
+ overflow: "hidden",
1541
+ zIndex: 2
1533
1542
  },
1534
1543
  style: {
1535
1544
  marginRight: "auto",
@@ -1542,15 +1551,43 @@ function ExportPage() {
1542
1551
  children: [
1543
1552
  download && /* @__PURE__ */ jsx(LoadingOverlay, { ref: loadingOverlayRef, visible: !0 }),
1544
1553
  /* @__PURE__ */ jsx(
1545
- StaticLikeC4Diagram,
1554
+ LikeC4Diagram,
1546
1555
  {
1547
1556
  view: diagram,
1548
1557
  fitView: !1,
1549
- fitViewPadding: 0,
1558
+ fitViewPadding: {
1559
+ top: "0px",
1560
+ bottom: "0px",
1561
+ left: "0px",
1562
+ right: "0px"
1563
+ },
1550
1564
  background: "transparent",
1551
1565
  reduceGraphics: !1,
1552
- initialWidth: diagram.bounds.width,
1553
- initialHeight: diagram.bounds.height
1566
+ dynamicViewVariant: dynamic,
1567
+ readonly: !0,
1568
+ className: "likec4-static-view",
1569
+ pannable: !1,
1570
+ zoomable: !1,
1571
+ controls: !1,
1572
+ showNotations: !1,
1573
+ enableElementDetails: !1,
1574
+ enableRelationshipDetails: !1,
1575
+ enableRelationshipBrowser: !1,
1576
+ enableDynamicViewWalkthrough: !1,
1577
+ enableFocusMode: !1,
1578
+ enableSearch: !1,
1579
+ nodesSelectable: !1,
1580
+ nodesDraggable: !1,
1581
+ enableElementTags: !1,
1582
+ onInitialized: () => {
1583
+ if (!viewportRef.current) {
1584
+ console.error("viewportRef.current is null");
1585
+ return;
1586
+ }
1587
+ [...viewportRef.current.querySelectorAll(".react-flow__viewport")].forEach((el) => {
1588
+ el.style.transform = "translate(" + padding + "px, " + padding + "px)";
1589
+ }), download && downloadDiagram();
1590
+ }
1554
1591
  }
1555
1592
  )
1556
1593
  ]
@@ -1569,10 +1606,16 @@ const asBoolean$1 = (v) => {
1569
1606
  })
1570
1607
  });
1571
1608
  function EmbedPage() {
1572
- const { padding = 20 } = useSearch({
1609
+ const {
1610
+ padding = 20,
1611
+ dynamic
1612
+ } = useSearch({
1573
1613
  strict: !1
1574
1614
  }), diagram = useCurrentDiagram();
1575
- return useTransparentBackground(!!diagram), diagram ? /* @__PURE__ */ jsx(
1615
+ if (useTransparentBackground(!!diagram), !diagram)
1616
+ return /* @__PURE__ */ jsx("div", { children: "Loading..." });
1617
+ const bounds = getViewBounds(diagram, dynamic);
1618
+ return /* @__PURE__ */ jsx(
1576
1619
  "div",
1577
1620
  {
1578
1621
  style: {
@@ -1582,9 +1625,9 @@ function EmbedPage() {
1582
1625
  boxSizing: "border-box",
1583
1626
  padding,
1584
1627
  transform: "translateX(-50%)",
1585
- aspectRatio: `${diagram.bounds.width + padding * 2} / ${diagram.bounds.height + padding * 2}`,
1628
+ aspectRatio: `${bounds.width + padding * 2} / ${bounds.height + padding * 2}`,
1586
1629
  width: "100vw",
1587
- maxWidth: diagram.bounds.width + padding * 2,
1630
+ maxWidth: bounds.width + padding * 2,
1588
1631
  height: "auto",
1589
1632
  maxHeight: "100vh"
1590
1633
  },
@@ -1595,19 +1638,21 @@ function EmbedPage() {
1595
1638
  fitView: !0,
1596
1639
  background: "transparent",
1597
1640
  fitViewPadding: 0,
1598
- initialWidth: diagram.bounds.width,
1599
- initialHeight: diagram.bounds.height
1641
+ dynamicViewVariant: dynamic,
1642
+ initialWidth: bounds.width,
1643
+ initialHeight: bounds.height
1600
1644
  }
1601
1645
  )
1602
1646
  }
1603
- ) : /* @__PURE__ */ jsx("div", { children: "Loading..." });
1647
+ );
1604
1648
  }
1605
1649
  const Route$b = createFileRoute("/_single/embed/$viewId")({
1606
1650
  component: EmbedPage
1607
1651
  });
1608
1652
  function ViewReact() {
1609
- var _a;
1610
- const navigate = useNavigate(), view = useCurrentDiagram(), model = useLikeC4Model$1(), onNavigateTo = useCallbackRef((viewId) => {
1653
+ const navigate = useNavigate(), view = useCurrentDiagram(), model = useLikeC4Model$1(), { dynamic } = useSearch({
1654
+ from: "__root__"
1655
+ }), onNavigateTo = useCallbackRef((viewId) => {
1611
1656
  navigate({
1612
1657
  to: "./",
1613
1658
  viewTransition: !1,
@@ -1620,7 +1665,7 @@ function ViewReact() {
1620
1665
  }), title2 = view ? view.title ?? view.id : "View not found", pageTitle$1 = model.project.title ?? pageTitle;
1621
1666
  if (useDocumentTitle(`${title2} - ${pageTitle$1}`), !view)
1622
1667
  return /* @__PURE__ */ jsx(NotFound, {});
1623
- const hasNotations = (((_a = view.notation) == null ? void 0 : _a.nodes) ?? []).length > 0;
1668
+ const hasNotations = (view.notation?.nodes ?? []).length > 0;
1624
1669
  return /* @__PURE__ */ jsx(
1625
1670
  LikeC4Diagram,
1626
1671
  {
@@ -1628,17 +1673,18 @@ function ViewReact() {
1628
1673
  readonly: !0,
1629
1674
  zoomable: !0,
1630
1675
  pannable: !0,
1631
- controls: "next",
1676
+ controls: !0,
1632
1677
  fitViewPadding: {
1633
1678
  top: "70px",
1634
- bottom: "16px",
1635
- left: "16px",
1636
- right: "16px"
1679
+ bottom: "32px",
1680
+ left: "32px",
1681
+ right: "32px"
1637
1682
  },
1638
- showDiagramTitle: !0,
1639
1683
  showNavigationButtons: !0,
1684
+ enableSearch: !0,
1640
1685
  enableFocusMode: !0,
1641
1686
  enableDynamicViewWalkthrough: !0,
1687
+ dynamicViewVariant: dynamic,
1642
1688
  enableElementDetails: !0,
1643
1689
  enableRelationshipDetails: !0,
1644
1690
  enableRelationshipBrowser: !0,
@@ -1652,10 +1698,23 @@ function ViewReact() {
1652
1698
  navigate({
1653
1699
  to: "/"
1654
1700
  });
1655
- }
1701
+ },
1702
+ children: /* @__PURE__ */ jsx(DiagramListener, {})
1656
1703
  }
1657
1704
  );
1658
1705
  }
1706
+ function DiagramListener() {
1707
+ const router = useRouter(), dynamicViewVariant = useDiagramContext((c) => c.dynamicViewVariant);
1708
+ return useUpdateEffect(() => {
1709
+ (router.latestLocation.search.dynamic ?? "diagram") !== dynamicViewVariant && router.buildAndCommitLocation({
1710
+ search: (current) => ({
1711
+ ...current,
1712
+ dynamic: dynamicViewVariant
1713
+ }),
1714
+ viewTransition: !1
1715
+ });
1716
+ }, [dynamicViewVariant]), null;
1717
+ }
1659
1718
  const Route$a = createFileRoute("/_single/view/$viewId/")({
1660
1719
  component: ViewReact
1661
1720
  }), Route$9 = createFileRoute("/project/$projectId/view/$viewId")({
@@ -1710,8 +1769,8 @@ const cssScrollArea = css({
1710
1769
  return {
1711
1770
  source: pumlSource(viewId)
1712
1771
  };
1713
- } catch {
1714
- throw notFound();
1772
+ } catch (error) {
1773
+ throw console.error(error), notFound();
1715
1774
  }
1716
1775
  }
1717
1776
  }), fetchFromKroki$1 = async (puml) => await (await fetch(krokiPumlSvgUrl, {
@@ -1726,7 +1785,6 @@ const cssScrollArea = css({
1726
1785
  }
1727
1786
  })).text();
1728
1787
  function ViewAsPuml() {
1729
- var _a;
1730
1788
  const { source } = Route$6.useLoaderData(), [krokiSvg, { execute }] = useAsync(fetchFromKroki$1, null);
1731
1789
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1732
1790
  /* @__PURE__ */ jsxs(PanelGroup, { className: viewWithTopPadding, direction: "horizontal", autoSaveId: "viewAsPuml", children: [
@@ -1766,7 +1824,7 @@ function ViewAsPuml() {
1766
1824
  children: krokiSvg.status === "loading" ? "Loading..." : "Render with Kroki"
1767
1825
  }
1768
1826
  ),
1769
- krokiSvg.status === "error" && /* @__PURE__ */ jsx(Box, { children: (_a = krokiSvg.error) == null ? void 0 : _a.message })
1827
+ krokiSvg.status === "error" && /* @__PURE__ */ jsx(Box, { children: krokiSvg.error?.message })
1770
1828
  ] }),
1771
1829
  krokiSvg.status === "success" && /* @__PURE__ */ jsx(Box, { className: svgContainer, children: krokiSvg.result ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: krokiSvg.result } }) : /* @__PURE__ */ jsx(Box, { children: "Empty result" }) })
1772
1830
  ] }) })
@@ -1799,8 +1857,8 @@ const Route$5 = createFileRoute("/_single/view/$viewId/mmd")({
1799
1857
  return {
1800
1858
  source: mmdSource(viewId)
1801
1859
  };
1802
- } catch {
1803
- throw notFound();
1860
+ } catch (error) {
1861
+ throw console.error(error), notFound();
1804
1862
  }
1805
1863
  }
1806
1864
  }), renderSvg = async (viewId, diagram) => {
@@ -1862,7 +1920,6 @@ function ViewAsMmd() {
1862
1920
  ] });
1863
1921
  }
1864
1922
  function ViewEditor() {
1865
- var _a;
1866
1923
  const router = useRouter(), view = useCurrentDiagram(), onNavigateTo = useCallbackRef((viewId) => {
1867
1924
  const loc = router.buildLocation({
1868
1925
  to: ".",
@@ -1876,7 +1933,7 @@ function ViewEditor() {
1876
1933
  });
1877
1934
  if (!view)
1878
1935
  return /* @__PURE__ */ jsx(NotFound, {});
1879
- const hasNotations = (((_a = view.notation) == null ? void 0 : _a.nodes) ?? []).length > 0;
1936
+ const hasNotations = (view.notation?.nodes ?? []).length > 0;
1880
1937
  return /* @__PURE__ */ jsx(
1881
1938
  LikeC4Diagram,
1882
1939
  {
@@ -1884,18 +1941,18 @@ function ViewEditor() {
1884
1941
  readonly: !1,
1885
1942
  zoomable: !0,
1886
1943
  pannable: !0,
1887
- controls: "next",
1944
+ controls: !0,
1888
1945
  nodesDraggable: !0,
1889
1946
  experimentalEdgeEditing: !0,
1890
1947
  fitViewPadding: {
1891
1948
  top: "70px",
1892
- bottom: "10px",
1949
+ bottom: "32px",
1893
1950
  left: "50px",
1894
- right: "10px"
1951
+ right: "32px"
1895
1952
  },
1896
- showDiagramTitle: !0,
1897
1953
  showNavigationButtons: !0,
1898
1954
  showNotations: isDevelopment || hasNotations,
1955
+ enableSearch: !0,
1899
1956
  enableDynamicViewWalkthrough: !0,
1900
1957
  enableFocusMode: !0,
1901
1958
  enableElementDetails: !0,
@@ -1988,8 +2045,8 @@ const Route$2 = createFileRoute("/_single/view/$viewId/d2")({
1988
2045
  return {
1989
2046
  source: d2Source(viewId)
1990
2047
  };
1991
- } catch {
1992
- throw notFound();
2048
+ } catch (error) {
2049
+ throw console.error(error), notFound();
1993
2050
  }
1994
2051
  }
1995
2052
  }), fetchFromKroki = async (d2) => await (await fetch(krokiD2SvgUrl, {
@@ -2007,7 +2064,6 @@ const Route$2 = createFileRoute("/_single/view/$viewId/d2")({
2007
2064
  }
2008
2065
  })).text();
2009
2066
  function ViewAsD2() {
2010
- var _a;
2011
2067
  const { source } = Route$2.useLoaderData(), [krokiSvg, { execute }] = useAsync(fetchFromKroki, null);
2012
2068
  return /* @__PURE__ */ jsxs(Fragment, { children: [
2013
2069
  /* @__PURE__ */ jsxs(PanelGroup, { className: viewWithTopPadding, direction: "horizontal", autoSaveId: "viewAsD2", children: [
@@ -2047,7 +2103,7 @@ function ViewAsD2() {
2047
2103
  children: krokiSvg.status === "loading" ? "Loading..." : "Render with Kroki"
2048
2104
  }
2049
2105
  ),
2050
- krokiSvg.status === "error" && /* @__PURE__ */ jsx(Box, { children: (_a = krokiSvg.error) == null ? void 0 : _a.message })
2106
+ krokiSvg.status === "error" && /* @__PURE__ */ jsx(Box, { children: krokiSvg.error?.message })
2051
2107
  ] }),
2052
2108
  krokiSvg.status === "success" && /* @__PURE__ */ jsx(Box, { className: svgContainer, children: krokiSvg.result ? /* @__PURE__ */ jsx("div", { dangerouslySetInnerHTML: { __html: krokiSvg.result } }) : /* @__PURE__ */ jsx(Box, { children: "Empty result" }) })
2053
2109
  ] }) })