@likec4/diagram 1.36.1 → 1.38.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 (173) hide show
  1. package/bundle/{chunk-DHvr-RGh.js → chunk-BZV0K82k.js} +870 -900
  2. package/bundle/custom.js +64 -56
  3. package/bundle/index.js +3565 -3327
  4. package/dist/LikeC4Diagram.props.d.ts +5 -5
  5. package/dist/LikeC4Styles.js +17 -15
  6. package/dist/StaticLikeC4Diagram.d.ts +1 -1
  7. package/dist/StaticLikeC4Diagram.js +3 -0
  8. package/dist/base/BaseXYFlow.d.ts +1 -1
  9. package/dist/base/BaseXYFlow.js +25 -27
  10. package/dist/base/const.d.ts +4 -4
  11. package/dist/base/const.js +5 -4
  12. package/dist/base/primitives/MarkdownBlock.js +4 -1
  13. package/dist/base/primitives/compound/CompoundActionButton.js +27 -42
  14. package/dist/base/primitives/compound/CompoundDetailsButton.js +23 -48
  15. package/dist/base/primitives/compound/CompoundNodeContainer.js +16 -48
  16. package/dist/base/primitives/compound/CompoundTitle.js +5 -80
  17. package/dist/base/primitives/compound/actionbtns.css.js +1 -13
  18. package/dist/base/primitives/customEdge.d.ts +1 -1
  19. package/dist/base/primitives/customNode.d.ts +4 -4
  20. package/dist/base/primitives/customNode.js +7 -7
  21. package/dist/base/primitives/edge/EdgeLabel.d.ts +5 -4
  22. package/dist/base/primitives/edge/EdgeLabel.js +39 -21
  23. package/dist/base/primitives/edge/EdgeLabelContainer.js +11 -23
  24. package/dist/base/primitives/edge/edge.css.js +19 -11
  25. package/dist/base/primitives/element/ElementShape.js +38 -18
  26. package/dist/base/primitives/element/ElementTags.js +7 -4
  27. package/dist/base/primitives/element/ElementTitle.js +10 -2
  28. package/dist/base/types.d.ts +17 -21
  29. package/dist/bundle/LikeC4View.d.ts +2 -2
  30. package/dist/bundle/LikeC4View.js +4 -1
  31. package/dist/bundle/LikeC4View.props.d.ts +2 -2
  32. package/dist/bundle/ReactLikeC4.d.ts +3 -3
  33. package/dist/bundle/custom.js +2 -1
  34. package/dist/bundle/index.js +2 -1
  35. package/dist/components/Link.js +3 -2
  36. package/dist/context/ReduceGraphics.js +2 -5
  37. package/dist/context/RootContainer.js +1 -5
  38. package/dist/custom/customNodes.d.ts +32 -26
  39. package/dist/custom/customNodes.js +12 -8
  40. package/dist/custom/hooks.d.ts +2 -1
  41. package/dist/custom/index.js +2 -1
  42. package/dist/globals.css.js +1 -1
  43. package/dist/hooks/index.d.ts +1 -1
  44. package/dist/hooks/useDiagram.d.ts +18 -1
  45. package/dist/hooks/useDiagram.js +18 -2
  46. package/dist/hooks/useXYFlow.d.ts +40 -21
  47. package/dist/index.d.ts +1 -1
  48. package/dist/index.js +2 -1
  49. package/dist/likec4diagram/DiagramUI.js +5 -2
  50. package/dist/likec4diagram/DiagramXYFlow.js +9 -9
  51. package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +3 -3
  52. package/dist/likec4diagram/custom/edges/RelationshipEdge.js +27 -44
  53. package/dist/likec4diagram/custom/index.js +3 -3
  54. package/dist/likec4diagram/custom/nodes/nodes.d.ts +8 -6
  55. package/dist/likec4diagram/custom/nodes/nodes.js +13 -14
  56. package/dist/likec4diagram/custom/nodes/toolbar/CompoundToolbar.js +3 -2
  57. package/dist/likec4diagram/custom/nodes/toolbar/_shared.d.ts +2 -2
  58. package/dist/likec4diagram/relationship-popover/RelationshipPopover.d.ts +2 -0
  59. package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +441 -0
  60. package/dist/likec4diagram/relationship-popover/actor.d.ts +177 -0
  61. package/dist/likec4diagram/relationship-popover/actor.js +155 -0
  62. package/dist/likec4diagram/relationship-popover/styles.css.d.ts +2 -0
  63. package/dist/likec4diagram/{custom/edges/RelationshipsDropdownMenu.css.js → relationship-popover/styles.css.js} +4 -17
  64. package/dist/likec4diagram/useLayoutConstraints.js +0 -1
  65. package/dist/likec4model/useLikeC4ElementsTree.js +1 -1
  66. package/dist/likec4model/useLikeC4Project.js +15 -1
  67. package/dist/navigationpanel/NavigationPanelDropdown.js +1 -2
  68. package/dist/navigationpanel/actor.js +1 -2
  69. package/dist/navigationpanel/controls/NavigationButtons.js +1 -5
  70. package/dist/navigationpanel/controls/ViewDetailsCard.js +2 -0
  71. package/dist/overlays/element-details/actor.d.ts +564 -8
  72. package/dist/overlays/overlay/Overlay.css.d.ts +1 -1
  73. package/dist/overlays/relationship-details/actor.d.ts +3 -1
  74. package/dist/overlays/relationship-details/hooks.d.ts +19 -1
  75. package/dist/overlays/relationship-details/layout-to-xyflow.js +0 -1
  76. package/dist/overlays/relationship-details/layout.js +1 -2
  77. package/dist/overlays/relationships-browser/actor.d.ts +26 -2
  78. package/dist/overlays/relationships-browser/custom/nodeTypes.d.ts +16 -0
  79. package/dist/overlays/relationships-browser/custom/nodeTypes.js +18 -8
  80. package/dist/overlays/relationships-browser/useViewToNodesEdges.js +0 -1
  81. package/dist/search/components/_shared.css.d.ts +1 -1
  82. package/dist/state/DiagramActorProvider.js +2 -19
  83. package/dist/state/assign.js +24 -10
  84. package/dist/state/diagram-machine.d.ts +149 -474
  85. package/dist/state/diagram-machine.js +94 -54
  86. package/dist/state/types.d.ts +1 -1
  87. package/dist/styles-min.css +1 -1
  88. package/dist/styles-xyflow.css +1 -1
  89. package/dist/styles.css +1 -1
  90. package/dist/styles.css2.js +1 -1
  91. package/dist/utils/index.d.ts +2 -1
  92. package/dist/utils/roundDpr.d.ts +1 -0
  93. package/dist/utils/roundDpr.js +20 -0
  94. package/dist/utils/xyflow.d.ts +0 -1
  95. package/dist/utils/xyflow.js +1 -7
  96. package/package.json +16 -15
  97. package/panda.buildinfo.json +91 -156
  98. package/src/LikeC4Diagram.props.ts +5 -5
  99. package/src/LikeC4Styles.tsx +22 -14
  100. package/src/StaticLikeC4Diagram.tsx +3 -0
  101. package/src/base/BaseXYFlow.tsx +26 -29
  102. package/src/base/const.ts +5 -4
  103. package/src/base/primitives/MarkdownBlock.tsx +6 -1
  104. package/src/base/primitives/compound/CompoundActionButton.tsx +31 -43
  105. package/src/base/primitives/compound/CompoundDetailsButton.tsx +26 -48
  106. package/src/base/primitives/compound/CompoundNodeContainer.tsx +15 -43
  107. package/src/base/primitives/compound/CompoundTitle.tsx +4 -76
  108. package/src/base/primitives/compound/actionbtns.css.ts +0 -12
  109. package/src/base/primitives/customEdge.ts +1 -1
  110. package/src/base/primitives/customNode.tsx +20 -24
  111. package/src/base/primitives/edge/EdgeLabel.tsx +23 -8
  112. package/src/base/primitives/edge/EdgeLabelContainer.tsx +9 -21
  113. package/src/base/primitives/edge/edge.css.ts +19 -11
  114. package/src/base/primitives/element/ElementShape.tsx +40 -18
  115. package/src/base/primitives/element/ElementTags.tsx +7 -4
  116. package/src/base/primitives/element/ElementTitle.tsx +23 -11
  117. package/src/base/types.ts +21 -25
  118. package/src/bundle/LikeC4View.props.ts +2 -2
  119. package/src/bundle/LikeC4View.tsx +8 -5
  120. package/src/bundle/ReactLikeC4.tsx +3 -3
  121. package/src/components/Link.tsx +3 -2
  122. package/src/context/RootContainer.tsx +1 -5
  123. package/src/context/TagStylesContext.tsx +2 -0
  124. package/src/custom/{customNodes.tsx → customNodes.ts} +58 -52
  125. package/src/custom/hooks.ts +7 -0
  126. package/src/globals.css +58 -5
  127. package/src/hooks/index.ts +1 -1
  128. package/src/hooks/useDiagram.ts +39 -5
  129. package/src/hooks/useXYFlow.ts +3 -1
  130. package/src/index.ts +1 -0
  131. package/src/likec4diagram/DiagramUI.tsx +3 -0
  132. package/src/likec4diagram/DiagramXYFlow.tsx +9 -11
  133. package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +25 -49
  134. package/src/likec4diagram/custom/index.ts +5 -4
  135. package/src/likec4diagram/custom/nodes/nodes.tsx +13 -11
  136. package/src/likec4diagram/custom/nodes/toolbar/CompoundToolbar.tsx +3 -2
  137. package/src/likec4diagram/relationship-popover/RelationshipPopover.tsx +535 -0
  138. package/src/likec4diagram/relationship-popover/actor.ts +192 -0
  139. package/src/likec4diagram/{custom/edges/RelationshipsDropdownMenu.css.ts → relationship-popover/styles.css.ts} +3 -19
  140. package/src/likec4diagram/useLayoutConstraints.ts +0 -1
  141. package/src/likec4model/useLikeC4ElementsTree.ts +1 -1
  142. package/src/navigationpanel/NavigationPanelDropdown.tsx +1 -2
  143. package/src/navigationpanel/actor.ts +2 -2
  144. package/src/navigationpanel/controls/NavigationButtons.tsx +1 -5
  145. package/src/navigationpanel/controls/ViewDetailsCard.tsx +2 -0
  146. package/src/overlays/relationship-details/layout-to-xyflow.ts +0 -1
  147. package/src/overlays/relationship-details/layout.ts +4 -3
  148. package/src/overlays/relationships-browser/custom/nodeTypes.tsx +22 -8
  149. package/src/overlays/relationships-browser/useViewToNodesEdges.ts +0 -1
  150. package/src/state/DiagramActorProvider.tsx +2 -20
  151. package/src/state/assign.ts +24 -10
  152. package/src/state/diagram-machine.ts +101 -53
  153. package/src/state/types.ts +4 -1
  154. package/src/utils/index.ts +2 -1
  155. package/src/utils/roundDpr.ts +27 -0
  156. package/src/utils/xyflow.ts +0 -7
  157. package/dist/base/primitives/compound/CompoundNodeContainer.css.d.ts +0 -35
  158. package/dist/base/primitives/compound/CompoundNodeContainer.css.js +0 -132
  159. package/dist/base/primitives/edge/EdgeLabel.css.d.ts +0 -7
  160. package/dist/base/primitives/edge/EdgeLabel.css.js +0 -57
  161. package/dist/base/primitives/element/ElementShape.css.d.ts +0 -6
  162. package/dist/base/primitives/element/ElementShape.css.js +0 -107
  163. package/dist/likec4diagram/custom/edges/NotePopover.css.js +0 -21
  164. package/dist/likec4diagram/custom/edges/NotePopover.js +0 -91
  165. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.css.d.ts +0 -5
  166. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.d.ts +0 -13
  167. package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +0 -215
  168. package/dist/likec4diagram/custom/index.d.ts +0 -62
  169. package/dist/overlays/relationship-details/custom/nodeTypes.d.ts +0 -10
  170. package/src/base/primitives/compound/CompoundNodeContainer.css.ts +0 -138
  171. package/src/base/primitives/edge/EdgeLabel.css.ts +0 -64
  172. package/src/base/primitives/element/ElementShape.css.ts +0 -112
  173. package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +0 -281
