@likec4/diagram 1.42.0 → 1.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.
@@ -8,4 +8,4 @@ export type LikeC4DiagramProps<A extends Any = Any> = PropsWithChildren<LikeC4Di
8
8
  *
9
9
  * Use {@link ReactLikeC4} or {@link LikeC4View} for ready-to-use component
10
10
  */
11
- export declare function LikeC4Diagram<A extends Any = Any>({ onCanvasClick, onCanvasContextMenu, onCanvasDblClick, onEdgeClick, onChange, onEdgeContextMenu, onNavigateTo, onNodeClick, onNodeContextMenu, onOpenSource, onBurgerMenuClick, onInitialized, view, className, readonly, controls, fitView, fitViewPadding, pannable, zoomable, background, enableElementTags, enableFocusMode, enableElementDetails, enableRelationshipDetails, enableRelationshipBrowser, nodesDraggable, nodesSelectable, showNotations, showNavigationButtons, enableDynamicViewWalkthrough, dynamicViewVariant, enableSearch, initialWidth, initialHeight, experimentalEdgeEditing, reduceGraphics, renderIcon, renderControls, where, reactFlowProps, renderNodes, children, }: LikeC4DiagramProps<A>): import("react/jsx-runtime").JSX.Element;
11
+ export declare function LikeC4Diagram<A extends Any = Any>({ onCanvasClick, onCanvasContextMenu, onCanvasDblClick, onEdgeClick, onChange, onEdgeContextMenu, onNavigateTo, onNodeClick, onNodeContextMenu, onOpenSource, onBurgerMenuClick, onInitialized, view, className, readonly, controls, fitView, fitViewPadding: _fitViewPadding, pannable, zoomable, background, enableElementTags, enableFocusMode, enableElementDetails, enableRelationshipDetails, enableRelationshipBrowser, nodesDraggable, nodesSelectable, showNotations, showNavigationButtons, enableDynamicViewWalkthrough, dynamicViewVariant, enableSearch, initialWidth, initialHeight, experimentalEdgeEditing, reduceGraphics, renderIcon, where, reactFlowProps, renderNodes, children, }: LikeC4DiagramProps<A>): import("react/jsx-runtime").JSX.Element;
@@ -1,9 +1,10 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { useCustomCompareMemo } from '@react-hookz/web';
2
3
  import { ReactFlowProvider } from '@xyflow/react';
4
+ import { deepEqual } from 'fast-equals';
3
5
  import { useRef } from 'react';
6
+ import { isPlainObject, mapValues } from 'remeda';
4
7
  import { RootContainer } from './components/RootContainer.js';
5
- import { ControlsCustomLayoutProvider } from './context/ControlsCustomLayout.js';
6
- import { ReduceGraphicsContext } from './context/ReduceGraphics.js';
7
8
  import { TagStylesProvider } from './context/TagStylesContext.js';
8
9
  import { useId } from './hooks/useId.js';
9
10
  import { LikeC4DiagramUI } from './likec4diagram/DiagramUI.js';
@@ -11,12 +12,12 @@ import { LikeC4DiagramXYFlow } from './likec4diagram/DiagramXYFlow.js';
11
12
  import { DiagramActorProvider } from './likec4diagram/state/DiagramActorProvider.js';
12
13
  import { LikeC4Styles } from './LikeC4Styles.js';
13
14
  import { getViewBounds } from './utils/get-view-bounds.js';
15
+ import { MinZoom, MaxZoom, FitViewPaddings } from './base/const.js';
14
16
  import { EnsureMantine } from './context/EnsureMantine.js';
15
17
  import { FramerMotionConfig } from './context/FramerMotionConfig.js';
16
18
  import { IconRendererProvider } from './context/IconRenderer.js';
17
19
  import { DiagramFeatures } from './context/DiagramFeatures.js';
18
20
  import { DiagramEventHandlers } from './context/DiagramEventHandlers.js';
19
- import { FitViewPaddings } from './base/const.js';
20
21
 
