@likec4/diagram 1.32.2 → 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 (155) hide show
  1. package/bundle/{chunk-DlHyKoeo.js → chunk-DyFK-AJ5.js} +516 -488
  2. package/bundle/custom.js +53 -50
  3. package/bundle/index.js +317 -154
  4. package/dist/base/primitives/MarkdownBlock.d.ts +27 -0
  5. package/dist/base/primitives/MarkdownBlock.js +42 -0
  6. package/dist/base/primitives/compound/CompoundActionButton.js +1 -1
  7. package/dist/base/primitives/compound/CompoundDetailsButton.js +1 -1
  8. package/dist/base/primitives/edge/EdgeActionButton.js +1 -1
  9. package/dist/base/primitives/element/ElementDetailsButton.js +1 -1
  10. package/dist/base/primitives/element/ElementTags.d.ts +1 -1
  11. package/dist/base/primitives/element/ElementTags.js +116 -125
  12. package/dist/base/primitives/element/ElementTitle.css.js +6 -1
  13. package/dist/base/primitives/element/ElementTitle.d.ts +3 -2
  14. package/dist/base/primitives/element/ElementTitle.js +9 -6
  15. package/dist/base/primitives/index.d.ts +1 -0
  16. package/dist/bundle/LikeC4View.js +1 -1
  17. package/dist/bundle/custom.js +31 -0
  18. package/dist/bundle/index.js +1 -0
  19. package/dist/components/ErrorFallback.js +1 -1
  20. package/dist/components/Link.js +2 -1
  21. package/dist/components/SearchControl.js +1 -1
  22. package/dist/context/DiagramFeatures.d.ts +3 -2
  23. package/dist/context/DiagramFeatures.js +16 -1
  24. package/dist/context/IconRenderer.js +6 -1
  25. package/dist/context/TagStylesContext.js +1 -1
  26. package/dist/custom/components.d.ts +2 -2
  27. package/dist/custom/customNodes.js +18 -0
  28. package/dist/custom/hooks.d.ts +3 -3
  29. package/dist/custom/index.js +31 -0
  30. package/dist/hooks/safeContext.js +1 -1
  31. package/dist/hooks/useXYFlow.d.ts +2 -1
  32. package/dist/index.d.ts +4 -6
  33. package/dist/index.js +1 -0
  34. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +5 -2
  35. package/dist/likec4diagram/custom/nodes/ElementActions.js +2 -1
  36. package/dist/likec4diagram/custom/nodes/nodes.js +3 -3
  37. package/dist/likec4diagram/custom/nodes/toolbar/ElementToolbar.js +2 -1
  38. package/dist/likec4diagram/custom/nodes/toolbar/_shared.js +2 -1
  39. package/dist/likec4diagram/types.d.ts +3 -2
  40. package/dist/likec4diagram/ui/controls/ChangeAutoLayoutButton.js +1 -1
  41. package/dist/likec4diagram/ui/controls/Controls.js +3 -1
  42. package/dist/likec4diagram/ui/controls/LayoutDriftNotification.js +1 -1
  43. package/dist/likec4diagram/ui/controls/ManualLayoutToolsButton.js +9 -1
  44. package/dist/likec4diagram/ui/controls/NavigationButtons.js +2 -1
  45. package/dist/likec4diagram/ui/controls/ToggleReadonly.js +2 -1
  46. package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +19 -15
  47. package/dist/likec4diagram/ui/notation/NotationPanel.js +3 -1
  48. package/dist/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.js +4 -1
  49. package/dist/likec4diagram/useViewToNodesEdges.js +2 -2
  50. 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
  51. 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
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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
  57. 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
  58. 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
  59. 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
  60. 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
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. 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
  92. 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
  93. 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
  94. 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
  95. 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
  96. package/dist/overlays/element-details/ElementDetailsCard.css.js +4 -2
  97. package/dist/overlays/element-details/ElementDetailsCard.js +127 -12
  98. package/dist/overlays/element-details/TabPanelDeployments.js +3 -1
  99. package/dist/overlays/element-details/TabPanelRelationships.js +3 -1
  100. package/dist/overlays/element-details/TabPanelStructure.js +1 -1
  101. package/dist/overlays/relationship-details/RelationshipDetails.d.ts +2 -2
  102. package/dist/overlays/relationship-details/RelationshipDetails.js +3 -1
  103. package/dist/overlays/relationship-details/SelectEdge.js +2 -1
  104. package/dist/overlays/relationship-details/_types.d.ts +4 -3
  105. package/dist/overlays/relationship-details/actor.d.ts +2 -2
  106. package/dist/overlays/relationship-details/custom/ElementActions.js +3 -1
  107. package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +2 -2
  108. package/dist/overlays/relationship-details/hooks.d.ts +10 -10
  109. package/dist/overlays/relationship-details/layout-to-xyflow.js +4 -4
  110. package/dist/overlays/relationship-details/layout.d.ts +5 -3
  111. package/dist/overlays/relationship-details/layout.js +2 -2
  112. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +3 -1
  113. package/dist/overlays/relationships-browser/SelectElement.js +2 -1
  114. package/dist/overlays/relationships-browser/_types.d.ts +3 -2
  115. package/dist/overlays/relationships-browser/custom/ElementActions.js +3 -1
  116. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +2 -2
  117. package/dist/overlays/relationships-browser/layout.d.ts +4 -3
  118. package/dist/overlays/relationships-browser/layout.js +3 -3
  119. package/dist/search/components/ElementsColumn.js +2 -2
  120. package/dist/search/components/PickView.js +1 -1
  121. package/dist/search/components/SearchByTags.js +1 -1
  122. package/dist/search/components/SearchInput.js +1 -1
  123. package/dist/search/components/ViewsColum.js +4 -3
  124. package/dist/state/DiagramActorProvider.js +9 -1
  125. package/dist/state/diagram-machine.js +1 -1
  126. package/dist/styles-min.css +1 -1
  127. package/dist/styles.css +1 -1
  128. package/dist/styles.css2.js +1 -1
  129. package/package.json +20 -14
  130. package/panda.buildinfo.json +25 -6
  131. package/src/base/primitives/MarkdownBlock.tsx +66 -0
  132. package/src/base/primitives/element/ElementTags.tsx +118 -116
  133. package/src/base/primitives/element/ElementTitle.css.ts +7 -1
  134. package/src/base/primitives/element/ElementTitle.tsx +14 -9
  135. package/src/base/primitives/index.ts +1 -0
  136. package/src/context/DiagramFeatures.tsx +7 -7
  137. package/src/custom/components.ts +2 -0
  138. package/src/custom/hooks.ts +5 -0
  139. package/src/hooks/useXYFlow.ts +9 -1
  140. package/src/index.ts +18 -6
  141. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +1 -1
  142. package/src/likec4diagram/types.ts +2 -2
  143. package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +21 -16
  144. package/src/likec4diagram/useViewToNodesEdges.ts +2 -1
  145. package/src/overlays/element-details/ElementDetailsCard.css.ts +3 -1
  146. package/src/overlays/element-details/ElementDetailsCard.tsx +101 -17
  147. package/src/overlays/relationship-details/_types.ts +12 -3
  148. package/src/overlays/relationship-details/layout-to-xyflow.ts +3 -2
  149. package/src/overlays/relationship-details/layout.ts +7 -4
  150. package/src/overlays/relationships-browser/_types.ts +2 -1
  151. package/src/overlays/relationships-browser/layout.ts +7 -4
  152. package/src/search/components/ElementsColumn.tsx +1 -1
  153. package/src/search/components/ViewsColum.tsx +2 -2
  154. package/src/state/DiagramActorProvider.tsx +10 -2
  155. package/src/state/diagram-machine.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@likec4/diagram",
