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.
- package/README.md +108 -0
- package/dist/__app__/src/App.jsx +1 -1
- package/dist/__app__/src/components/view-page/ExportDiagram.jsx +72 -0
- package/dist/__app__/src/components/view-page/ViewActionsToolbar.jsx +38 -12
- package/dist/cli/index.js +53 -53
- package/package.json +6 -6
- package/dist/@likec4/diagrams/cjs/components/EmbeddedDiagram.js +0 -83
- package/dist/@likec4/diagrams/cjs/components/FullscreenDiagramBrowser.js +0 -50
- package/dist/@likec4/diagrams/cjs/components/index.js +0 -49
- package/dist/@likec4/diagrams/cjs/components/primitives/fullscreen/CloseButton.js +0 -44
- package/dist/@likec4/diagrams/cjs/components/primitives/fullscreen/FullscreenDiagram.js +0 -110
- package/dist/@likec4/diagrams/cjs/components/primitives/fullscreen/FullscreenDiagramTitle.js +0 -39
- package/dist/@likec4/diagrams/cjs/components/primitives/index.js +0 -38
- package/dist/@likec4/diagrams/cjs/components/primitives/responsive/ResponsiveDiagram.js +0 -56
- package/dist/@likec4/diagrams/cjs/components/types.js +0 -1
- package/dist/@likec4/diagrams/cjs/diagram/Diagram.js +0 -326
- package/dist/@likec4/diagrams/cjs/diagram/Edges.js +0 -121
- package/dist/@likec4/diagrams/cjs/diagram/Nodes.js +0 -204
- package/dist/@likec4/diagrams/cjs/diagram/icons/BrainIcon.js +0 -25
- package/dist/@likec4/diagrams/cjs/diagram/icons/ExternalLink.js +0 -82
- package/dist/@likec4/diagrams/cjs/diagram/icons/index.js +0 -27
- package/dist/@likec4/diagrams/cjs/diagram/index.js +0 -27
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Browser.js +0 -67
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Compound.js +0 -55
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Cylinder.js +0 -71
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Edge.js +0 -62
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Mobile.js +0 -45
- package/dist/@likec4/diagrams/cjs/diagram/shapes/NodeIcon.js +0 -38
- package/dist/@likec4/diagrams/cjs/diagram/shapes/NodeLabel.js +0 -62
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Person.js +0 -48
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Queue.js +0 -72
- package/dist/@likec4/diagrams/cjs/diagram/shapes/Rectangle.js +0 -30
- package/dist/@likec4/diagrams/cjs/diagram/shapes/index.js +0 -54
- package/dist/@likec4/diagrams/cjs/diagram/shapes/types.js +0 -1
- package/dist/@likec4/diagrams/cjs/diagram/shapes/utils.js +0 -19
- package/dist/@likec4/diagrams/cjs/diagram/springs.js +0 -61
- package/dist/@likec4/diagrams/cjs/diagram/state/atoms.js +0 -63
- package/dist/@likec4/diagrams/cjs/diagram/state/gestures.js +0 -26
- package/dist/@likec4/diagrams/cjs/diagram/state/hooks.js +0 -36
- package/dist/@likec4/diagrams/cjs/diagram/state/index.js +0 -38
- package/dist/@likec4/diagrams/cjs/diagram/state/provider.js +0 -18
- package/dist/@likec4/diagrams/cjs/diagram/types.js +0 -1
- package/dist/@likec4/diagrams/cjs/hooks/index.js +0 -49
- package/dist/@likec4/diagrams/cjs/hooks/useDarkMode.js +0 -11
- package/dist/@likec4/diagrams/cjs/hooks/useDiagramApi.js +0 -27
- package/dist/@likec4/diagrams/cjs/hooks/useImageLoader.js +0 -68
- package/dist/@likec4/diagrams/cjs/hooks/useViewIdFromHash.js +0 -93
- package/dist/@likec4/diagrams/cjs/index.js +0 -51
- package/dist/@likec4/diagrams/cjs/konva-html.js +0 -93
- package/dist/@likec4/diagrams/cjs/konva-portal.js +0 -50
- package/dist/@likec4/diagrams/cjs/konva.js +0 -102
- package/dist/@likec4/diagrams/cjs/likec4.js +0 -91
- package/dist/@likec4/diagrams/components/EmbeddedDiagram.mjs +0 -77
- package/dist/@likec4/diagrams/components/FullscreenDiagramBrowser.mjs +0 -52
- package/dist/@likec4/diagrams/components/index.mjs +0 -4
- package/dist/@likec4/diagrams/components/primitives/fullscreen/CloseButton.mjs +0 -43
- package/dist/@likec4/diagrams/components/primitives/fullscreen/FullscreenDiagram.mjs +0 -116
- package/dist/@likec4/diagrams/components/primitives/fullscreen/FullscreenDiagramTitle.mjs +0 -32
- package/dist/@likec4/diagrams/components/primitives/index.mjs +0 -3
- package/dist/@likec4/diagrams/components/primitives/responsive/ResponsiveDiagram.mjs +0 -42
- package/dist/@likec4/diagrams/components/types.mjs +0 -0
- package/dist/@likec4/diagrams/diagram/Diagram.mjs +0 -307
- package/dist/@likec4/diagrams/diagram/Edges.mjs +0 -117
- package/dist/@likec4/diagrams/diagram/Nodes.mjs +0 -178
- package/dist/@likec4/diagrams/diagram/icons/BrainIcon.mjs +0 -20
- package/dist/@likec4/diagrams/diagram/icons/ExternalLink.mjs +0 -90
- package/dist/@likec4/diagrams/diagram/icons/index.mjs +0 -2
- package/dist/@likec4/diagrams/diagram/index.mjs +0 -2
- package/dist/@likec4/diagrams/diagram/shapes/Browser.mjs +0 -49
- package/dist/@likec4/diagrams/diagram/shapes/Compound.mjs +0 -48
- package/dist/@likec4/diagrams/diagram/shapes/Cylinder.mjs +0 -57
- package/dist/@likec4/diagrams/diagram/shapes/Edge.mjs +0 -63
- package/dist/@likec4/diagrams/diagram/shapes/Mobile.mjs +0 -33
- package/dist/@likec4/diagrams/diagram/shapes/NodeIcon.mjs +0 -28
- package/dist/@likec4/diagrams/diagram/shapes/NodeLabel.mjs +0 -59
- package/dist/@likec4/diagrams/diagram/shapes/Person.mjs +0 -42
- package/dist/@likec4/diagrams/diagram/shapes/Queue.mjs +0 -58
- package/dist/@likec4/diagrams/diagram/shapes/Rectangle.mjs +0 -20
- package/dist/@likec4/diagrams/diagram/shapes/index.mjs +0 -7
- package/dist/@likec4/diagrams/diagram/shapes/types.mjs +0 -0
- package/dist/@likec4/diagrams/diagram/shapes/utils.mjs +0 -12
- package/dist/@likec4/diagrams/diagram/springs.mjs +0 -57
- package/dist/@likec4/diagrams/diagram/state/atoms.mjs +0 -71
- package/dist/@likec4/diagrams/diagram/state/gestures.mjs +0 -19
- package/dist/@likec4/diagrams/diagram/state/hooks.mjs +0 -28
- package/dist/@likec4/diagrams/diagram/state/index.mjs +0 -3
- package/dist/@likec4/diagrams/diagram/state/provider.mjs +0 -7
- package/dist/@likec4/diagrams/diagram/types.mjs +0 -0
- package/dist/@likec4/diagrams/esm/components/EmbeddedDiagram.js +0 -77
- package/dist/@likec4/diagrams/esm/components/FullscreenDiagramBrowser.js +0 -52
- package/dist/@likec4/diagrams/esm/components/index.js +0 -4
- package/dist/@likec4/diagrams/esm/components/primitives/fullscreen/CloseButton.js +0 -43
- package/dist/@likec4/diagrams/esm/components/primitives/fullscreen/FullscreenDiagram.js +0 -116
- package/dist/@likec4/diagrams/esm/components/primitives/fullscreen/FullscreenDiagramTitle.js +0 -32
- package/dist/@likec4/diagrams/esm/components/primitives/index.js +0 -3
- package/dist/@likec4/diagrams/esm/components/primitives/responsive/ResponsiveDiagram.js +0 -42
- package/dist/@likec4/diagrams/esm/components/types.js +0 -0
- package/dist/@likec4/diagrams/esm/diagram/Diagram.js +0 -307
- package/dist/@likec4/diagrams/esm/diagram/Edges.js +0 -117
- package/dist/@likec4/diagrams/esm/diagram/Nodes.js +0 -178
- package/dist/@likec4/diagrams/esm/diagram/icons/BrainIcon.js +0 -20
- package/dist/@likec4/diagrams/esm/diagram/icons/ExternalLink.js +0 -90
- package/dist/@likec4/diagrams/esm/diagram/icons/index.js +0 -2
- package/dist/@likec4/diagrams/esm/diagram/index.js +0 -2
- package/dist/@likec4/diagrams/esm/diagram/shapes/Browser.js +0 -49
- package/dist/@likec4/diagrams/esm/diagram/shapes/Compound.js +0 -48
- package/dist/@likec4/diagrams/esm/diagram/shapes/Cylinder.js +0 -57
- package/dist/@likec4/diagrams/esm/diagram/shapes/Edge.js +0 -63
- package/dist/@likec4/diagrams/esm/diagram/shapes/Mobile.js +0 -33
- package/dist/@likec4/diagrams/esm/diagram/shapes/NodeIcon.js +0 -28
- package/dist/@likec4/diagrams/esm/diagram/shapes/NodeLabel.js +0 -59
- package/dist/@likec4/diagrams/esm/diagram/shapes/Person.js +0 -42
- package/dist/@likec4/diagrams/esm/diagram/shapes/Queue.js +0 -58
- package/dist/@likec4/diagrams/esm/diagram/shapes/Rectangle.js +0 -20
- package/dist/@likec4/diagrams/esm/diagram/shapes/index.js +0 -7
- package/dist/@likec4/diagrams/esm/diagram/shapes/types.js +0 -0
- package/dist/@likec4/diagrams/esm/diagram/shapes/utils.js +0 -12
- package/dist/@likec4/diagrams/esm/diagram/springs.js +0 -57
- package/dist/@likec4/diagrams/esm/diagram/state/atoms.js +0 -71
- package/dist/@likec4/diagrams/esm/diagram/state/gestures.js +0 -19
- package/dist/@likec4/diagrams/esm/diagram/state/hooks.js +0 -28
- package/dist/@likec4/diagrams/esm/diagram/state/index.js +0 -3
- package/dist/@likec4/diagrams/esm/diagram/state/provider.js +0 -7
- package/dist/@likec4/diagrams/esm/diagram/types.js +0 -0
- package/dist/@likec4/diagrams/esm/hooks/index.js +0 -4
- package/dist/@likec4/diagrams/esm/hooks/useDarkMode.js +0 -5
- package/dist/@likec4/diagrams/esm/hooks/useDiagramApi.js +0 -27
- package/dist/@likec4/diagrams/esm/hooks/useImageLoader.js +0 -64
- package/dist/@likec4/diagrams/esm/hooks/useViewIdFromHash.js +0 -87
- package/dist/@likec4/diagrams/esm/index.js +0 -4
- package/dist/@likec4/diagrams/esm/konva-html.js +0 -74
- package/dist/@likec4/diagrams/esm/konva-portal.js +0 -34
- package/dist/@likec4/diagrams/esm/konva.js +0 -22
- package/dist/@likec4/diagrams/esm/likec4.js +0 -54
- package/dist/@likec4/diagrams/hooks/index.mjs +0 -4
- package/dist/@likec4/diagrams/hooks/useDarkMode.mjs +0 -5
- package/dist/@likec4/diagrams/hooks/useDiagramApi.mjs +0 -27
- package/dist/@likec4/diagrams/hooks/useImageLoader.mjs +0 -64
- package/dist/@likec4/diagrams/hooks/useViewIdFromHash.mjs +0 -87
- package/dist/@likec4/diagrams/index.mjs +0 -4
- package/dist/@likec4/diagrams/konva-html.mjs +0 -74
- package/dist/@likec4/diagrams/konva-portal.mjs +0 -34
- package/dist/@likec4/diagrams/konva.mjs +0 -33
- package/dist/@likec4/diagrams/likec4.mjs +0 -54
|
@@ -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,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,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,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
|
-
}
|