@@ -1,4 +1,5 @@
1
1
  import type { Any, UnknownLayouted } from '@likec4/core/types'
2
+ import { cx } from '@likec4/styles/css'
2
3
  import { LikeC4Diagram } from './LikeC4Diagram'
3
4
  import type { LikeC4DiagramProperties } from './LikeC4Diagram.props'
4
5
 
@@ -28,12 +29,14 @@ export function StaticLikeC4Diagram<A extends Any = UnknownLayouted>({
28
29
  enableRelationshipDetails = false,
29
30
  enableRelationshipBrowser = enableRelationshipDetails,
30
31
  background = 'transparent',
32
+ className,
31
33
  ...rest
32
34
  }: StaticLikeC4DiagramProps<A>) {
33
35
  return (
34
36
  <LikeC4Diagram
35
37
  view={view}
36
38
  readonly
39
+ className={cx(className, 'likec4-static-view')}
37
40
  fitView={fitView}
38
41
  fitViewPadding={fitViewPadding}
39
42
  pannable={false}
@@ -1,4 +1,4 @@
1
- import { css, cva, cx } from '@likec4/styles/css'
1
+ import { cx } from '@likec4/styles/css'
2
2
  import { useCallbackRef } from '@mantine/hooks'
3
3
  import {
4
4
  type ReactFlowProps,
@@ -11,6 +11,7 @@ import type { SetRequired, Simplify } from 'type-fest'
11
11
  import { useUpdateEffect } from '../hooks/useUpdateEffect'
12
12
  import { useIsZoomTooSmall, useXYStoreApi } from '../hooks/useXYFlow'
13
13
  import type { ViewPadding } from '../LikeC4Diagram.props'
14
+ import { roundDpr } from '../utils/roundDpr'
14
15
  import { stopPropagation } from '../utils/xyflow'
15
16
  import { type XYBackground, Background } from './Background'
16
17
  import { MaxZoom, MinZoom } from './const'
@@ -44,29 +45,6 @@ export type BaseXYFlowProps<NodeType extends Base.Node, EdgeType extends Base.Ed
44
45
  >
45
46
  >
46
47
 
47
- const cssReactFlow = cva({
48
- base: {
49
- '& .react-flow__pane': {
50
- WebkitUserSelect: 'none',
51
- },
52
- '& .react-flow__attribution': {
53
- display: 'none',
54
- },
55
- },
56
- variants: {
57
- transparent: {
58
- true: {
59
- background: 'transparent !important',
60
- ['--xy-background-color']: 'transparent !important',
61
- },
62
- false: {
63
- ['--xy-background-color']: '{colors.likec4.background}',
64
- ['--xy-background-pattern-color']: '{colors.likec4.background.pattern}',
65
- },
66
- },
67
- },
68
- })
69
-
70
48
  export const BaseXYFlow = <
71
49
  NodeType extends Base.Node,
72
50
  EdgeType extends Base.Edge,
@@ -88,6 +66,10 @@ export const BaseXYFlow = <
88
66
  zoomOnDoubleClick = false,
89
67
  onViewportResize,
90
68
  onMoveEnd,
69
+ onNodeMouseEnter,
70
+ onNodeMouseLeave,
71
+ onEdgeMouseEnter,
72
+ onEdgeMouseLeave,
91
73
  ...props
92
74
  }: BaseXYFlowProps<NodeType, EdgeType>) => {
93
75
  const isBgWithPattern = background !== 'transparent' && background !== 'solid'
@@ -100,9 +82,7 @@ export const BaseXYFlow = <
100
82
  nodes={nodes}
101
83
  edges={edges}
102
84
  className={cx(
103
- cssReactFlow({
104
- transparent: background === 'transparent',
105
- }),
85
+ background === 'transparent' && 'bg-transparent',
106
86
  className,
107
87
  )}
108
88
  {...isZoomTooSmall && {
@@ -127,6 +107,7 @@ export const BaseXYFlow = <
127
107
  defaultMarkerColor="var(--xy-edge-stroke)"
128
108
  noDragClassName="nodrag"
129
109
  noPanClassName="nopan"
110
+ noWheelClassName="nowheel"
130
111
  panOnScroll={pannable}
131
112
  panOnDrag={pannable}
132
113
  {...(!pannable && {
@@ -151,14 +132,18 @@ export const BaseXYFlow = <
151
132
  * https://github.com/xyflow/xyflow/issues/3282
152
133
  * https://github.com/likec4/likec4/issues/734
153
134
  */
154
- const roundedX = Math.round(x),
155
- roundedY = Math.round(y)
135
+ const roundedX = roundDpr(x),
136
+ roundedY = roundDpr(y)
156
137
  if (x !== roundedX || y !== roundedY) {
157
138
  xystore.setState({ transform: [roundedX, roundedY, zoom] })
158
139
  }
159
140
  onMoveEnd?.(event, { x: roundedX, y: roundedY, zoom })
160
141
  })}
161
142
  onNodeMouseEnter={useCallbackRef((_event, node) => {
143
+ if (onNodeMouseEnter) {
144
+ onNodeMouseEnter(_event, node)
145
+ return
146
+ }
162
147
  if (!node.data.hovered) {
163
148
  onNodesChange([{
164
149
  id: node.id,
@@ -168,6 +153,10 @@ export const BaseXYFlow = <
168
153
  }
169
154
  })}
170
155
  onNodeMouseLeave={useCallbackRef((_event, node) => {
156
+ if (onNodeMouseLeave) {
157
+ onNodeMouseLeave(_event, node)
158
+ return
159
+ }
171
160
  if (node.data.hovered) {
172
161
  onNodesChange([{
173
162
  id: node.id,
@@ -177,6 +166,10 @@ export const BaseXYFlow = <
177
166
  }
178
167
  })}
179
168
  onEdgeMouseEnter={useCallbackRef((_event, edge) => {
169
+ if (onEdgeMouseEnter) {
170
+ onEdgeMouseEnter(_event, edge)
171
+ return
172
+ }
180
173
  if (!edge.data.hovered) {
181
174
  onEdgesChange([{
182
175
  id: edge.id,
@@ -186,6 +179,10 @@ export const BaseXYFlow = <
186
179
  }
187
180
  })}
188
181
  onEdgeMouseLeave={useCallbackRef((_event, edge) => {
182
+ if (onEdgeMouseLeave) {
183
+ onEdgeMouseLeave(_event, edge)
184
+ return
185
+ }
189
186
  if (edge.data.hovered) {
190
187
  onEdgesChange([{
191
188
  id: edge.id,
package/src/base/const.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  export const ZIndexes = {
2
- Compound: 0,
3
- Edge: 2,
4
- Element: 2,
5
- Max: 8,
2
+ Compound: 1,
3
+ // XYFlow increments zIndexes of compounds
4
+ Edge: 20,
5
+ Element: 20,
6
+ Max: 30,
6
7
  } as const
7
8
 
8
9
  export const MinZoom = 0.05
@@ -51,7 +51,9 @@ export const MarkdownBlock = forwardRef<HTMLDivElement, MarkdownBlockProps>(({
51
51
  return null
52
52
  }
53
53
  const content = value.nonEmpty
54
- ? { dangerouslySetInnerHTML: { __html: value.html } }
54
+ ? value.isMarkdown
55
+ ? { dangerouslySetInnerHTML: { __html: value.html } }
56
+ : { children: <p>{value.text}</p> }
55
57
  : { children: <Text component="span" fz={'xs'} c="dimmed" style={{ userSelect: 'none' }}>{emptyText}</Text> }
56
58
  return (
57
59
  <Box
@@ -64,6 +66,9 @@ export const MarkdownBlock = forwardRef<HTMLDivElement, MarkdownBlockProps>(({
64
66
  className,
65
67
  )}
66
68
  style={{
69
+ ...props.fontSize && {
70
+ '--text-fz': `var(--font-sizes-${props.fontSize}, var(--font-sizes-md))`,
71
+ },
67
72
  // @ts-expect-error
68
73
  ['--mantine-scale']: textScale,
69
74
  }}
@@ -1,5 +1,4 @@
1
- import { css, cx } from '@likec4/styles/css'
2
- import { Box } from '@likec4/styles/jsx'
1
+ import { cx } from '@likec4/styles/css'
3
2
  import { actionBtn } from '@likec4/styles/recipes'
4
3
  import { ActionIcon } from '@mantine/core'
5
4
  import { useDebouncedValue } from '@mantine/hooks'
@@ -28,47 +27,36 @@ export function CompoundActionButton({
28
27
  const debounced = useDebouncedValue(isHovered, isHovered ? 130 : 0)
29
28
  const isHoverDebounced = debounced[0] && isHovered
30
29
  return (
31
- <Box
32
- className={cx(
33
- css({
34
- position: 'absolute',
35
- top: '[5px]',
36
- left: '[4px]',
37
- _smallZoom: {
38
- display: 'none',
39
- },
40
- }),
41
- 'compound-action',
42
- )}>
43
- <m.div
44
- initial={false}
45
- animate={{
46
- scale: isHoverDebounced ? 1.2 : 1,
47
- x: isHoverDebounced ? -1 : 0,
48
- y: isHoverDebounced ? -1 : 0,
49
- }}
50
- whileHover={{
51
- scale: 1.4,
52
- x: -2,
53
- y: -2,
54
- }}
55
- whileTap={{ scale: 1 }}
30
+ <m.div
31
+ initial={false}
32
+ animate={{
33
+ scale: isHoverDebounced ? 1.2 : 1,
34
+ x: isHoverDebounced ? -1 : 0,
35
+ y: isHoverDebounced ? -1 : 0,
36
+ }}
37
+ whileHover={{
38
+ scale: 1.4,
39
+ x: -3,
40
+ y: -1,
41
+ }}
42
+ className="likec4-compound-navigation compound-action"
43
+ whileTap={{ scale: 1 }}
44
+ onClick={stopPropagation}
45
+ >
46
+ <ActionIcon
47
+ className={cx(
48
+ 'nodrag nopan',
49
+ compoundActionBtn({
50
+ delay: isHovered && !isHoverDebounced,
51
+ }),
52
+ actionBtn({ variant: 'transparent' }),
53
+ )}
54
+ // Otherwise node receives click event and is selected
55
+ onClick={onClick}
56
+ onDoubleClick={stopPropagation}
56
57
  >
57
- <ActionIcon
58
- className={cx(
59
- 'nodrag nopan',
60
- compoundActionBtn({
61
- delay: isHovered && !isHoverDebounced,
62
- }),
63
- actionBtn(),
64
- )}
65
- // Otherwise node receives click event and is selected
66
- onClick={onClick}
67
- onDoubleClick={stopPropagation}
68
- >
69
- {icon ?? <IconZoomScan stroke={2} />}
70
- </ActionIcon>
71
- </m.div>
72
- </Box>
58
+ {icon ?? <IconZoomScan stroke={2} />}
59
+ </ActionIcon>
60
+ </m.div>
73
61
  )
74
62
  }
@@ -1,5 +1,4 @@
1
- import { css, cx } from '@likec4/styles/css'
2
- import { Box } from '@likec4/styles/jsx'
1
+ import { cx } from '@likec4/styles/css'
3
2
  import { actionBtn } from '@likec4/styles/recipes'
4
3
  import { ActionIcon } from '@mantine/core'
5
4
  import { useDebouncedValue } from '@mantine/hooks'
@@ -28,51 +27,30 @@ export function CompoundDetailsButton({
28
27
  const debounced = useDebouncedValue(isHovered, isHovered ? 130 : 0)
29
28
  const isHoverDebounced = debounced[0] && isHovered
30
29
  return (
31
- <Box
32
- className={cx(
33
- css({
34
- position: 'absolute',
35
- top: '0.5',
36
- right: '0.5',
37
- _smallZoom: {
38
- display: 'none',
39
- },
40
- }),
41
- 'details-button',
42
- )}
43
- onClick={stopPropagation}>
44
- <m.div
45
- initial={false}
46
- animate={{
47
- scale: isHoverDebounced ? 1.2 : 1,
48
- opacity: isHoverDebounced ? 1 : 0.6,
49
- }}
50
- whileHover={{
51
- scale: 1.4,
52
- }}
53
- whileTap={{ scale: 1 }}
54
- >
55
- <ActionIcon
56
- className={cx(
57
- 'nodrag nopan',
58
- compoundActionBtn({
59
- delay: isHovered && !isHoverDebounced,
60
- }),
61
- css({
62
- _whenHovered: {
63
- opacity: .75,
64
- },
65
- _hover: {
66
- opacity: 1,
67
- },
68
- }),
69
- actionBtn({ variant: 'transparent' }),
70
- )}
71
- onClick={onClick}
72
- onDoubleClick={stopPropagation}>
73
- {icon ?? <IconId stroke={1.8} style={{ width: '75%' }} />}
74
- </ActionIcon>
75
- </m.div>
76
- </Box>
30
+ <m.div
31
+ initial={false}
32
+ animate={{
33
+ scale: isHoverDebounced ? 1.2 : 1,
34
+ // opacity: isHoverDebounced ? 1 : 0.6,
35
+ }}
36
+ whileHover={{
37
+ scale: 1.4,
38
+ }}
39
+ whileTap={{ scale: 1 }}
40
+ className="likec4-compound-details details-button"
41
+ >
42
+ <ActionIcon
43
+ className={cx(
44
+ 'nodrag nopan',
45
+ compoundActionBtn({
46
+ delay: isHovered && !isHoverDebounced,
47
+ }),
48
+ actionBtn({ variant: 'transparent' }),
49
+ )}
50
+ onClick={onClick}
51
+ onDoubleClick={stopPropagation}>
52
+ {icon ?? <IconId stroke={1.8} style={{ width: '75%' }} />}
53
+ </ActionIcon>
54
+ </m.div>
77
55
  )
78
56
  }
@@ -1,11 +1,11 @@
1
1
  import type { Color, ElementStyle } from '@likec4/core/types'
2
- import { css, cx } from '@likec4/styles/css'
2
+ import { cx } from '@likec4/styles/css'
3
+ import { compoundNode } from '@likec4/styles/recipes'
3
4
  import { type HTMLMotionProps, m } from 'motion/react'
4
5
  import { type PropsWithChildren } from 'react'
5
- import { clamp, isNumber } from 'remeda'
6
- import { useIsReducedGraphics } from '../../../hooks/useReducedGraphics'
6
+ import { clamp } from 'remeda'
7
7
  import type { NodeProps } from '../../types'
8
- import * as styles from './CompoundNodeContainer.css'
8
+ // import * as styles from './CompoundNodeContainer.css'
9
9
 
10
10
  export type RequiredData = {
11
11
  color: Color
@@ -33,27 +33,24 @@ export function CompoundNodeContainer({
33
33
  style,
34
34
  ...rest
35
35
  }: CompoundNodeContainerProps) {
36
- const isReducedGraphics = useIsReducedGraphics()
37
- const isTransparent = isNumber(data.style.opacity) && data.style.opacity < 99
38
- let opacity = clamp((data.style.opacity ?? 100) / 100, {
36
+ let opacity = clamp(data.style.opacity ?? 100, {
39
37
  min: 0,
40
- max: 1,
38
+ max: 100,
41
39
  })
42
- if (isTransparent && isHovered && !isReducedGraphics) {
43
- opacity = Math.min(opacity + 0.08, 1)
44
- }
45
-
46
- // const [opacity] = useDebouncedValue(Math.round(_opacity * 100) / 100, isHovered ? 200 : 50)
40
+ const isTransparent = opacity < 99
47
41
 
48
42
  const MIN_OPACITY = 65
49
- const borderOpacity = MIN_OPACITY + clamp((100 - MIN_OPACITY) * opacity, {
43
+ const borderOpacity = MIN_OPACITY + clamp((100 - MIN_OPACITY) * (opacity / 100), {
50
44
  min: 0,
51
45
  max: 100 - MIN_OPACITY,
52
46
  })
53
47
 
54
- const classes = styles.compound({
48
+ const compoundClass = compoundNode({
55
49
  isTransparent,
50
+ inverseColor: opacity < 60,
51
+ borderStyle: data.style.border ?? (isTransparent ? 'dashed' : 'none'),
56
52
  })
53
+
57
54
  const depth = clamp(data.depth ?? 1, {
58
55
  min: 1,
59
56
  max: 5,
@@ -62,49 +59,24 @@ export function CompoundNodeContainer({
62
59
  return (
63
60
  <m.div
64
61
  className={cx(
65
- classes.root,
66
- 'likec4-compound-node',
62
+ compoundClass,
67
63
  className,
68
64
  )}
69
65
  initial={false}
70
66
  data-likec4-hovered={isHovered}
71
67
  data-likec4-color={data.color}
72
68
  data-compound-depth={depth}
73
- {...isTransparent && {
74
- 'data-compound-transparent': true,
75
- 'data-compound-title-inverse': opacity < 0.5,
76
- }}
77
69
  {...isDimmed !== false && {
78
70
  'data-likec4-dimmed': isDimmed,
79
71
  }}
80
72
  style={{
81
73
  ...style,
82
74
  // @ts-expect-error
83
- [styles.compoundOpacity.var]: opacity,
84
- [styles.borderWidth.var]: `3px`,
85
- [styles.borderRadius.var]: `6px`,
86
- [styles.borderOpacityPercent.var]: `${borderOpacity}%`,
75
+ ['--_border-transparency']: `${borderOpacity}%`,
76
+ ['--_compound-transparency']: `${opacity}%`,
87
77
  }}
88
78
  {...rest}
89
79
  >
90
- {isTransparent && data.style.border !== 'none' && (
91
- <div
92
- className={classes.compoundBorder}
93
- style={{
94
- borderStyle: data.style.border ?? 'dashed',
95
- }}
96
- />
97
- )}
98
- <svg className={classes.indicatorSvg}>
99
- <rect
100
- className={classes.indicatorRect}
101
- x={0}
102
- y={0}
103
- width={'100%'}
104
- height={'100%'}
105
- rx={6}
106
- />
107
- </svg>
108
80
  {children}
109
81
  </m.div>
110
82
  )
@@ -1,6 +1,4 @@
1
1
  import type { DiagramNode } from '@likec4/core/types'
2
- import { css, cx } from '@likec4/styles/css'
3
- import { Box } from '@likec4/styles/jsx'
4
2
  import { Text } from '@mantine/core'
5
3
  import { IconRenderer } from '../../../context'
6
4
  import type { NodeProps } from '../../types'
@@ -15,72 +13,6 @@ type Data = Pick<
15
13
 
16
14
  type CompoundTitleProps = NodeProps<Data>
17
15
 
18
- const titleContainer = css({
19
- position: 'absolute',
20
- display: 'flex',
21
- alignItems: 'center',
22
- gap: '1.5', // 6px
23
- left: '[14px]',
24
- top: '[4px]',
25
- right: '[30px]',
26
- width: 'auto',
27
- minHeight: '30px',
28
- [`:where(.react-flow__node.draggable) &`]: {
29
- pointerEvents: 'all',
30
- cursor: 'grab',
31
- },
32
- [`.likec4-compound-node:has(.compound-action) &`]: {
33
- paddingLeft: '[22px]',
34
- },
35
- })
36
-
37
- const titleText = css({
38
- flex: '1',
39
- fontFamily: 'likec4.compound',
40
- fontWeight: 600,
41
- fontSize: '15px',
42
- textTransform: 'uppercase',
43
- letterSpacing: '0.2px',
44
- color: 'var(--likec4-palette-loContrast)',
45
- '[data-compound-title-inverse] &': {
46
- color: {
47
- base: '[color-mix(in srgb, var(--likec4-palette-loContrast) 60%, var(--likec4-palette-fill))]',
48
- _light: 'var(--likec4-palette-stroke)',
49
- },
50
- },
51
- })
52
-
53
- const iconSize = '20px'
54
- const cssIcon = css({
55
- flex: `0 0 ${iconSize}`,
56
- height: `${iconSize}`,
57
- width: `${iconSize}`,
58
- display: 'flex',
59
- alignItems: 'center',
60
- justifyContent: 'center',
61
- mixBlendMode: {
62
- base: 'hard-light',
63
- _reduceGraphicsOnPan: 'normal',
64
- },
65
- [`& svg, & img`]: {
66
- width: '100%',
67
- height: 'auto',
68
- maxHeight: '100%',
69
- pointerEvents: 'none',
70
- filter: {
71
- base: [
72
- 'drop-shadow(0 0 3px rgb(0 0 0 / 12%))',
73
- 'drop-shadow(0 1px 8px rgb(0 0 0 / 8%))',
74
- 'drop-shadow(1px 1px 16px rgb(0 0 0 / 3%))',
75
- ],
76
- _reduceGraphicsOnPan: 'none',
77
- },
78
- },
79
- [`& img`]: {
80
- objectFit: 'contain',
81
- },
82
- })
83
-
84
16
  export function CompoundTitle({ id, data }: CompoundTitleProps) {
85
17
  const elementIcon = IconRenderer({
86
18
  element: {
@@ -88,19 +20,15 @@ export function CompoundTitle({ id, data }: CompoundTitleProps) {
88
20
  title: data.title,
89
21
  icon: data.icon,
90
22
  },
91
- className: cssIcon,
23
+ className: 'likec4-compound-icon',
92
24
  })
93
25
 
94
26
  return (
95
- <Box
96
- className={cx(
97
- titleContainer,
98
- 'likec4-compound-title',
99
- )}>
27
+ <div className={'likec4-compound-title-container'}>
100
28
  {elementIcon}
101
- <Text className={titleText} truncate="end">
29
+ <Text component="h3" className={'likec4-compound-title'} truncate="end">
102
30
  {data.title}
103
31
  </Text>
104
- </Box>
32
+ </div>
105
33
  )
106
34
  }
@@ -3,18 +3,6 @@ import { cva } from '@likec4/styles/css'
3
3
  export const compoundActionBtn = cva({
4
4
  base: {
5
5
  transitionDuration: 'normal',
6
- '[data-compound-title-inverse] &': {
7
- _dark: {
8
- '--actionbtn-color': 'color-mix(in srgb, var(--likec4-palette-loContrast) 60%, var(--likec4-palette-fill))',
9
- },
10
- _light: {
11
- '--actionbtn-color': 'var(--likec4-palette-stroke)',
12
- '--actionbtn-color-hovered': 'var(--likec4-palette-stroke)',
13
- '--actionbtn-color-hovered-btn': 'var(--likec4-palette-hiContrast)',
14
- '--actionbtn-bg-hovered': `var(--likec4-palette-fill)/50`,
15
- '--actionbtn-bg-hovered-btn': `var(--likec4-palette-fill)`,
16
- },
17
- },
18
6
  },
19
7
  variants: {
20
8
  delay: {
@@ -27,7 +27,7 @@ export const edgePropsEqual = <P extends Record<string, unknown> = Base.EdgeData
27
27
  && eq(prev.data, next.data)
28
28
  )
29
29
 
30
- export function customEdge<P extends Record<string, unknown> = Base.NodeData>(
30
+ export function customEdge<P extends Record<string, unknown> = Base.EdgeData>(
31
31
  Edge: FunctionComponent<EdgeProps<P>>,
32
32
  ): FunctionComponent<EdgeProps<P>> {
33
33
  return memo(Edge, edgePropsEqual)
@@ -1,33 +1,29 @@
1
1
  import { deepEqual as eq } from 'fast-equals'
2
2
  import { type FunctionComponent, memo } from 'react'
3
- import type { Base, NodeProps } from '../types'
4
- import { DefaultHandles } from './NodeHandles'
3
+ import type { NodeProps } from '../types'
5
4
 
6
- export const nodePropsEqual = <P extends Record<string, unknown> = Base.NodeData>(
7
- prev: NodeProps<P>,
8
- next: NodeProps<P>,
9
- ) => (
10
- prev.id === next.id
11
- && eq(prev.selected ?? false, next.selected ?? false)
12
- && eq(prev.dragging ?? false, next.dragging ?? false)
13
- && eq(prev.width ?? 0, next.width ?? 0)
14
- && eq(prev.height ?? 0, next.height ?? 0)
15
- && eq(prev.zIndex ?? 0, next.zIndex ?? 0)
16
- // we can ignore position, as custom nodes positioned relative to it's NodeRenderer
17
- // && eq(prev.positionAbsoluteX, next.positionAbsoluteX)
18
- // && eq(prev.positionAbsoluteY, next.positionAbsoluteY)
19
- && eq(prev.data, next.data)
20
- )
5
+ export function nodePropsEqual<P extends NodeProps<any, any>>(prev: P, next: P) {
6
+ return (
7
+ prev.id === next.id
8
+ && eq(prev.selected ?? false, next.selected ?? false)
9
+ && eq(prev.dragging ?? false, next.dragging ?? false)
10
+ && eq(prev.width ?? 0, next.width ?? 0)
11
+ && eq(prev.height ?? 0, next.height ?? 0)
12
+ && eq(prev.zIndex ?? 0, next.zIndex ?? 0)
13
+ // we can ignore position, as custom nodes positioned relative to it's NodeRenderer
14
+ // && eq(prev.positionAbsoluteX, next.positionAbsoluteX)
15
+ // && eq(prev.positionAbsoluteY, next.positionAbsoluteY)
16
+ && eq(prev.data, next.data)
17
+ )
18
+ }
21
19
 
22
20
  export function customNode<P extends Record<string, unknown> = {}, NodeType extends string = string>(
23
21
  Node: FunctionComponent<NodeProps<P, NodeType>>,
24
- ) {
25
- const NodeComponent = memo((props: NodeProps<P, NodeType>) => (
26
- <>
27
- <Node {...props} />
28
- <DefaultHandles />
29
- </>
30
- ), nodePropsEqual)
22
+ ): FunctionComponent<NodeProps<P, NodeType>> {
23
+ const NodeComponent = memo(
24
+ Node,
25
+ (prev, next) => nodePropsEqual(prev as NodeProps, next as NodeProps),
26
+ )
31
27
  NodeComponent.displayName = 'Node'
32
28
  return NodeComponent
33
29
  }