3
- "version": "1.32.2",
3
+ "version": "1.33.0",
4
4
  "license": "MIT",
5
5
  "bugs": "https://github.com/likec4/likec4/issues",
6
6
  "homepage": "https://likec4.dev",
@@ -67,11 +67,10 @@
67
67
  },
68
68
  "dependencies": {
69
69
  "@dagrejs/dagre": "1.1.4",
70
- "@mantine/core": "8.1.0",
71
- "@mantine/hooks": "8.1.0",
70
+ "@mantine/core": "8.1.1",
71
+ "@mantine/hooks": "8.1.1",
72
72
  "@nanostores/react": "1.0.0",
73
73
  "@react-hookz/web": "^25.1.1",
74
- "@tabler/icons-react": "3.31.0",
75
74
  "@xstate/react": "^5.0.4",
76
75
  "@xyflow/react": "^12.6.4",
77
76
  "@xyflow/system": "^0.0.61",
@@ -82,25 +81,31 @@
82
81
  "nanostores": "1.0.1",
83
82
  "react-error-boundary": "^6.0.0",
84
83
  "react-shadow": "^20.6.0",
85
- "remeda": "^2.23.0",
84
+ "remeda": "^2.23.1",
86
85
  "type-fest": "^4.41.0",
87
86
  "xstate": "^5.19.3",
88
- "@likec4/core": "1.32.2",
89
- "@likec4/style-preset": "1.32.2",
90
- "@likec4/styles": "1.32.2"
87
+ "@likec4/core": "1.33.0",
88
+ "@likec4/styles": "1.33.0"
91
89
  },
