@likec4/diagram 1.32.1 → 1.33.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 (156) hide show
  1. package/README.md +12 -5
  2. package/bundle/{chunk-DlHyKoeo.js → chunk-DyFK-AJ5.js} +516 -488
  3. package/bundle/custom.js +53 -50
  4. package/bundle/index.js +317 -154
  5. package/dist/base/primitives/MarkdownBlock.d.ts +27 -0
  6. package/dist/base/primitives/MarkdownBlock.js +42 -0
  7. package/dist/base/primitives/compound/CompoundActionButton.js +1 -1
  8. package/dist/base/primitives/compound/CompoundDetailsButton.js +1 -1
  9. package/dist/base/primitives/edge/EdgeActionButton.js +1 -1
  10. package/dist/base/primitives/element/ElementDetailsButton.js +1 -1
  11. package/dist/base/primitives/element/ElementTags.d.ts +1 -1
  12. package/dist/base/primitives/element/ElementTags.js +116 -125
  13. package/dist/base/primitives/element/ElementTitle.css.js +6 -1
  14. package/dist/base/primitives/element/ElementTitle.d.ts +3 -2
  15. package/dist/base/primitives/element/ElementTitle.js +9 -6
  16. package/dist/base/primitives/index.d.ts +1 -0
  17. package/dist/bundle/LikeC4View.js +1 -1
  18. package/dist/bundle/custom.js +31 -0
  19. package/dist/bundle/index.js +1 -0
  20. package/dist/components/ErrorFallback.js +1 -1
  21. package/dist/components/Link.js +2 -1
  22. package/dist/components/SearchControl.js +1 -1
  23. package/dist/context/DiagramFeatures.d.ts +3 -2
  24. package/dist/context/DiagramFeatures.js +16 -1
  25. package/dist/context/IconRenderer.js +6 -1
  26. package/dist/context/TagStylesContext.js +1 -1
  27. package/dist/custom/components.d.ts +2 -2
  28. package/dist/custom/customNodes.js +18 -0
  29. package/dist/custom/hooks.d.ts +3 -3
  30. package/dist/custom/index.js +31 -0
  31. package/dist/hooks/safeContext.js +1 -1
  32. package/dist/hooks/useXYFlow.d.ts +2 -1
  33. package/dist/index.d.ts +4 -6
  34. package/dist/index.js +1 -0
  35. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +5 -2
  36. package/dist/likec4diagram/custom/nodes/ElementActions.js +2 -1
  37. package/dist/likec4diagram/custom/nodes/nodes.js +3 -3
  38. package/dist/likec4diagram/custom/nodes/toolbar/ElementToolbar.js +2 -1
  39. package/dist/likec4diagram/custom/nodes/toolbar/_shared.js +2 -1
  40. package/dist/likec4diagram/types.d.ts +3 -2
  41. package/dist/likec4diagram/ui/controls/ChangeAutoLayoutButton.js +1 -1
  42. package/dist/likec4diagram/ui/controls/Controls.js +3 -1
  43. package/dist/likec4diagram/ui/controls/LayoutDriftNotification.js +1 -1
  44. package/dist/likec4diagram/ui/controls/ManualLayoutToolsButton.js +9 -1
  45. package/dist/likec4diagram/ui/controls/NavigationButtons.js +2 -1
  46. package/dist/likec4diagram/ui/controls/ToggleReadonly.js +2 -1
  47. package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +19 -15
  48. package/dist/likec4diagram/ui/notation/NotationPanel.js +3 -1
  49. package/dist/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.js +4 -1
  50. package/dist/likec4diagram/useViewToNodesEdges.js +2 -2
  51. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/createReactComponent.js +41 -0
  52. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/defaultAttributes.js +30 -0
  53. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconAlertTriangle.js +13 -0
  54. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowDownRight.js +13 -0
  55. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconArrowRight.js +13 -0
  56. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconBrowser.js +13 -0
  57. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconCheck.js +13 -0
  58. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronLeft.js +13 -0
  59. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconChevronRight.js +13 -0
  60. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconCopy.js +13 -0
  61. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconCylinder.js +13 -0
  62. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconDeviceMobile.js +13 -0
  63. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconExternalLink.js +13 -0
  64. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconFileSymlink.js +13 -0
  65. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconFocusCentered.js +13 -0
  66. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconHelpCircle.js +13 -0
  67. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconId.js +13 -0
  68. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconInfoCircle.js +13 -0
  69. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutAlignBottom.js +13 -0
  70. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutAlignCenter.js +13 -0
  71. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutAlignLeft.js +13 -0
  72. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutAlignMiddle.js +13 -0
  73. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutAlignRight.js +13 -0
  74. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutAlignTop.js +13 -0
  75. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutBoardSplit.js +13 -0
  76. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutCollage.js +13 -0
  77. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLayoutDashboard.js +13 -0
  78. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLock.js +13 -0
  79. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconLockOpen2.js +13 -0
  80. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconMenu.js +13 -0
  81. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconMenu2.js +13 -0
  82. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconPlayerPlayFilled.js +13 -0
  83. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconPlayerSkipBackFilled.js +13 -0
  84. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconPlayerSkipForwardFilled.js +13 -0
  85. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconPlayerStopFilled.js +13 -0
  86. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconRectangularPrism.js +13 -0
  87. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconReorder.js +13 -0
  88. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconRouteOff.js +13 -0
  89. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconSearch.js +13 -0
  90. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconSelector.js +13 -0
  91. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconStack2.js +13 -0
  92. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconTarget.js +13 -0
  93. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconTransform.js +13 -0
  94. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconUser.js +13 -0
  95. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconX.js +13 -0
  96. package/dist/node_modules/.pnpm/@tabler_icons-react@3.31.0_react@19.1.0/node_modules/@tabler/icons-react/dist/esm/icons/IconZoomScan.js +13 -0
  97. package/dist/overlays/element-details/ElementDetailsCard.css.js +4 -2
  98. package/dist/overlays/element-details/ElementDetailsCard.js +127 -12
  99. package/dist/overlays/element-details/TabPanelDeployments.js +3 -1
  100. package/dist/overlays/element-details/TabPanelRelationships.js +3 -1
  101. package/dist/overlays/element-details/TabPanelStructure.js +1 -1
  102. package/dist/overlays/relationship-details/RelationshipDetails.d.ts +2 -2
  103. package/dist/overlays/relationship-details/RelationshipDetails.js +3 -1
  104. package/dist/overlays/relationship-details/SelectEdge.js +2 -1
  105. package/dist/overlays/relationship-details/_types.d.ts +4 -3
  106. package/dist/overlays/relationship-details/actor.d.ts +2 -2
  107. package/dist/overlays/relationship-details/custom/ElementActions.js +3 -1
  108. package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +2 -2
  109. package/dist/overlays/relationship-details/hooks.d.ts +10 -10
  110. package/dist/overlays/relationship-details/layout-to-xyflow.js +4 -4
  111. package/dist/overlays/relationship-details/layout.d.ts +5 -3
  112. package/dist/overlays/relationship-details/layout.js +2 -2
  113. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +3 -1
  114. package/dist/overlays/relationships-browser/SelectElement.js +2 -1
  115. package/dist/overlays/relationships-browser/_types.d.ts +3 -2
  116. package/dist/overlays/relationships-browser/custom/ElementActions.js +3 -1
  117. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +2 -2
  118. package/dist/overlays/relationships-browser/layout.d.ts +4 -3
  119. package/dist/overlays/relationships-browser/layout.js +3 -3
  120. package/dist/search/components/ElementsColumn.js +2 -2
  121. package/dist/search/components/PickView.js +1 -1
  122. package/dist/search/components/SearchByTags.js +1 -1
  123. package/dist/search/components/SearchInput.js +1 -1
  124. package/dist/search/components/ViewsColum.js +4 -3
  125. package/dist/state/DiagramActorProvider.js +9 -1
  126. package/dist/state/diagram-machine.js +1 -1
  127. package/dist/styles-min.css +1 -1
  128. package/dist/styles.css +1 -1
  129. package/dist/styles.css2.js +1 -1
  130. package/package.json +26 -20
  131. package/panda.buildinfo.json +26 -7
  132. package/src/base/primitives/MarkdownBlock.tsx +66 -0
  133. package/src/base/primitives/element/ElementTags.tsx +118 -116
  134. package/src/base/primitives/element/ElementTitle.css.ts +7 -1
  135. package/src/base/primitives/element/ElementTitle.tsx +14 -9
  136. package/src/base/primitives/index.ts +1 -0
  137. package/src/context/DiagramFeatures.tsx +7 -7
  138. package/src/custom/components.ts +2 -0
  139. package/src/custom/hooks.ts +5 -0
  140. package/src/hooks/useXYFlow.ts +9 -1
  141. package/src/index.ts +18 -6
  142. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +1 -1
  143. package/src/likec4diagram/types.ts +2 -2
  144. package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +21 -16
  145. package/src/likec4diagram/useViewToNodesEdges.ts +2 -1
  146. package/src/overlays/element-details/ElementDetailsCard.css.ts +3 -1
  147. package/src/overlays/element-details/ElementDetailsCard.tsx +101 -17
  148. package/src/overlays/relationship-details/_types.ts +12 -3
  149. package/src/overlays/relationship-details/layout-to-xyflow.ts +3 -2
  150. package/src/overlays/relationship-details/layout.ts +7 -4
  151. package/src/overlays/relationships-browser/_types.ts +2 -1
  152. package/src/overlays/relationships-browser/layout.ts +7 -4
  153. package/src/search/components/ElementsColumn.tsx +1 -1
  154. package/src/search/components/ViewsColum.tsx +2 -2
  155. package/src/state/DiagramActorProvider.tsx +10 -2
  156. package/src/state/diagram-machine.ts +1 -1
