@likec4/diagram 1.42.0 → 1.43.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/bundle/index.js +3768 -3370
  2. package/dist/LikeC4Diagram.d.ts +1 -1
  3. package/dist/LikeC4Diagram.js +40 -14
  4. package/dist/LikeC4Diagram.props.d.ts +12 -17
  5. package/dist/LikeC4View.d.ts +23 -4
  6. package/dist/LikeC4View.js +6 -6
  7. package/dist/ReactLikeC4.d.ts +1 -1
  8. package/dist/ReactLikeC4.js +3 -5
  9. package/dist/StaticLikeC4Diagram.js +1 -1
  10. package/dist/base/const.d.ts +1 -1
  11. package/dist/base/const.js +1 -1
  12. package/dist/components/Logo.js +42 -0
  13. package/dist/components/RootContainer.js +10 -7
  14. package/dist/context/RootContainerContext.d.ts +11 -0
  15. package/dist/context/RootContainerContext.js +14 -1
  16. package/dist/hooks/useReducedGraphics.d.ts +1 -1
  17. package/dist/index.d.ts +0 -1
  18. package/dist/likec4diagram/DiagramXYFlow.js +2 -4
  19. package/dist/likec4diagram/state/DiagramActorProvider.js +3 -4
  20. package/dist/likec4diagram/ui/notation/NotationPanel.js +5 -8
  21. package/dist/navigationpanel/NavigationPanelControls.js +2 -2
  22. package/dist/navigationpanel/NavigationPanelDropdown.js +30 -6
  23. package/dist/navigationpanel/controls/BurgerButton.js +46 -8
  24. package/dist/navigationpanel/styles.css.js +1 -1
  25. package/dist/node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconDirectionSignFilled.js +14 -0
  26. package/dist/overlays/element-details/ElementDetailsCard.js +11 -83
  27. package/dist/overlays/element-details/MetadataValue.d.ts +9 -0
  28. package/dist/overlays/element-details/MetadataValue.js +261 -0
  29. package/dist/overlays/relationship-details/actor.js +6 -2
  30. package/dist/overlays/relationships-browser/const.d.ts +3 -3
  31. package/dist/overlays/relationships-browser/const.js +3 -3
  32. package/dist/shadowroot/ShadowRoot.js +53 -12
  33. package/dist/shadowroot/styles.css.d.ts +0 -4
  34. package/dist/shadowroot/styles.css.js +1 -41
  35. package/dist/styles.css2.js +1 -1
  36. package/package.json +20 -20
  37. package/panda.buildinfo.json +42 -22
  38. package/styles-min.css +1 -1
  39. package/styles.css +1 -1
  40. package/dist/context/ControlsCustomLayout.d.ts +0 -12
  41. package/dist/context/ControlsCustomLayout.js +0 -8
  42. package/dist/context/ReduceGraphics.d.ts +0 -12
  43. package/dist/context/ReduceGraphics.js +0 -26
  44. package/dist/node_modules/.pnpm/@tabler_icons-react@3.35.0_react@19.1.1/node_modules/@tabler/icons-react/dist/esm/icons/IconMenu2.js +0 -14