92
90
  "peerDependencies": {
91
+ "@pandacss/dev": "^0.53.7",
93
92
  "react": "^18.x || ^19.x",
94
93
  "react-dom": "^18.x || ^19.x"
95
94
  },
95
+ "peerDependenciesMeta": {
96
+ "@pandacss/dev": {
97
+ "optional": true
98
+ }
99
+ },
96
100
  "devDependencies": {
101
+ "@tabler/icons-react": "3.31.0",
97
102
  "@pandacss/dev": "^0.53.7",
98
103
  "@statelyai/inspect": "^0.4.0",
99
104
  "@types/bezier-js": "^4.1.3",
100
105
  "@types/d3-shape": "^3.1.7",
101
- "@types/react": "19.1.5",
102
- "@types/react-dom": "19.1.5",
103
- "@types/node": "~20.19.0",
106
+ "@types/react": "19.1.8",
107
+ "@types/react-dom": "19.1.6",
108
+ "@types/node": "~20.19.1",
104
109
  "@vitejs/plugin-react": "^4.5.2",
105
110
  "postcss": "8.5.5",
106
111
  "react": "^19.1.0",
@@ -108,9 +113,9 @@
108
113
  "typescript": "5.8.3",
109
114
  "vite": "^6.3.5",
110
115
  "vite-plugin-dts": "^4.5.4",
111
- "vitest": "3.2.3",
116
+ "vitest": "3.2.4",
112
117
  "wireit": "0.14.12",
113
- "@likec4/tsconfig": "1.32.2"
118
+ "@likec4/tsconfig": "1.33.0"
114
119
  },
115
120
  "scripts": {
116
121
  "typecheck": "tsc --build --verbose",
@@ -119,6 +124,7 @@
119
124
  "build": "echo \"use pnpm turbo run build\" || true",
120
125
  "pack": "pnpm pack",
121
126
  "test": "vitest run --no-isolate",
122
- "clean": "pnpm rimraf dist lib bundle"
127
+ "clean": "pnpm rimraf dist lib bundle *.tgz",
128
+ "lint:package": "pnpx publint ./package.tgz"
123
129
  }
124
130
  }
@@ -260,8 +260,6 @@
260
260
  "filter]___[value:none]___[cond:_smallZoom",
261
261
  "transition]___[value:none]___[cond:_whenPanning",
262
262
  "filter]___[value:none]___[cond:_whenPanning",
263
- "position]___[value:bottom-start",
264
- "mainAxis]___[value:8",
265
263
  "alignItems]___[value:flex-end",
266
264
  "gap]___[value:4",
267
265
  "justifyItems]___[value:stretch",
@@ -277,17 +275,19 @@
277
275
  "height]___[value:12]___[cond:_whenHovered",
278
276
  "borderRadius]___[value:4]___[cond:_whenHovered",
279
277
  "transitionDelay]___[value:.08s]___[cond:_whenHovered",
280
- "border]___[value:none",
281
278
  "userSelect]___[value:none",
282
279
  "fontSize]___[value:lg",
283
280
  "borderRadius]___[value:4",
284
281
  "paddingInline]___[value:6",
285
282
  "flexWrap]___[value:wrap",
286
283
  "paddingBottom]___[value:sm",
284
+ "translate]___[value:auto",
285
+ "translateX]___[value:-8",
287
286
  "gap]___[value:sm",
288
287
  "textStyle]___[value:likec4.node.primary",
289
288
  "color]___[value:likec4.palette.hiContrast",
290
- "flex]___[value:0 1 auto",
289
+ "flexGrow]___[value:0",
290
+ "flexShrink]___[value:1",
291
291
  "textStyle]___[value:likec4.node.secondary",
292
292
  "textOverflow]___[value:ellipsis",
293
293
  "overflow]___[value:hidden",
@@ -303,6 +303,7 @@
303
303
  "alignSelf]___[value:flex-start",
304
304
  "height]___[value:fit-content",
305
305
  "width]___[value:fit-content",
306
+ "maxHeight]___[value:100%",
306
307
  "margin]___[value:0 auto",
307
308
  "paddingTop]___[value:var(--likec4-spacing)",
308
309
  "paddingBottom]___[value:var(--likec4-spacing)",