21
22
  function LikeC4Diagram({
22
23
  onCanvasClick,
@@ -36,7 +37,7 @@ function LikeC4Diagram({
36
37
  readonly = true,
37
38
  controls = !readonly,
38
39
  fitView = true,
39
- fitViewPadding = controls ? FitViewPaddings.withControls : FitViewPaddings.default,
40
+ fitViewPadding: _fitViewPadding = controls ? FitViewPaddings.withControls : FitViewPaddings.default,
40
41
  pannable = true,
41
42
  zoomable = true,
42
43
  background = "dots",
@@ -57,7 +58,6 @@ function LikeC4Diagram({
57
58
  experimentalEdgeEditing = !readonly,
58
59
  reduceGraphics = "auto",
59
60
  renderIcon,
60
- renderControls,
61
61
  where,
62
62
  reactFlowProps,
63
63
  renderNodes,
@@ -66,15 +66,23 @@ function LikeC4Diagram({
66
66
  const id = useId();
67
67
  const initialRef = useRef(null);
68
68
  const bounds = getViewBounds(view, dynamicViewVariant);
69
+ const fitViewPadding = useNormalizedViewPadding(_fitViewPadding);
69
70
  if (initialRef.current == null) {
70
71
  initialRef.current = {
71
72
  defaultEdges: [],
72
73
  defaultNodes: [],
73
74
  initialWidth: initialWidth ?? bounds.width,
74
- initialHeight: initialHeight ?? bounds.height
75
+ initialHeight: initialHeight ?? bounds.height,
76
+ initialFitViewOptions: {
77
+ maxZoom: MaxZoom,
78
+ minZoom: MinZoom,
79
+ padding: fitViewPadding
80
+ },
81
+ initialMaxZoom: MaxZoom,
82
+ initialMinZoom: MinZoom
75
83
  };
76
84
  }
77
- const isReducedGraphicsMode = reduceGraphics === "auto" ? pannable && (bounds.width ?? 1) * (bounds.height ?? 1) > 6e6 : reduceGraphics;
85
+ const isReducedGraphicsMode = reduceGraphics === "auto" ? pannable && (bounds.width ?? 1) * (bounds.height ?? 1) > 6e6 && view.nodes.some((n) => n.children?.length > 0) : reduceGraphics;
78
86
  return /* @__PURE__ */ jsx(EnsureMantine, { children: /* @__PURE__ */ jsx(
79
87
  FramerMotionConfig,
80
88
  {
@@ -118,12 +126,12 @@ function LikeC4Diagram({
118
126
  },
119
127
  children: [
120
128
  /* @__PURE__ */ jsx(LikeC4Styles, { id }),
121
- /* @__PURE__ */ jsx(TagStylesProvider, { rootSelector: `#${id}`, children: /* @__PURE__ */ jsx(ReduceGraphicsContext, { reduceGraphics: isReducedGraphicsMode, children: /* @__PURE__ */ jsx(RootContainer, { id, className, reduceGraphics: isReducedGraphicsMode, children: /* @__PURE__ */ jsx(
129
+ /* @__PURE__ */ jsx(TagStylesProvider, { rootSelector: `#${id}`, children: /* @__PURE__ */ jsx(RootContainer, { id, className, reduceGraphics: isReducedGraphicsMode, children: /* @__PURE__ */ jsx(
122
130
  ReactFlowProvider,
123
131
  {
124
132
  fitView,
125
133
  ...initialRef.current,
126
- children: /* @__PURE__ */ jsx(
134
+ children: /* @__PURE__ */ jsxs(
127
135
  DiagramActorProvider,
128
136
  {
129
137
  view,
@@ -133,7 +141,7 @@ function LikeC4Diagram({
133
141
  nodesSelectable,
134
142
  where: where ?? null,
135
143
  dynamicViewVariant,
136
- children: /* @__PURE__ */ jsxs(ControlsCustomLayoutProvider, { value: renderControls ?? null, children: [
144
+ children: [
137
145
  /* @__PURE__ */ jsx(
138
146
  LikeC4DiagramXYFlow,
139
147
  {
@@ -146,11 +154,11 @@ function LikeC4Diagram({
146
154
  }
147
155
  ),
148
156
  /* @__PURE__ */ jsx(LikeC4DiagramUI, {})
149
- ] })
157
+ ]
150
158
  }
151
159
  )
152
160
  }
153
- ) }) }) })
161
+ ) }) })
154
162
  ]
155
163
  }
156
164
  )
@@ -159,5 +167,23 @@ function LikeC4Diagram({
159
167
  }
160
168
  ) });
161
169
  }
170
+ const toLiteralPaddingWithUnit = (value) => {
171
+ if (typeof value === "number") {
172
+ return `${value}px`;
173
+ }
174
+ return value;
175
+ };
176
+ function useNormalizedViewPadding(raw) {
177
+ return useCustomCompareMemo(
178
+ () => {
179
+ if (isPlainObject(raw)) {
180
+ return mapValues(raw, toLiteralPaddingWithUnit);
181
+ }
182
+ return toLiteralPaddingWithUnit(raw);
183
+ },
184
+ [raw],
185
+ deepEqual
186
+ );
187
+ }
162
188
 
163
189
  export { LikeC4Diagram };
@@ -2,7 +2,6 @@ import { DiagramEdge, DiagramNode, DynamicViewDisplayVariant, LayoutedView, View
2
2
  import { ReactFlowProps } from '@xyflow/react';
3
3
  import { MouseEvent as ReactMouseEvent, ReactNode } from 'react';
4
4
  import { CamelCasedProperties, SetRequired } from 'type-fest';
5
- import { ControlsCustomLayout } from './context/ControlsCustomLayout';
6
5
  import { DiagramApi } from './hooks/useDiagram';
7
6
  import { XYFlowInstance } from './hooks/useXYFlow';
8
7
  import { Types } from './likec4diagram/types';
@@ -198,15 +197,6 @@ export interface LikeC4DiagramProperties<A extends Any = Unknown> {
198
197
  * By default, if icon is http:// or https://, it will be rendered as an image
199
198
  */
200
199
  renderIcon?: ElementIconRenderer | undefined;
201
- /**
202
- * Customize layout of the controls on the top left
203
- *
204
- * @note
205
- * Ignored if `controls="next"`
206
- *
207
- * @see {@link controls}
208
- */
209
- renderControls?: ControlsCustomLayout | undefined;
210
200
  /**
211
201
  * Override node renderers
212
202
  */
@@ -0,0 +1,42 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { css } from '@likec4/styles/css';
3
+ import { forwardRef } from 'react';
4
+
5
+ const Logo = forwardRef(
6
+ (props, ref) => {
7
+ return /* @__PURE__ */ jsxs("svg", { ref, xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 222 56", ...props, children: [
8
+ /* @__PURE__ */ jsx(
9
+ "path",
10
+ {
11
+ fill: "#5E98AF",
12
+ d: "M33.95 33.78V0H2.37A2.37 2.37 0 0 0 0 2.35V33.9h33.95v-.12ZM38.57 33.78H55.6v-14.6c0-1.3-1.06-2.35-2.36-2.35H38.57v16.95ZM33.95 38.37H17.04v14.6c0 1.29 1.06 2.35 2.36 2.35h14.67V38.37h-.12ZM38.57 38.37v16.95h14.67c1.3 0 2.36-1.06 2.36-2.36v-14.6H38.57Z"
13
+ }
14
+ ),
15
+ /* @__PURE__ */ jsx(
16
+ "path",
17
+ {
18
+ className: css({
19
+ fill: "[#FCFBF7]",
20
+ _light: {
21
+ fill: "[#222221]"
22
+ }
23
+ }),
24
+ d: "M71.61 12.08c-.06 3.61.3 29.95.23 31.87 0 1.8 0 3.6.06 5.41 0 .3.18.58.47.58 4.1.18 8.13-.17 12.22-.11 1.34.05 2.69 0 3.97 0 1.29-.06 1.4-.59 1.35-1.63-.06-1.63-.06-3.08-.06-4.65-.06-.82-.53-1.11-1.23-1.11-2.4.06-4.8-.06-7.19.06-.4.06-.82.06-1.23.06-.7-.06-.87-.24-.93-1v-.86c-.18-4.83.17-9.83.17-14.66-.06-4.07 0-7.73-.06-11.34 0-1.57 0-3.14-.05-4.65-.06-.93 0-1.92-.24-2.85-.11-.35-.29-.81-.7-.81h-5.5c-.93 0-1.22.64-1.28 1.57v4.12ZM103.81 35c-.17-6.63-.1-13.67-.05-20.24 0-2.04-.12-4.25-.12-6.28 0-2.21-.87-2.1-2.04-2.15-1.7-.06-2.46-.06-4.15-.06-1.11-.06-1.58.23-1.58 1.34 0 5.7-.18 21.8-.12 24.13.06 2.33.3 12.91.18 15.24-.06.81 0 1.62.06 2.44.05.29.23.58.7.58 1.93-.12 3.74-.12 5.67-.17.7-.06 1.28-.24 1.58-1 .05-.4-.12-11.04-.12-13.83Zm13.92 4.47c0-2.03-.3-7.56-.23-8.72 0-.17.11-.4.17-.4.12 0 .35.11.41.17 1.87 2.44 10.64 19.36 11.7 19.42.28.06.58.06.87.06 1.99-.12 3.74 0 5.73 0 2.04 0 .7-1.98.35-2.5-.53-.76-7.48-13.14-7.9-13.9-1.16-1.98-2.16-4.13-3.32-6.05-.12-.23-.24-.58-.18-.81.12-.7.3-1.34.59-1.98a93.18 93.18 0 0 1 4.55-8.14c1.88-2.97 2.93-4.83 4.45-7.5.35-.64.58-1.34.82-2.1.05-.29-.18-.58-.53-.58-1.11-.05-5.15 0-6.43 0-.59 0-1.17.12-1.46.64-.76 1.46-8.6 15.7-9.35 16.98-.06.12-.24.18-.41.18 0 0-.12-.18-.12-.3-.06-3.25.53-13.9.4-16.04-.05-1.28-.28-1.4-1.57-1.46-1.4-.05-3.33-.05-4.73-.05-1.3 0-1.4.7-1.58 1.62-.06.18-.06 5.64-.06 8.09 0 3.54-.3 25.76.11 32.8 0 .7.18 1.1.77 1.1 1.57-.12 3.91 0 5.49 0 1.11 0 1.29-.12 1.29-1.98 0-2.5.23-4.77.23-7.85 0-.23-.06-.46-.06-.7Zm25.66-1.4h-.06c0 1.46-.05 2.97 0 4.49.06 1.86.18 3.72.3 5.58 0 .64.17.81.76.93 1.22.29 2.4.35 3.62.35 3.16-.12 6.31.11 9.47 0 1.29-.06 1.87.06 3.16-.18 1.17-.23 1.58-.87 1.58-2.61-.12-1.1-.06-1.57-.06-2.91 0-1.92-1.35-2.56-2.52-2.5-.81.06-4.73-.06-6.31-.06-2.63.06-2.22.4-2.22-2.33 0-2.2.06-5.05.06-7.32 0-1.22.11-1.63 1.28-1.63h7.31c1.17.17 1.99-.64 1.99-1.86 0-1.22.12-1.28.12-2.5l-.18-1.75c-.12-.99-.47-1.33-1.46-1.33-.64 0-1.29.05-1.93.11-2.52.18-3.68-.17-6.14 0-.82 0-.93-.11-1-.87-.23-2.27 0-4.77.24-7.04.06-.93.3-1.1 1.17-1.16l8.24-.06c1.11-.11 1.46-.06 1.4-1.16-.11-1.69.06-3.43-.11-5.12-.12-.93-.41-1.1-1.46-1.1-1.76.05-2.17.05-3.92.17-1.75.06-8.77.06-10.46.06-2.46 0-2.63-.18-2.7 2.8-.1 2.32-.05 4.7-.05 7.09 0 4.07-.23 18.66-.12 21.92Zm47.76-24.82c.06-1.92 0-3.5 0-5.35 0-2.15-3.92-1.92-5.32-1.86a18.95 18.95 0 0 0-15.08 9.77c-.82 1.57-1.4 3.2-1.81 4.88a34 34 0 0 0-.59 12.15c.41 3.78 1.4 7.56 3.74 10.59 4.04 5.3 11.46 7.15 17.83 6.16.3-.06.59-.11.82-.29.18-.11.35-.35.35-.58l.18-3.31c.06-1.05 0-1 0-2.04 0-1.4-2.93-.35-4.74-.35-1.75 0-3.62-.06-5.2-.87-2.8-1.57-4.38-4.71-5.26-7.68-1-3.2-1.23-6.63-.64-9.88.7-4.25 2.74-9.13 7.25-10.59 2.57-.87 5.31-.58 7.89-.29.35.06.58-.17.58-.46Zm26.77 15.3c.06-2.5 0-14.84 0-18.38.06-.82 0-1.63-.11-2.45-.06-.99-.24-1.28-1.29-1.33h-4.44c-.82 0-1.35.4-1.82 1.27-1.34 3.2-10.75 24.02-12.15 26.58-.53.99-1 1.63-1 2.68v4.24c0 .76-.06 1.28 1.23 1.28l11.1-.06c1.47 0 1.47.3 1.47 1.1 0 .88-.12 4.9-.12 5.3 0 .58.12 1.16 1.23 1.16h5.08c1.23 0 1.23-.7 1.23-2.03.06-1.17-.06-3.5-.06-4.66 0-.93.18-.98 1.76-.98 1.22 0 1.75-.12 1.75-.88.06-1.57 0-2.67 0-4.42 0-1.04-.93-.98-2.92-.98-.65 0-.7-.18-.7-1.05-.12-1.8-.24-4.6-.24-6.4Zm-7.25-5.94c-.05.7-.11 10.82-.11 12.27-.06.81-.24 1.05-1 1.1-1.93.06-3.85.06-5.78.06-.47 0-.65-.4-.41-.87.23-.4 4.85-11.57 6.13-14.48.18-.17.24-.35.41-.52.18-.12.41-.18.59-.23.06 0 .23.29.23.46 0 .76-.06 1.51-.06 2.21Z"
25
+ }
26
+ )
27
+ ] });
28
+ }
29
+ );
30
+ const LogoIcon = forwardRef(
31
+ (props, ref) => {
32
+ return /* @__PURE__ */ jsx("svg", { ref, xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 56 56", ...props, children: /* @__PURE__ */ jsx(
33
+ "path",
34
+ {
35
+ fill: "#5E98AF",
36
+ d: "M33.95 33.78V0H2.37A2.37 2.37 0 0 0 0 2.35V33.9h33.95v-.12ZM38.57 33.78H55.6v-14.6c0-1.3-1.06-2.35-2.36-2.35H38.57v16.95ZM33.95 38.37H17.04v14.6c0 1.29 1.06 2.35 2.36 2.35h14.67V38.37h-.12ZM38.57 38.37v16.95h14.67c1.3 0 2.36-1.06 2.36-2.36v-14.6H38.57Z"
37
+ }
38
+ ) });
39
+ }
40
+ );
41
+
42
+ export { Logo, LogoIcon };
@@ -1,9 +1,9 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { cx } from '@likec4/styles/css';
3
3
  import { useIsomorphicLayoutEffect } from '@react-hookz/web';
4
+ import { atom } from 'nanostores';
4
5
  import { useState, useRef, useEffect, useMemo } from 'react';
5
- import { usePanningAtom } from '../context/ReduceGraphics.js';
6
- import { RootContainerContext } from '../context/RootContainerContext.js';
6
+ import { PanningAtomSafeCtx, ReduceGraphicsModeCtx, RootContainerContext } from '../context/RootContainerContext.js';
7
7
 
8
8
  function RootContainer({
9
9
  id,
@@ -13,17 +13,20 @@ function RootContainer({
13
13
  }) {
14
14
  const [mounted, setMounted] = useState(false);
15
15
  const ref = useRef(null);
16
- const $isPanning = usePanningAtom();
16
+ const $isPanningRef = useRef(null);
17
+ if (!$isPanningRef.current) {
18
+ $isPanningRef.current = atom(false);
19
+ }
17
20
  useIsomorphicLayoutEffect(() => {
18
21
  setMounted(true);
19
22
  }, []);
20
23
  useEffect(() => {
21
- return $isPanning.listen((isPanning) => {
24
+ return $isPanningRef.current?.subscribe((isPanning) => {
22
25
  ref.current?.setAttribute("data-likec4-diagram-panning", isPanning ? "true" : "false");
23
26
  });
24
- }, [$isPanning]);
27
+ }, []);
25
28
  const ctx = useMemo(() => ({ id, ref }), [id, ref]);
26
- return /* @__PURE__ */ jsx(
29
+ return /* @__PURE__ */ jsx(PanningAtomSafeCtx, { value: $isPanningRef.current, children: /* @__PURE__ */ jsx(ReduceGraphicsModeCtx.Provider, { value: reduceGraphics, children: /* @__PURE__ */ jsx(
27
30
  "div",
28
31
  {
29
32
  id,
@@ -34,7 +37,7 @@ function RootContainer({
34
37
  },
35
38
  children: mounted && !!ctx.ref.current && /* @__PURE__ */ jsx(RootContainerContext.Provider, { value: ctx, children })
36
39
  }
37
- );
40
+ ) }) });
38
41
  }
39
42
 
40
43
  export { RootContainer };
@@ -1,3 +1,4 @@
1
+ import { WritableAtom } from 'nanostores';
1
2
  import { RefObject, Context } from 'react';
2
3
  export declare const RootContainerContext: Context<{
3
4
  id: string;
@@ -9,3 +10,13 @@ export declare function useRootContainer(): {
9
10
  };
10
11
  export declare function useRootContainerRef(): RefObject<HTMLDivElement | null>;
11
12
  export declare function useRootContainerElement(): HTMLDivElement | null;
13
+ export declare const ReduceGraphicsModeCtx: Context<boolean | null>;
14
+ /**
15
+ * Hook to determine if reduced graphics mode is enabled.
16
+ */
17
+ export declare function useIsReducedGraphics(): boolean;
18
+ export declare const PanningAtomSafeCtx: ({ children, value }: {
19
+ value: WritableAtom<boolean>;
20
+ children: React.ReactNode;
21
+ }) => import("react/jsx-runtime").JSX.Element, usePanningAtom: () => WritableAtom<boolean>;
22
+ export declare function useIsPanning(): boolean;
@@ -1,3 +1,5 @@
1
+ import { createSafeContext } from '@mantine/core';
2
+ import '@nanostores/react';
1
3
  import { createContext, useContext } from 'react';
2
4
 
3
5
  const RootContainerContext = createContext(null);
@@ -14,5 +16,16 @@ function useRootContainerRef() {
14
16
  function useRootContainerElement() {
15
17
  return useRootContainer().ref.current;
16
18
  }
19
+ const ReduceGraphicsModeCtx = createContext(null);
20
+ function useIsReducedGraphics() {
21
+ const isReduced = useContext(ReduceGraphicsModeCtx);
22
+ if (isReduced === null) {
23
+ console.warn("ReduceGraphicsMode is not provided");
24
+ }
25
+ return isReduced ?? false;
26
+ }
27
+ const [PanningAtomSafeCtx, usePanningAtom] = createSafeContext(
28
+ "PanningAtomSafeCtx is not provided"
29
+ );
17
30
 
18
- export { RootContainerContext, useRootContainer, useRootContainerElement, useRootContainerRef };
31
+ export { PanningAtomSafeCtx, ReduceGraphicsModeCtx, RootContainerContext, useIsReducedGraphics, usePanningAtom, useRootContainer, useRootContainerElement, useRootContainerRef };
@@ -1 +1 @@
1
- export { useIsPanning, useIsReducedGraphics } from '../context/ReduceGraphics';
1
+ export { useIsPanning, useIsReducedGraphics } from '../context/RootContainerContext';
package/dist/index.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- export type { ControlsCustomLayout, ControlsCustomLayoutProps } from './context/ControlsCustomLayout';
2
1
  export { IconRendererProvider } from './context/IconRenderer';
3
2
  export { LikeC4Diagram, type LikeC4DiagramProps, } from './LikeC4Diagram';
4
3
  export type { ElementIconRenderer, ElementIconRendererProps, LikeC4ColorScheme, NodeRenderers, OnCanvasClick, OnChange, OnEdgeClick, OnInitialized, OnNavigateTo, OnNodeClick, OnOpenSource, PaddingWithUnit, ViewPadding, WhereOperator, } from './LikeC4Diagram.props';
@@ -7,7 +7,7 @@ import { deepEqual, shallowEqual } from 'fast-equals';
7
7
  import { isEmpty } from 'remeda';
8
8
  import { memoNode } from '../base-primitives/memoNode.js';
9
9
  import { BaseXYFlow } from '../base/BaseXYFlow.js';
10
- import { useIsReducedGraphics, usePanningAtom } from '../context/ReduceGraphics.js';
10
+ import { useIsReducedGraphics, usePanningAtom } from '../context/RootContainerContext.js';
11
11
  import { useDiagram, useDiagramContext } from '../hooks/useDiagram.js';
12
12
  import { depsShallowEqual, useUpdateEffect } from '../hooks/useUpdateEffect.js';
13
13
  import { BuiltinEdges, BuiltinNodes } from './custom/index.js';
@@ -174,9 +174,7 @@ function LikeC4DiagramXYFlow({
174
174
  diagram.send({ type: "xyflow.edgeMouseLeave", edge, event });
175
175
  }
176
176
  }),
177
- ...props.pannable && {
178
- onMove
179
- },
177
+ onMove,
180
178
  onMoveEnd,
181
179
  onInit: useCallbackRef((instance) => {
182
180
  diagram.send({ type: "xyflow.init", instance });
@@ -3,7 +3,7 @@ import { useCustomCompareEffect, useRafEffect } from '@react-hookz/web';
3
3
  import { useActorRef, useSelector } from '@xstate/react';
4
4
  import { useStoreApi } from '@xyflow/react';
5
5
  import { shallowEqual, deepEqual } from 'fast-equals';
6
- import { useRef, useMemo, useEffect } from 'react';
6
+ import { useRef, useEffect, useMemo } from 'react';
7
7
  import { ErrorBoundary } from '../../components/ErrorFallback.js';
8
8
  import { useDiagramEventHandlers } from '../../context/DiagramEventHandlers.js';
9
9
  import { useEnabledFeatures, DiagramFeatures } from '../../context/DiagramFeatures.js';
@@ -70,12 +70,11 @@ function DiagramActorProvider({
70
70
  [features],
71
71
  shallowEqual
72
72
  );
73
- useCustomCompareEffect(
73
+ useEffect(
74
74
  () => {
75
75
  actorRef.send({ type: "update.inputs", inputs: { zoomable, pannable, fitViewPadding, nodesSelectable } });
76
76
  },
77
- [zoomable, pannable, fitViewPadding, nodesSelectable],
78
- deepEqual
77
+ [zoomable, pannable, fitViewPadding, nodesSelectable]
79
78
  );
80
79
  const dynamicViewVariant = useSelector(actorRef, selectDynamicViewVariant);
81
80
  const update = useMemo(
@@ -102,7 +102,7 @@ const NavigationPanelControls = () => {
102
102
  {
103
103
  layout: "position",
104
104
  className: hstack({
105
- gap: "[3px]",
105
+ gap: "1",
106
106
  flexShrink: 1,
107
107
  flexGrow: 1,
108
108
  overflow: "hidden"
@@ -119,7 +119,7 @@ const NavigationPanelControls = () => {
119
119
  {
120
120
  layout: "position",
121
121
  className: hstack({
122
- gap: "[1px]",
122
+ gap: "0.5",
123
123
  flexGrow: 0,
124
124
  _empty: {
125
125
  display: "none"
@@ -6,8 +6,10 @@ import { HStack, VStack, Box } from '@likec4/styles/jsx';
6
6
  import { vstack, hstack } from '@likec4/styles/patterns';
7
7
  import { PopoverDropdown, createScopedKeydownHandler, ScrollAreaAutosize, Input, rem, Button, Divider, Highlight, UnstyledButton, Breadcrumbs } from '@mantine/core';
8
8
  import { useThrottledCallback, useUncontrolled } from '@mantine/hooks';
9
+ import { useMountEffect } from '@react-hookz/web';
9
10
  import { useSelector } from '@xstate/react';
10
11
  import { deepEqual } from 'fast-equals';
12
+ import { useRef } from 'react';
11
13
  import { isEmpty, pipe, sort, isArray } from 'remeda';
12
14
  import { NavigationLink } from '../components/NavigationLink.js';
13
15
  import { useLikeC4Model } from '../hooks/useLikeC4Model.js';
@@ -17,6 +19,7 @@ import { breadcrumbTitle } from './styles.css.js';
17
19
  import { useOnDiagramEvent } from '../hooks/useDiagram.js';
18
20
  import IconSearch from '../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconSearch.js';
19
21
  import IconChevronRight from '../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronRight.js';
22
+ import IconDirectionSignFilled from '../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconDirectionSignFilled.js';
20
23
  import IconStack2 from '../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconStack2.js';
21
24
  import IconZoomScan from '../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconZoomScan.js';
22
25
  import IconStarFilled from '../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconStarFilled.js';
@@ -70,7 +73,7 @@ function NavigationPanelDropdown() {
70
73
  /* @__PURE__ */ jsx(
71
74
  ScrollAreaAutosize,
72
75
  {
73
- scrollbars: "xy",
76
+ scrollbars: "x",
74
77
  type: "auto",
75
78
  offsetScrollbars: "present",
76
79
  classNames: {
@@ -81,6 +84,11 @@ function NavigationPanelDropdown() {
81
84
  ]
82
85
  })
83
86
  },
87
+ styles: {
88
+ viewport: {
89
+ overscrollBehavior: "none"
90
+ }
91
+ },
84
92
  children: hasSearchQuery ? /* @__PURE__ */ jsx(SearchResults, { searchQuery: normalizeViewPath(searchQuery).toLowerCase() }) : /* @__PURE__ */ jsx(FolderColumns, {})
85
93
  }
86
94
  )
@@ -123,7 +131,7 @@ function SearchResults({ searchQuery }) {
123
131
  "calc(100cqh - 200px)"
124
132
  ]
125
133
  }),
126
- children: /* @__PURE__ */ jsx(VStack, { gap: "[1px]", children: found.map((v) => /* @__PURE__ */ jsx(
134
+ children: /* @__PURE__ */ jsx(VStack, { gap: "0.5", children: found.map((v) => /* @__PURE__ */ jsx(
127
135
  FoundedView,
128
136
  {
129
137
  view: v,
@@ -282,7 +290,7 @@ const ViewTypeIcon = {
282
290
  }
283
291
  ),
284
292
  deployment: /* @__PURE__ */ jsx(IconStack2, { size: 16, stroke: 1.5, className: viewTypeIconCss }),
285
- dynamic: /* @__PURE__ */ jsx(IconStack2, { size: 16, stroke: 1.5, className: viewTypeIconCss })
293
+ dynamic: /* @__PURE__ */ jsx(IconDirectionSignFilled, { size: 18, className: viewTypeIconCss })
286
294
  };
287
295
  const ColumnScrollArea = ScrollAreaAutosize.withProps({
288
296
  scrollbars: "y",
@@ -332,10 +340,18 @@ function FolderColumns() {
332
340
  const columns = useNavigationActorContext(selectColumns, deepEqual);
333
341
  return /* @__PURE__ */ jsx(HStack, { gap: "xs", alignItems: "stretch", children: columns.flatMap((column, i) => [
334
342
  i > 0 && /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }, "divider" + i),
335
- /* @__PURE__ */ jsx(FolderColumn, { data: column }, column.folderPath)
343
+ /* @__PURE__ */ jsx(
344
+ FolderColumn,
345
+ {
346
+ data: column,
347
+ isLast: i == columns.length - 1
348
+ },
349
+ column.folderPath
350
+ )
336
351
  ]) });
337
352
  }
338
- function FolderColumn({ data }) {
353
+ function FolderColumn({ data, isLast }) {
354
+ const ref = useRef(null);
339
355
  const actor = useNavigationActorRef();
340
356
  const onItemClicked = (item) => (e) => {
341
357
  e.stopPropagation();
@@ -345,7 +361,15 @@ function FolderColumn({ data }) {
345
361
  actor.send({ type: "select.view", viewId: item.viewId });
346
362
  }
347
363
  };
348
- return /* @__PURE__ */ jsx(Box, { mb: "1", children: /* @__PURE__ */ jsx(ColumnScrollArea, { children: /* @__PURE__ */ jsx(VStack, { gap: "[1px]", children: data.items.map((item, i) => /* @__PURE__ */ jsx(
364
+ useMountEffect(() => {
365
+ if (isLast && ref.current) {
366
+ ref.current.scrollIntoView({
367
+ inline: "nearest",
368
+ behavior: "smooth"
369
+ });
370
+ }
371
+ });
372
+ return /* @__PURE__ */ jsx(Box, { mb: "1", ref, children: /* @__PURE__ */ jsx(ColumnScrollArea, { children: /* @__PURE__ */ jsx(VStack, { gap: "0.5", children: data.items.map((item, i) => /* @__PURE__ */ jsx(
349
373
  FolderColumnItem,
350
374
  {
351
375
  columnItem: item,
@@ -1,16 +1,18 @@
1
- import { jsx } from 'react/jsx-runtime';
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import { cx, css } from '@likec4/styles/css';
3
+ import { hstack } from '@likec4/styles/patterns';
4
+ import { UnstyledButton } from '@mantine/core';
5
+ import * as m from 'motion/react-m';
6
+ import { Logo, LogoIcon } from '../../components/Logo.js';
2
7
  import { useDiagramEventHandlers } from '../../context/DiagramEventHandlers.js';
3
- import { PanelActionIcon } from '../_common.js';
4
8
  import { useNavigationActor } from '../hooks.js';
5
- import IconMenu2 from '../../node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconMenu2.js';
6
9
 
7
10
  const BurgerButton = () => {
8
11
  const actor = useNavigationActor();
9
12
  const { onBurgerMenuClick } = useDiagramEventHandlers();
10
- return /* @__PURE__ */ jsx(
11
- PanelActionIcon,
13
+ return /* @__PURE__ */ jsx(m.div, { layout: "position", children: /* @__PURE__ */ jsxs(
14
+ UnstyledButton,
12
15
  {
13
- layout: "position",
14
16
  onMouseEnter: () => {
15
17
  actor.send({ type: "breadcrumbs.mouseEnter.root" });
16
18
  },
@@ -26,9 +28,45 @@ const BurgerButton = () => {
26
28
  }
27
29
  actor.send({ type: "breadcrumbs.click.root" });
28
30
  },
29
- children: /* @__PURE__ */ jsx(IconMenu2, { style: { width: "80%", height: "80%" } })
31
+ className: cx(
32
+ "mantine-active",
33
+ hstack({
34
+ padding: "0.5",
35
+ // _active: {
36
+ // transform: 'translateY(1px)',
37
+ // },
38
+ width: {
39
+ base: "[20px]",
40
+ "@/md": "[64px]"
41
+ }
42
+ })
43
+ ),
44
+ children: [
45
+ /* @__PURE__ */ jsx(
46
+ Logo,
47
+ {
48
+ className: css({
49
+ display: {
50
+ base: "none",
51
+ "@/md": "block"
52
+ }
53
+ })
54
+ }
55
+ ),
56
+ /* @__PURE__ */ jsx(
57
+ LogoIcon,
58
+ {
59
+ className: css({
60
+ display: {
61
+ base: "block",
62
+ "@/md": "none"
63
+ }
64
+ })
65
+ }
66
+ )
67
+ ]
30
68
  }
31
- );
69
+ ) });
32
70
  };
33
71
 
34
72
  export { BurgerButton };
@@ -7,7 +7,7 @@ const breadcrumbTitle = cva({
7
7
  transition: "fast",
8
8
  color: {
9
9
  base: "mantine.colors.text/90",
10
- _hover: "mantine.colors.text"
10
+ _hover: "[var(--mantine-color-bright)]"
11
11
  }
12
12
  },
13
13
  variants: {
@@ -0,0 +1,14 @@
1
+ import createReactComponent from '../createReactComponent.js';
2
+
3
+ /**
4
+ * @license @tabler/icons-react v3.35.0 - MIT
5
+ *
6
+ * This source code is licensed under the MIT license.
7
+ * See the LICENSE file in the root directory of this source tree.
8
+ */
9
+
10
+
11
+ const __iconNode = [["path", { "d": "M10.52 2.614a2.095 2.095 0 0 1 2.835 -.117l.126 .117l7.905 7.905c.777 .777 .816 2.013 .117 2.836l-.117 .126l-7.905 7.905a2.094 2.094 0 0 1 -2.836 .117l-.126 -.117l-7.907 -7.906a2.096 2.096 0 0 1 -.115 -2.835l.117 -.126l7.905 -7.905zm5.969 9.535l.01 -.116l-.003 -.12l-.016 -.114l-.03 -.11l-.044 -.112l-.052 -.098l-.076 -.105l-.07 -.081l-3.5 -3.5l-.095 -.083a1 1 0 0 0 -1.226 0l-.094 .083l-.083 .094a1 1 0 0 0 0 1.226l.083 .094l1.792 1.793h-5.085l-.117 .007a1 1 0 0 0 0 1.986l.117 .007h5.085l-1.792 1.793l-.083 .094a1 1 0 0 0 1.403 1.403l.094 -.083l3.5 -3.5l.097 -.112l.05 -.074l.037 -.067l.05 -.112l.023 -.076l.025 -.117z", "key": "svg-0" }]];
12
+ const IconDirectionSignFilled = createReactComponent("filled", "direction-sign-filled", "DirectionSignFilled", __iconNode);
13
+
14
+ export { __iconNode, IconDirectionSignFilled as default };