@tldiagram/core-ui 1.87.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 (272) hide show
  1. package/dist/App.d.ts +1 -0
  2. package/dist/api/client.d.ts +143 -0
  3. package/dist/api/transport-vscode.d.ts +8 -0
  4. package/dist/api/transport.d.ts +1 -0
  5. package/dist/components/CodePreviewPanel-vscode.d.ts +7 -0
  6. package/dist/components/CodePreviewPanel.d.ts +9 -0
  7. package/dist/components/ConfirmDialog.d.ts +12 -0
  8. package/dist/components/ConnectorPanel.d.ts +21 -0
  9. package/dist/components/ContextBoundaryElement.d.ts +11 -0
  10. package/dist/components/ContextNeighborElement.d.ts +29 -0
  11. package/dist/components/ContextStraightConnector.d.ts +4 -0
  12. package/dist/components/CrossBranchControls.d.ts +9 -0
  13. package/dist/components/DependenciesOnboarding.d.ts +5 -0
  14. package/dist/components/DrawingCanvas.d.ts +39 -0
  15. package/dist/components/ElementLibrary-vscode.d.ts +7 -0
  16. package/dist/components/ElementLibrary.d.ts +22 -0
  17. package/dist/components/ElementNode.d.ts +36 -0
  18. package/dist/components/ElementPanel.d.ts +25 -0
  19. package/dist/components/ExploreOnboarding.d.ts +5 -0
  20. package/dist/components/ExplorePageOnboarding.d.ts +5 -0
  21. package/dist/components/ExportModal.d.ts +16 -0
  22. package/dist/components/FloatingEdge.d.ts +9 -0
  23. package/dist/components/GitSourceLinker.d.ts +8 -0
  24. package/dist/components/HeaderContext.d.ts +16 -0
  25. package/dist/components/Icons.d.ts +95 -0
  26. package/dist/components/ImportModal.d.ts +10 -0
  27. package/dist/components/InlineElementAdder.d.ts +17 -0
  28. package/dist/components/LayoutSection.d.ts +7 -0
  29. package/dist/components/LocalSourceLinker.d.ts +8 -0
  30. package/dist/components/MiniZoomOnboarding.d.ts +5 -0
  31. package/dist/components/NavBreadcrumb.d.ts +6 -0
  32. package/dist/components/NodeBody.d.ts +12 -0
  33. package/dist/components/NodeContainer.d.ts +8 -0
  34. package/dist/components/NodeHoverCard.d.ts +10 -0
  35. package/dist/components/PanelHeader.d.ts +8 -0
  36. package/dist/components/PanelUI.d.ts +3 -0
  37. package/dist/components/ProxyConnectorEdge.d.ts +4 -0
  38. package/dist/components/ProxyConnectorPanel.d.ts +9 -0
  39. package/dist/components/SafeBackground.d.ts +13 -0
  40. package/dist/components/ScrollIndicatorWrapper.d.ts +8 -0
  41. package/dist/components/SetChildModal.d.ts +10 -0
  42. package/dist/components/SetParentModal.d.ts +10 -0
  43. package/dist/components/SlidingPanel.d.ts +16 -0
  44. package/dist/components/TagUpsert.d.ts +8 -0
  45. package/dist/components/TopMenuBar.d.ts +8 -0
  46. package/dist/components/ViewBezierConnector.d.ts +4 -0
  47. package/dist/components/ViewDrawMenu.d.ts +22 -0
  48. package/dist/components/ViewEditorEdgeLabelLayout.d.ts +16 -0
  49. package/dist/components/ViewEditorOnboarding.d.ts +5 -0
  50. package/dist/components/ViewExplorer/TagManager/ColorPicker.d.ts +7 -0
  51. package/dist/components/ViewExplorer/TagManager/GroupNamingPopover.d.ts +10 -0
  52. package/dist/components/ViewExplorer/TagManager/LayerItem.d.ts +27 -0
  53. package/dist/components/ViewExplorer/TagManager/TagItem.d.ts +25 -0
  54. package/dist/components/ViewExplorer/TagManager/index.d.ts +21 -0
  55. package/dist/components/ViewExplorer/ViewNavigator.d.ts +11 -0
  56. package/dist/components/ViewExplorer/ViewSearch.d.ts +8 -0
  57. package/dist/components/ViewExplorer/ViewTree.d.ts +18 -0
  58. package/dist/components/ViewExplorer/index.d.ts +31 -0
  59. package/dist/components/ViewExplorer/types.d.ts +11 -0
  60. package/dist/components/ViewExplorer/utils.d.ts +6 -0
  61. package/dist/components/ViewExplorer-vscode.d.ts +6 -0
  62. package/dist/components/ViewFloatingMenu-vscode.d.ts +27 -0
  63. package/dist/components/ViewFloatingMenu.d.ts +39 -0
  64. package/dist/components/ViewGridNode.d.ts +29 -0
  65. package/dist/components/ViewHeaderButton.d.ts +11 -0
  66. package/dist/components/ViewPanel.d.ts +18 -0
  67. package/dist/components/ViewsGridOnboarding.d.ts +5 -0
  68. package/dist/components/ZUI/ZUICanvas.d.ts +18 -0
  69. package/dist/components/ZUI/index.d.ts +2 -0
  70. package/dist/components/ZUI/layout.d.ts +18 -0
  71. package/dist/components/ZUI/proxy.d.ts +25 -0
  72. package/dist/components/ZUI/renderer.d.ts +30 -0
  73. package/dist/components/ZUI/types.d.ts +140 -0
  74. package/dist/components/ZUI/useZUIInteraction.d.ts +21 -0
  75. package/dist/config/runtime-vscode.d.ts +22 -0
  76. package/dist/config/runtime.d.ts +5 -0
  77. package/dist/constants/colors.d.ts +27 -0
  78. package/dist/constants/diagramColors.d.ts +1 -0
  79. package/dist/context/ThemeContext.d.ts +27 -0
  80. package/dist/crossBranch/graph.d.ts +13 -0
  81. package/dist/crossBranch/resolve.d.ts +22 -0
  82. package/dist/crossBranch/settings.d.ts +6 -0
  83. package/dist/crossBranch/store.d.ts +11 -0
  84. package/dist/crossBranch/types.d.ts +96 -0
  85. package/dist/demo/DemoPage.d.ts +9 -0
  86. package/dist/demo/seed.d.ts +9 -0
  87. package/dist/demo/store.d.ts +137 -0
  88. package/dist/demo/viewEditor.d.ts +26 -0
  89. package/dist/favicon.svg +35 -0
  90. package/dist/hooks/useSafeFitView.d.ts +16 -0
  91. package/dist/index.css +1 -0
  92. package/dist/index.d.ts +115 -0
  93. package/dist/index.js +19966 -0
  94. package/dist/lib/vscodeBridge-vscode.d.ts +13 -0
  95. package/dist/lib/vscodeBridge.d.ts +5 -0
  96. package/dist/logo-120.png +0 -0
  97. package/dist/logo-bw.png +0 -0
  98. package/dist/logo-bw.svg +15 -0
  99. package/dist/logo-text.svg +51 -0
  100. package/dist/logo.svg +35 -0
  101. package/dist/pages/AppearanceSettings.d.ts +3 -0
  102. package/dist/pages/Dependencies.d.ts +1 -0
  103. package/dist/pages/InfiniteZoom.d.ts +7 -0
  104. package/dist/pages/Settings.d.ts +7 -0
  105. package/dist/pages/ViewEditor/components/EditorMenus.d.ts +24 -0
  106. package/dist/pages/ViewEditor/components/EditorOverlays.d.ts +30 -0
  107. package/dist/pages/ViewEditor/components/EmptyCanvasState.d.ts +7 -0
  108. package/dist/pages/ViewEditor/context.d.ts +13 -0
  109. package/dist/pages/ViewEditor/hooks/useCanvasInteractions.d.ts +201 -0
  110. package/dist/pages/ViewEditor/hooks/useDrawingEngine.d.ts +40 -0
  111. package/dist/pages/ViewEditor/hooks/useViewContextNeighbours.d.ts +20 -0
  112. package/dist/pages/ViewEditor/hooks/useViewData.d.ts +74 -0
  113. package/dist/pages/ViewEditor/index.d.ts +8 -0
  114. package/dist/pages/ViewEditor/utils.d.ts +14 -0
  115. package/dist/pages/Views.d.ts +6 -0
  116. package/dist/pages/ViewsGrid.d.ts +6 -0
  117. package/dist/pkg/importer/mermaid.d.ts +7 -0
  118. package/dist/pkg/importer/mermaid.test.d.ts +1 -0
  119. package/dist/platform/PlatformContext.d.ts +6 -0
  120. package/dist/platform/context.d.ts +3 -0
  121. package/dist/platform/local.d.ts +2 -0
  122. package/dist/platform/types.d.ts +17 -0
  123. package/dist/slots.d.ts +67 -0
  124. package/dist/theme.d.ts +2 -0
  125. package/dist/types/index.d.ts +193 -0
  126. package/dist/types/vscode-messages.d.ts +60 -0
  127. package/dist/utils/edgeDistribution.d.ts +34 -0
  128. package/dist/utils/githubApi.d.ts +4 -0
  129. package/dist/utils/githubCache.d.ts +17 -0
  130. package/dist/utils/ids.d.ts +2 -0
  131. package/dist/utils/technologyCatalog.d.ts +15 -0
  132. package/dist/utils/toast.d.ts +15 -0
  133. package/dist/utils/treesitter.d.ts +13 -0
  134. package/dist/utils/url.d.ts +12 -0
  135. package/package.json +159 -0
  136. package/src/App.tsx +141 -0
  137. package/src/api/client.ts +618 -0
  138. package/src/api/transport-vscode.ts +28 -0
  139. package/src/api/transport.ts +7 -0
  140. package/src/assets/logo-mark.svg +31 -0
  141. package/src/assets/logo-wordmark.svg +22 -0
  142. package/src/assets/logo.svg +35 -0
  143. package/src/components/CodePreviewPanel-vscode.tsx +85 -0
  144. package/src/components/CodePreviewPanel.tsx +384 -0
  145. package/src/components/ConfirmDialog.tsx +66 -0
  146. package/src/components/ConnectorPanel.tsx +403 -0
  147. package/src/components/ContextBoundaryElement.tsx +35 -0
  148. package/src/components/ContextNeighborElement.tsx +282 -0
  149. package/src/components/ContextStraightConnector.tsx +144 -0
  150. package/src/components/CrossBranchControls.tsx +105 -0
  151. package/src/components/DependenciesOnboarding.tsx +427 -0
  152. package/src/components/DrawingCanvas.tsx +391 -0
  153. package/src/components/ElementLibrary-vscode.tsx +9 -0
  154. package/src/components/ElementLibrary.tsx +512 -0
  155. package/src/components/ElementNode.tsx +1033 -0
  156. package/src/components/ElementPanel.tsx +928 -0
  157. package/src/components/ExploreOnboarding.tsx +347 -0
  158. package/src/components/ExplorePageOnboarding.tsx +383 -0
  159. package/src/components/ExportModal.tsx +132 -0
  160. package/src/components/FloatingEdge.tsx +115 -0
  161. package/src/components/GitSourceLinker.tsx +1053 -0
  162. package/src/components/HeaderContext.tsx +30 -0
  163. package/src/components/Icons.tsx +245 -0
  164. package/src/components/ImportModal.tsx +219 -0
  165. package/src/components/InlineElementAdder.tsx +216 -0
  166. package/src/components/LayoutSection.tsx +624 -0
  167. package/src/components/LocalSourceLinker.tsx +330 -0
  168. package/src/components/MiniZoomOnboarding.tsx +78 -0
  169. package/src/components/NavBreadcrumb.tsx +24 -0
  170. package/src/components/NodeBody.tsx +89 -0
  171. package/src/components/NodeContainer.tsx +58 -0
  172. package/src/components/NodeHoverCard.tsx +135 -0
  173. package/src/components/PanelHeader.tsx +36 -0
  174. package/src/components/PanelUI.tsx +24 -0
  175. package/src/components/ProxyConnectorEdge.tsx +169 -0
  176. package/src/components/ProxyConnectorPanel.tsx +130 -0
  177. package/src/components/SafeBackground.tsx +19 -0
  178. package/src/components/ScrollIndicatorWrapper.tsx +117 -0
  179. package/src/components/SetChildModal.tsx +191 -0
  180. package/src/components/SetParentModal.tsx +187 -0
  181. package/src/components/SlidingPanel.tsx +114 -0
  182. package/src/components/TagUpsert.tsx +142 -0
  183. package/src/components/TopMenuBar.tsx +380 -0
  184. package/src/components/ViewBezierConnector.tsx +143 -0
  185. package/src/components/ViewDrawMenu.tsx +270 -0
  186. package/src/components/ViewEditorEdgeLabelLayout.ts +189 -0
  187. package/src/components/ViewEditorOnboarding.tsx +445 -0
  188. package/src/components/ViewExplorer/TagManager/ColorPicker.tsx +49 -0
  189. package/src/components/ViewExplorer/TagManager/GroupNamingPopover.tsx +96 -0
  190. package/src/components/ViewExplorer/TagManager/LayerItem.tsx +228 -0
  191. package/src/components/ViewExplorer/TagManager/TagItem.tsx +242 -0
  192. package/src/components/ViewExplorer/TagManager/index.tsx +418 -0
  193. package/src/components/ViewExplorer/ViewNavigator.tsx +121 -0
  194. package/src/components/ViewExplorer/ViewSearch.tsx +33 -0
  195. package/src/components/ViewExplorer/ViewTree.tsx +98 -0
  196. package/src/components/ViewExplorer/index.tsx +384 -0
  197. package/src/components/ViewExplorer/types.ts +13 -0
  198. package/src/components/ViewExplorer/utils.ts +56 -0
  199. package/src/components/ViewExplorer-vscode.tsx +8 -0
  200. package/src/components/ViewFloatingMenu-vscode.tsx +248 -0
  201. package/src/components/ViewFloatingMenu.tsx +379 -0
  202. package/src/components/ViewGridNode.tsx +451 -0
  203. package/src/components/ViewHeaderButton.tsx +60 -0
  204. package/src/components/ViewPanel.tsx +162 -0
  205. package/src/components/ViewsGridOnboarding.tsx +400 -0
  206. package/src/components/ZUI/ZUICanvas.tsx +853 -0
  207. package/src/components/ZUI/index.ts +3 -0
  208. package/src/components/ZUI/layout.ts +323 -0
  209. package/src/components/ZUI/proxy.ts +278 -0
  210. package/src/components/ZUI/renderer.ts +1189 -0
  211. package/src/components/ZUI/types.ts +150 -0
  212. package/src/components/ZUI/useZUIInteraction.ts +720 -0
  213. package/src/config/runtime-vscode.ts +46 -0
  214. package/src/config/runtime.ts +30 -0
  215. package/src/constants/colors.ts +80 -0
  216. package/src/constants/diagramColors.ts +9 -0
  217. package/src/context/ThemeContext.tsx +158 -0
  218. package/src/crossBranch/graph.ts +207 -0
  219. package/src/crossBranch/resolve.ts +643 -0
  220. package/src/crossBranch/settings.ts +59 -0
  221. package/src/crossBranch/store.ts +71 -0
  222. package/src/crossBranch/types.ts +102 -0
  223. package/src/demo/DemoPage.tsx +184 -0
  224. package/src/demo/seed.ts +67 -0
  225. package/src/demo/store.ts +536 -0
  226. package/src/demo/viewEditor.ts +110 -0
  227. package/src/hooks/useSafeFitView.ts +60 -0
  228. package/src/index.css +309 -0
  229. package/src/index.ts +184 -0
  230. package/src/kafka-ss.png +0 -0
  231. package/src/lib/vscodeBridge-vscode.ts +27 -0
  232. package/src/lib/vscodeBridge.ts +7 -0
  233. package/src/main.tsx +46 -0
  234. package/src/pages/AppearanceSettings.tsx +135 -0
  235. package/src/pages/Dependencies.tsx +926 -0
  236. package/src/pages/InfiniteZoom.tsx +404 -0
  237. package/src/pages/Settings.tsx +91 -0
  238. package/src/pages/ViewEditor/EDGE_DISTRIBUTION.md +64 -0
  239. package/src/pages/ViewEditor/components/EditorMenus.tsx +112 -0
  240. package/src/pages/ViewEditor/components/EditorOverlays.tsx +172 -0
  241. package/src/pages/ViewEditor/components/EmptyCanvasState.tsx +42 -0
  242. package/src/pages/ViewEditor/context.tsx +21 -0
  243. package/src/pages/ViewEditor/hooks/useCanvasInteractions.ts +1349 -0
  244. package/src/pages/ViewEditor/hooks/useDrawingEngine.ts +127 -0
  245. package/src/pages/ViewEditor/hooks/useViewContextNeighbours.ts +501 -0
  246. package/src/pages/ViewEditor/hooks/useViewData.ts +491 -0
  247. package/src/pages/ViewEditor/index.tsx +1366 -0
  248. package/src/pages/ViewEditor/utils.ts +88 -0
  249. package/src/pages/Views.tsx +171 -0
  250. package/src/pages/ViewsGrid.tsx +1310 -0
  251. package/src/pkg/importer/mermaid.test.ts +141 -0
  252. package/src/pkg/importer/mermaid.ts +76 -0
  253. package/src/platform/PlatformContext.tsx +17 -0
  254. package/src/platform/context.ts +9 -0
  255. package/src/platform/local.tsx +15 -0
  256. package/src/platform/types.ts +19 -0
  257. package/src/slots.ts +92 -0
  258. package/src/styles/editor-panels.css +66 -0
  259. package/src/styles/theme.css +56 -0
  260. package/src/theme.ts +336 -0
  261. package/src/types/index.ts +234 -0
  262. package/src/types/offline-ambient.d.ts +14 -0
  263. package/src/types/vscode-messages.ts +32 -0
  264. package/src/utils/edgeDistribution.ts +103 -0
  265. package/src/utils/githubApi.ts +121 -0
  266. package/src/utils/githubCache.ts +108 -0
  267. package/src/utils/ids.ts +9 -0
  268. package/src/utils/technologyCatalog.ts +143 -0
  269. package/src/utils/toast.ts +100 -0
  270. package/src/utils/treesitter.ts +147 -0
  271. package/src/utils/url.ts +72 -0
  272. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,228 @@