@@ -325,6 +326,7 @@
325
326
  "--icon-size]___[value:90px]___[cond:_shapeSizeXl",
326
327
  "gap]___[value:16px]___[cond:_shapeSizeXl",
327
328
  "gap]___[value:16px",
329
+ "flex]___[value:0 1 auto",
328
330
  "alignItems]___[value:stretch",
329
331
  "flexWrap]___[value:nowrap",
330
332
  "gap]___[value:8px",
@@ -332,6 +334,7 @@
332
334
  "alignItems]___[value:flex-start",
333
335
  "lineClamp]___[value:2",
334
336
  "lineClamp]___[value:3",
337
+ "maxHeight]___[value:8rem",
335
338
  "top]___[value:1rem",
336
339
  "right]___[value:1rem",
337
340
  "color]___[value:gray",
@@ -416,6 +419,7 @@
416
419
  "color]___[value:likec4.palette.loContrast]___[cond:_dark",
417
420
  "fontSize]___[value:xs",
418
421
  "opacity]___[value:0.65",
422
+ "position]___[value:bottom-start",
419
423
  "top]___[value:5",
420
424
  "right]___[value:6",
421
425
  "gap]___[value:10px",
@@ -522,7 +526,7 @@
522
526
  "paddingBlock]___[value:2",
523
527
  "opacity]___[value:0.7",
524
528
  "marginBottom]___[value:sm",
525
- "maxHeight]___[value:42",
529
+ "maxHeight]___[value:60",
526
530
  "display]___[value:inline-block",
527
531
  "right]___[value:0",
528
532
  "--ai-radius]___[value:0px",
@@ -589,6 +593,7 @@
589
593
  "gap]___[value:lg",
590
594
  "backgroundColor]___[value:mantine.colors.body",
591
595
  "backgroundColor]___[value:mantine.colors.dark[6]]___[cond:_dark",
596
+ "border]___[value:none",
592
597
  "backgroundImage]___[value: linear-gradient(180deg, color-mix(in srgb, {colors.likec4.palette.fill} 60%, transparent), color-mix(in srgb, {colors.likec4.palette.fill} 20%, transparent) 8px, color-mix(in srgb, {colors.likec4.palette.fill} 14%, transparent) 20px, transparent 80px ), linear-gradient(180deg, {colors.likec4.palette.fill}, {colors.likec4.palette.fill} 4px, transparent 4px) ",
593
598
  "cursor]___[value:move",
594
599
  "fontFamily]___[value:likec4.element",
@@ -645,9 +650,10 @@
645
650
  "display]___[value:grid",
646
651
  "gridTemplateColumns]___[value:min-content 1fr",
647
652
  "gridAutoRows]___[value:min-content max-content",
648
- "gap]___[value:[20px 16px]",
653
+ "gap]___[value:[24px 20px]",
649
654
  "alignItems]___[value:baseline",
650
655
  "justifySelf]___[value:end",
656
+ "textAlign]___[value:right",
651
657
  "width]___[value:14px",
652
658
  "height]___[value:14px",
653
659
  "border]___[value:3.5px solid",
@@ -660,10 +666,18 @@
660
666
  "cursor]___[value:se-resize",
661
667
  "borderWidth]___[value:4px]___[cond:_hover",
662
668
  "borderColor]___[value:mantine.colors.dark[1]]___[cond:_hover",
669
+ "gap]___[value:[4px 4px]",
670
+ "paddingRight]___[value:2xs",
671
+ "color]___[value:mantine.colors.gray[8]",
672
+ "color]___[value:mantine.colors.defaultColor]___[cond:_groupHover",
673
+ "background]___[value:mantine.colors.defaultHover]___[cond:_groupHover",
674
+ "whiteSpace]___[value:pre",
675
+ "fontFamily]___[value:[var(--mantine-font-family-monospace)]",
663
676
  "lineClamp]___[value:1",
664
677
  "marginTop]___[value:6",
665
678
  "stroke]___[value:1.6",
666
679
  "paddingTop]___[value:xs",
680
+ "overscrollBehavior]___[value:none",
667
681
  "marginBottom]___[value:sm]___[cond:&[data-level='1']",
668
682
  "marginTop]___[value:0",
669
683
  "marginBottom]___[value:0",
@@ -974,6 +988,11 @@
974
988
  "likec4RelationPalette]___[value:sky"
975
989
  ],
