likec4 0.41.0 → 0.42.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 (144) hide show
  1. package/README.md +108 -0
  2. package/dist/__app__/src/App.jsx +1 -1
  3. package/dist/__app__/src/components/view-page/ExportDiagram.jsx +72 -0
  4. package/dist/__app__/src/components/view-page/ViewActionsToolbar.jsx +38 -12
  5. package/dist/cli/index.js +53 -53
  6. package/package.json +6 -6
  7. package/dist/@likec4/diagrams/cjs/components/EmbeddedDiagram.js +0 -83
  8. package/dist/@likec4/diagrams/cjs/components/FullscreenDiagramBrowser.js +0 -50
  9. package/dist/@likec4/diagrams/cjs/components/index.js +0 -49
  10. package/dist/@likec4/diagrams/cjs/components/primitives/fullscreen/CloseButton.js +0 -44
  11. package/dist/@likec4/diagrams/cjs/components/primitives/fullscreen/FullscreenDiagram.js +0 -110
  12. package/dist/@likec4/diagrams/cjs/components/primitives/fullscreen/FullscreenDiagramTitle.js +0 -39
  13. package/dist/@likec4/diagrams/cjs/components/primitives/index.js +0 -38
  14. package/dist/@likec4/diagrams/cjs/components/primitives/responsive/ResponsiveDiagram.js +0 -56
  15. package/dist/@likec4/diagrams/cjs/components/types.js +0 -1
  16. package/dist/@likec4/diagrams/cjs/diagram/Diagram.js +0 -326
  17. package/dist/@likec4/diagrams/cjs/diagram/Edges.js +0 -121
  18. package/dist/@likec4/diagrams/cjs/diagram/Nodes.js +0 -204
  19. package/dist/@likec4/diagrams/cjs/diagram/icons/BrainIcon.js +0 -25
  20. package/dist/@likec4/diagrams/cjs/diagram/icons/ExternalLink.js +0 -82
  21. package/dist/@likec4/diagrams/cjs/diagram/icons/index.js +0 -27
  22. package/dist/@likec4/diagrams/cjs/diagram/index.js +0 -27
  23. package/dist/@likec4/diagrams/cjs/diagram/shapes/Browser.js +0 -67
  24. package/dist/@likec4/diagrams/cjs/diagram/shapes/Compound.js +0 -55
  25. package/dist/@likec4/diagrams/cjs/diagram/shapes/Cylinder.js +0 -71
  26. package/dist/@likec4/diagrams/cjs/diagram/shapes/Edge.js +0 -62
  27. package/dist/@likec4/diagrams/cjs/diagram/shapes/Mobile.js +0 -45
  28. package/dist/@likec4/diagrams/cjs/diagram/shapes/NodeIcon.js +0 -38
  29. package/dist/@likec4/diagrams/cjs/diagram/shapes/NodeLabel.js +0 -62
  30. package/dist/@likec4/diagrams/cjs/diagram/shapes/Person.js +0 -48
  31. package/dist/@likec4/diagrams/cjs/diagram/shapes/Queue.js +0 -72
  32. package/dist/@likec4/diagrams/cjs/diagram/shapes/Rectangle.js +0 -30
  33. package/dist/@likec4/diagrams/cjs/diagram/shapes/index.js +0 -54
  34. package/dist/@likec4/diagrams/cjs/diagram/shapes/types.js +0 -1
  35. package/dist/@likec4/diagrams/cjs/diagram/shapes/utils.js +0 -19
  36. package/dist/@likec4/diagrams/cjs/diagram/springs.js +0 -61
  37. package/dist/@likec4/diagrams/cjs/diagram/state/atoms.js +0 -63
  38. package/dist/@likec4/diagrams/cjs/diagram/state/gestures.js +0 -26
  39. package/dist/@likec4/diagrams/cjs/diagram/state/hooks.js +0 -36
  40. package/dist/@likec4/diagrams/cjs/diagram/state/index.js +0 -38
  41. package/dist/@likec4/diagrams/cjs/diagram/state/provider.js +0 -18
  42. package/dist/@likec4/diagrams/cjs/diagram/types.js +0 -1
  43. package/dist/@likec4/diagrams/cjs/hooks/index.js +0 -49
  44. package/dist/@likec4/diagrams/cjs/hooks/useDarkMode.js +0 -11
  45. package/dist/@likec4/diagrams/cjs/hooks/useDiagramApi.js +0 -27
  46. package/dist/@likec4/diagrams/cjs/hooks/useImageLoader.js +0 -68
  47. package/dist/@likec4/diagrams/cjs/hooks/useViewIdFromHash.js +0 -93
  48. package/dist/@likec4/diagrams/cjs/index.js +0 -51
  49. package/dist/@likec4/diagrams/cjs/konva-html.js +0 -93
  50. package/dist/@likec4/diagrams/cjs/konva-portal.js +0 -50
  51. package/dist/@likec4/diagrams/cjs/konva.js +0 -102
  52. package/dist/@likec4/diagrams/cjs/likec4.js +0 -91
  53. package/dist/@likec4/diagrams/components/EmbeddedDiagram.mjs +0 -77
  54. package/dist/@likec4/diagrams/components/FullscreenDiagramBrowser.mjs +0 -52
  55. package/dist/@likec4/diagrams/components/index.mjs +0 -4
  56. package/dist/@likec4/diagrams/components/primitives/fullscreen/CloseButton.mjs +0 -43
  57. package/dist/@likec4/diagrams/components/primitives/fullscreen/FullscreenDiagram.mjs +0 -116
  58. package/dist/@likec4/diagrams/components/primitives/fullscreen/FullscreenDiagramTitle.mjs +0 -32
  59. package/dist/@likec4/diagrams/components/primitives/index.mjs +0 -3
  60. package/dist/@likec4/diagrams/components/primitives/responsive/ResponsiveDiagram.mjs +0 -42
  61. package/dist/@likec4/diagrams/components/types.mjs +0 -0
  62. package/dist/@likec4/diagrams/diagram/Diagram.mjs +0 -307
  63. package/dist/@likec4/diagrams/diagram/Edges.mjs +0 -117
  64. package/dist/@likec4/diagrams/diagram/Nodes.mjs +0 -178
  65. package/dist/@likec4/diagrams/diagram/icons/BrainIcon.mjs +0 -20
  66. package/dist/@likec4/diagrams/diagram/icons/ExternalLink.mjs +0 -90
  67. package/dist/@likec4/diagrams/diagram/icons/index.mjs +0 -2
  68. package/dist/@likec4/diagrams/diagram/index.mjs +0 -2
  69. package/dist/@likec4/diagrams/diagram/shapes/Browser.mjs +0 -49
  70. package/dist/@likec4/diagrams/diagram/shapes/Compound.mjs +0 -48
  71. package/dist/@likec4/diagrams/diagram/shapes/Cylinder.mjs +0 -57
  72. package/dist/@likec4/diagrams/diagram/shapes/Edge.mjs +0 -63
  73. package/dist/@likec4/diagrams/diagram/shapes/Mobile.mjs +0 -33
  74. package/dist/@likec4/diagrams/diagram/shapes/NodeIcon.mjs +0 -28
  75. package/dist/@likec4/diagrams/diagram/shapes/NodeLabel.mjs +0 -59
  76. package/dist/@likec4/diagrams/diagram/shapes/Person.mjs +0 -42
  77. package/dist/@likec4/diagrams/diagram/shapes/Queue.mjs +0 -58
  78. package/dist/@likec4/diagrams/diagram/shapes/Rectangle.mjs +0 -20
  79. package/dist/@likec4/diagrams/diagram/shapes/index.mjs +0 -7
  80. package/dist/@likec4/diagrams/diagram/shapes/types.mjs +0 -0
  81. package/dist/@likec4/diagrams/diagram/shapes/utils.mjs +0 -12
  82. package/dist/@likec4/diagrams/diagram/springs.mjs +0 -57
  83. package/dist/@likec4/diagrams/diagram/state/atoms.mjs +0 -71
  84. package/dist/@likec4/diagrams/diagram/state/gestures.mjs +0 -19
  85. package/dist/@likec4/diagrams/diagram/state/hooks.mjs +0 -28
  86. package/dist/@likec4/diagrams/diagram/state/index.mjs +0 -3
  87. package/dist/@likec4/diagrams/diagram/state/provider.mjs +0 -7
  88. package/dist/@likec4/diagrams/diagram/types.mjs +0 -0
  89. package/dist/@likec4/diagrams/esm/components/EmbeddedDiagram.js +0 -77
  90. package/dist/@likec4/diagrams/esm/components/FullscreenDiagramBrowser.js +0 -52
  91. package/dist/@likec4/diagrams/esm/components/index.js +0 -4
  92. package/dist/@likec4/diagrams/esm/components/primitives/fullscreen/CloseButton.js +0 -43
  93. package/dist/@likec4/diagrams/esm/components/primitives/fullscreen/FullscreenDiagram.js +0 -116
  94. package/dist/@likec4/diagrams/esm/components/primitives/fullscreen/FullscreenDiagramTitle.js +0 -32
  95. package/dist/@likec4/diagrams/esm/components/primitives/index.js +0 -3
  96. package/dist/@likec4/diagrams/esm/components/primitives/responsive/ResponsiveDiagram.js +0 -42
  97. package/dist/@likec4/diagrams/esm/components/types.js +0 -0
  98. package/dist/@likec4/diagrams/esm/diagram/Diagram.js +0 -307
  99. package/dist/@likec4/diagrams/esm/diagram/Edges.js +0 -117
  100. package/dist/@likec4/diagrams/esm/diagram/Nodes.js +0 -178
  101. package/dist/@likec4/diagrams/esm/diagram/icons/BrainIcon.js +0 -20
  102. package/dist/@likec4/diagrams/esm/diagram/icons/ExternalLink.js +0 -90
  103. package/dist/@likec4/diagrams/esm/diagram/icons/index.js +0 -2
  104. package/dist/@likec4/diagrams/esm/diagram/index.js +0 -2
  105. package/dist/@likec4/diagrams/esm/diagram/shapes/Browser.js +0 -49
  106. package/dist/@likec4/diagrams/esm/diagram/shapes/Compound.js +0 -48
  107. package/dist/@likec4/diagrams/esm/diagram/shapes/Cylinder.js +0 -57
  108. package/dist/@likec4/diagrams/esm/diagram/shapes/Edge.js +0 -63
  109. package/dist/@likec4/diagrams/esm/diagram/shapes/Mobile.js +0 -33
  110. package/dist/@likec4/diagrams/esm/diagram/shapes/NodeIcon.js +0 -28
  111. package/dist/@likec4/diagrams/esm/diagram/shapes/NodeLabel.js +0 -59
  112. package/dist/@likec4/diagrams/esm/diagram/shapes/Person.js +0 -42
  113. package/dist/@likec4/diagrams/esm/diagram/shapes/Queue.js +0 -58
  114. package/dist/@likec4/diagrams/esm/diagram/shapes/Rectangle.js +0 -20
  115. package/dist/@likec4/diagrams/esm/diagram/shapes/index.js +0 -7
  116. package/dist/@likec4/diagrams/esm/diagram/shapes/types.js +0 -0
  117. package/dist/@likec4/diagrams/esm/diagram/shapes/utils.js +0 -12
  118. package/dist/@likec4/diagrams/esm/diagram/springs.js +0 -57
  119. package/dist/@likec4/diagrams/esm/diagram/state/atoms.js +0 -71
  120. package/dist/@likec4/diagrams/esm/diagram/state/gestures.js +0 -19
  121. package/dist/@likec4/diagrams/esm/diagram/state/hooks.js +0 -28
  122. package/dist/@likec4/diagrams/esm/diagram/state/index.js +0 -3
  123. package/dist/@likec4/diagrams/esm/diagram/state/provider.js +0 -7
  124. package/dist/@likec4/diagrams/esm/diagram/types.js +0 -0
  125. package/dist/@likec4/diagrams/esm/hooks/index.js +0 -4
  126. package/dist/@likec4/diagrams/esm/hooks/useDarkMode.js +0 -5
  127. package/dist/@likec4/diagrams/esm/hooks/useDiagramApi.js +0 -27
  128. package/dist/@likec4/diagrams/esm/hooks/useImageLoader.js +0 -64
  129. package/dist/@likec4/diagrams/esm/hooks/useViewIdFromHash.js +0 -87
  130. package/dist/@likec4/diagrams/esm/index.js +0 -4
  131. package/dist/@likec4/diagrams/esm/konva-html.js +0 -74
  132. package/dist/@likec4/diagrams/esm/konva-portal.js +0 -34
  133. package/dist/@likec4/diagrams/esm/konva.js +0 -22
  134. package/dist/@likec4/diagrams/esm/likec4.js +0 -54
  135. package/dist/@likec4/diagrams/hooks/index.mjs +0 -4
  136. package/dist/@likec4/diagrams/hooks/useDarkMode.mjs +0 -5
  137. package/dist/@likec4/diagrams/hooks/useDiagramApi.mjs +0 -27
  138. package/dist/@likec4/diagrams/hooks/useImageLoader.mjs +0 -64
  139. package/dist/@likec4/diagrams/hooks/useViewIdFromHash.mjs +0 -87
  140. package/dist/@likec4/diagrams/index.mjs +0 -4
  141. package/dist/@likec4/diagrams/konva-html.mjs +0 -74
  142. package/dist/@likec4/diagrams/konva-portal.mjs +0 -34
  143. package/dist/@likec4/diagrams/konva.mjs +0 -33
  144. package/dist/@likec4/diagrams/likec4.mjs +0 -54