1
+ import React, { useState } from 'react'
2
+ import {
3
+ Box,
4
+ HStack,
5
+ Text,
6
+ VStack,
7
+ IconButton,
8
+ Wrap,
9
+ WrapItem,
10
+ Popover,
11
+ PopoverTrigger,
12
+ useDisclosure,
13
+ Flex,
14
+ } from '@chakra-ui/react'
15
+ import { GroupNamingPopover } from './GroupNamingPopover'
16
+ import { DeleteIcon } from '@chakra-ui/icons'
17
+ import { EyeIcon, EyeOffIcon, ChevronDownIcon } from '../../Icons'
18
+ import { ViewLayer } from '../../../types'
19
+ import { TagItem } from './TagItem'
20
+ import { ColorPicker } from './ColorPicker'
21
+
22
+ interface Props {
23
+ layer: ViewLayer
24
+ isActive: boolean
25
+ isExpanded: boolean
26
+ tagCount: number
27
+ tagColors: Record<string, import('../../../types').Tag>
28
+ onToggleActive: () => void
29
+ onToggleExpanded: () => void
30
+ onDelete: () => void
31
+ onSetColor: (color: string) => void
32
+ onSetTagColor?: (tag: string, color: string, description?: string) => void
33
+ onAddTag: (tag: string) => void
34
+ onRemoveTag: (tag: string) => void
35
+ onHover: (active: boolean) => void
36
+ selectedElementTags?: string[]
37
+ onToggleTagOnElement?: (tag: string) => void
38
+ namingPopover?: { isOpen: boolean; defaultName: string }
39
+ onConfirmNaming?: (name: string) => void
40
+ onCloseNaming?: () => void
41
+ }
42
+
43
+ export const LayerItem: React.FC<Props> = ({
44
+ layer,
45
+ isActive,
46
+ isExpanded,
47
+ tagCount,
48
+ tagColors,
49
+ onToggleActive,
50
+ onToggleExpanded,
51
+ onDelete,
52
+ onSetColor,
53
+ onSetTagColor,
54
+ onAddTag,
55
+ onRemoveTag,
56
+ onHover,
57
+ selectedElementTags,
58
+ onToggleTagOnElement,
59
+ namingPopover,
60
+ onConfirmNaming,
61
+ onCloseNaming,
62
+ }) => {
63
+ const [isOver, setIsOver] = useState(false)
64
+ const { isOpen: isColorOpen, onOpen: onColorOpen, onClose: onColorClose } = useDisclosure()
65
+
66
+ const handleDragOver = (e: React.DragEvent) => {
67
+ if (e.dataTransfer.types.includes('application/diag-tag')) {
68
+ e.preventDefault()
69
+ e.dataTransfer.dropEffect = 'copy'
70
+ setIsOver(true)
71
+ }
72
+ }
73
+
74
+ const handleDragLeave = () => {
75
+ setIsOver(false)
76
+ }
77
+
78
+ const handleDrop = (e: React.DragEvent) => {
79
+ e.preventDefault()
80
+ setIsOver(false)
81
+ const tag = e.dataTransfer.getData('application/diag-tag')
82
+ if (tag && !layer.tags.includes(tag)) {
83
+ onAddTag(tag)
84
+ }
85
+ }
86
+
87
+ const handleDragStart = (e: React.DragEvent) => {
88
+ e.dataTransfer.setData('application/diag-layer', String(layer.id))
89
+ e.dataTransfer.effectAllowed = 'copyMove'
90
+ }
91
+
92
+ return (
93
+ <Box
94
+ borderBottom="1px solid"
95
+ borderColor="whiteAlpha.100"
96
+ bg={isOver ? 'whiteAlpha.100' : 'transparent'}
97
+ onDragOver={handleDragOver}
98
+ onDragLeave={handleDragLeave}
99
+ onDrop={handleDrop}
100
+ draggable
101
+ onDragStart={handleDragStart}
102
+ transition="background-color 0.2s"
103
+ >
104
+ <Popover
105
+ isOpen={!!namingPopover?.isOpen}
106
+ onClose={onCloseNaming || (() => {})}
107
+ placement="top"
108
+ isLazy
109
+ closeOnBlur
110
+ >
111
+ <PopoverTrigger>
112
+ <HStack
113
+ px={3}
114
+ py={2}
115
+ spacing={2}
116
+ _hover={{ bg: 'whiteAlpha.50' }}
117
+ cursor="pointer"
118
+ onClick={onToggleExpanded}
119
+ onMouseEnter={() => onHover(true)}
120
+ onMouseLeave={() => onHover(false)}
121
+ >
122
+ <IconButton
123
+ aria-label={isActive ? 'Hide Layer' : 'Show Layer'}
124
+ icon={isActive ? <EyeIcon size={14} /> : <EyeOffIcon size={14} />}
125
+ size="xs"
126
+ variant="ghost"
127
+ color={isActive ? 'whiteAlpha.800' : 'whiteAlpha.400'}
128
+ onClick={(e) => {
129
+ e.stopPropagation()
130
+ onToggleActive()
131
+ }}
132
+ />
133
+
134
+ <Popover
135
+ isOpen={isColorOpen}
136
+ onClose={onColorClose}
137
+ placement="right"
138
+ closeOnBlur
139
+ >
140
+ <PopoverTrigger>
141
+ <Box
142
+ w="10px"
143
+ h="10px"
144
+ rounded="full"
145
+ bg={layer.color || 'gray.500'}
146
+ flexShrink={0}
147
+ _hover={{ transform: 'scale(1.2)' }}
148
+ transition="transform 0.1s"
149
+ onClick={(e) => {
150
+ e.stopPropagation()
151
+ onColorOpen()
152
+ }}
153
+ />
154
+ </PopoverTrigger>
155
+ <ColorPicker onSelect={onSetColor} onClose={onColorClose} />
156
+ </Popover>
157
+
158
+ <VStack align="start" spacing={0} flex={1} minW={0}>
159
+ <Text fontSize="xs" fontWeight="600" color="white" isTruncated>
160
+ {layer.name}
161
+ </Text>
162
+ <Text fontSize="10px" color="gray.500">
163
+ {layer.tags.length} tags · {tagCount} elements
164
+ </Text>
165
+ </VStack>
166
+
167
+ <Box
168
+ color="whiteAlpha.400"
169
+ transform={isExpanded ? 'none' : 'rotate(-90deg)'}
170
+ transition="transform 0.15s"
171
+ >
172
+ <ChevronDownIcon size={12} />
173
+ </Box>
174
+ </HStack>
175
+ </PopoverTrigger>
176
+ {namingPopover && onConfirmNaming && (
177
+ <GroupNamingPopover
178
+ isOpen={namingPopover.isOpen}
179
+ onClose={onCloseNaming || (() => {})}
180
+ onConfirm={onConfirmNaming}
181
+ defaultName={namingPopover.defaultName}
182
+ />
183
+ )}
184
+ </Popover>
185
+
186
+ {isExpanded && (
187
+ <Box px={4} pb={3} pt={1}>
188
+ <Flex align="flex-start" justify="space-between">
189
+ <Wrap spacing={1.5} align="center" flex={1}>
190
+ {layer.tags.map((tag) => (
191
+ <WrapItem key={tag}>
192
+ <TagItem
193
+ tag={tag}
194
+ color={tagColors[tag]?.color || '#A0AEC0'}
195
+ description={tagColors[tag]?.description || null}
196
+ isAssigned={selectedElementTags?.includes(tag)}
197
+ onToggle={() => onToggleTagOnElement?.(tag)}
198
+ onConfirmNaming={onConfirmNaming}
199
+ onCloseNaming={onCloseNaming}
200
+ onHover={(active) => onHover(active)}
201
+ onSetColor={onSetTagColor ? (color) => onSetTagColor(tag, color) : undefined}
202
+ onSetDescription={onSetTagColor ? (desc) => onSetTagColor(tag, tagColors[tag]?.color, desc) : undefined}
203
+ onRemove={() => onRemoveTag(tag)}
204
+ />
205
+ </WrapItem>
206
+ ))}
207
+ </Wrap>
208
+ <IconButton
209
+ aria-label="Delete Layer"
210
+ icon={<DeleteIcon />}
211
+ size="xs"
212
+ variant="ghost"
213
+ colorScheme="red"
214
+ opacity={0.4}
215
+ _hover={{ opacity: 1 }}
216
+ onClick={(e) => {
217
+ e.stopPropagation()
218
+ onDelete()
219
+ }}
220
+ ml={2}
221
+ flexShrink={0}
222
+ />
223
+ </Flex>
224
+ </Box>
225
+ )}
226
+ </Box>
227
+ )
228
+ }
@@ -0,0 +1,242 @@
1
+ import React, { useState } from 'react'
2
+ import { HStack, Box, Popover, PopoverTrigger, PopoverContent, useDisclosure, IconButton, VStack, Text, Input, Tooltip } from '@chakra-ui/react'
3
+ import { SmallCloseIcon } from '@chakra-ui/icons'
4
+ import { EyeIcon, EyeOffIcon } from '../../Icons'
5
+ import { GroupNamingPopover } from './GroupNamingPopover'
6
+ import { ColorPicker } from './ColorPicker'
7
+
8
+ interface Props {
9
+ tag: string
10
+ color: string
11
+ isAssigned?: boolean
12
+ tagCount?: number
13
+ onToggle?: () => void
14
+ onHover?: (active: boolean) => void
15
+ onDropTag?: (draggedTag: string) => void
16
+ onDropLayer?: (layerId: number) => void
17
+ namingPopover?: { isOpen: boolean; defaultName: string }
18
+ onConfirmNaming?: (name: string) => void
19
+ onCloseNaming?: () => void
20
+ onSetColor?: (color: string) => void
21
+ onSetDescription?: (description: string) => void
22
+ onRemove?: () => void
23
+ description?: string | null
24
+ isVisible?: boolean
25
+ onToggleVisibility?: () => void
26
+ }
27
+
28
+ export const TagItem: React.FC<Props> = ({
29
+ tag,
30
+ color,
31
+ isAssigned,
32
+ tagCount = 0,
33
+ onToggle,
34
+ onHover,
35
+ onDropTag,
36
+ onDropLayer,
37
+ namingPopover,
38
+ onConfirmNaming,
39
+ onCloseNaming,
40
+ onSetColor,
41
+ onSetDescription,
42
+ onRemove,
43
+ description,
44
+ isVisible = true,
45
+ onToggleVisibility,
46
+ }) => {
47
+ const [isOver, setIsOver] = useState(false)
48
+ const { isOpen: isColorOpen, onOpen: onColorOpen, onClose: onColorClose } = useDisclosure()
49
+
50
+ const handleDragStart = (e: React.DragEvent) => {
51
+ e.dataTransfer.setData('application/diag-tag', tag)
52
+ e.dataTransfer.effectAllowed = 'copyMove'
53
+ }
54
+
55
+ const handleDragOver = (e: React.DragEvent) => {
56
+ if (e.dataTransfer.types.includes('application/diag-tag') || e.dataTransfer.types.includes('application/diag-layer')) {
57
+ const draggedTag = e.dataTransfer.getData('application/diag-tag')
58
+ if (draggedTag !== tag) {
59
+ e.preventDefault()
60
+ e.dataTransfer.dropEffect = 'link'
61
+ setIsOver(true)
62
+ }
63
+ }
64
+ }
65
+
66
+ const handleDragLeave = () => {
67
+ setIsOver(false)
68
+ }
69
+
70
+ const handleDrop = (e: React.DragEvent) => {
71
+ e.preventDefault()
72
+ setIsOver(false)
73
+ const draggedTag = e.dataTransfer.getData('application/diag-tag')
74
+ const draggedLayerId = e.dataTransfer.getData('application/diag-layer')
75
+
76
+ if (draggedTag && draggedTag !== tag) {
77
+ onDropTag?.(draggedTag)
78
+ } else if (draggedLayerId) {
79
+ onDropLayer?.(Number(draggedLayerId))
80
+ }
81
+ }
82
+
83
+ return (
84
+ <Popover
85
+ isOpen={!!namingPopover?.isOpen}
86
+ onClose={onCloseNaming || (() => {})}
87
+ placement="top"
88
+ isLazy
89
+ closeOnBlur
90
+ >
91
+ <PopoverTrigger>
92
+ <HStack
93
+ spacing={0}
94
+ align="center"
95
+ px={2}
96
+ overflow="hidden"
97
+ rounded="md"
98
+ border="1px solid"
99
+ borderColor={isAssigned ? color + '55' : isOver ? 'var(--accent)' : 'whiteAlpha.100'}
100
+ bg={isOver ? 'whiteAlpha.100' : 'transparent'}
101
+ transition="all 0.15s"
102
+ onMouseEnter={() => onHover?.(true)}
103
+ onMouseLeave={() => onHover?.(false)}
104
+ onDragOver={handleDragOver}
105
+ onDragLeave={handleDragLeave}
106
+ onDrop={handleDrop}
107
+ cursor="grab"
108
+ _active={{ cursor: 'grabbing' }}
109
+ role="group"
110
+ opacity={isVisible ? 1 : 0.6}
111
+ >
112
+ {onToggleVisibility && (
113
+ <IconButton
114
+ aria-label={isVisible ? 'Hide Tagged Elements' : 'Show Tagged Elements'}
115
+ icon={isVisible ? <EyeIcon size={10} /> : <EyeOffIcon size={10} />}
116
+ size="xs"
117
+ variant="ghost"
118
+ color={isVisible ? 'whiteAlpha.600' : 'whiteAlpha.300'}
119
+ _hover={{ color: isVisible ? 'white' : 'whiteAlpha.600', bg: 'transparent' }}
120
+ onClick={(e) => {
121
+ e.stopPropagation()
122
+ onToggleVisibility()
123
+ }}
124
+ w="14px"
125
+ h="14px"
126
+ minW="auto"
127
+ p={0}
128
+ mr={1}
129
+ flexShrink={0}
130
+ />
131
+ )}
132
+ {onSetColor && (
133
+ <Popover
134
+ isOpen={isColorOpen}
135
+ onClose={onColorClose}
136
+ placement="top"
137
+ closeOnBlur
138
+ >
139
+ <PopoverTrigger>
140
+ <Box
141
+ w="8px"
142
+ h="8px"
143
+ rounded="full"
144
+ bg={color}
145
+ cursor="pointer"
146
+ _hover={{ transform: 'scale(1.2)' }}
147
+ onClick={(e) => {
148
+ e.stopPropagation()
149
+ onColorOpen()
150
+ }}
151
+ flexShrink={0}
152
+ transition="transform 0.1s"
153
+ />
154
+ </PopoverTrigger>
155
+ <PopoverContent bg="gray.800" borderColor="whiteAlpha.200" p={2} w="200px" shadow="xl">
156
+ <VStack spacing={3} align="stretch">
157
+ <ColorPicker onSelect={onSetColor} onClose={onColorClose} />
158
+ {onSetDescription && (
159
+ <Box pt={1}>
160
+ <Text fontSize="10px" fontWeight="bold" color="gray.500" mb={1} textTransform="uppercase">Description</Text>
161
+ <Input
162
+ size="xs"
163
+ placeholder="Tag description..."
164
+ defaultValue={description || ''}
165
+ onKeyDown={(e) => {
166
+ if (e.key === 'Enter') {
167
+ onSetDescription((e.target as HTMLInputElement).value)
168
+ onColorClose()
169
+ }
170
+ }}
171
+ bg="whiteAlpha.50"
172
+ borderColor="whiteAlpha.100"
173
+ _focus={{ borderColor: 'var(--accent)' }}
174
+ />
175
+ </Box>
176
+ )}
177
+ </VStack>
178
+ </PopoverContent>
179
+ </Popover>
180
+ )}
181
+ <Tooltip label={description} placement="top" openDelay={500} isDisabled={!description}>
182
+ <Box
183
+ as="button"
184
+ pl={onSetColor ? 2 : 0}
185
+ pr={onRemove ? 1 : 0}
186
+ py={1}
187
+ fontSize="11px"
188
+ fontWeight="600"
189
+ bg="transparent"
190
+ color={isAssigned ? color : 'gray.500'}
191
+ _hover={{ color: color }}
192
+ transition="all 0.1s"
193
+ onClick={onToggle}
194
+ draggable
195
+ onDragStart={handleDragStart}
196
+ width="full"
197
+ textAlign="left"
198
+ >
199
+ <Text isTruncated>
200
+ {tag}
201
+ {tagCount > 0 && (
202
+ <Box as="span" ml={1.5} opacity={0.6} fontWeight="normal">
203
+ {tagCount}
204
+ </Box>
205
+ )}
206
+ </Text>
207
+ </Box>
208
+ </Tooltip>
209
+ {onRemove && (
210
+ <IconButton
211
+ aria-label="Remove tag"
212
+ icon={<SmallCloseIcon />}
213
+ size="xs"
214
+ variant="ghost"
215
+ fontSize="10px"
216
+ w="14px"
217
+ h="14px"
218
+ minW="auto"
219
+ p={0}
220
+ color="gray.500"
221
+ opacity={0}
222
+ _groupHover={{ opacity: 0.6 }}
223
+ _hover={{ opacity: 1, color: 'red.400' }}
224
+ onClick={(e) => {
225
+ e.stopPropagation()
226
+ onRemove()
227
+ }}
228
+ />
229
+ )}
230
+ </HStack>
231
+ </PopoverTrigger>
232
+ {namingPopover && onConfirmNaming && (
233
+ <GroupNamingPopover
234
+ isOpen={namingPopover.isOpen}
235
+ onClose={onCloseNaming || (() => {})}
236
+ onConfirm={onConfirmNaming}
237
+ defaultName={namingPopover.defaultName}
238
+ />
239
+ )}
240
+ </Popover>
241
+ )
242
+ }