@@ -11,6 +11,7 @@ export {
11
11
  ElementTag,
12
12
  ElementTags,
13
13
  ElementTitle,
14
+ MarkdownBlock,
14
15
  } from '../base/primitives'
15
16
 
16
17
  export {
@@ -41,6 +42,7 @@ export {
41
42
  IfEnabled,
42
43
  IfNotEnabled,
43
44
  IfNotReadOnly,
45
+ IfReadOnly,
44
46
  } from '../context/DiagramFeatures'
45
47
 
46
48
  export {
@@ -10,13 +10,16 @@ export {
10
10
 
11
11
  export {
12
12
  type EnabledFeatures,
13
+ type FeatureName,
13
14
  useEnabledFeatures,
14
15
  } from '../context/DiagramFeatures'
15
16
  export {
16
17
  useCurrentViewId,
17
18
  } from '../hooks/useCurrentViewId'
18
19
  export {
20
+ type DiagramApi,
19
21
  useDiagram,
22
+ useDiagramActorRef,
20
23
  useDiagramContext,
21
24
  } from '../hooks/useDiagram'
22
25
  export {
@@ -24,6 +27,8 @@ export {
24
27
  useXYInternalNode,
25
28
  useXYStore,
26
29
  useXYStoreApi,
30
+ type XYFlowInstance,
31
+ type XYStoreApi,
27
32
  } from '../hooks/useXYFlow'
28
33
 
29
34
  export {
@@ -1,9 +1,17 @@
1
1
  import { useCallbackRef } from '@mantine/hooks'
2
- import { type ReactFlowState, useInternalNode, useReactFlow, useStore, useStoreApi } from '@xyflow/react'
2
+ import {
3
+ type ReactFlowInstance,
4
+ type ReactFlowState,
5
+ useInternalNode,
6
+ useReactFlow,
7
+ useStore,
8
+ useStoreApi,
9
+ } from '@xyflow/react'
3
10
  import { shallowEqual } from 'fast-equals'
4
11
  import type { Types } from '../likec4diagram/types'
5
12
 
6
13
  export const useXYFlow = useReactFlow<Types.Node, Types.Edge>
14
+ export type XYFlowInstance = ReactFlowInstance<Types.Node, Types.Edge>
7
15
 
8
16
  export function useXYStore<StateSlice = unknown>(
9
17
  selector: (state: ReactFlowState<Types.Node, Types.Edge>) => StateSlice,
package/src/index.ts CHANGED
@@ -1,11 +1,21 @@
1
1
  export type { ControlsCustomLayout, ControlsCustomLayoutProps } from './context/ControlsCustomLayout'
2
2
  export { FramerMotionConfig } from './context/FramerMotionConfig'
3
3
  export { IconRendererProvider } from './context/IconRenderer'
4
- export { LikeC4Diagram } from './LikeC4Diagram'
5
- export type { LikeC4DiagramProps } from './LikeC4Diagram'
6
- export { Overlay } from './overlays/overlay/Overlay'
7
4
 
8
- export { LikeC4ModelProvider } from './LikeC4ModelProvider'
5
+ export {
6
+ LikeC4Diagram,
7
+ type LikeC4DiagramProps,
8
+ } from './LikeC4Diagram'
9
+
10
+ export {
11
+ Overlay,
12
+ type OverlayProps,
13
+ } from './overlays/overlay/Overlay'
14
+
15
+ export {
16
+ LikeC4ModelProvider,
17
+ type LikeC4ModelProviderProps,
18
+ } from './LikeC4ModelProvider'
9
19
 
10
20
  export * from './custom/hooks'
11
21
 
@@ -28,5 +38,7 @@ export type {
28
38
  WhereOperator,
29
39
  } from './LikeC4Diagram.props'
30
40
 
31
- export { StaticLikeC4Diagram } from './StaticLikeC4Diagram'
32
- export type { StaticLikeC4DiagramProps } from './StaticLikeC4Diagram'
41
+ export {
42
+ StaticLikeC4Diagram,
43
+ type StaticLikeC4DiagramProps,
44
+ } from './StaticLikeC4Diagram'
@@ -253,7 +253,7 @@ const Relationship = forwardRef<
253
253
  )}
254
254
  </Group>
255
255
  <Box className={styles.title}>{r.title || 'untitled'}</Box>
256
- {r.description && <Text size="xs" c="dimmed">{r.description}</Text>}
256
+ {r.description.nonEmpty && <Text size="xs" c="dimmed">{r.description.text}</Text>}
257
257
  {links.length > 0 && (
258
258
  <Stack
259
259
  gap={3}
@@ -1,4 +1,4 @@
1
- import type { DeploymentFqn, DiagramEdge, DiagramNode, Fqn, IconUrl, ViewId } from '@likec4/core/types'
1
+ import type { DeploymentFqn, DiagramEdge, DiagramNode, Fqn, IconUrl, RichTextOrEmpty, ViewId } from '@likec4/core/types'
2
2
  import type { XYPosition } from '@xyflow/system'
3
3
  import type { OptionalKeysOf, Simplify } from 'type-fest'
4
4
  import type { Base, ReactFlowEdge, ReactFlowNode } from '../base/types'
@@ -21,7 +21,6 @@ export namespace Types {
21
21
  | 'id'
22
22
  | 'title'
23
23
  | 'technology'
24
- | 'description'
25
24
  | 'color'
26
25
  | 'shape'
27
26
  | 'width'
@@ -33,6 +32,7 @@ export namespace Types {
33
32
  >
34
33
  >
35
34
  & {
35
+ description: RichTextOrEmpty
36
36
  /**
37
37
  * View this node belongs to
38
38
  */
@@ -1,20 +1,27 @@
1
+ import { RichText } from '@likec4/core/types'
1
2
  import { cx as clsx } from '@likec4/styles/css'
2
3
  import { Button, Card, CardSection, Group, Spoiler, Stack, Text } from '@mantine/core'
3
4
  import { useLocalStorage } from '@mantine/hooks'
4
5
  import { IconMenu } from '@tabler/icons-react'
5
6
  import { AnimatePresence, m } from 'motion/react'
7
+ import { MarkdownBlock } from '../../../base/primitives'
6
8
  import { Link } from '../../../components/Link'
7
9
  import { useDiagramContext } from '../../../hooks/useDiagram'
10
+ import type { DiagramContext } from '../../../state/types'
8
11
  import * as styles from './DiagramTitlePanel.css'
9
12
 
13
+ function selector(context: DiagramContext) {
14
+ return {
15
+ id: context.view.id,
16
+ title: context.view.title ?? 'untitled',
17
+ description: RichText.from(context.view.description),
18
+ links: context.view.links,
19
+ isNotActiveWalkthrough: context.activeWalkthrough === null,
20
+ }
21
+ }
22
+
10
23
  export function DiagramTitlePanel() {
11
- const { id, title, description, links, isNotActiveWalkthrough } = useDiagramContext(s => ({
12
- id: s.view.id,
13
- title: s.view.title ?? 'untitled',
14
- description: s.view.description,
15
- links: s.view.links,
16
- isNotActiveWalkthrough: s.activeWalkthrough === null,
17
- }))
24
+ const { id, title, description, links, isNotActiveWalkthrough } = useDiagramContext(selector)
18
25
  const [isCollapsed, setCollapsed] = useLocalStorage({
19
26
  key: 'diagram-title-webview-collapsed',
20
27
  defaultValue: false,
@@ -120,9 +127,9 @@ export function DiagramTitlePanel() {
120
127
  {id}
121
128
  </Text>
122
129
  </Group>
123
- {description && (
130
+ {description.nonEmpty && (
124
131
  <Spoiler
125
- maxHeight={42}
132
+ maxHeight={60}
126
133
  showLabel={
127
134
  <Button component={'div'} color="gray" variant="light" fz={'10'} size="compact-xs" tabIndex={-1}>
128
135
  show more
@@ -133,15 +140,13 @@ export function DiagramTitlePanel() {
133
140
  hide
134
141
  </Button>
135
142
  }>
136
- <Text
137
- component={'div'}
138
- size="sm"
139
- className={styles.description}>
140
- {description || 'no description'}
141
- </Text>
143
+ <MarkdownBlock
144
+ className={styles.description}
145
+ textScale={0.9}
146
+ value={description} />
142
147
  </Spoiler>
143
148
  )}
144
- {!description && (
149
+ {description.isEmpty && (
145
150
  <Text
146
151
  component={'div'}
147
152
  size="xs"
@@ -10,6 +10,7 @@ import {
10
10
  invariant,
11
11
  nonNullable,
12
12
  Queue,
13
+ RichText,
13
14
  whereOperatorAsPredicate,
14
15
  } from '@likec4/core'
15
16
  import { useCustomCompareMemo } from '@react-hookz/web'
@@ -129,7 +130,7 @@ function viewToNodesEdge(opts: {
129
130
  id: node.id,
130
131
  title: node.title,
131
132
  technology: node.technology,
132
- description: node.description,
133
+ description: RichText.from(node.description),
133
134
  height: node.height,
134
135
  width: node.width,
135
136
  level: node.level,
@@ -226,13 +226,15 @@ export const propertiesGrid = css({
226
226
  display: 'grid',
227
227
  gridTemplateColumns: 'min-content 1fr',
228
228
  gridAutoRows: 'min-content max-content',
229
- gap: `[20px 16px]`,
229
+ gap: `[24px 20px]`,
230
230
  alignItems: 'baseline',
231
231
  justifyItems: 'stretch',
232
232
  })
233
233
 
234
234
  export const propertyLabel = css({
235
235
  justifySelf: 'end',
236
+ textAlign: 'right',
237
+ userSelect: 'none',
236
238
  })
237
239
 
238
240
  export const resizeHandle = css({
@@ -17,12 +17,12 @@ import {
17
17
  Box,
18
18
  Card,
19
19
  CloseButton,
20
- Code,
21
20
  Divider as MantineDivider,
22
21
  Flex,
23
22
  Group,
24
23
  RemoveScroll,
25
24
  ScrollArea,
25
+ ScrollAreaAutosize,
26
26
  Stack,
27
27
  Tabs,
28
28
  TabsList,
@@ -39,7 +39,8 @@ import { IconExternalLink, IconFileSymlink, IconStack2, IconZoomScan } from '@ta
39
39
  import type { Rect } from '@xyflow/system'
40
40
  import { type PanInfo, m, useDragControls, useMotionValue } from 'motion/react'
41
41
  import { type PropsWithChildren, useCallback, useRef, useState } from 'react'
42
- import { clamp, isNullish, map, only, partition, pipe } from 'remeda'
42
+ import { clamp, entries, isNullish, map, only, partition, pipe } from 'remeda'
43
+ import { MarkdownBlock } from '../../base/primitives'
43
44
  import { ElementTag } from '../../base/primitives/element/ElementTags'
44
45
  import { Link } from '../../components/Link'
45
46
  import { DiagramFeatures, IconRenderer, IfEnabled } from '../../context'
@@ -126,6 +127,7 @@ export function ElementDetailsCard({
126
127
  )
127
128
 
128
129
  let defaultView = nodeModel?.navigateTo?.$view ?? elementModel.defaultView?.$view ?? null
130
+ // Ignore default view if it's the current view
129
131
  if (defaultView?.id === viewId) {
130
132
  defaultView = null
131
133
  }
@@ -324,7 +326,21 @@ export function ElementDetailsCard({
324
326
  <Group align="baseline" gap={'sm'} wrap="nowrap">
325
327
  <div>
326
328
  <SmallLabel>kind</SmallLabel>
327
- <Badge radius={'sm'} size="sm" fw={600} color="gray">{elementModel.kind}</Badge>
329
+ <Badge
330
+ radius={'sm'}
331
+ size="sm"
332
+ fw={600}
333
+ color="gray"
334
+ style={{
335
+ cursor: 'pointer',
336
+ }}
337
+ onClick={e => {
338
+ e.stopPropagation()
339
+ diagram.openSearch(`kind:${elementModel.kind}`)
340
+ }}
341
+ >
342
+ {elementModel.kind}
343
+ </Badge>
328
344
  </div>
329
345
  <div style={{ flex: 1 }}>
330
346
  <SmallLabel>tags</SmallLabel>
@@ -369,9 +385,9 @@ export function ElementDetailsCard({
369
385
  radius="sm"
370
386
  onClick={e => {
371
387
  e.stopPropagation()
372
- // diagram.openSource({
373
- // element: elementModel.id,
374
- // })
388
+ diagram.openSource({
389
+ element: elementModel.id,
390
+ })
375
391
  }}>
376
392
  <IconFileSymlink stroke={1.8} style={{ width: '62%' }} />
377
393
  </ActionIcon>
@@ -413,11 +429,15 @@ export function ElementDetailsCard({
413
429
  </TabsList>
414
430
 
415
431
  <TabsPanel value="Properties">
416
- <ScrollArea scrollbars="y" type="auto">
432
+ <ScrollArea scrollbars="y" type="scroll" offsetScrollbars>
417
433
  <Box className={styles.propertiesGrid} pt={'xs'}>
418
- <ElementProperty title="description" emptyValue="no description">
419
- {elementModel.description}
420
- </ElementProperty>
434
+ <>
435
+ <PropertyLabel>description</PropertyLabel>
436
+ <MarkdownBlock
437
+ value={elementModel.description}
438
+ emptyText="no description"
439
+ />
440
+ </>
421
441
  {elementModel.technology && (
422
442
  <ElementProperty title="technology">
423
443
  {elementModel.technology}
@@ -527,11 +547,13 @@ const ViewButton = <A extends Any>({
527
547
  <Text component="div" className={styles.viewButtonTitle} lineClamp={1}>
528
548
  {view.title || 'untitled'}
529
549
  </Text>
530
- {view.description && (
550
+ {
551
+ /* {view.description && (
531
552
  <Text component="div" mt={2} fz={'xs'} c={'dimmed'} lh={1.4} lineClamp={1}>
532
553
  {view.description}
533
554
  </Text>
534
- )}
555
+ )} */
556
+ }
535
557
  </Box>
536
558
  </Group>
537
559
  </UnstyledButton>
@@ -559,6 +581,7 @@ function ElementProperty({
559
581
  fz={'md'}
560
582
  style={{
561
583
  whiteSpace: 'preserve-breaks',
584
+ userSelect: 'all',
562
585
  ...style,
563
586
  }}
564
587
  {...props}
@@ -570,17 +593,78 @@ function ElementProperty({
570
593
  }
571
594
 
572
595
  function ElementMetata({
573
- value,
596
+ value: metadata,
574
597
  }: {
575
598
  value: NonNullable<Element['metadata']>
576
599
  }) {
577
600
  return (
578
601
  <>
579
602
  <PropertyLabel>metadata</PropertyLabel>
580
- <Box>
581
- <Code block>
582
- {JSON.stringify(value, null, 2)}
583
- </Code>
603
+ <Box
604
+ className={css({
605
+ flex: 1,
606
+ display: 'grid',
607
+ gridTemplateColumns: 'min-content 1fr',
608
+ gridAutoRows: 'min-content max-content',
609
+ gap: `[4px 4px]`,
610
+ alignItems: 'baseline',
611
+ justifyItems: 'stretch',
612
+ paddingRight: '2xs',
613
+ })}>
614
+ {entries(metadata).map(([key, value]) => (
615
+ <div
616
+ key={key}
617
+ className={cx(
618
+ 'group',
619
+ css({
620
+ display: 'contents',
621
+ }),
622
+ )}
623
+ >
624
+ <div
625
+ className={css({
626
+ fontSize: 'sm',
627
+ fontWeight: 500,
628
+ justifySelf: 'end',
629
+ whiteSpace: 'nowrap',
630
+ })}>
631
+ {key}:
632
+ </div>
633
+ <div
634
+ className={css({})}>
635
+ <ScrollAreaAutosize
636
+ type="auto"
637
+ mah={200}
638
+ overscrollBehavior="none"
639
+ className={css({
640
+ transitionProperty: 'all',
641
+ transitionDuration: 'fast',
642
+ transitionTimingFunction: 'inOut',
643
+ rounded: 'sm',
644
+ color: 'mantine.colors.gray[8]',
645
+ _dark: {
646
+ color: 'mantine.colors.dark[1]',
647
+ },
648
+ _groupHover: {
649
+ transitionTimingFunction: 'out',
650
+ color: 'mantine.colors.defaultColor',
651
+ background: 'mantine.colors.defaultHover',
652
+ },
653
+ })}>
654
+ <div
655
+ className={css({
656
+ fontSize: 'sm',
657
+ padding: '2xs',
658
+ whiteSpace: 'pre',
659
+ fontFamily: '[var(--mantine-font-family-monospace)]',
660
+ userSelect: 'all',
661
+ })}>
662
+ {value}
663
+ </div>
664
+ </ScrollAreaAutosize>
665
+ </div>
666
+ </div>
667
+ ))}
584
668
  </Box>
585
669
  </>
586
670
  )
@@ -1,4 +1,13 @@
1
- import type { Color, DiagramNode, Fqn, IconUrl, RelationId, RelationshipLineType, ViewId } from '@likec4/core/types'
1
+ import type {
2
+ Color,
3
+ DiagramNode,
4
+ Fqn,
5
+ IconUrl,
6
+ RelationId,
7
+ RelationshipLineType,
8
+ RichTextOrEmpty,
9
+ ViewId,
10
+ } from '@likec4/core/types'
2
11
  import type { Simplify } from 'type-fest'
3
12
  import type { Base, NonOptional, ReactFlowEdge, ReactFlowNode } from '../../base/types'
4
13
 
@@ -19,7 +28,6 @@ export namespace RelationshipDetailsTypes {
19
28
  DiagramNode,
20
29
  | 'title'
21
30
  | 'technology'
22
- | 'description'
23
31
  | 'color'
24
32
  | 'shape'
25
33
  | 'width'
@@ -34,6 +42,7 @@ export namespace RelationshipDetailsTypes {
34
42
  fqn: Fqn
35
43
  icon: IconUrl
36
44
  ports: Ports
45
+ description: RichTextOrEmpty
37
46
  }
38
47
 
39
48
  export type CompoundNodeData =
@@ -69,9 +78,9 @@ export namespace RelationshipDetailsTypes {
69
78
  color: Color | undefined
70
79
  label: string | null
71
80
  technology?: string | undefined
72
- description?: string | undefined
73
81
  navigateTo: ViewId | null
74
82
  line: RelationshipLineType
83
+ description: RichTextOrEmpty
75
84
  }
76
85
  >
77
86
 
@@ -2,6 +2,7 @@ import {
2
2
  type Fqn,
3
3
  nonNullable,
4
4
  Queue,
5
+ RichText,
5
6
  } from '@likec4/core'
6
7
  import { hasAtLeast } from 'remeda'
7
8
  import { ZIndexes } from '../../base/const'
@@ -111,7 +112,7 @@ export function layoutResultToXYFlow(
111
112
  fqn,
112
113
  title: node.title,
113
114
  technology: node.technology,
114
- description: node.description,
115
+ description: RichText.from(node.description),
115
116
  height: node.height,
116
117
  width: node.width,
117
118
  color: node.color,
@@ -159,8 +160,8 @@ export function layoutResultToXYFlow(
159
160
  color,
160
161
  navigateTo,
161
162
  line,
163
+ description: RichText.from(description),
162
164
  ...(technology && { technology }),
163
- ...(description && { description }),
164
165
  },
165
166
  })
166
167
  }
@@ -12,10 +12,11 @@ import type {
12
12
  NonEmptyArray,
13
13
  Point,
14
14
  RelationId,
15
+ RichTextOrEmpty,
15
16
  } from '@likec4/core/types'
16
17
 
17
18
  import dagre, { type EdgeConfig, type GraphLabel } from '@dagrejs/dagre'
18
- import { invariant } from '@likec4/core'
19
+ import { invariant, RichText } from '@likec4/core'
19
20
  import type { AnyAux, ElementModel, LikeC4ViewModel, RelationshipModel } from '@likec4/core/model'
20
21
  import {
21
22
  DefaultMap,
@@ -216,16 +217,18 @@ export type LayoutResult = {
216
217
  }
217
218
 
218
219
  export namespace LayoutResult {
219
- export type Node = Omit<DiagramNode, 'modelRef' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
220
+ export type Node = Omit<DiagramNode, 'modelRef' | 'description' | 'deploymentRef' | 'inEdges' | 'outEdges'> & {
221
+ description: RichTextOrEmpty
220
222
  modelRef: Fqn
221
223
  column: RelationshipDetailsTypes.Column
222
224
  ports: RelationshipDetailsTypes.Ports
223
225
  // existsInCurrentView: boolean
224
226
  }
225
- export type Edge = Omit<DiagramEdge, 'relations'> & {
227
+ export type Edge = Omit<DiagramEdge, 'relations' | 'description'> & {
226
228
  relationId: RelationId
227
229
  sourceHandle: string
228
230
  targetHandle: string
231
+ description: RichTextOrEmpty
229
232
  // existsInCurrentView: boolean
230
233
  // column: RelationshipsBrowserTypes.Column
231
234
  }
@@ -398,7 +401,7 @@ export function layoutRelationshipDetails(
398
401
  y: position.y,
399
402
  position: [position.x, position.y],
400
403
  title: element.title,
401
- description: element.description,
404
+ description: RichText.from(element.description),
402
405
  technology: element.technology,
403
406
  tags: [...element.tags],
404
407
  links: null,
@@ -6,6 +6,7 @@ import type {
6
6
  NonEmptyArray,
7
7
  RelationId,
8
8
  RelationshipLineType,
9
+ RichTextOrEmpty,
9
10
  ViewId,
10
11
  } from '@likec4/core/types'
11
12
  import type { Simplify } from 'type-fest'
@@ -29,7 +30,6 @@ export namespace RelationshipsBrowserTypes {
29
30
  DiagramNode,
30
31
  | 'title'
31
32
  | 'technology'
32
- | 'description'
33
33
  | 'color'
34
34
  | 'shape'
35
35
  | 'style'
@@ -45,6 +45,7 @@ export namespace RelationshipsBrowserTypes {
45
45
  icon: string | null
46
46
  ports: Ports
47
47
  existsInCurrentView: boolean
48
+ description: RichTextOrEmpty
48
49
  }
49
50
  >
50
51
 
@@ -14,6 +14,7 @@ import type {
14
14
  NodeId,
15
15
  NonEmptyArray,
16
16
  Point,
17
+ RichTextOrEmpty,
17
18
  ViewId,
18
19
  } from '@likec4/core/types'
19
20
  import { useMemo } from 'react'
@@ -24,6 +25,7 @@ import {
24
25
  ifind,
25
26
  invariant,
26
27
  nonNullable,
28
+ RichText,
27
29
  toArray,
28
30
  } from '@likec4/core'
29
31
  import type { ElementModel, LikeC4ViewModel, RelationshipModel } from '@likec4/core/model'
@@ -200,12 +202,13 @@ export type LayoutRelationshipsViewResult = {
200
202
  export namespace LayoutRelationshipsViewResult {
201
203
  export const Empty = '@empty' as ElementKind
202
204
 
203
- export type Node = Omit<DiagramNode, 'deploymentRef' | 'inEdges' | 'outEdges'> & {
205
+ export type Node = Omit<DiagramNode, 'deploymentRef' | 'description' | 'inEdges' | 'outEdges'> & {
206
+ description: RichTextOrEmpty
204
207
  column: RelationshipsBrowserTypes.Column
205
208
  ports: RelationshipsBrowserTypes.Ports
206
209
  existsInCurrentView: boolean
207
210
  }
208
- export type Edge = DiagramEdge & {
211
+ export type Edge = Omit<DiagramEdge, 'description'> & {
209
212
  sourceFqn: Fqn
210
213
  targetFqn: Fqn
211
214
  sourceHandle: string
@@ -464,7 +467,7 @@ export function layoutRelationshipsView(
464
467
  y: position.y,
465
468
  position: [position.x, position.y],
466
469
  title: 'empty node',
467
- description: null,
470
+ description: RichText.EMPTY,
468
471
  technology: null,
469
472
  tags: [],
470
473
  links: [],
@@ -515,7 +518,7 @@ export function layoutRelationshipsView(
515
518
  y: position.y,
516
519
  position: [position.x, position.y],
517
520
  title: element.title,
518
- description: element.description,
521
+ description: RichText.from(element.description),
519
522
  technology: element.technology,
520
523
  tags: [...element.tags],
521
524
  links: null,
@@ -279,7 +279,7 @@ function ElementTreeNode(
279
279
  </Tooltip>
280
280
  </Group>
281
281
  <Highlight component="div" highlight={searchTerms} className={btn.description!} lineClamp={1}>
282
- {element.description || 'No description'}
282
+ {element.description.text || 'No description'}
283
283
  </Highlight>
284
284
  </Box>
285
285
 
@@ -155,11 +155,11 @@ export function ViewButton(
155
155
  {isCurrentView && <Badge size="xs" fz={9} radius={'sm'}>current</Badge>}
156
156
  </Group>
157
157
  <Highlight
158
- highlight={view.$view.description ? search : ''}
158
+ highlight={view.description.nonEmpty ? search : ''}
159
159
  component="div"
160
160
  className={btn.description!}
161
161
  lineClamp={1}>
162
- {view.$view.description || 'No description'}
162
+ {view.description.text || 'No description'}
163
163
  </Highlight>
164
164
  </Box>
165
165
  </UnstyledButton>
@@ -1,5 +1,4 @@
1
1
  import type { DiagramView, WhereOperator } from '@likec4/core/types'
2
- import { useLogger } from '@mantine/hooks'
3
2
  import { useActorRef, useSelector } from '@xstate/react'
4
3
  import { useStoreApi } from '@xyflow/react'
5
4
  import { shallowEqual } from 'fast-equals'
@@ -14,7 +13,16 @@ import { type DiagramMachine, diagramMachine } from './diagram-machine'
14
13
  import { syncManualLayoutActorLogic } from './syncManualLayoutActor'
15
14
  import type { DiagramActorSnapshot } from './types'
16
15
 
17
- const selectToggledFeatures = (state: DiagramActorSnapshot) => state.context.toggledFeatures
16
+ const selectToggledFeatures = (state: DiagramActorSnapshot) => {
17
+ if (state.context.features.enableReadOnly) {
18
+ return {
19
+ ...state.context.toggledFeatures,
20
+ enableReadOnly: true,
21
+ }
22
+ }
23
+ return state.context.toggledFeatures
24
+ }
25
+
18
26
  export function DiagramActorProvider({
19
27
  view,
20
28
  zoomable,
@@ -499,7 +499,7 @@ const _diagramMachine = setup({
499
499
  if (n.data.tags?.includes(event.tag)) {
500
500
  return Base.setDimmed(n, false)
501
501
  }
502
- return Base.setDimmed(n, 'immediate')
502
+ return Base.setDimmed(n, true)
503
503
  }),
504
504
  }
505
505
  }),