@@ -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, enableNotations, 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",
@@ -47,7 +48,7 @@ function LikeC4Diagram({
47
48
  enableRelationshipBrowser = false,
48
49
  nodesDraggable = !readonly,
49
50
  nodesSelectable = !readonly || enableFocusMode || !!onNavigateTo || !!onNodeClick,
50
- showNotations = true,
51
+ enableNotations = false,
51
52
  showNavigationButtons = !!onNavigateTo,
52
53
  enableDynamicViewWalkthrough = false,
53
54
  dynamicViewVariant,
@@ -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
  {
@@ -94,7 +102,7 @@ function LikeC4Diagram({
94
102
  enableNavigationButtons: showNavigationButtons && !!onNavigateTo,
95
103
  enableDynamicViewWalkthrough: view._type === "dynamic" && enableDynamicViewWalkthrough,
96
104
  enableEdgeEditing: experimentalEdgeEditing,
97
- enableNotations: showNotations,
105
+ enableNotations,
98
106
  enableVscode: !!onOpenSource,
99
107
  enableControls: controls,
100
108
  enableElementTags
@@ -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';
@@ -40,6 +39,11 @@ export type PaddingWithUnit = `${number}${PaddingUnit}` | number;
40
39
  * bottom: '8px',
41
40
  * left: '8px',
42
41
  * }
42
+ *
43
+ * {
44
+ * x: '16px',
45
+ * y: '16px',
46
+ * }
43
47
  */
44
48
  export type ViewPadding = PaddingWithUnit | {
45
49
  top?: PaddingWithUnit;
@@ -79,8 +83,8 @@ export interface LikeC4DiagramProperties<A extends Any = Unknown> {
79
83
  */
80
84
  fitView?: boolean | undefined;
81
85
  /**
82
- * Padding around the diagram
83
- * @default '8px'
86
+ * Padding around the diagram (number - pixels)
87
+ * @default 16 - 16px
84
88
  *
85
89
  * @see {@link ViewPadding}
86
90
  *
@@ -89,15 +93,15 @@ export interface LikeC4DiagramProperties<A extends Any = Unknown> {
89
93
  * <LikeC4Diagram
90
94
  * fitViewPadding={{
91
95
  * x: '16px',
92
- * y: '16px',
96
+ * y: 16,
93
97
  * }}
94
98
  * />
95
99
  *
96
100
  * <LikeC4Diagram
97
101
  * fitViewPadding={{
98
- * top: '8px',
102
+ * top: 8,
99
103
  * right: '8px',
100
- * bottom: '8px',
104
+ * bottom: '1px',
101
105
  * left: '8px',
102
106
  * }}
103
107
  * />
@@ -136,9 +140,9 @@ export interface LikeC4DiagramProperties<A extends Any = Unknown> {
136
140
  * Display notations in the bottom right corner
137
141
  * (Active if only notations are present)
138
142
  *
139
- * @default true
143
+ * @default false
140
144
  */
141
- showNotations?: boolean | undefined;
145
+ enableNotations?: boolean | undefined;
142
146
  /**
143
147
  * Display dropdown with details on relationship's label click
144
148
  * @default false
@@ -198,15 +202,6 @@ export interface LikeC4DiagramProperties<A extends Any = Unknown> {
198
202
  * By default, if icon is http:// or https://, it will be rendered as an image
199
203
  */
200
204
  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
205
  /**
211
206
  * Override node renderers
212
207
  */
@@ -56,9 +56,28 @@ export interface LikeC4ViewProps<A extends t.aux.Any = t.aux.UnknownLayouted> {
56
56
  fitView?: boolean | undefined;
57
57
  /**
58
58
  * Padding around the diagram
59
- * @default '8px'
59
+ * @default '16px'
60
60
  *
61
61
  * @see {@link ViewPadding}
62
+ *
63
+ * @example
64
+ * ```tsx
65
+ * <LikeC4View
66
+ * fitViewPadding={{
67
+ * x: '16px',
68
+ * y: 16,
69
+ * }}
70
+ * />
71
+ *
72
+ * <LikeC4View
73
+ * fitViewPadding={{
74
+ * top: 8,
75
+ * right: '8px',
76
+ * bottom: '1px',
77
+ * left: '8px',
78
+ * }}
79
+ * />
80
+ * ```
62
81
  */
63
82
  fitViewPadding?: ViewPadding | undefined;
64
83
  /**
@@ -70,7 +89,7 @@ export interface LikeC4ViewProps<A extends t.aux.Any = t.aux.UnknownLayouted> {
70
89
  * Display notations of the view
71
90
  * @default false
72
91
  */
73
- showNotations?: boolean | undefined;
92
+ enableNotations?: boolean | undefined;
74
93
  /**
75
94
  * If double click on a node should enable focus mode, i.e. highlight incoming/outgoing edges
76
95
  * Conflicts with `browser` prop
@@ -210,7 +229,7 @@ export interface LikeC4BrowserProps {
210
229
  * Display notations of the view
211
230
  * @default true
212
231
  */
213
- showNotations?: boolean | undefined;
232
+ enableNotations?: boolean | undefined;
214
233
  /**
215
234
  * Improve performance by hiding certain elements and reducing visual effects (disable mix-blend, shadows, animations)
216
235
  *
@@ -236,4 +255,4 @@ export interface LikeC4BrowserProps {
236
255
  *
237
256
  * Component is wrapped in ShadowRoot to isolate styles.
238
257
  */
239
- export declare function LikeC4View<A extends t.aux.Any = t.aux.UnknownLayouted>({ viewId, className, pannable, zoomable, keepAspectRatio, colorScheme, injectFontCss, controls, background, browser, showNavigationButtons, showNotations, enableFocusMode, enableDynamicViewWalkthrough, enableElementDetails, enableRelationshipDetails, enableRelationshipBrowser, reduceGraphics, mantineTheme, styleNonce, style, reactFlowProps, renderNodes, children, ...props }: LikeC4ViewProps<A>): import("react/jsx-runtime").JSX.Element;
258
+ export declare function LikeC4View<A extends t.aux.Any = t.aux.UnknownLayouted>({ viewId, className, pannable, zoomable, keepAspectRatio, colorScheme, injectFontCss, controls, background, browser, showNavigationButtons, enableNotations, enableFocusMode, enableDynamicViewWalkthrough, enableElementDetails, enableRelationshipDetails, enableRelationshipBrowser, reduceGraphics, mantineTheme, styleNonce, style, reactFlowProps, renderNodes, children, ...props }: LikeC4ViewProps<A>): import("react/jsx-runtime").JSX.Element;
@@ -33,7 +33,7 @@ function LikeC4View({
33
33
  background = "transparent",
34
34
  browser = true,
35
35
  showNavigationButtons = false,
36
- showNotations,
36
+ enableNotations,
37
37
  enableFocusMode = false,
38
38
  enableDynamicViewWalkthrough = false,
39
39
  enableElementDetails = false,
@@ -68,9 +68,8 @@ function LikeC4View({
68
68
  ] });
69
69
  }
70
70
  const browserView = browserViewId ? likec4model.findView(browserViewId)?.$view : null;
71
- const notations = view.notation?.nodes ?? [];
72
- const hasNotations = notations.length > 0;
73
- showNotations ??= hasNotations;
71
+ const hasNotations = !!enableNotations && (view.notation?.nodes?.length ?? 0) > 0;
72
+ const browserViewHasNotations = (browserView?.notation?.nodes?.length ?? 0) > 0;
74
73
  const isBrowserEnabled = browser !== false;
75
74
  const browserProps = isBoolean(browser) ? {} : browser;
76
75
  const bounds = getViewBounds(view, props.dynamicViewVariant);
@@ -98,7 +97,7 @@ function LikeC4View({
98
97
  background,
99
98
  fitView: true,
100
99
  fitViewPadding: FitViewPaddings.default,
101
- showNotations,
100
+ enableNotations: hasNotations,
102
101
  enableDynamicViewWalkthrough,
103
102
  showNavigationButtons,
104
103
  experimentalEdgeEditing: false,
@@ -144,11 +143,12 @@ function LikeC4View({
144
143
  enableElementTags: true,
145
144
  controls: true,
146
145
  readonly: true,
146
+ nodesDraggable: false,
147
147
  fitView: true,
148
148
  ...props,
149
149
  fitViewPadding: FitViewPaddings.withControls,
150
150
  ...browserProps,
151
- showNotations: browserProps.showNotations ?? showNotations,
151
+ enableNotations: browserViewHasNotations && (browserProps.enableNotations ?? true),
152
152
  renderNodes
153
153
  }
154
154
  ),
@@ -36,4 +36,4 @@ export type ReactLikeC4Props<A extends t.aux.Any = t.aux.UnknownLayouted> = {
36
36
  *
37
37
  * Component is wrapped in ShadowRoot to isolate styles.
38
38
  */
39
- export declare function ReactLikeC4<A extends t.aux.Any = t.aux.UnknownLayouted>({ viewId, className, colorScheme, injectFontCss, keepAspectRatio, showNotations, style, mantineTheme, styleNonce, ...props }: ReactLikeC4Props<A>): import("react/jsx-runtime").JSX.Element;
39
+ export declare function ReactLikeC4<A extends t.aux.Any = t.aux.UnknownLayouted>({ viewId, className, colorScheme, injectFontCss, enableNotations, keepAspectRatio, style, mantineTheme, styleNonce, ...props }: ReactLikeC4Props<A>): import("react/jsx-runtime").JSX.Element;
@@ -11,8 +11,8 @@ function ReactLikeC4({
11
11
  className,
12
12
  colorScheme,
13
13
  injectFontCss = true,
14
+ enableNotations,
14
15
  keepAspectRatio,
15
- showNotations,
16
16
  style,
17
17
  mantineTheme,
18
18
  styleNonce,
@@ -33,10 +33,8 @@ function ReactLikeC4({
33
33
  '" is not layouted. Make sure you have LikeC4ModelProvider with layouted model.'
34
34
  ] });
35
35
  }
36
- const notations = view.notation?.nodes ?? [];
37
- const hasNotations = notations.length > 0;
38
- showNotations ??= hasNotations;
39
36
  const bounds = getViewBounds(view, props.dynamicViewVariant);
37
+ const hasNotations = !!enableNotations && (view.notation?.nodes?.length ?? 0) > 0;
40
38
  return /* @__PURE__ */ jsx(
41
39
  ShadowRoot,
42
40
  {
@@ -54,7 +52,7 @@ function ReactLikeC4({
54
52
  LikeC4Diagram,
55
53
  {
56
54
  view,
57
- showNotations,
55
+ enableNotations: hasNotations,
58
56
  ...props
59
57
  }
60
58
  )
@@ -24,7 +24,7 @@ function StaticLikeC4Diagram({
24
24
  zoomable: false,
25
25
  controls: false,
26
26
  background,
27
- showNotations: false,
27
+ enableNotations: false,
28
28
  enableElementDetails: false,
29
29
  enableRelationshipDetails,
30
30
  enableRelationshipBrowser,
@@ -9,7 +9,7 @@ export declare const MaxZoom = 3;
9
9
  export declare const FitViewPaddings: {
10
10
  default: "16px";
11
11
  withControls: {
12
- top: "50px";
12
+ top: "58px";
13
13
  left: "16px";
14
14
  right: "16px";
15
15
  bottom: "16px";
@@ -10,7 +10,7 @@ const MaxZoom = 3;
10
10
  const FitViewPaddings = {
11
11
  default: "16px",
12
12
  withControls: {
13
- top: "50px",
13
+ top: "58px",
14
14
  left: "16px",
15
15
  right: "16px",
16
16
  bottom: "16px"
@@ -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(
@@ -112,16 +112,13 @@ const ElementNotation = ({ value }) => {
112
112
  };
113
113
  const selector = (s) => ({
114
114
  id: s.view.id,
115
- notations: s.view.notation?.nodes ?? [],
116
- isVisible: true
117
- // isVisible: isNullish(s.focusedNodeId ?? s.activeWalkthrough),
115
+ notations: s.view.notation?.nodes ?? []
118
116
  });
119
117
  const NotationPanel = memo(() => {
120
118
  const height = useXYStore((s) => s.height);
121
119
  const {
122
120
  id,
123
- notations,
124
- isVisible
121
+ notations
125
122
  } = useDiagramContext(selector);
126
123
  const [isCollapsed, setCollapsed] = useLocalStorage({
127
124
  key: "notation-webview-collapsed",
@@ -130,7 +127,7 @@ const NotationPanel = memo(() => {
130
127
  const hasNotations = notations.length > 0;
131
128
  const portalProps = useMantinePortalProps();
132
129
  return /* @__PURE__ */ jsxs(AnimatePresence, { children: [
133
- !hasNotations && isVisible && /* @__PURE__ */ jsx(
130
+ !hasNotations && /* @__PURE__ */ jsx(
134
131
  m.div,
135
132
  {
136
133
  initial: { opacity: 0.75, translateX: "50%" },
@@ -153,7 +150,7 @@ const NotationPanel = memo(() => {
153
150
  },
154
151
  "empty"
155
152
  ),
156
- hasNotations && isVisible && isCollapsed && /* @__PURE__ */ jsx(
153
+ hasNotations && isCollapsed && /* @__PURE__ */ jsx(
157
154
  m.div,
158
155
  {
159
156
  initial: { opacity: 0.75, translateX: "50%" },
@@ -177,7 +174,7 @@ const NotationPanel = memo(() => {
177
174
  },
178
175
  "collapsed"
179
176
  ),
180
- hasNotations && isVisible && !isCollapsed && /* @__PURE__ */ jsx(
177
+ hasNotations && !isCollapsed && /* @__PURE__ */ jsx(
181
178
  m.div,
182
179
  {
183
180
  initial: {
@@ -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"