976
990
  "recipes": {
991
+ "markdownBlock": [
992
+ "uselikec4palette]___[value:false]___[recipe:markdownBlock",
993
+ "uselikec4palette]___[value:true]___[recipe:markdownBlock",
994
+ "uselikec4palette]___[value:true]___[cond:_hover]___[recipe:markdownBlock"
995
+ ],
977
996
  "actionBtn": [
978
997
  "size]___[value:md]___[recipe:actionBtn",
979
998
  "radius]___[value:md]___[recipe:actionBtn",
@@ -0,0 +1,66 @@
1
+ import { type RichTextOrEmpty as RichTextType } from '@likec4/core/types'
2
+ import { cx } from '@likec4/styles/css'
3
+ import { type BoxProps, Box } from '@likec4/styles/jsx'
4
+ import { type MarkdownBlockVariant, markdownBlock } from '@likec4/styles/recipes'
5
+ import { Text } from '@mantine/core'
6
+ import { forwardRef } from 'react'
7
+
8
+ export type MarkdownBlockProps = Omit<BoxProps, 'dangerouslySetInnerHTML' | 'children'> & {
9
+ value: RichTextType
10
+
11
+ /**
12
+ * When markdown block is used inside a diagram node, this variant should be used to apply the likec4 palette.
13
+ * @default false
14
+ */
15
+ uselikec4palette?: boolean
16
+ /**
17
+ * Scale factor for the font size.
18
+ * @default 1
19
+ */
20
+ textScale?: number
21
+ /**
22
+ * If true, the component will not render anything if the value is empty.
23
+ * @default false
24
+ */
25
+ hideIfEmpty?: boolean
26
+ /**
27
+ * Text to show if the value is empty.
28
+ * @default "no content"
29
+ */
30
+ emptyText?: string
31
+ }
32
+
33
+ export const MarkdownBlock = forwardRef<HTMLDivElement, MarkdownBlockProps>(({
34
+ value,
35
+ textScale = 1,
36
+ uselikec4palette = false,
37
+ hideIfEmpty = false,
38
+ emptyText = 'no content',
39
+ className,
40
+ ...props
41
+ }, ref) => {
42
+ if (value.isEmpty && hideIfEmpty) {
43
+ return null
44
+ }
45
+ const content = value.nonEmpty
46
+ ? { dangerouslySetInnerHTML: { __html: value.html } }
47
+ : { children: <Text component="span" fz={'xs'} c="dimmed">{emptyText}</Text> }
48
+ return (
49
+ <Box
50
+ ref={ref}
51
+ {...props}
52
+ className={cx(
53
+ markdownBlock({
54
+ uselikec4palette,
55
+ }),
56
+ className,
57
+ )}
58
+ style={{
59
+ // @ts-expect-error
60
+ ['--mantine-scale']: textScale,
61
+ }}
62
+ {...content}
63
+ />
64
+ )
65
+ })
66
+ MarkdownBlock.displayName = 'MarkdownBlock'
@@ -3,12 +3,12 @@ import { css, cx } from '@likec4/styles/css'
3
3
  import { type BoxProps, Box, HStack } from '@likec4/styles/jsx'
4
4
  import { hstack } from '@likec4/styles/patterns'
5
5
  import { likec4tag } from '@likec4/styles/recipes'
6
- import { HoverCard } from '@mantine/core'
6
+ import { useDebouncedState, useHover } from '@mantine/hooks'
7
+ import { NodeToolbar, Position } from '@xyflow/react'
7
8
  import { deepEqual } from 'fast-equals'
8
- import { forwardRef, memo, useCallback } from 'react'
9
+ import { forwardRef, memo, useCallback, useEffect } from 'react'
9
10
  import { useTagSpecification } from '../../../context/TagStylesContext'
10
11
  import { useDiagram } from '../../../hooks/useDiagram'
11
- import { useMantinePortalProps } from '../../../hooks/useMantinePortalProps'
12
12
  import { useCurrentZoom } from '../../../hooks/useXYFlow'
13
13
  import { stopPropagation } from '../../../utils/xyflow'
14
14
  import type { NodeProps } from '../../types'
@@ -46,137 +46,139 @@ type Data = {
46
46
  type ElementTagsProps = NodeProps<Data>
47
47
 
48
48
  const propsAreEqual = (prev: ElementTagsProps, next: ElementTagsProps) => {
49
- return prev.data.width === next.data.width && deepEqual(prev.data.tags, next.data.tags)
49
+ return (
50
+ prev.data.width === next.data.width &&
51
+ deepEqual(prev.data.tags, next.data.tags) &&
52
+ (prev.data.hovered ?? false) === (next.data.hovered ?? false)
53
+ )
50
54
  }
51
- export const ElementTags = memo(({ id, data: { tags, width } }: ElementTagsProps) => {
55
+ export const ElementTags = memo(({ id, data: { tags, width, hovered = false } }: ElementTagsProps) => {
56
+ const {
57
+ hovered: isTagsBarHovered,
58
+ ref: tagsBarRef,
59
+ } = useHover()
60
+ const {
61
+ hovered: isTagsToolbarHovered,
62
+ ref: tagsToolbarRef,
63
+ } = useHover()
64
+
65
+ const [isVisible, setVisible] = useDebouncedState(false, hovered ? 120 : 300)
66
+
67
+ useEffect(() => {
68
+ setVisible(visibleNow => {
69
+ if (!visibleNow) {
70
+ return hovered && (isTagsBarHovered || isTagsToolbarHovered)
71
+ }
72
+ return hovered || isTagsBarHovered || isTagsToolbarHovered
73
+ })
74
+ }, [isTagsBarHovered, isTagsToolbarHovered, hovered])
75
+
52
76
  const zoom = useCurrentZoom()
53
77
  const zoomIsLargeEnough = zoom > 1.2
54
- const portalProps = useMantinePortalProps()
78
+
79
+ const diagram = useDiagram()
80
+
81
+ const onHover = (tag: string) => {
82
+ diagram.send({ type: 'tag.highlight', tag })
83
+ }
84
+
85
+ const onLeave = useCallback(() => {
86
+ diagram.send({ type: 'tag.unhighlight' })
87
+ }, [])
88
+
55
89
  if (!tags || tags.length === 0) {
56
90
  return null
57
91
  }
58
92
  const maxWidth = Math.max(Math.round(width * zoom) - 10, 200)
59
93
 
60
94
  return (
61
- <HoverCard
62
- {...portalProps}
63
- floatingStrategy="fixed"
64
- position="bottom-start"
65
- offset={{
66
- alignmentAxis: Math.round(4 * zoom),
67
- mainAxis: 8,
68
- }}
69
- keepMounted={false}
70
- openDelay={300}
71
- closeDelay={500}
72
- >
73
- <HoverCard.Target>
74
- <div
75
- className={cx(
76
- 'likec4-element-tags',
77
- hstack({
78
- pointerEvents: 'all',
79
- gap: 4,
80
- alignItems: 'flex-end',
81
- justifyItems: 'stretch',
82
- position: 'absolute',
83
- width: '100%',
95
+ <>
96
+ <div
97
+ ref={tagsBarRef}
98
+ className={cx(
99
+ 'likec4-element-tags',
100
+ hstack({
101
+ pointerEvents: 'all',
102
+ gap: 4,
103
+ alignItems: 'flex-end',
104
+ justifyItems: 'stretch',
105
+ position: 'absolute',
106
+ width: '100%',
107
+ bottom: 0,
108
+ left: 0,
109
+ padding: 4,
110
+ _shapeCylinder: {
111
+ bottom: 5,
112
+ },
113
+ _shapeStorage: {
114
+ bottom: 5,
115
+ },
116
+ _shapeQueue: {
84
117
  bottom: 0,
85
- left: 0,
86
- padding: 4,
87
- _shapeCylinder: {
88
- bottom: 5,
89
- },
90
- _shapeStorage: {
91
- bottom: 5,
92
- },
93
- _shapeQueue: {
94
- bottom: 0,
95
- paddingLeft: 14,
118
+ paddingLeft: 14,
119
+ },
120
+ }),
121
+ )}
122
+ onClick={stopPropagation}
123
+ >
124
+ {tags.map((tag) => (
125
+ <Box
126
+ key={id + '#' + tag}
127
+ data-likec4-tag={tag}
128
+ className={css({
129
+ layerStyle: 'likec4.tag',
130
+ flex: 1,
131
+ display: 'flex',
132
+ alignItems: 'center',
133
+ justifyContent: 'center',
134
+ maxWidth: 50,
135
+ height: 5,
136
+ _whenHovered: {
137
+ height: 12,
138
+ borderRadius: 4,
139
+ transitionDelay: '.08s',
96
140
  },
97
- }),
98
- )}
99
- onClick={stopPropagation}
141
+ transition: 'fast',
142
+ })}
143
+ />
144
+ ))}
145
+ </div>
146
+ <NodeToolbar isVisible={isVisible} align="start" position={Position.Bottom}>
147
+ <HStack
148
+ ref={tagsToolbarRef}
149
+ css={{
150
+ gap: 4,
151
+ flexWrap: 'wrap',
152
+ pb: 'sm',
153
+ translate: 'auto',
154
+ x: -8,
155
+ maxWidth,
156
+ }}
100
157
  >
101
158
  {tags.map((tag) => (
102
- <Box
103
- key={id + '#' + tag}
104
- data-likec4-tag={tag}
159
+ <ElementTag
160
+ key={tag}
161
+ tag={tag}
105
162
  className={css({
106
- layerStyle: 'likec4.tag',
107
- flex: 1,
108
- display: 'flex',
109
- alignItems: 'center',
110
- justifyContent: 'center',
111
- maxWidth: 50,
112
- height: 5,
113
- _whenHovered: {
114
- height: 12,
163
+ userSelect: 'none',
164
+ cursor: 'pointer',
165
+ ...(zoomIsLargeEnough && {
166
+ fontSize: 'lg',
115
167
  borderRadius: 4,
116
- transitionDelay: '.08s',
117
- },
118
- transition: 'fast',
168
+ px: 6,
169
+ }),
119
170
  })}
171
+ onClick={e => {
172
+ e.stopPropagation()
173
+ diagram.openSearch(`#${tag}`)
174
+ }}
175
+ onMouseEnter={() => onHover(tag)}
176
+ onMouseLeave={onLeave}
120
177
  />
121
178
  ))}
122
- </div>
123
- </HoverCard.Target>
124
- <HoverCard.Dropdown
125
- p={0}
126
- w={'auto'}
127
- maw={maxWidth}
128
- className={css({
129
- background: 'transparent',
130
- border: 'none',
131
- })}
132
- >
133
- <ElementTagsDropdown tags={tags} zoomIsLargeEnough={zoomIsLargeEnough} />
134
- </HoverCard.Dropdown>
135
- </HoverCard>
179
+ </HStack>
180
+ </NodeToolbar>
181
+ </>
136
182
  )
137
183
  }, propsAreEqual)
138
184
  ElementTags.displayName = 'ElementTags'
139
-
140
- function ElementTagsDropdown({ tags, zoomIsLargeEnough }: { tags: readonly string[]; zoomIsLargeEnough: boolean }) {
141
- const diagram = useDiagram()
142
-
143
- const onHover = (tag: string) => {
144
- diagram.send({ type: 'tag.highlight', tag })
145
- }
146
-
147
- const onLeave = useCallback(() => {
148
- diagram.send({ type: 'tag.unhighlight' })
149
- }, [])
150
-
151
- return (
152
- <HStack
153
- css={{
154
- gap: 4,
155
- flexWrap: 'wrap',
156
- pb: 'sm',
157
- }}
158
- >
159
- {tags.map((tag) => (
160
- <ElementTag
161
- key={tag}
162
- tag={tag}
163
- className={css({
164
- userSelect: 'none',
165
- cursor: 'pointer',
166
- ...(zoomIsLargeEnough && {
167
- fontSize: 'lg',
168
- borderRadius: 4,
169
- px: 6,
170
- }),
171
- })}
172
- onClick={e => {
173
- e.stopPropagation()
174
- diagram.openSearch(`#${tag}`)
175
- }}
176
- onMouseEnter={() => onHover(tag)}
177
- onMouseLeave={onLeave}
178
- />
179
- ))}
180
- </HStack>
181
- )
182
- }
@@ -10,7 +10,9 @@ const title = css.raw({
10
10
  })
11
11
 
12
12
  const description = css.raw({
13
- flex: '0 1 auto',
13
+ flexGrow: '0',
14
+ flexShrink: '1',
15
+
14
16
  textStyle: 'likec4.node.secondary',
15
17
  color: 'likec4.palette.loContrast',
16
18
  textAlign: 'center',
@@ -87,6 +89,8 @@ export const elementTitle = sva({
87
89
  flex: '1',
88
90
  height: 'fit-content',
89
91
  width: 'fit-content',
92
+ maxHeight: '100%',
93
+ maxWidth: '100%',
90
94
  margin: '0 auto',
91
95
  display: 'flex',
92
96
  alignItems: 'center',
@@ -139,6 +143,8 @@ export const elementTitle = sva({
139
143
  textContainer: {
140
144
  height: 'fit-content',
141
145
  width: 'fit-content',
146
+ maxHeight: '100%',
147
+ maxWidth: '100%',
142
148
  flex: '0 1 auto',
143
149
  display: 'flex',
144
150
  flexDirection: 'column',
@@ -1,4 +1,4 @@
1
- import type { DiagramNode } from '@likec4/core/types'
1
+ import type { DiagramNode, RichTextOrEmpty } from '@likec4/core/types'
2
2
  import { cx } from '@likec4/styles/css'
3
3
  import { Box } from '@likec4/styles/jsx'
4
4
  import { Text } from '@mantine/core'
@@ -6,6 +6,7 @@ import { isEmpty, isNumber, isTruthy } from 'remeda'
6
6
  import type { Simplify } from 'type-fest'
7
7
  import { IconRenderer } from '../../../context/IconRenderer'
8
8
  import type { NodeProps, NonOptional } from '../../types'
9
+ import { MarkdownBlock } from '../MarkdownBlock'
9
10
  import { nodeSizes } from './ElementNodeContainer'
10
11
  import * as styles from './ElementTitle.css'
11
12
 
@@ -15,12 +16,12 @@ type Data = Simplify<
15
16
  DiagramNode,
16
17
  | 'title'
17
18
  | 'technology'
18
- | 'description'
19
19
  | 'color'
20
20
  | 'style'
21
21
  >
22
22
  >
23
23
  & {
24
+ description?: RichTextOrEmpty
24
25
  icon?: string | null
25
26
  }
26
27
  >
@@ -40,7 +41,7 @@ export function ElementTitle({ id, data, iconSize }: ElementTitleProps) {
40
41
  })
41
42
  const classes = styles.elementTitle({
42
43
  hasIcon: isTruthy(elementIcon),
43
- hasDescription: !isEmpty(data.description ?? ''),
44
+ hasDescription: !!data.description?.nonEmpty,
44
45
  hasTechnology: !isEmpty(data.technology ?? ''),
45
46
  })
46
47
  const size = nodeSizes(data.style).size
@@ -62,7 +63,7 @@ export function ElementTitle({ id, data, iconSize }: ElementTitleProps) {
62
63
  {elementIcon}
63
64
  <Box className={cx(classes.textContainer, 'likec4-element-main-props')}>
64
65
  <Text
65
- component="h3"
66
+ component="div"
66
67
  className={cx(classes.title, 'likec4-element-title')}
67
68
  lineClamp={isSmOrXs ? 2 : 3}>
68
69
  {data.title}
@@ -77,12 +78,16 @@ export function ElementTitle({ id, data, iconSize }: ElementTitleProps) {
77
78
  )}
78
79
 
79
80
  {data.description && (
80
- <Text
81
- component="div"
81
+ <MarkdownBlock
82
82
  className={cx(classes.description, 'likec4-element-description')}
83
- lineClamp={isSmOrXs ? 3 : 5}>
84
- {data.description}
85
- </Text>
83
+ value={data.description}
84
+ uselikec4palette
85
+ hideIfEmpty
86
+ // Workaround for lineClamp not working with nested TABLE elements (if markdown has tables)
87
+ maxHeight={data.description.isMarkdown ? '8rem' : undefined}
88
+ // textScale={0.95}
89
+ lineClamp={isSmOrXs ? 3 : 5}
90
+ />
86
91
  )}
87
92
  </Box>
88
93
  </Box>
@@ -16,4 +16,5 @@ export { ElementNodeContainer } from './element/ElementNodeContainer'
16
16
  export { ElementShape } from './element/ElementShape'
17
17
  export { ElementTag, ElementTags } from './element/ElementTags'
18
18
  export { ElementTitle } from './element/ElementTitle'
19
+ export { MarkdownBlock } from './MarkdownBlock'
19
20
  export { DefaultHandles } from './NodeHandles'
@@ -117,17 +117,17 @@ export function IfEnabled({
117
117
  return enabled && and ? <>{children}</> : null
118
118
  }
119
119
 
120
- export function IfNotEnabled({
121
- feature,
122
- children,
123
- }: PropsWithChildren<{ feature: FeatureName }>) {
120
+ export function IfNotEnabled({ feature, children }: PropsWithChildren<{ feature: FeatureName }>) {
124
121
  const notEnabled = useEnabledFeatures()[`enable${feature}`] !== true
125
122
  return notEnabled ? <>{children}</> : null
126
123
  }
127
124
 
128
- export function IfNotReadOnly({
129
- children,
130
- }: PropsWithChildren) {
125
+ export function IfReadOnly({ children }: PropsWithChildren) {
126
+ const isReadOnly = useEnabledFeatures()[`enableReadOnly`] === true
127
+ return isReadOnly ? <>{children}</> : null
128
+ }
129
+
130
+ export function IfNotReadOnly({ children }: PropsWithChildren) {
131
131
  const isReadOnly = useEnabledFeatures()[`enableReadOnly`] === true
132
132
  if (isReadOnly) {
133
133
  return null
@@ -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 {