@likec4/diagram 1.32.2 → 1.34.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 (166) hide show
  1. package/README.md +25 -0
  2. package/bundle/{chunk-DlHyKoeo.js → chunk-Dd7et66b.js} +533 -487
  3. package/bundle/custom.js +53 -50
  4. package/bundle/index.js +471 -311
  5. package/dist/LikeC4Diagram.props.d.ts +1 -1
  6. package/dist/StaticLikeC4Diagram.d.ts +1 -1
  7. package/dist/base/primitives/MarkdownBlock.d.ts +27 -0
  8. package/dist/base/primitives/MarkdownBlock.js +42 -0
  9. package/dist/base/primitives/compound/CompoundActionButton.js +1 -1
  10. package/dist/base/primitives/compound/CompoundDetailsButton.js +1 -1
  11. package/dist/base/primitives/edge/EdgeActionButton.js +1 -1
  12. package/dist/base/primitives/element/ElementDetailsButton.js +1 -1
  13. package/dist/base/primitives/element/ElementTags.d.ts +1 -1
  14. package/dist/base/primitives/element/ElementTags.js +116 -125
  15. package/dist/base/primitives/element/ElementTitle.css.js +6 -1
  16. package/dist/base/primitives/element/ElementTitle.d.ts +3 -2
  17. package/dist/base/primitives/element/ElementTitle.js +9 -6
  18. package/dist/base/primitives/index.d.ts +1 -0
  19. package/dist/bundle/LikeC4View.d.ts +1 -1
  20. package/dist/bundle/LikeC4View.js +1 -1
  21. package/dist/bundle/LikeC4View.props.d.ts +1 -1
  22. package/dist/bundle/ReactLikeC4.d.ts +1 -1
  23. package/dist/bundle/custom.js +31 -0
  24. package/dist/bundle/index.js +1 -0
  25. package/dist/components/ErrorFallback.js +1 -1
  26. package/dist/components/Link.js +2 -1
  27. package/dist/components/SearchControl.js +1 -1
  28. package/dist/context/DiagramFeatures.d.ts +3 -2
  29. package/dist/context/DiagramFeatures.js +16 -1
  30. package/dist/context/IconRenderer.js +6 -1
  31. package/dist/context/TagStylesContext.js +1 -1
  32. package/dist/custom/components.d.ts +2 -2
  33. package/dist/custom/customNodes.js +18 -0
  34. package/dist/custom/hooks.d.ts +3 -3
  35. package/dist/custom/index.js +31 -0
  36. package/dist/hooks/safeContext.js +1 -1
  37. package/dist/hooks/useXYFlow.d.ts +2 -1
  38. package/dist/index.d.ts +4 -6
  39. package/dist/index.js +1 -0
  40. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +5 -2
  41. package/dist/likec4diagram/custom/nodes/ElementActions.js +2 -1
  42. package/dist/likec4diagram/custom/nodes/nodes.js +3 -3
  43. package/dist/likec4diagram/custom/nodes/toolbar/ElementToolbar.js +2 -1
  44. package/dist/likec4diagram/custom/nodes/toolbar/_shared.js +2 -1
  45. package/dist/likec4diagram/types.d.ts +3 -2
  46. package/dist/likec4diagram/ui/controls/ChangeAutoLayoutButton.js +1 -1
  47. package/dist/likec4diagram/ui/controls/Controls.js +3 -1
  48. package/dist/likec4diagram/ui/controls/LayoutDriftNotification.js +1 -1
  49. package/dist/likec4diagram/ui/controls/ManualLayoutToolsButton.js +9 -1
  50. package/dist/likec4diagram/ui/controls/NavigationButtons.js +2 -1
  51. package/dist/likec4diagram/ui/controls/ToggleReadonly.js +2 -1
  52. package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +19 -15
  53. package/dist/likec4diagram/ui/notation/NotationPanel.js +3 -1
  54. package/dist/likec4diagram/ui/walkthrough/DynamicViewWalkthrough.js +4 -1
  55. package/dist/likec4diagram/useViewToNodesEdges.js +2 -2
  56. 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
  57. 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
  58. 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
  59. 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
  60. 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
  61. 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
  62. 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
  63. 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
  64. 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
  65. 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
  66. 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
  67. 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
  68. 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
  69. 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
  70. 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
  71. 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
  72. 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
  73. 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
  74. 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
  75. 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
  76. 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
  77. 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
  78. 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
  79. 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
  80. 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
  81. 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
  82. 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
  83. 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
  84. 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
  85. 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
  86. 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
  87. 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
  88. 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
  89. 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
  90. 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
  91. 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
  92. 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
  93. 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
  94. 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
  95. 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
  96. 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
  97. 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
  98. 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
  99. 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
  100. 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
  101. 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
  102. package/dist/overlays/element-details/ElementDetailsCard.css.js +4 -2
  103. package/dist/overlays/element-details/ElementDetailsCard.js +127 -12
  104. package/dist/overlays/element-details/TabPanelDeployments.js +3 -1
  105. package/dist/overlays/element-details/TabPanelRelationships.js +3 -1
  106. package/dist/overlays/element-details/TabPanelStructure.js +1 -1
  107. package/dist/overlays/relationship-details/RelationshipDetails.d.ts +2 -2
  108. package/dist/overlays/relationship-details/RelationshipDetails.js +3 -1
  109. package/dist/overlays/relationship-details/SelectEdge.js +2 -1
  110. package/dist/overlays/relationship-details/_types.d.ts +4 -3
  111. package/dist/overlays/relationship-details/actor.d.ts +2 -2
  112. package/dist/overlays/relationship-details/custom/ElementActions.js +3 -1
  113. package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +2 -2
  114. package/dist/overlays/relationship-details/hooks.d.ts +10 -10
  115. package/dist/overlays/relationship-details/layout-to-xyflow.js +4 -4
  116. package/dist/overlays/relationship-details/layout.d.ts +5 -3
  117. package/dist/overlays/relationship-details/layout.js +2 -2
  118. package/dist/overlays/relationships-browser/RelationshipsBrowser.js +3 -1
  119. package/dist/overlays/relationships-browser/SelectElement.js +2 -1
  120. package/dist/overlays/relationships-browser/_types.d.ts +3 -2
  121. package/dist/overlays/relationships-browser/custom/ElementActions.js +3 -1
  122. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +3 -3
  123. package/dist/overlays/relationships-browser/layout.d.ts +4 -3
  124. package/dist/overlays/relationships-browser/layout.js +3 -3
  125. package/dist/search/components/ElementsColumn.js +2 -2
  126. package/dist/search/components/PickView.js +1 -1
  127. package/dist/search/components/SearchByTags.js +1 -1
  128. package/dist/search/components/SearchInput.js +1 -1
  129. package/dist/search/components/ViewsColum.js +4 -3
  130. package/dist/state/DiagramActorProvider.js +9 -1
  131. package/dist/state/diagram-machine.js +1 -1
  132. package/dist/styles-min.css +1 -1
  133. package/dist/styles.css +1 -1
  134. package/dist/styles.css2.js +1 -1
  135. package/package.json +25 -19
  136. package/panda.buildinfo.json +881 -862
  137. package/src/LikeC4Diagram.props.ts +1 -1
  138. package/src/StaticLikeC4Diagram.tsx +1 -1
  139. package/src/base/primitives/MarkdownBlock.tsx +66 -0
  140. package/src/base/primitives/element/ElementTags.tsx +118 -116
  141. package/src/base/primitives/element/ElementTitle.css.ts +7 -1
  142. package/src/base/primitives/element/ElementTitle.tsx +14 -9
  143. package/src/base/primitives/index.ts +1 -0
  144. package/src/bundle/LikeC4View.props.ts +1 -1
  145. package/src/bundle/LikeC4View.tsx +1 -1
  146. package/src/bundle/ReactLikeC4.tsx +1 -1
  147. package/src/context/DiagramFeatures.tsx +7 -7
  148. package/src/custom/components.ts +2 -0
  149. package/src/custom/hooks.ts +5 -0
  150. package/src/hooks/useXYFlow.ts +9 -1
  151. package/src/index.ts +18 -6
  152. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +1 -1
  153. package/src/likec4diagram/types.ts +2 -2
  154. package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +21 -16
  155. package/src/likec4diagram/useViewToNodesEdges.ts +2 -1
  156. package/src/overlays/element-details/ElementDetailsCard.css.ts +3 -1
  157. package/src/overlays/element-details/ElementDetailsCard.tsx +101 -17
  158. package/src/overlays/relationship-details/_types.ts +12 -3
  159. package/src/overlays/relationship-details/layout-to-xyflow.ts +3 -2
  160. package/src/overlays/relationship-details/layout.ts +7 -4
  161. package/src/overlays/relationships-browser/_types.ts +2 -1
  162. package/src/overlays/relationships-browser/layout.ts +7 -4
  163. package/src/search/components/ElementsColumn.tsx +1 -1
  164. package/src/search/components/ViewsColum.tsx +2 -2
  165. package/src/state/DiagramActorProvider.tsx +10 -2
  166. package/src/state/diagram-machine.ts +1 -1
