@likec4/diagram 1.32.0 → 1.32.2
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 +12 -5
- package/bundle/{chunk-BvTQaUYl.js → chunk-DlHyKoeo.js} +236 -210
- package/bundle/custom.js +50 -49
- package/bundle/index.js +144 -121
- package/dist/LikeC4Diagram.js +1 -1
- package/dist/LikeC4Diagram.props.d.ts +14 -3
- package/dist/bundle/LikeC4View.js +16 -15
- package/dist/bundle/ReactLikeC4.js +7 -6
- package/dist/bundle/index.js +1 -1
- package/dist/custom/customNodes.d.ts +5 -0
- package/dist/custom/hooks.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/likec4diagram/DiagramXYFlow.js +3 -3
- package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +5 -5
- package/dist/likec4model/index.d.ts +1 -1
- package/dist/likec4model/useLikeC4Model.d.ts +2 -1
- package/dist/likec4model/useLikeC4Model.js +13 -2
- package/dist/overlays/overlay/Overlay.js +24 -4
- package/dist/search/Search.d.ts +2 -3
- package/dist/search/Search.js +27 -46
- package/dist/search/components/ElementsColumn.js +12 -13
- package/dist/search/components/PickView.js +6 -6
- package/dist/search/components/SearchByTags.js +5 -2
- package/dist/search/components/SearchInput.js +16 -14
- package/dist/search/components/ViewsColum.js +16 -9
- package/dist/search/components/utils.d.ts +3 -2
- package/dist/search/components/utils.js +37 -5
- package/dist/search/hooks.d.ts +2 -8
- package/dist/search/hooks.js +4 -4
- package/dist/state/DiagramActorProvider.js +1 -1
- package/dist/state/diagram-machine.d.ts +216 -8
- package/dist/state/diagram-machine.js +8 -6
- package/package.json +17 -16
- package/panda.buildinfo.json +1 -1
- package/src/LikeC4Diagram.props.ts +14 -3
- package/src/LikeC4Diagram.tsx +1 -1
- package/src/bundle/LikeC4View.tsx +12 -19
- package/src/bundle/ReactLikeC4.tsx +2 -10
- package/src/custom/customNodes.tsx +5 -0
- package/src/custom/hooks.ts +1 -0
- package/src/likec4diagram/DiagramXYFlow.tsx +3 -3
- package/src/likec4model/index.ts +2 -0
- package/src/likec4model/useLikeC4Model.ts +16 -2
- package/src/overlays/overlay/Overlay.tsx +20 -5
- package/src/search/Search.tsx +34 -51
- package/src/search/components/ElementsColumn.tsx +12 -15
- package/src/search/components/PickView.tsx +41 -47
- package/src/search/components/SearchByTags.tsx +5 -2
- package/src/search/components/SearchInput.tsx +17 -14
- package/src/search/components/ViewsColum.tsx +18 -10
- package/src/search/components/utils.ts +41 -4
- package/src/search/hooks.ts +5 -8
- package/src/state/DiagramActorProvider.tsx +2 -1
- package/src/state/diagram-machine.ts +8 -6
package/dist/LikeC4Diagram.js
CHANGED
|
@@ -33,7 +33,7 @@ function LikeC4Diagram({
|
|
|
33
33
|
pannable = true,
|
|
34
34
|
zoomable = true,
|
|
35
35
|
background = "dots",
|
|
36
|
-
enableElementTags =
|
|
36
|
+
enableElementTags = false,
|
|
37
37
|
enableFocusMode = false,
|
|
38
38
|
enableElementDetails = false,
|
|
39
39
|
enableRelationshipDetails = enableElementDetails,
|
|
@@ -73,7 +73,15 @@ export interface LikeC4DiagramProperties<A extends aux.Any> {
|
|
|
73
73
|
* @default false if readonly
|
|
74
74
|
*/
|
|
75
75
|
nodesDraggable?: boolean | undefined;
|
|
76
|
+
/**
|
|
77
|
+
* Initial width of the diagram
|
|
78
|
+
* (supposed to be used during SSR)
|
|
79
|
+
*/
|
|
76
80
|
initialWidth?: number | undefined;
|
|
81
|
+
/**
|
|
82
|
+
* Initial height of the diagram
|
|
83
|
+
* (supposed to be used during SSR)
|
|
84
|
+
*/
|
|
77
85
|
initialHeight?: number | undefined;
|
|
78
86
|
/**
|
|
79
87
|
* Background pattern
|
|
@@ -91,7 +99,9 @@ export interface LikeC4DiagramProperties<A extends aux.Any> {
|
|
|
91
99
|
*/
|
|
92
100
|
showNavigationButtons?: undefined | boolean;
|
|
93
101
|
/**
|
|
94
|
-
* Display notations
|
|
102
|
+
* Display notations in the bottom right corner
|
|
103
|
+
* (Active if only notations are present)
|
|
104
|
+
*
|
|
95
105
|
* @default true
|
|
96
106
|
*/
|
|
97
107
|
showNotations?: boolean | undefined;
|
|
@@ -128,7 +138,7 @@ export interface LikeC4DiagramProperties<A extends aux.Any> {
|
|
|
128
138
|
enableDynamicViewWalkthrough?: boolean | undefined;
|
|
129
139
|
/**
|
|
130
140
|
* Display element tags in the bottom left corner
|
|
131
|
-
* @default
|
|
141
|
+
* @default false
|
|
132
142
|
*/
|
|
133
143
|
enableElementTags?: boolean | undefined;
|
|
134
144
|
/**
|
|
@@ -138,8 +148,9 @@ export interface LikeC4DiagramProperties<A extends aux.Any> {
|
|
|
138
148
|
experimentalEdgeEditing?: boolean | undefined;
|
|
139
149
|
/**
|
|
140
150
|
* Improve performance by hiding certain elements and reducing visual effects (disable mix-blend, shadows, animations)
|
|
151
|
+
* Enable it if you have a large or static view
|
|
141
152
|
*
|
|
142
|
-
* @default 'auto' - will be
|
|
153
|
+
* @default 'auto' - will be `true` if view has more then 3000 * 2000 pixels
|
|
143
154
|
*/
|
|
144
155
|
reduceGraphics?: 'auto' | boolean | undefined;
|
|
145
156
|
/**
|
|
@@ -11,23 +11,24 @@ import { useLikeC4Model } from '../likec4model/useLikeC4Model.js';
|
|
|
11
11
|
import { Overlay } from '../overlays/overlay/Overlay.js';
|
|
12
12
|
import { ShadowRoot } from './ShadowRoot.js';
|
|
13
13
|
import { useColorScheme, useShadowRootStyle, cssInteractive } from './styles.css.js';
|
|
14
|
-
import {
|
|
14
|
+
import { ViewNotFound, ErrorMessage } from './ViewNotFound.js';
|
|
15
15
|
|
|
16
16
|
function LikeC4View({
|
|
17
17
|
viewId,
|
|
18
18
|
...props
|
|
19
19
|
}) {
|
|
20
20
|
const likec4model = useLikeC4Model();
|
|
21
|
-
const view = likec4model
|
|
22
|
-
if (!
|
|
23
|
-
return /* @__PURE__ */ jsx(ErrorMessage, { children: "LikeC4Model not found. Make sure you have LikeC4ModelProvider." });
|
|
24
|
-
}
|
|
25
|
-
if (likec4model.stage !== "layouted") {
|
|
26
|
-
return /* @__PURE__ */ jsx(ErrorMessage, { children: "LikeC4Model is not layouted. Make sure you have LikeC4ModelProvider with layouted model." });
|
|
27
|
-
}
|
|
28
|
-
if (!view || !view.isDiagram()) {
|
|
21
|
+
const view = likec4model.findView(viewId);
|
|
22
|
+
if (!view) {
|
|
29
23
|
return /* @__PURE__ */ jsx(ViewNotFound, { viewId });
|
|
30
24
|
}
|
|
25
|
+
if (!view.isDiagram()) {
|
|
26
|
+
return /* @__PURE__ */ jsxs(ErrorMessage, { children: [
|
|
27
|
+
'LikeC4 View "$',
|
|
28
|
+
viewId,
|
|
29
|
+
'" is not layouted. Make sure you have LikeC4ModelProvider with layouted model.'
|
|
30
|
+
] });
|
|
31
|
+
}
|
|
31
32
|
return /* @__PURE__ */ jsx(LikeC4ViewInner, { view: view.$view, ...props });
|
|
32
33
|
}
|
|
33
34
|
const LikeC4ViewInner = memo(({
|
|
@@ -40,7 +41,7 @@ const LikeC4ViewInner = memo(({
|
|
|
40
41
|
injectFontCss = true,
|
|
41
42
|
controls = false,
|
|
42
43
|
fitView = true,
|
|
43
|
-
fitViewPadding = "
|
|
44
|
+
fitViewPadding = "16px",
|
|
44
45
|
background = "transparent",
|
|
45
46
|
browser = true,
|
|
46
47
|
showDiagramTitle = false,
|
|
@@ -134,13 +135,13 @@ const LikeC4ViewInner = memo(({
|
|
|
134
135
|
...props
|
|
135
136
|
}
|
|
136
137
|
),
|
|
137
|
-
browserView && /* @__PURE__ */ jsxs(Overlay, { onClose: () => onNavigateTo(null), children: [
|
|
138
|
+
browserView && /* @__PURE__ */ jsxs(Overlay, { openDelay: 0, onClose: () => onNavigateTo(null), children: [
|
|
138
139
|
/* @__PURE__ */ jsx(
|
|
139
140
|
LikeC4Diagram,
|
|
140
141
|
{
|
|
141
142
|
view: browserView,
|
|
142
143
|
background: "dots",
|
|
143
|
-
onNavigateTo
|
|
144
|
+
onNavigateTo,
|
|
144
145
|
enableDynamicViewWalkthrough: true,
|
|
145
146
|
enableFocusMode: true,
|
|
146
147
|
enableRelationshipBrowser: true,
|
|
@@ -151,11 +152,11 @@ const LikeC4ViewInner = memo(({
|
|
|
151
152
|
controls: true,
|
|
152
153
|
readonly: true,
|
|
153
154
|
fitView: true,
|
|
154
|
-
fitViewPadding: "
|
|
155
|
-
renderNodes,
|
|
155
|
+
fitViewPadding: "32px",
|
|
156
156
|
...props,
|
|
157
157
|
...browserProps,
|
|
158
|
-
showNotations: (browserProps.showNotations ?? true) && (browserView.notation?.nodes.length ?? 0) > 0
|
|
158
|
+
showNotations: (browserProps.showNotations ?? true) && (browserView.notation?.nodes.length ?? 0) > 0,
|
|
159
|
+
renderNodes
|
|
159
160
|
}
|
|
160
161
|
),
|
|
161
162
|
/* @__PURE__ */ jsx(Box, { pos: "absolute", top: "1rem", right: "1rem", children: /* @__PURE__ */ jsx(
|
|
@@ -5,22 +5,23 @@ import { LikeC4Diagram } from '../LikeC4Diagram.js';
|
|
|
5
5
|
import { useLikeC4Model } from '../likec4model/useLikeC4Model.js';
|
|
6
6
|
import { ShadowRoot } from './ShadowRoot.js';
|
|
7
7
|
import { useColorScheme, useShadowRootStyle } from './styles.css.js';
|
|
8
|
-
import {
|
|
8
|
+
import { ViewNotFound, ErrorMessage } from './ViewNotFound.js';
|
|
9
9
|
|
|
10
10
|
function ReactLikeC4({
|
|
11
11
|
viewId,
|
|
12
12
|
...props
|
|
13
13
|
}) {
|
|
14
14
|
const likec4model = useLikeC4Model();
|
|
15
|
-
const view = likec4model
|
|
16
|
-
if (!likec4model) {
|
|
17
|
-
return /* @__PURE__ */ jsx(ErrorMessage, { children: "LikeC4Model not found. Make sure you have LikeC4ModelProvider." });
|
|
18
|
-
}
|
|
15
|
+
const view = likec4model.findView(viewId);
|
|
19
16
|
if (!view) {
|
|
20
17
|
return /* @__PURE__ */ jsx(ViewNotFound, { viewId });
|
|
21
18
|
}
|
|
22
19
|
if (!view.isDiagram()) {
|
|
23
|
-
return /* @__PURE__ */
|
|
20
|
+
return /* @__PURE__ */ jsxs(ErrorMessage, { children: [
|
|
21
|
+
'LikeC4 View "$',
|
|
22
|
+
viewId,
|
|
23
|
+
'" is not layouted. Make sure you have LikeC4ModelProvider with layouted model.'
|
|
24
|
+
] });
|
|
24
25
|
}
|
|
25
26
|
return /* @__PURE__ */ jsx(ReactLikeC4Inner, { view: view.$view, ...props });
|
|
26
27
|
}
|
package/dist/bundle/index.js
CHANGED
|
@@ -7,7 +7,7 @@ export { useEnabledFeatures } from '../context/DiagramFeatures.js';
|
|
|
7
7
|
export { useCurrentViewId } from '../hooks/useCurrentViewId.js';
|
|
8
8
|
export { useDiagram, useDiagramContext } from '../hooks/useDiagram.js';
|
|
9
9
|
export { useXYFlow, useXYInternalNode, useXYStore, useXYStoreApi } from '../hooks/useXYFlow.js';
|
|
10
|
-
export { useLikeC4Model, useLikeC4Specification } from '../likec4model/useLikeC4Model.js';
|
|
10
|
+
export { useLikeC4Model, useLikeC4Specification, useLikeC4ViewModel } from '../likec4model/useLikeC4Model.js';
|
|
11
11
|
export { useMantinePortalProps } from '../hooks/useMantinePortalProps.js';
|
|
12
12
|
export { useSetState } from '../hooks/useSetState.js';
|
|
13
13
|
export { useUpdateEffect } from '../hooks/useUpdateEffect.js';
|
|
@@ -26,15 +26,20 @@ export type CustomElementNodeProps<M extends Any = Any> = {
|
|
|
26
26
|
* ElementTitle,
|
|
27
27
|
* ElementActions,
|
|
28
28
|
* ElementDetailsButtonWithHandler,
|
|
29
|
+
* IfEnabled,
|
|
29
30
|
* IfNotReadOnly,
|
|
30
31
|
* ElementToolbar,
|
|
31
32
|
* DefaultHandles,
|
|
33
|
+
* ElementTags
|
|
32
34
|
* } from '@likec4/diagram/custom'
|
|
33
35
|
*
|
|
34
36
|
* const CustomElementNode = elementNode(({ nodeProps, nodeModel }) => (
|
|
35
37
|
* <ElementNodeContainer nodeProps={nodeProps}>
|
|
36
38
|
* <ElementShape {...nodeProps} />
|
|
37
39
|
* <ElementTitle {...nodeProps} />
|
|
40
|
+
* <IfEnabled feature="ElementTags">
|
|
41
|
+
* <ElementTags {...nodeProps} />
|
|
42
|
+
* </IfEnabled>
|
|
38
43
|
* <ElementActions
|
|
39
44
|
* {...nodeProps}
|
|
40
45
|
* extraButtons={[
|
package/dist/custom/hooks.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { type EnabledFeatures, useEnabledFeatures, } from '../context/DiagramFea
|
|
|
4
4
|
export { useCurrentViewId, } from '../hooks/useCurrentViewId';
|
|
5
5
|
export { useDiagram, useDiagramContext, } from '../hooks/useDiagram';
|
|
6
6
|
export { useXYFlow, useXYInternalNode, useXYStore, useXYStoreApi, } from '../hooks/useXYFlow';
|
|
7
|
-
export { useLikeC4Model, useLikeC4Specification, } from '../likec4model/useLikeC4Model';
|
|
7
|
+
export { useLikeC4Model, useLikeC4Specification, useLikeC4ViewModel, } from '../likec4model/useLikeC4Model';
|
|
8
8
|
export { useMantinePortalProps } from '../hooks/useMantinePortalProps';
|
|
9
9
|
export { useSetState } from '../hooks/useSetState';
|
|
10
10
|
export { useUpdateEffect } from '../hooks/useUpdateEffect';
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ export { useEnabledFeatures } from './context/DiagramFeatures.js';
|
|
|
9
9
|
export { useCurrentViewId } from './hooks/useCurrentViewId.js';
|
|
10
10
|
export { useDiagram, useDiagramContext } from './hooks/useDiagram.js';
|
|
11
11
|
export { useXYFlow, useXYInternalNode, useXYStore, useXYStoreApi } from './hooks/useXYFlow.js';
|
|
12
|
-
export { useLikeC4Model, useLikeC4Specification } from './likec4model/useLikeC4Model.js';
|
|
12
|
+
export { useLikeC4Model, useLikeC4Specification, useLikeC4ViewModel } from './likec4model/useLikeC4Model.js';
|
|
13
13
|
export { useMantinePortalProps } from './hooks/useMantinePortalProps.js';
|
|
14
14
|
export { useSetState } from './hooks/useSetState.js';
|
|
15
15
|
export { useUpdateEffect } from './hooks/useUpdateEffect.js';
|
|
@@ -59,12 +59,12 @@ function LikeC4DiagramXYFlow({
|
|
|
59
59
|
} = useDiagramEventHandlers();
|
|
60
60
|
const notReadOnly = !enableReadOnly, isReducedGraphics = useIsReducedGraphics(), layoutConstraints = useLayoutConstraints(), $isPanning = usePanningAtom(), isPanning = useTimeout(() => {
|
|
61
61
|
$isPanning.set(true);
|
|
62
|
-
}, isReducedGraphics ?
|
|
62
|
+
}, isReducedGraphics ? 120 : 200), notPanning = useDebouncedCallback(() => {
|
|
63
63
|
isPanning.clear();
|
|
64
64
|
if ($isPanning.get()) {
|
|
65
65
|
$isPanning.set(false);
|
|
66
66
|
}
|
|
67
|
-
}, 200), onMove = useCallbackRef((event) => {
|
|
67
|
+
}, isReducedGraphics ? 350 : 200), onMove = useCallbackRef((event) => {
|
|
68
68
|
if (!event) {
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
@@ -73,7 +73,7 @@ function LikeC4DiagramXYFlow({
|
|
|
73
73
|
}
|
|
74
74
|
notPanning();
|
|
75
75
|
}), onMoveEnd = useCallbackRef((event, viewport) => {
|
|
76
|
-
if (!!event) {
|
|
76
|
+
if (!!event && !isReducedGraphics) {
|
|
77
77
|
notPanning.flush();
|
|
78
78
|
}
|
|
79
79
|
diagram.send({ type: "xyflow.viewportMoved", viewport, manually: !!event });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DeploymentFqn, Fqn, ThemeColor, ViewChange } from '@likec4/core';
|
|
1
|
+
import { DeploymentFqn, Fqn, ThemeColor, ViewChange, ColorLiteral } from '@likec4/core';
|
|
2
2
|
import { MergeExclusive } from 'type-fest';
|
|
3
3
|
import { NodeProps } from '../../../../base';
|
|
4
4
|
import { Types } from '../../../types';
|
|
@@ -7,17 +7,17 @@ import { TooltipProps } from '@mantine/core';
|
|
|
7
7
|
export type OnStyleChange = (style: ViewChange.ChangeElementStyle['style']) => void;
|
|
8
8
|
export declare const themedColors: ({
|
|
9
9
|
key: "primary";
|
|
10
|
-
value:
|
|
10
|
+
value: ColorLiteral;
|
|
11
11
|
} | {
|
|
12
12
|
key: "secondary";
|
|
13
|
-
value:
|
|
13
|
+
value: ColorLiteral;
|
|
14
14
|
} | {
|
|
15
15
|
key: "muted";
|
|
16
|
-
value:
|
|
16
|
+
value: ColorLiteral;
|
|
17
17
|
})[];
|
|
18
18
|
export declare const colors: {
|
|
19
19
|
key: "blue" | "gray" | "green" | "indigo" | "red" | "amber" | "slate" | "sky";
|
|
20
|
-
value:
|
|
20
|
+
value: ColorLiteral;
|
|
21
21
|
}[];
|
|
22
22
|
export type ThemeColorKey = typeof themedColors[0]['key'];
|
|
23
23
|
export type ColorKey = typeof colors[0]['key'];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { useLikeC4ElementsTree, } from './useLikeC4ElementsTree';
|
|
2
|
-
export { useLikeC4Model, } from './useLikeC4Model';
|
|
2
|
+
export { useLikeC4Model, useLikeC4Specification, useLikeC4ViewModel, } from './useLikeC4Model';
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { aux, LikeC4Model } from '@likec4/core/model';
|
|
1
|
+
import { aux, LikeC4Model, LikeC4ViewModel } from '@likec4/core/model';
|
|
2
2
|
import { TagSpecification, ElementSpecification, RelationshipSpecification, CustomColorDefinitions } from '@likec4/core';
|
|
3
3
|
export declare function useLikeC4Model<A extends aux.Any = aux.Unknown>(): LikeC4Model<A>;
|
|
4
4
|
export declare function useLikeC4Model<A extends aux.Any = aux.Unknown>(type: 'layouted'): LikeC4Model.Layouted<A>;
|
|
5
5
|
export declare function useLikeC4Model<A extends aux.Any = aux.Unknown>(type: 'computed'): LikeC4Model.Computed<A>;
|
|
6
6
|
export declare function useLikeC4Model<A extends aux.Any = aux.Unknown>(type: 'layouted' | 'computed' | undefined): LikeC4Model<A>;
|
|
7
|
+
export declare function useLikeC4ViewModel<A extends aux.Any = aux.Unknown>(viewId: aux.LooseViewId<A>): LikeC4ViewModel<aux.toLayouted<A>> | null;
|
|
7
8
|
export declare function useLikeC4Specification(): {
|
|
8
9
|
tags: {
|
|
9
10
|
[x: string]: TagSpecification;
|
|
@@ -5,16 +5,27 @@ import { LikeC4ModelContext } from './LikeC4ModelContext.js';
|
|
|
5
5
|
function useLikeC4Model(type) {
|
|
6
6
|
const model = useContext(LikeC4ModelContext);
|
|
7
7
|
if (!model) {
|
|
8
|
-
throw new Error("
|
|
8
|
+
throw new Error("LikeC4Model not found. Make sure you have LikeC4ModelProvider.");
|
|
9
9
|
}
|
|
10
10
|
if (isString(type) && model.stage !== type) {
|
|
11
11
|
throw new Error(`Invalid LikeC4ModelContext, expected "${type}" but got "${model.stage}" in context`);
|
|
12
12
|
}
|
|
13
13
|
return model;
|
|
14
14
|
}
|
|
15
|
+
function useLikeC4ViewModel(viewId) {
|
|
16
|
+
const model = useLikeC4Model("layouted");
|
|
17
|
+
const view = model.findView(viewId);
|
|
18
|
+
if (!view) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
if (!view.isDiagram()) {
|
|
22
|
+
throw new Error(`View "${viewId}" is not layouted`);
|
|
23
|
+
}
|
|
24
|
+
return view;
|
|
25
|
+
}
|
|
15
26
|
function useLikeC4Specification() {
|
|
16
27
|
const model = useLikeC4Model();
|
|
17
28
|
return model.$data.specification;
|
|
18
29
|
}
|
|
19
30
|
|
|
20
|
-
export { useLikeC4Model, useLikeC4Specification };
|
|
31
|
+
export { useLikeC4Model, useLikeC4Specification, useLikeC4ViewModel };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { cx } from '@likec4/styles/css';
|
|
3
3
|
import { RemoveScroll } from '@mantine/core';
|
|
4
|
-
import { useMergedRef } from '@mantine/hooks';
|
|
4
|
+
import { useFocusTrap, useMergedRef } from '@mantine/hooks';
|
|
5
5
|
import { useDebouncedCallback, useTimeoutEffect } from '@react-hookz/web';
|
|
6
6
|
import { useReducedMotionConfig, m } from 'motion/react';
|
|
7
7
|
import { forwardRef, useState, useRef, useLayoutEffect } from 'react';
|
|
@@ -21,6 +21,7 @@ const Overlay = forwardRef(({
|
|
|
21
21
|
...rest
|
|
22
22
|
}, ref) => {
|
|
23
23
|
const [opened, setOpened] = useState(openDelay === 0);
|
|
24
|
+
const focusTrapRef = useFocusTrap(opened);
|
|
24
25
|
const dialogRef = useRef(null);
|
|
25
26
|
const isClosingRef = useRef(false);
|
|
26
27
|
const motionNotReduced = useReducedMotionConfig() !== true;
|
|
@@ -54,8 +55,17 @@ const Overlay = forwardRef(({
|
|
|
54
55
|
return /* @__PURE__ */ jsx(
|
|
55
56
|
m.dialog,
|
|
56
57
|
{
|
|
57
|
-
ref: useMergedRef(
|
|
58
|
-
|
|
58
|
+
ref: useMergedRef(
|
|
59
|
+
dialogRef,
|
|
60
|
+
focusTrapRef,
|
|
61
|
+
ref
|
|
62
|
+
),
|
|
63
|
+
className: cx(
|
|
64
|
+
classes?.dialog,
|
|
65
|
+
className,
|
|
66
|
+
styles.dialog,
|
|
67
|
+
fullscreen && RemoveScroll.classNames.fullWidth
|
|
68
|
+
),
|
|
59
69
|
layout: true,
|
|
60
70
|
style: {
|
|
61
71
|
// @ts-ignore
|
|
@@ -115,7 +125,17 @@ const Overlay = forwardRef(({
|
|
|
115
125
|
close();
|
|
116
126
|
},
|
|
117
127
|
...rest,
|
|
118
|
-
children: /* @__PURE__ */ jsx(RemoveScroll, { forwardProps: true,
|
|
128
|
+
children: /* @__PURE__ */ jsx(RemoveScroll, { forwardProps: true, children: /* @__PURE__ */ jsx(
|
|
129
|
+
"div",
|
|
130
|
+
{
|
|
131
|
+
className: cx(
|
|
132
|
+
classes?.body,
|
|
133
|
+
styles.body,
|
|
134
|
+
"overlay-body"
|
|
135
|
+
),
|
|
136
|
+
children: opened && /* @__PURE__ */ jsx(Fragment, { children })
|
|
137
|
+
}
|
|
138
|
+
) })
|
|
119
139
|
}
|
|
120
140
|
);
|
|
121
141
|
});
|
package/dist/search/Search.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { SearchActorRef } from './searchActor';
|
|
2
|
-
|
|
3
|
-
export declare const Search: NamedExoticComponent<{
|
|
2
|
+
export declare function Search({ searchActorRef }: {
|
|
4
3
|
searchActorRef: SearchActorRef;
|
|
5
|
-
}
|
|
4
|
+
}): import("react/jsx-runtime").JSX.Element;
|
package/dist/search/Search.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
2
|
import { css } from '@likec4/styles/css';
|
|
3
|
-
import { VStack } from '@likec4/styles/jsx';
|
|
4
|
-
import {
|
|
3
|
+
import { Box, VStack } from '@likec4/styles/jsx';
|
|
4
|
+
import { Group, Grid, GridCol, Title, ScrollArea } from '@mantine/core';
|
|
5
5
|
import { useCallbackRef, useHotkeys } from '@mantine/hooks';
|
|
6
6
|
import { useTimeoutEffect } from '@react-hookz/web';
|
|
7
7
|
import { useSelector } from '@xstate/react';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import { AnimatePresence, LayoutGroup } from 'motion/react';
|
|
9
|
+
import { useRef } from 'react';
|
|
10
10
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
11
11
|
import { isTruthy } from 'remeda';
|
|
12
12
|
import { ErrorFallback } from '../components/ErrorFallback.js';
|
|
@@ -57,24 +57,13 @@ const body = css({
|
|
|
57
57
|
// },
|
|
58
58
|
});
|
|
59
59
|
const selectIsOpened = (s) => !s.matches("inactive");
|
|
60
|
-
|
|
60
|
+
function Search({ searchActorRef }) {
|
|
61
61
|
const isOpened = useSelector(searchActorRef, selectIsOpened);
|
|
62
62
|
const openSearch = () => {
|
|
63
63
|
searchActorRef.send({ type: "open" });
|
|
64
64
|
};
|
|
65
|
-
const
|
|
65
|
+
const close = useCallbackRef(() => {
|
|
66
66
|
searchActorRef.send({ type: "close" });
|
|
67
|
-
};
|
|
68
|
-
const afterCloseCbRef = useRef(null);
|
|
69
|
-
const close = useCallbackRef((cb) => {
|
|
70
|
-
afterCloseCbRef.current = cb ?? null;
|
|
71
|
-
sendClose();
|
|
72
|
-
});
|
|
73
|
-
const onExitComplete = useCallbackRef(() => {
|
|
74
|
-
if (afterCloseCbRef.current) {
|
|
75
|
-
afterCloseCbRef.current();
|
|
76
|
-
afterCloseCbRef.current = null;
|
|
77
|
-
}
|
|
78
67
|
});
|
|
79
68
|
useHotkeys([
|
|
80
69
|
["mod+k", openSearch, {
|
|
@@ -84,34 +73,25 @@ const Search = memo(({ searchActorRef }) => {
|
|
|
84
73
|
preventDefault: true
|
|
85
74
|
}]
|
|
86
75
|
]);
|
|
87
|
-
return /* @__PURE__ */ jsx(
|
|
88
|
-
|
|
76
|
+
return /* @__PURE__ */ jsx(SearchActorContext, { value: searchActorRef, children: /* @__PURE__ */ jsx(DiagramFeatures.Overlays, { children: /* @__PURE__ */ jsx(ErrorBoundary, { FallbackComponent: ErrorFallback, onReset: close, children: /* @__PURE__ */ jsx(AnimatePresence, { children: isOpened && /* @__PURE__ */ jsx(
|
|
77
|
+
Overlay,
|
|
89
78
|
{
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
79
|
+
fullscreen: true,
|
|
80
|
+
withBackdrop: false,
|
|
81
|
+
backdrop: {
|
|
82
|
+
opacity: 0.9
|
|
93
83
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
classes: {
|
|
103
|
-
dialog,
|
|
104
|
-
body
|
|
105
|
-
},
|
|
106
|
-
openDelay: 0,
|
|
107
|
-
onClose: close,
|
|
108
|
-
"data-likec4-search": "true",
|
|
109
|
-
children: /* @__PURE__ */ jsx(SearchOverlay, { close, searchActorRef })
|
|
110
|
-
}
|
|
111
|
-
) }) }) }) })
|
|
84
|
+
classes: {
|
|
85
|
+
dialog,
|
|
86
|
+
body
|
|
87
|
+
},
|
|
88
|
+
openDelay: 0,
|
|
89
|
+
onClose: close,
|
|
90
|
+
"data-likec4-search": "true",
|
|
91
|
+
children: /* @__PURE__ */ jsx(SearchOverlay, { searchActorRef })
|
|
112
92
|
}
|
|
113
|
-
);
|
|
114
|
-
}
|
|
93
|
+
) }) }) }) });
|
|
94
|
+
}
|
|
115
95
|
const scrollArea = css({
|
|
116
96
|
height: [
|
|
117
97
|
"100%",
|
|
@@ -125,14 +105,15 @@ const scrollArea = css({
|
|
|
125
105
|
}
|
|
126
106
|
}
|
|
127
107
|
});
|
|
128
|
-
const SearchOverlay = ({
|
|
108
|
+
const SearchOverlay = ({ searchActorRef }) => {
|
|
109
|
+
const ref = useRef(null);
|
|
129
110
|
const pickViewFor = usePickViewFor();
|
|
130
111
|
useTimeoutEffect(() => {
|
|
131
112
|
if (isTruthy(searchActorRef.getSnapshot().context.openedWithSearch)) {
|
|
132
|
-
focusToFirstFoundElement();
|
|
113
|
+
focusToFirstFoundElement(ref.current);
|
|
133
114
|
}
|
|
134
115
|
}, 150);
|
|
135
|
-
return /* @__PURE__ */ jsxs(
|
|
116
|
+
return /* @__PURE__ */ jsxs(Box, { ref, display: "contents", children: [
|
|
136
117
|
/* @__PURE__ */ jsx(
|
|
137
118
|
Group,
|
|
138
119
|
{
|
|
@@ -140,7 +121,7 @@ const SearchOverlay = ({ close, searchActorRef }) => {
|
|
|
140
121
|
wrap: "nowrap",
|
|
141
122
|
onClick: (e) => {
|
|
142
123
|
e.stopPropagation();
|
|
143
|
-
moveFocusToSearchInput();
|
|
124
|
+
moveFocusToSearchInput(ref.current);
|
|
144
125
|
},
|
|
145
126
|
children: /* @__PURE__ */ jsxs(VStack, { flex: 1, px: "sm", children: [
|
|
146
127
|
/* @__PURE__ */ jsx(LikeC4SearchInput, {}),
|
|
@@ -5,7 +5,7 @@ import { useTree, Tree, ActionIcon, UnstyledButton, Box, Group, Highlight, Toolt
|
|
|
5
5
|
import { useCallbackRef } from '@mantine/hooks';
|
|
6
6
|
import { IconChevronRight } from '@tabler/icons-react';
|
|
7
7
|
import * as m from 'motion/react-m';
|
|
8
|
-
import { memo, useMemo,
|
|
8
|
+
import { memo, useMemo, useEffect } from 'react';
|
|
9
9
|
import { isEmpty, pipe, reduce, only, first } from 'remeda';
|
|
10
10
|
import { IconOrShapeRenderer } from '../../context/IconRenderer.js';
|
|
11
11
|
import { useDiagram } from '../../hooks/useDiagram.js';
|
|
@@ -14,7 +14,7 @@ import { useLikeC4Model } from '../../likec4model/useLikeC4Model.js';
|
|
|
14
14
|
import { useNormalizedSearch, useSearchActor } from '../hooks.js';
|
|
15
15
|
import { focusable, buttonsva } from './_shared.css.js';
|
|
16
16
|
import { treeSubtree, treeLabel, treeRoot, treeNode, elementIcon, elementExpandIcon, elementTitleAndId, elementId, elementViewsCount } from './ElementsColumn.css.js';
|
|
17
|
-
import { stopAndPrevent, moveFocusToSearchInput, centerY } from './utils.js';
|
|
17
|
+
import { stopAndPrevent, moveFocusToSearchInput, queryAllFocusable, centerY } from './utils.js';
|
|
18
18
|
import { NothingFound } from './ViewsColum.js';
|
|
19
19
|
|
|
20
20
|
const btn = buttonsva();
|
|
@@ -108,7 +108,7 @@ function ElementsTree({
|
|
|
108
108
|
if (e.key === "ArrowUp") {
|
|
109
109
|
if (id === roots[0]?.value) {
|
|
110
110
|
stopAndPrevent(e);
|
|
111
|
-
moveFocusToSearchInput();
|
|
111
|
+
moveFocusToSearchInput(target);
|
|
112
112
|
}
|
|
113
113
|
return;
|
|
114
114
|
}
|
|
@@ -119,9 +119,7 @@ function ElementsTree({
|
|
|
119
119
|
}
|
|
120
120
|
const label = e.target.querySelector(".mantine-Tree-label") ?? target;
|
|
121
121
|
const maxY = label.getBoundingClientRect().y;
|
|
122
|
-
const viewButtons =
|
|
123
|
-
`[data-likec4-search-views] .${focusable}`
|
|
124
|
-
)];
|
|
122
|
+
const viewButtons = queryAllFocusable(target, "views");
|
|
125
123
|
let view = viewButtons.length > 1 ? viewButtons.find((el, i, all2) => centerY(el) > maxY || i === all2.length - 1) : null;
|
|
126
124
|
view ??= first(viewButtons);
|
|
127
125
|
if (view) {
|
|
@@ -240,23 +238,24 @@ function ElementTreeNode({ node, elementProps, hasChildren, expanded }) {
|
|
|
240
238
|
}
|
|
241
239
|
function useHandleElementSelection() {
|
|
242
240
|
const diagram = useDiagram();
|
|
243
|
-
const
|
|
244
|
-
return
|
|
241
|
+
const searchActorRef = useSearchActor();
|
|
242
|
+
return useCallbackRef((element) => {
|
|
245
243
|
const views = [...element.views()];
|
|
246
244
|
if (views.length === 0) {
|
|
247
245
|
return;
|
|
248
246
|
}
|
|
249
247
|
const singleView = only(views);
|
|
250
248
|
if (singleView) {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
249
|
+
searchActorRef.send({ type: "close" });
|
|
250
|
+
if (singleView.id !== diagram.currentView.id) {
|
|
251
|
+
setTimeout(() => {
|
|
252
|
+
diagram.navigateTo(singleView.id);
|
|
253
|
+
}, 100);
|
|
255
254
|
}
|
|
256
255
|
return;
|
|
257
256
|
}
|
|
258
257
|
searchActorRef.send({ type: "pickview.open", elementFqn: element.id });
|
|
259
|
-
}
|
|
258
|
+
});
|
|
260
259
|
}
|
|
261
260
|
|
|
262
261
|
export { ElementsColumn };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
2
|
-
import { Group, Title, ActionIcon,
|
|
2
|
+
import { FocusTrap, Group, Title, ActionIcon, ScrollAreaAutosize, Stack } from '@mantine/core';
|
|
3
3
|
import { useWindowEvent } from '@mantine/hooks';
|
|
4
4
|
import { IconX } from '@tabler/icons-react';
|
|
5
5
|
import * as m from 'motion/react-m';
|
|
@@ -9,7 +9,7 @@ import { ViewButton } from './ViewsColum.js';
|
|
|
9
9
|
import { useLikeC4Model } from '../../likec4model/useLikeC4Model.js';
|
|
10
10
|
|
|
11
11
|
function PickView({ elementFqn }) {
|
|
12
|
-
const
|
|
12
|
+
const searchActorRef = useSearchActor();
|
|
13
13
|
const element = useLikeC4Model().element(elementFqn);
|
|
14
14
|
const scoped = [];
|
|
15
15
|
const others = [];
|
|
@@ -52,7 +52,7 @@ function PickView({ elementFqn }) {
|
|
|
52
52
|
},
|
|
53
53
|
"pickview-backdrop"
|
|
54
54
|
),
|
|
55
|
-
/* @__PURE__ */ jsxs(
|
|
55
|
+
/* @__PURE__ */ jsx(FocusTrap, { children: /* @__PURE__ */ jsxs(
|
|
56
56
|
m.div,
|
|
57
57
|
{
|
|
58
58
|
initial: {
|
|
@@ -93,7 +93,7 @@ function PickView({ elementFqn }) {
|
|
|
93
93
|
}
|
|
94
94
|
)
|
|
95
95
|
] }),
|
|
96
|
-
/* @__PURE__ */
|
|
96
|
+
/* @__PURE__ */ jsxs(ScrollAreaAutosize, { mah: "calc(100vh - 110px)", type: "never", children: [
|
|
97
97
|
scoped.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "sm", px: "sm", className: pickviewGroup, children: [
|
|
98
98
|
/* @__PURE__ */ jsx(Title, { order: 6, c: "dimmed", children: "scoped views of the element" }),
|
|
99
99
|
scoped.map((view, i) => /* @__PURE__ */ jsx(
|
|
@@ -124,11 +124,11 @@ function PickView({ elementFqn }) {
|
|
|
124
124
|
view.id
|
|
125
125
|
))
|
|
126
126
|
] })
|
|
127
|
-
] })
|
|
127
|
+
] })
|
|
128
128
|
]
|
|
129
129
|
},
|
|
130
130
|
"pickview"
|
|
131
|
-
)
|
|
131
|
+
) })
|
|
132
132
|
] });
|
|
133
133
|
}
|
|
134
134
|
|