@@ -1,4 +0,0 @@
1
- export * from "./useDarkMode.js";
2
- export * from "./useDiagramApi.js";
3
- export * from "./useImageLoader.js";
4
- export * from "./useViewIdFromHash.js";
@@ -1,5 +0,0 @@
1
- import { useMediaQuery } from "@react-hookz/web/esm";
2
- const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
3
- export function useDarkMode() {
4
- return useMediaQuery(COLOR_SCHEME_QUERY) ?? true;
5
- }
@@ -1,27 +0,0 @@
1
- import { useRef, useMemo } from "react";
2
- import { nonNullable } from "@likec4/core";
3
- export function useDiagramApi() {
4
- const ref = useRef(null);
5
- return useMemo(
6
- () => [
7
- ref,
8
- {
9
- get stage() {
10
- return nonNullable(ref.current, "not mounted, use ref").stage;
11
- },
12
- get diagramView() {
13
- return nonNullable(ref.current, "not mounted, use ref").diagramView;
14
- },
15
- get container() {
16
- return nonNullable(ref.current, "not mounted, use ref").container;
17
- },
18
- resetStageZoom: (_immediate) => {
19
- nonNullable(ref.current, "not mounted, use ref").resetStageZoom(_immediate);
20
- },
21
- centerOnNode: (node) => nonNullable(ref.current, "not mounted, use ref").centerOnNode(node),
22
- centerAndFit: () => nonNullable(ref.current, "not mounted, use ref").centerAndFit()
23
- }
24
- ],
25
- [ref]
26
- );
27
- }
@@ -1,64 +0,0 @@
1
- import { useLayoutEffect, useRef, useState } from "react";
2
- import { useIsMounted } from "@react-hookz/web/esm/useIsMounted";
3
- import { invariant } from "@likec4/core";
4
- const imageElements = /* @__PURE__ */ new Map();
5
- export default function useImageLoader(url, crossOrigin, referrerpolicy) {
6
- const isMounted = useIsMounted();
7
- const imageRef = useRef(url ? imageElements.get(url) : void 0);
8
- const statusRef = useRef(imageRef.current ? "loaded" : "loading");
9
- const [_, setStateToken] = useState(0);
10
- const urlRef = useRef(url);
11
- if (!url || urlRef.current !== url) {
12
- statusRef.current = "loading";
13
- imageRef.current = void 0;
14
- urlRef.current = url;
15
- }
16
- useLayoutEffect(() => {
17
- if (!url) {
18
- return;
19
- }
20
- const urlClosure = url;
21
- const imgCached = imageElements.get(url);
22
- if (imgCached) {
23
- statusRef.current = "loaded";
24
- if (imageRef.current !== imgCached) {
25
- imageRef.current = imgCached;
26
- setStateToken(Math.random());
27
- }
28
- return;
29
- }
30
- const img = document.createElement("img");
31
- function onload() {
32
- if (!isMounted())
33
- return;
34
- imageElements.set(urlClosure, img);
35
- if (urlRef.current === urlClosure) {
36
- statusRef.current = "loaded";
37
- imageRef.current = img;
38
- setStateToken(Math.random());
39
- }
40
- }
41
- function onerror() {
42
- if (!isMounted() || urlRef.current !== urlClosure)
43
- return;
44
- statusRef.current = "failed";
45
- imageRef.current = void 0;
46
- setStateToken(Math.random());
47
- }
48
- img.addEventListener("load", onload);
49
- img.addEventListener("error", onerror);
50
- crossOrigin && (img.crossOrigin = crossOrigin);
51
- referrerpolicy && (img.referrerPolicy = referrerpolicy);
52
- img.src = url;
53
- return () => {
54
- img.removeEventListener("load", onload);
55
- img.removeEventListener("error", onerror);
56
- };
57
- }, [url, crossOrigin ?? null, referrerpolicy ?? null]);
58
- if (imageRef.current !== void 0) {
59
- statusRef.current = "loaded";
60
- return [imageRef.current, "loaded"];
61
- }
62
- invariant(statusRef.current !== "loaded", "image status cant be loaded");
63
- return [imageRef.current, statusRef.current];
64
- }
@@ -1,87 +0,0 @@
1
- import { isString } from "@likec4/core";
2
- import { useCallback, useEffect, useRef, useState } from "react";
3
- function readViewIdFromUrl(url) {
4
- return readViewId(new URL(url).hash);
5
- }
6
- function readViewId(hash = window.location.hash) {
7
- if (hash.startsWith("#")) {
8
- hash = hash.slice(1);
9
- }
10
- if (hash.includes("likec4")) {
11
- return new URLSearchParams(hash).get("likec4");
12
- }
13
- return null;
14
- }
15
- function writeViewId(viewId) {
16
- let hash = window.location.hash;
17
- if (hash.startsWith("#")) {
18
- hash = hash.slice(1);
19
- }
20
- const hashParams = new URLSearchParams(hash);
21
- if (viewId != null) {
22
- if (hashParams.get("likec4") !== viewId) {
23
- hashParams.set("likec4", viewId);
24
- window.location.hash = hashParams.toString();
25
- }
26
- return;
27
- }
28
- if (viewId === null && hashParams.has("likec4")) {
29
- hashParams.delete("likec4");
30
- window.location.hash = hashParams.toString();
31
- return;
32
- }
33
- }
34
- const noopIsViewId = (value) => isString(value) && value.length > 0;
35
- export function useViewIdFromHash({
36
- initialViewId,
37
- onReturnToInitial,
38
- resetHashOnUnmount = true,
39
- isViewId = noopIsViewId
40
- }) {
41
- const [viewId, setStateViewId] = useState(() => {
42
- const id = readViewId();
43
- return isViewId(id) ? id : initialViewId;
44
- });
45
- const viewIdRef = useRef(viewId);
46
- const prevIdRef = useRef();
47
- if (viewIdRef.current !== viewId) {
48
- prevIdRef.current = viewIdRef.current;
49
- viewIdRef.current = viewId;
50
- }
51
- const onReturnRef = useRef(onReturnToInitial);
52
- onReturnRef.current = onReturnToInitial;
53
- useEffect(() => {
54
- const tm = setTimeout(() => {
55
- writeViewId(viewIdRef.current);
56
- }, 300);
57
- return () => clearTimeout(tm);
58
- }, []);
59
- useEffect(() => {
60
- const onHashChange = (ev) => {
61
- const newViewId = readViewIdFromUrl(ev.newURL);
62
- if (newViewId === null) {
63
- const oldViewId = readViewIdFromUrl(ev.oldURL);
64
- if (oldViewId != null && onReturnRef.current) {
65
- onReturnRef.current?.();
66
- }
67
- return;
68
- }
69
- if (isViewId(newViewId) && newViewId !== viewIdRef.current) {
70
- setStateViewId(newViewId);
71
- }
72
- };
73
- window.addEventListener("hashchange", onHashChange);
74
- return () => {
75
- window.removeEventListener("hashchange", onHashChange);
76
- if (resetHashOnUnmount) {
77
- writeViewId(null);
78
- }
79
- };
80
- }, []);
81
- const setViewId = useCallback((nextViewId) => {
82
- if (isViewId(nextViewId) && nextViewId !== viewIdRef.current) {
83
- writeViewId(nextViewId);
84
- }
85
- }, []);
86
- return [viewId, setViewId];
87
- }
@@ -1,4 +0,0 @@
1
- export * from "./diagram/index.js";
2
- export * from "./components/index.js";
3
- export * from "./hooks/index.js";
4
- export { LikeC4 } from "./likec4.js";
@@ -1,74 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
3
- import ReactDOM from "react-dom/client";
4
- import { Group } from "./konva.js";
5
- function needForceStyle(el) {
6
- const pos = window.getComputedStyle(el).position;
7
- const ok = pos === "absolute" || pos === "relative";
8
- return !ok;
9
- }
10
- export function KonvaHtml({ children, groupProps, divProps, transform, transformFunc }) {
11
- const groupRef = useRef(null);
12
- const [div] = useState(() => document.createElement("div"));
13
- const root = useMemo(() => ReactDOM.createRoot(div), [div]);
14
- const shouldTransform = transform ?? true;
15
- const handleTransform = useCallback(() => {
16
- if (shouldTransform && groupRef.current) {
17
- const tr = groupRef.current.getAbsoluteTransform();
18
- let attrs = tr.decompose();
19
- if (transformFunc) {
20
- attrs = transformFunc(attrs);
21
- }
22
- div.style.position = "absolute";
23
- div.style.zIndex = "10";
24
- div.style.top = "0px";
25
- div.style.left = "0px";
26
- div.style.transform = `translate(${attrs.x}px, ${attrs.y}px) rotate(${attrs.rotation}deg) scaleX(${attrs.scaleX}) scaleY(${attrs.scaleY})`;
27
- div.style.transformOrigin = "top left";
28
- } else {
29
- div.style.position = "";
30
- div.style.zIndex = "";
31
- div.style.top = "";
32
- div.style.left = "";
33
- div.style.transform = ``;
34
- div.style.transformOrigin = "";
35
- }
36
- const { style, ...restProps } = divProps || {};
37
- Object.assign(div.style, style);
38
- Object.assign(div, restProps);
39
- }, []);
40
- useLayoutEffect(() => {
41
- const group = groupRef.current;
42
- if (!group) {
43
- return;
44
- }
45
- const parent = group.getStage()?.container();
46
- if (!parent) {
47
- return;
48
- }
49
- parent.appendChild(div);
50
- if (shouldTransform && needForceStyle(parent)) {
51
- parent.style.position = "relative";
52
- }
53
- group.on("absoluteTransformChange", handleTransform);
54
- handleTransform();
55
- return () => {
56
- group.off("absoluteTransformChange", handleTransform);
57
- div.parentNode?.removeChild(div);
58
- };
59
- }, [shouldTransform]);
60
- useLayoutEffect(() => {
61
- handleTransform();
62
- }, [divProps, transformFunc]);
63
- useLayoutEffect(() => {
64
- root.render(children);
65
- });
66
- useLayoutEffect(() => {
67
- return () => {
68
- setTimeout(() => {
69
- root.unmount();
70
- });
71
- };
72
- }, []);
73
- return /* @__PURE__ */ jsx(Group, { ref: groupRef, ...groupProps });
74
- }
@@ -1,34 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { useEffect, useLayoutEffect, useRef } from "react";
3
- import { Group } from "./konva.js";
4
- export function Portal({ selector, enabled, children }) {
5
- const outer = useRef(null);
6
- const inner = useRef(null);
7
- const safeRef = useRef();
8
- const shouldMove = enabled ?? true;
9
- useLayoutEffect(() => {
10
- if (!outer.current || !inner.current) {
11
- return;
12
- }
13
- const stage = outer.current.getStage();
14
- if (!stage) {
15
- return;
16
- }
17
- if (shouldMove) {
18
- const newContainer = stage.findOne(selector);
19
- if (newContainer) {
20
- safeRef.current = inner.current;
21
- inner.current.moveTo(newContainer);
22
- }
23
- } else if (safeRef.current) {
24
- safeRef.current.moveTo(outer.current);
25
- safeRef.current = void 0;
26
- }
27
- }, [selector, shouldMove]);
28
- useEffect(() => {
29
- return () => {
30
- safeRef.current?.destroy();
31
- };
32
- }, []);
33
- return /* @__PURE__ */ jsx(Group, { ref: outer, children: /* @__PURE__ */ jsx(Group, { ref: inner, children }) });
34
- }
@@ -1,22 +0,0 @@
1
- import { Rect, Stage, Text, Group, Path, Circle, Line, Layer, Image, Ellipse } from "react-konva/es/ReactKonvaCore";
2
- import KonvaCore from "konva/lib/Core";
3
- import "konva/lib/shapes/Rect";
4
- import "konva/lib/shapes/Text";
5
- import "konva/lib/shapes/Path";
6
- import "konva/lib/shapes/Circle";
7
- import "konva/lib/shapes/Line";
8
- import "konva/lib/shapes/Image";
9
- import "konva/lib/shapes/Ellipse";
10
- import { animated } from "@react-spring/konva";
11
- KonvaCore.hitOnDragEnabled = true;
12
- KonvaCore.capturePointerEventsEnabled = true;
13
- KonvaCore.dragButtons = [0, 2];
14
- export { KonvaCore, Stage, Group, Layer, Path, Text, Line, Circle, Rect, Image, Ellipse };
15
- export const AnimatedStage = /* @__PURE__ */ animated(Stage);
16
- export const AnimatedRect = /* @__PURE__ */ animated(Rect);
17
- export const AnimatedGroup = /* @__PURE__ */ animated(Group);
18
- export const AnimatedText = /* @__PURE__ */ animated(Text);
19
- export const AnimatedPath = /* @__PURE__ */ animated(Path);
20
- export const AnimatedLine = /* @__PURE__ */ animated(Line);
21
- export const AnimatedCircle = /* @__PURE__ */ animated(Circle);
22
- export const AnimatedEllipse = /* @__PURE__ */ animated(Ellipse);
@@ -1,54 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { forwardRef } from "react";
3
- import { Diagram } from "./diagram/index.js";
4
- import { FullscreenDiagramBrowser, EmbeddedDiagram } from "./components/index.js";
5
- import { ResponsiveDiagram, FullscreenDiagram } from "./components/primitives/index.js";
6
- import { useViewIdFromHash } from "./hooks/useViewIdFromHash.js";
7
- export class LikeC4 {
8
- constructor(views) {
9
- this.views = views;
10
- }
11
- isViewId = (value) => {
12
- return value != null && typeof value === "string" && Object.prototype.hasOwnProperty.call(this.views, value);
13
- };
14
- /**
15
- * React hook to use location hash for ViewId.
16
- * When the element with this hook is mounted, hash is set to `...#likec4={initialViewId}`
17
- * When element with this hook is unmounted, `likec4` is removed from hash if `resetHashOnUnmount` is true (default: true)
18
- * You can also provide `onReturnToInitial` callback to handle back navigation (when user goes beyond the initialViewId)
19
- */
20
- useViewId = (props) => useViewIdFromHash({ ...props, isViewId: this.isViewId });
21
- Diagram = forwardRef(({ viewId, ...props }, ref) => {
22
- const diagram = this.views[viewId];
23
- if (!diagram) {
24
- throw new Error(`View "${viewId}" not found in views`);
25
- }
26
- return /* @__PURE__ */ jsx(Diagram, { ref, diagram, ...props });
27
- });
28
- Responsive = forwardRef(({ viewId, ...props }, ref) => {
29
- const diagram = this.views[viewId];
30
- if (!diagram) {
31
- throw new Error(`View "${viewId}" not found in views`);
32
- }
33
- return /* @__PURE__ */ jsx(ResponsiveDiagram, { ref, diagram, ...props });
34
- });
35
- Fullscreen = ({ viewId, ...props }) => {
36
- const diagram = this.views[viewId];
37
- if (!diagram) {
38
- throw new Error(`View "${viewId}" not found in views`);
39
- }
40
- return /* @__PURE__ */ jsx(FullscreenDiagram, { diagram, ...props });
41
- };
42
- Embedded = forwardRef((props, ref) => {
43
- return /* @__PURE__ */ jsx(EmbeddedDiagram, { ref, views: this.views, ...props });
44
- });
45
- Browser = (props) => {
46
- return /* @__PURE__ */ jsx(FullscreenDiagramBrowser, { views: this.views, ...props });
47
- };
48
- static create(views) {
49
- if (Object.keys(views).length === 0) {
50
- throw new Error("LikeC4: views must not be empty");
51
- }
52
- return new LikeC4(views);
53
- }
54
- }
@@ -1,4 +0,0 @@
1
- export * from "./useDarkMode.mjs";
2
- export * from "./useDiagramApi.mjs";
3
- export * from "./useImageLoader.mjs";
4
- export * from "./useViewIdFromHash.mjs";
@@ -1,5 +0,0 @@
1
- import { useMediaQuery } from "@react-hookz/web/esm";
2
- const COLOR_SCHEME_QUERY = "(prefers-color-scheme: dark)";
3
- export function useDarkMode() {
4
- return useMediaQuery(COLOR_SCHEME_QUERY) ?? true;
5
- }
@@ -1,27 +0,0 @@
1
- import { useRef, useMemo } from "react";
2
- import { nonNullable } from "@likec4/core";
3
- export function useDiagramApi() {
4
- const ref = useRef(null);
5
- return useMemo(
6
- () => [
7
- ref,
8
- {
9
- get stage() {
10
- return nonNullable(ref.current, "not mounted, use ref").stage;
11
- },
12
- get diagramView() {
13
- return nonNullable(ref.current, "not mounted, use ref").diagramView;
14
- },
15
- get container() {
16
- return nonNullable(ref.current, "not mounted, use ref").container;
17
- },
18
- resetStageZoom: (_immediate) => {
19
- nonNullable(ref.current, "not mounted, use ref").resetStageZoom(_immediate);
20
- },
21
- centerOnNode: (node) => nonNullable(ref.current, "not mounted, use ref").centerOnNode(node),
22
- centerAndFit: () => nonNullable(ref.current, "not mounted, use ref").centerAndFit()
23
- }
24
- ],
25
- [ref]
26
- );
27
- }
@@ -1,64 +0,0 @@
1
- import { useLayoutEffect, useRef, useState } from "react";
2
- import { useIsMounted } from "@react-hookz/web/esm/useIsMounted";
3
- import { invariant } from "@likec4/core";
4
- const imageElements = /* @__PURE__ */ new Map();
5
- export default function useImageLoader(url, crossOrigin, referrerpolicy) {
6
- const isMounted = useIsMounted();
7
- const imageRef = useRef(url ? imageElements.get(url) : void 0);
8
- const statusRef = useRef(imageRef.current ? "loaded" : "loading");
9
- const [_, setStateToken] = useState(0);
10
- const urlRef = useRef(url);
11
- if (!url || urlRef.current !== url) {
12
- statusRef.current = "loading";
13
- imageRef.current = void 0;
14
- urlRef.current = url;
15
- }
16
- useLayoutEffect(() => {
17
- if (!url) {
18
- return;
19
- }
20
- const urlClosure = url;
21
- const imgCached = imageElements.get(url);
22
- if (imgCached) {
23
- statusRef.current = "loaded";
24
- if (imageRef.current !== imgCached) {
25
- imageRef.current = imgCached;
26
- setStateToken(Math.random());
27
- }
28
- return;
29
- }
30
- const img = document.createElement("img");
31
- function onload() {
32
- if (!isMounted())
33
- return;
34
- imageElements.set(urlClosure, img);
35
- if (urlRef.current === urlClosure) {
36
- statusRef.current = "loaded";
37
- imageRef.current = img;
38
- setStateToken(Math.random());
39
- }
40
- }
41
- function onerror() {
42
- if (!isMounted() || urlRef.current !== urlClosure)
43
- return;
44
- statusRef.current = "failed";
45
- imageRef.current = void 0;
46
- setStateToken(Math.random());
47
- }
48
- img.addEventListener("load", onload);
49
- img.addEventListener("error", onerror);
50
- crossOrigin && (img.crossOrigin = crossOrigin);
51
- referrerpolicy && (img.referrerPolicy = referrerpolicy);
52
- img.src = url;
53
- return () => {
54
- img.removeEventListener("load", onload);
55
- img.removeEventListener("error", onerror);
56
- };
57
- }, [url, crossOrigin ?? null, referrerpolicy ?? null]);
58
- if (imageRef.current !== void 0) {
59
- statusRef.current = "loaded";
60
- return [imageRef.current, "loaded"];
61
- }
62
- invariant(statusRef.current !== "loaded", "image status cant be loaded");
63
- return [imageRef.current, statusRef.current];
64
- }
@@ -1,87 +0,0 @@
1
- import { isString } from "@likec4/core";
2
- import { useCallback, useEffect, useRef, useState } from "react";
3
- function readViewIdFromUrl(url) {
4
- return readViewId(new URL(url).hash);
5
- }
6
- function readViewId(hash = window.location.hash) {
7
- if (hash.startsWith("#")) {
8
- hash = hash.slice(1);
9
- }
10
- if (hash.includes("likec4")) {
11
- return new URLSearchParams(hash).get("likec4");
12
- }
13
- return null;
14
- }
15
- function writeViewId(viewId) {
16
- let hash = window.location.hash;
17
- if (hash.startsWith("#")) {
18
- hash = hash.slice(1);
19
- }
20
- const hashParams = new URLSearchParams(hash);
21
- if (viewId != null) {
22
- if (hashParams.get("likec4") !== viewId) {
23
- hashParams.set("likec4", viewId);
24
- window.location.hash = hashParams.toString();
25
- }
26
- return;
27
- }
28
- if (viewId === null && hashParams.has("likec4")) {
29
- hashParams.delete("likec4");
30
- window.location.hash = hashParams.toString();
31
- return;
32
- }
33
- }
34
- const noopIsViewId = (value) => isString(value) && value.length > 0;
35
- export function useViewIdFromHash({
36
- initialViewId,
37
- onReturnToInitial,
38
- resetHashOnUnmount = true,
39
- isViewId = noopIsViewId
40
- }) {
41
- const [viewId, setStateViewId] = useState(() => {
42
- const id = readViewId();
43
- return isViewId(id) ? id : initialViewId;
44
- });
45
- const viewIdRef = useRef(viewId);
46
- const prevIdRef = useRef();
47
- if (viewIdRef.current !== viewId) {
48
- prevIdRef.current = viewIdRef.current;
49
- viewIdRef.current = viewId;
50
- }
51
- const onReturnRef = useRef(onReturnToInitial);
52
- onReturnRef.current = onReturnToInitial;
53
- useEffect(() => {
54
- const tm = setTimeout(() => {
55
- writeViewId(viewIdRef.current);
56
- }, 300);
57
- return () => clearTimeout(tm);
58
- }, []);
59
- useEffect(() => {
60
- const onHashChange = (ev) => {
61
- const newViewId = readViewIdFromUrl(ev.newURL);
62
- if (newViewId === null) {
63
- const oldViewId = readViewIdFromUrl(ev.oldURL);
64
- if (oldViewId != null && onReturnRef.current) {
65
- onReturnRef.current?.();
66
- }
67
- return;
68
- }
69
- if (isViewId(newViewId) && newViewId !== viewIdRef.current) {
70
- setStateViewId(newViewId);
71
- }
72
- };
73
- window.addEventListener("hashchange", onHashChange);
74
- return () => {
75
- window.removeEventListener("hashchange", onHashChange);
76
- if (resetHashOnUnmount) {
77
- writeViewId(null);
78
- }
79
- };
80
- }, []);
81
- const setViewId = useCallback((nextViewId) => {
82
- if (isViewId(nextViewId) && nextViewId !== viewIdRef.current) {
83
- writeViewId(nextViewId);
84
- }
85
- }, []);
86
- return [viewId, setViewId];
87
- }
@@ -1,4 +0,0 @@
1
- export * from "./diagram/index.mjs";
2
- export * from "./components/index.mjs";
3
- export * from "./hooks/index.mjs";
4
- export { LikeC4 } from "./likec4.mjs";
@@ -1,74 +0,0 @@
1
- import { jsx } from "react/jsx-runtime";
2
- import { useCallback, useLayoutEffect, useMemo, useRef, useState } from "react";
3
- import ReactDOM from "react-dom/client";
4
- import { Group } from "./konva.mjs";
5
- function needForceStyle(el) {
6
- const pos = window.getComputedStyle(el).position;
7
- const ok = pos === "absolute" || pos === "relative";
8
- return !ok;
9
- }
10
- export function KonvaHtml({ children, groupProps, divProps, transform, transformFunc }) {
11
- const groupRef = useRef(null);
12
- const [div] = useState(() => document.createElement("div"));
13
- const root = useMemo(() => ReactDOM.createRoot(div), [div]);
14
- const shouldTransform = transform ?? true;
15
- const handleTransform = useCallback(() => {
16
- if (shouldTransform && groupRef.current) {
17
- const tr = groupRef.current.getAbsoluteTransform();
18
- let attrs = tr.decompose();
19
- if (transformFunc) {
20
- attrs = transformFunc(attrs);
21
- }
22
- div.style.position = "absolute";
23
- div.style.zIndex = "10";
24
- div.style.top = "0px";
25
- div.style.left = "0px";
26
- div.style.transform = `translate(${attrs.x}px, ${attrs.y}px) rotate(${attrs.rotation}deg) scaleX(${attrs.scaleX}) scaleY(${attrs.scaleY})`;
27
- div.style.transformOrigin = "top left";
28
- } else {
29
- div.style.position = "";
30
- div.style.zIndex = "";
31
- div.style.top = "";
32
- div.style.left = "";
33
- div.style.transform = ``;
34
- div.style.transformOrigin = "";
35
- }
36
- const { style, ...restProps } = divProps || {};
37
- Object.assign(div.style, style);
38
- Object.assign(div, restProps);
39
- }, []);
40
- useLayoutEffect(() => {
41
- const group = groupRef.current;
42
- if (!group) {
43
- return;
44
- }
45
- const parent = group.getStage()?.container();
46
- if (!parent) {
47
- return;
48
- }
49
- parent.appendChild(div);
50
- if (shouldTransform && needForceStyle(parent)) {
51
- parent.style.position = "relative";
52
- }
53
- group.on("absoluteTransformChange", handleTransform);
54
- handleTransform();
55
- return () => {
56
- group.off("absoluteTransformChange", handleTransform);
57
- div.parentNode?.removeChild(div);
58
- };
59
- }, [shouldTransform]);
60
- useLayoutEffect(() => {
61
- handleTransform();
62
- }, [divProps, transformFunc]);
63
- useLayoutEffect(() => {
64
- root.render(children);
65
- });
66
- useLayoutEffect(() => {
67
- return () => {
68
- setTimeout(() => {
69
- root.unmount();
70
- });
71
- };
72
- }, []);
73
- return /* @__PURE__ */ jsx(Group, { ref: groupRef, ...groupProps });
74
- }