@@ -6,7 +6,7 @@ import type {
6
6
  ViewChange,
7
7
  WhereOperator,
8
8
  } from '@likec4/core/types'
9
- import type * as aux from '@likec4/core/types/aux'
9
+ import type * as aux from '@likec4/core/types/_aux'
10
10
  import type { ReactFlowProps as XYFlowProps } from '@xyflow/react'
11
11
  import type { MouseEvent as ReactMouseEvent, ReactNode } from 'react'
12
12
  import type { SetRequired } from 'type-fest'
@@ -1,4 +1,4 @@
1
- import type * as aux from '@likec4/core/types/aux'
1
+ import type * as aux from '@likec4/core/types/_aux'
2
2
  import { LikeC4Diagram } from './LikeC4Diagram'
3
3
  import type { LikeC4DiagramProperties } from './LikeC4Diagram.props'
4
4
 
@@ -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'
@@ -1,5 +1,5 @@
1
1
  import type { WhereOperator } from '@likec4/core/types'
2
- import type * as aux from '@likec4/core/types/aux'
2
+ import type * as aux from '@likec4/core/types/_aux'
3
3
  import type { CSSProperties } from 'react'
4
4
  import type { CustomNodes, ElementIconRenderer, OverrideReactFlowProps, PaddingWithUnit } from '../LikeC4Diagram.props'
5
5
 
@@ -1,5 +1,5 @@
1
1
  import type { Any, DiagramView } from '@likec4/core/types'
2
- import type * as aux from '@likec4/core/types/aux'
2
+ import type * as aux from '@likec4/core/types/_aux'
3
3
  import { cx } from '@likec4/styles/css'
4
4
  import { ActionIcon, Box } from '@mantine/core'
5
5
  import { shallowEqual } from '@mantine/hooks'
@@ -1,5 +1,5 @@
1
1
  import type { Any, DiagramView } from '@likec4/core/types'
2
- import type * as aux from '@likec4/core/types/aux'
2
+ import type * as aux from '@likec4/core/types/_aux'
3
3
  import { cx } from '@likec4/styles/css'
4
4
  import { type CSSProperties } from 'react'
5
5
  import { isFunction, isString } from 'remeda'
@@ -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 {
@@ -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
  */