@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,59 @@
1
+ import { useCallback, useEffect, useMemo, useState } from 'react'
2
+ import type { CrossBranchContextSettings, CrossBranchSurface } from './types'
3
+ import { CROSS_BRANCH_DEPTH_ALL } from './types'
4
+
5
+ const STORAGE_PREFIX = 'diag:cross-branch'
6
+
7
+ function storageKey(surface: CrossBranchSurface) {
8
+ return `${STORAGE_PREFIX}:${surface}`
9
+ }
10
+
11
+ function defaultSettings(surface: CrossBranchSurface): CrossBranchContextSettings {
12
+ return {
13
+ enabled: surface !== 'zui-shared',
14
+ depth: CROSS_BRANCH_DEPTH_ALL,
15
+ }
16
+ }
17
+
18
+ function readSettings(surface: CrossBranchSurface): CrossBranchContextSettings {
19
+ const defaults = defaultSettings(surface)
20
+ if (typeof window === 'undefined') return defaults
21
+ const raw = window.localStorage.getItem(storageKey(surface))
22
+ if (!raw) return defaults
23
+ try {
24
+ const parsed = JSON.parse(raw) as Partial<CrossBranchContextSettings>
25
+ return {
26
+ enabled: parsed.enabled ?? defaults.enabled,
27
+ depth: typeof parsed.depth === 'number' ? parsed.depth : CROSS_BRANCH_DEPTH_ALL,
28
+ }
29
+ } catch {
30
+ return defaults
31
+ }
32
+ }
33
+
34
+ export function useCrossBranchContextSettings(surface: CrossBranchSurface) {
35
+ const [settings, setSettings] = useState<CrossBranchContextSettings>(() => readSettings(surface))
36
+
37
+ useEffect(() => {
38
+ setSettings(readSettings(surface))
39
+ }, [surface])
40
+
41
+ useEffect(() => {
42
+ if (typeof window === 'undefined') return
43
+ window.localStorage.setItem(storageKey(surface), JSON.stringify(settings))
44
+ }, [surface, settings])
45
+
46
+ const setEnabled = useCallback((enabled: boolean) => {
47
+ setSettings((prev) => ({ ...prev, enabled }))
48
+ }, [])
49
+
50
+ const setDepth = useCallback((depth: number) => {
51
+ setSettings((prev) => ({ ...prev, depth }))
52
+ }, [])
53
+
54
+ return useMemo(() => ({
55
+ settings,
56
+ setEnabled,
57
+ setDepth,
58
+ }), [settings, setEnabled, setDepth])
59
+ }
@@ -0,0 +1,71 @@
1
+ import { useEffect, useState } from 'react'
2
+ import { api } from '../api/client'
3
+ import type { ExploreData } from '../types'
4
+ import { buildWorkspaceGraphSnapshot, removeConnectorFromSnapshot, removePlacementFromSnapshot, upsertConnectorInSnapshot, upsertPlacementInSnapshot } from './graph'
5
+ import type { WorkspaceGraphSnapshot } from './types'
6
+
7
+ let cachedSnapshot: WorkspaceGraphSnapshot | null = null
8
+ let inflightLoad: Promise<WorkspaceGraphSnapshot> | null = null
9
+ const listeners = new Set<(snapshot: WorkspaceGraphSnapshot | null) => void>()
10
+
11
+ function publish(snapshot: WorkspaceGraphSnapshot | null) {
12
+ cachedSnapshot = snapshot
13
+ for (const listener of listeners) listener(snapshot)
14
+ }
15
+
16
+ export function primeWorkspaceGraphSnapshot(data: ExploreData) {
17
+ publish(buildWorkspaceGraphSnapshot(data))
18
+ }
19
+
20
+ export async function loadWorkspaceGraphSnapshot(force = false): Promise<WorkspaceGraphSnapshot> {
21
+ if (!force && cachedSnapshot) return cachedSnapshot
22
+ if (!force && inflightLoad) return inflightLoad
23
+ inflightLoad = api.explore.load().then((data) => {
24
+ const snapshot = buildWorkspaceGraphSnapshot(data)
25
+ publish(snapshot)
26
+ inflightLoad = null
27
+ return snapshot
28
+ }).catch((error) => {
29
+ inflightLoad = null
30
+ throw error
31
+ })
32
+ return inflightLoad
33
+ }
34
+
35
+ export function subscribeWorkspaceGraphSnapshot(listener: (snapshot: WorkspaceGraphSnapshot | null) => void) {
36
+ listeners.add(listener)
37
+ return () => { listeners.delete(listener) }
38
+ }
39
+
40
+ export function useWorkspaceGraphSnapshot(enabled = true) {
41
+ const [snapshot, setSnapshot] = useState<WorkspaceGraphSnapshot | null>(cachedSnapshot)
42
+
43
+ useEffect(() => subscribeWorkspaceGraphSnapshot(setSnapshot), [])
44
+
45
+ useEffect(() => {
46
+ if (!enabled) return
47
+ if (cachedSnapshot) {
48
+ setSnapshot(cachedSnapshot)
49
+ return
50
+ }
51
+ void loadWorkspaceGraphSnapshot().catch(() => { /* intentionally empty */ })
52
+ }, [enabled])
53
+
54
+ return snapshot
55
+ }
56
+
57
+ export function upsertConnectorGraphSnapshot(connector: Parameters<typeof upsertConnectorInSnapshot>[1]) {
58
+ publish(upsertConnectorInSnapshot(cachedSnapshot, connector))
59
+ }
60
+
61
+ export function removeConnectorGraphSnapshot(viewId: number, connectorId: number) {
62
+ publish(removeConnectorFromSnapshot(cachedSnapshot, viewId, connectorId))
63
+ }
64
+
65
+ export function upsertPlacementGraphSnapshot(viewId: number, placement: Parameters<typeof upsertPlacementInSnapshot>[2]) {
66
+ publish(upsertPlacementInSnapshot(cachedSnapshot, viewId, placement))
67
+ }
68
+
69
+ export function removePlacementGraphSnapshot(viewId: number, elementId: number) {
70
+ publish(removePlacementFromSnapshot(cachedSnapshot, viewId, elementId))
71
+ }
@@ -0,0 +1,102 @@
1
+ import type { Connector, ExploreData, PlacedElement, ViewTreeNode } from '../types'
2
+
3
+ export const CROSS_BRANCH_DEPTH_ALL = 5
4
+ export const CROSS_BRANCH_DEPTH_MIN = 1
5
+ export const CROSS_BRANCH_DEPTH_MAX = CROSS_BRANCH_DEPTH_ALL
6
+
7
+ export type CrossBranchSurface = 'editor' | 'zui' | 'zui-shared'
8
+
9
+ export interface CrossBranchContextSettings {
10
+ enabled: boolean
11
+ depth: number
12
+ }
13
+
14
+ export interface GraphPlacementRef {
15
+ viewId: number
16
+ viewName: string
17
+ element: PlacedElement
18
+ }
19
+
20
+ export interface WorkspaceGraphSnapshot {
21
+ source: ExploreData
22
+ tree: ViewTreeNode[]
23
+ views: Record<number, { view: ViewTreeNode; placements: PlacedElement[]; connectors: Connector[] }>
24
+ viewById: Record<number, ViewTreeNode>
25
+ placementsByViewId: Record<number, PlacedElement[]>
26
+ connectorsByViewId: Record<number, Connector[]>
27
+ placementsByElementId: Record<number, GraphPlacementRef[]>
28
+ childViewIdByOwnerElementId: Record<number, number>
29
+ descendantsByViewId: Record<number, number[]>
30
+ ancestorsByViewId: Record<number, number[]>
31
+ }
32
+
33
+ export interface ProxyEndpoint {
34
+ actualElementId: number
35
+ actualElementName: string
36
+ anchorElementId: number
37
+ anchorElementName: string
38
+ anchorViewId: number | null
39
+ anchorViewName: string | null
40
+ placementViewId: number | null
41
+ placementViewName: string | null
42
+ depth: number
43
+ externalToView: boolean
44
+ currentBranchElementId: number | null
45
+ commonAncestorViewId: number | null
46
+ commonAncestorViewName: string | null
47
+ mergeAncestorElementId?: number | null
48
+ contextPathElementIds?: number[]
49
+ }
50
+
51
+ export interface ProxyConnectorLeaf {
52
+ connector: Connector
53
+ ownerViewId: number
54
+ ownerViewName: string
55
+ source: ProxyEndpoint
56
+ target: ProxyEndpoint
57
+ }
58
+
59
+ export interface ProxyConnectorDetails {
60
+ key: string
61
+ label: string
62
+ count: number
63
+ sourceAnchorId: string
64
+ targetAnchorId: string
65
+ sourceAnchorName: string
66
+ targetAnchorName: string
67
+ ownerViewIds: number[]
68
+ ownerViewNames: string[]
69
+ connectors: ProxyConnectorLeaf[]
70
+ }
71
+
72
+ export interface AggregatedProxyConnector {
73
+ key: string
74
+ sourceAnchorId: string
75
+ targetAnchorId: string
76
+ direction: string
77
+ style: string
78
+ label: string
79
+ count: number
80
+ sourceElementId: number | null
81
+ targetElementId: number | null
82
+ details: ProxyConnectorDetails
83
+ }
84
+
85
+ export interface ProxyContextNode {
86
+ id: string
87
+ anchorElementId: number
88
+ name: string
89
+ sortLevel: number
90
+ placementViewId: number | null
91
+ kind: string | null
92
+ description: string | null
93
+ technology: string | null
94
+ logoUrl: string | null
95
+ technologyConnectors: PlacedElement['technology_connectors']
96
+ ownerViewIds: number[]
97
+ ownerViewNames: string[]
98
+ commonAncestorViewId: number | null
99
+ commonAncestorViewName: string | null
100
+ currentBranchElementId: number | null
101
+ connectorCount: number
102
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Demo entry point.
3
+ * Overrides the real `api` singleton with localStorage-backed implementations
4
+ * and patches window.history to redirect /views/:id → /demo/:id, all for the
5
+ * lifetime of this component. Restores everything on unmount.
6
+ * No auth required; served at /demo and /demo/:id routes.
7
+ */
8
+
9
+ import React, { useEffect, useState } from 'react'
10
+ import { useNavigate } from 'react-router-dom'
11
+ import { Box } from '@chakra-ui/react'
12
+ import { api } from '../api/client'
13
+ import ViewEditor from '../pages/ViewEditor'
14
+ import { HeaderProvider } from '../components/HeaderContext'
15
+ import { ThemeProvider } from '../context/ThemeContext'
16
+ import { demoApi, initDemoStore } from './store'
17
+ import { DEMO_VIEW_EDITOR_OPTIONS } from './viewEditor'
18
+
19
+ // ── Override helpers ──────────────────────────────────────────────────────────
20
+
21
+ type ApiOverride = Record<string, unknown>
22
+
23
+ /**
24
+ * Swap api methods + patch window.history so any /views/:id navigation is
25
+ * silently rewritten to /demo/:id before React Router processes it.
26
+ * Returns a function that restores everything.
27
+ */
28
+ function applyOverrides(): () => void {
29
+ const originals: [obj: ApiOverride, key: string, original: unknown][] = []
30
+
31
+ function swap(obj: ApiOverride, key: string, replacement: unknown) {
32
+ originals.push([obj, key, obj[key]])
33
+ obj[key] = replacement
34
+ }
35
+
36
+ // elements
37
+ const realElements = api.elements as unknown as ApiOverride
38
+ const demoElements = demoApi.elements as ApiOverride
39
+ for (const key of ['list', 'get', 'create', 'update', 'delete', 'placements']) {
40
+ swap(realElements, key, demoElements[key])
41
+ }
42
+
43
+ // workspace.elements
44
+ const realWsElements = (api.workspace as unknown as ApiOverride).elements as ApiOverride
45
+ const demoWsElements = demoApi.workspace.elements as ApiOverride
46
+ for (const key of ['list', 'get', 'create', 'update', 'delete', 'placements']) {
47
+ swap(realWsElements, key, demoWsElements[key])
48
+ }
49
+
50
+ // workspace.orgs.tagColors
51
+ const realTagColors = ((api.workspace as unknown as ApiOverride).orgs as ApiOverride).tagColors as ApiOverride
52
+ const demoTagColors = demoApi.workspace.orgs.tagColors as ApiOverride
53
+ for (const key of ['list', 'set']) {
54
+ swap(realTagColors, key, demoTagColors[key])
55
+ }
56
+
57
+ // workspace.views top-level methods + nested namespaces
58
+ const realViews = (api.workspace as unknown as ApiOverride).views as ApiOverride
59
+ const demoViews = demoApi.workspace.views as ApiOverride
60
+ for (const key of ['list', 'get', 'content', 'tree', 'create', 'update', 'delete', 'thumbnail', 'rename', 'setLevel', 'reparent']) {
61
+ swap(realViews, key, demoViews[key])
62
+ }
63
+ for (const ns of ['placements', 'layers', 'reactions', 'threads']) {
64
+ const realNs = realViews[ns] as ApiOverride
65
+ const demoNs = demoViews[ns] as ApiOverride
66
+ for (const key of Object.keys(demoNs)) {
67
+ swap(realNs, key, demoNs[key])
68
+ }
69
+ }
70
+
71
+ // workspace.connectors
72
+ const realConnectors = (api.workspace as unknown as ApiOverride).connectors as ApiOverride
73
+ const demoConnectors = demoApi.workspace.connectors as ApiOverride
74
+ for (const key of ['list', 'create', 'update', 'delete']) {
75
+ swap(realConnectors, key, demoConnectors[key])
76
+ }
77
+
78
+ // explore.load (cross-branch graph snapshot)
79
+ const realExplore = (api as unknown as ApiOverride).explore as ApiOverride
80
+ swap(realExplore, 'load', demoApi.explore.load)
81
+
82
+ // ── Patch window.history so /views/:id → /demo/:id before React Router sees it
83
+ const origPush = window.history.pushState.bind(window.history)
84
+ const origReplace = window.history.replaceState.bind(window.history)
85
+
86
+ function rewriteUrl(url: string | URL | null | undefined): string | URL | null | undefined {
87
+ if (typeof url !== 'string') return url
88
+ return url.replace(/\/views\/(\d+)/, '/demo/$1')
89
+ }
90
+
91
+ window.history.pushState = (state, title, url) => origPush(state, title, rewriteUrl(url))
92
+ window.history.replaceState = (state, title, url) => origReplace(state, title, rewriteUrl(url))
93
+
94
+ return () => {
95
+ for (const [obj, key, original] of originals) {
96
+ obj[key] = original
97
+ }
98
+ window.history.pushState = origPush
99
+ window.history.replaceState = origReplace
100
+ }
101
+ }
102
+
103
+ // ── Inner component overrides applied before children mount ─────────────────
104
+
105
+ function DemoApp({
106
+ revealProgress,
107
+ }: {
108
+ revealProgress: number
109
+ }) {
110
+ // useState initializer runs synchronously during the first render of this
111
+ // component instance, before any child component mounts or any hook effect
112
+ // runs. This guarantees api overrides are in place for ViewEditor's first fetch.
113
+ const [restore] = useState<() => void>(() => {
114
+ initDemoStore()
115
+ return applyOverrides()
116
+ })
117
+
118
+ useEffect(() => restore, [restore])
119
+
120
+ return (
121
+ <ViewEditor
122
+ demoOptions={{ ...DEMO_VIEW_EDITOR_OPTIONS, revealProgress }}
123
+ />
124
+ )
125
+ }
126
+
127
+ // ── DemoNavigator: redirects bare /demo to the first root view ────────────────
128
+
129
+ export function DemoNavigator() {
130
+ const navigate = useNavigate()
131
+
132
+ useEffect(() => {
133
+ // Call demoApi directly no need to apply global overrides here, which
134
+ // would otherwise be cleaned up after DemoApp mounts and clobber its patches.
135
+ initDemoStore()
136
+ demoApi.workspace.views.tree().then((tree) => {
137
+ const root = tree.find((v) => v.parent_view_id === null)
138
+ navigate(root ? `/demo/${root.id}` : '/demo/1', { replace: true })
139
+ }).catch(() => navigate('/demo/1', { replace: true }))
140
+ }, [navigate])
141
+
142
+ return null
143
+ }
144
+
145
+ // ── DemoPage ──────────────────────────────────────────────────────────────────
146
+
147
+ export default function DemoPage() {
148
+ const [revealProgress, setRevealProgress] = useState(() => (window.self === window.top ? 1 : 0))
149
+
150
+ useEffect(() => {
151
+ if (window.self === window.top) {
152
+ setRevealProgress(1)
153
+ return
154
+ }
155
+
156
+ const handleMessage = (event: MessageEvent) => {
157
+ const data = event.data as { type?: unknown; progress?: unknown } | null
158
+ if (!data || data.type !== 'tldiagram-demo-progress') return
159
+
160
+ const nextProgress = Number(data.progress)
161
+ if (!Number.isFinite(nextProgress)) return
162
+
163
+ setRevealProgress(Math.max(0, Math.min(1, nextProgress)))
164
+ }
165
+
166
+ window.addEventListener('message', handleMessage)
167
+ return () => window.removeEventListener('message', handleMessage)
168
+ }, [])
169
+
170
+ return (
171
+ <ThemeProvider
172
+ storagePrefix="diag:demo"
173
+ defaultAccent="#63b3ed"
174
+ defaultBackground="#0d121e"
175
+ defaultElementColor="#2d3748"
176
+ >
177
+ <Box minH="100vh" bg="var(--bg-canvas)" style={{ '--editor-top-offset': '0px' } as React.CSSProperties}>
178
+ <HeaderProvider>
179
+ <DemoApp revealProgress={revealProgress} />
180
+ </HeaderProvider>
181
+ </Box>
182
+ </ThemeProvider>
183
+ )
184
+ }
@@ -0,0 +1,67 @@
1
+ import type { LibraryElement, PlacedElement, Connector, ViewTreeNode, ViewLayer } from '../types'
2
+
3
+ const NOW = new Date().toISOString()
4
+
5
+ export const DEMO_ELEMENTS: LibraryElement[] = [
6
+ { id: 1, name: 'User', kind: 'person', description: 'End user of the system', technology: null, url: null, logo_url: "https://tldiagram.com/app/icons/azure-users.png", technology_connectors: [], tags: ['external'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
7
+ { id: 2, name: 'Web App', kind: 'service', description: 'React single-page application', technology: 'React', url: null, logo_url: "https://tldiagram.com/app/icons/react.png", technology_connectors: [], tags: ['frontend'], has_view: true, view_label: null, created_at: NOW, updated_at: NOW },
8
+ { id: 3, name: 'API Gateway', kind: 'service', description: 'REST API gateway', technology: 'Golang', url: null, logo_url: "https://tldiagram.com/app/icons/golang.png", technology_connectors: [], tags: ['backend'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
9
+ { id: 4, name: 'Auth Service', kind: 'service', description: 'Handles authentication & sessions', technology: 'Go', url: null, logo_url: "https://tldiagram.com/app/icons/golang.png", technology_connectors: [], tags: ['backend'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
10
+ { id: 5, name: 'Frontend', kind: 'service', description: 'React frontend bundle', technology: 'React', url: null, logo_url: null, technology_connectors: [], tags: ['frontend'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
11
+ { id: 6, name: 'Backend', kind: 'service', description: 'Core business logic API', technology: 'Go', url: null, logo_url: "https://tldiagram.com/app/icons/golang.png", technology_connectors: [], tags: ['backend'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
12
+ { id: 7, name: 'PostgreSQL', kind: 'database', description: 'Primary relational database', technology: 'PostgreSQL', url: null, logo_url: null, technology_connectors: [], tags: ['data'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
13
+ { id: 8, name: 'Redis Cache', kind: 'database', description: 'In-memory cache and session store', technology: 'Redis', url: null, logo_url: null, technology_connectors: [], tags: ['data'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
14
+ { id: 9, name: 'CDN', kind: 'service', description: 'Content delivery network', technology: 'Cloudflare', url: null, logo_url: null, technology_connectors: [], tags: ['external', 'infrastructure'], has_view: false, view_label: null, created_at: NOW, updated_at: NOW },
15
+ ]
16
+
17
+ export const DEMO_VIEWS: ViewTreeNode[] = [
18
+ {
19
+ id: 1, name: 'System Context', description: 'Top-level system context view', level_label: 'Context', level: 1, depth: 0,
20
+ owner_element_id: null, parent_view_id: null, created_at: NOW, updated_at: NOW, children: [
21
+ {
22
+ id: 2, name: 'Web App – Containers', description: 'Container-level view of the Web App', level_label: 'Container', level: 2, depth: 1,
23
+ owner_element_id: 2, parent_view_id: 1, created_at: NOW, updated_at: NOW, children: [],
24
+ },
25
+ ],
26
+ },
27
+ ]
28
+
29
+ type ViewPlacements = Record<number, PlacedElement[]>
30
+ type ViewConnectors = Record<number, Connector[]>
31
+
32
+ export const DEMO_PLACEMENTS: ViewPlacements = {
33
+ 1: [
34
+ { id: 101, view_id: 1, element_id: 1, position_x: 80, position_y: 200, name: 'User', kind: 'person', description: 'End user of the system', technology: null, url: null, logo_url: "https://tldiagram.com/app/icons/azure-users.png", technology_connectors: [], tags: ['external'], has_view: false, view_label: null },
35
+ { id: 102, view_id: 1, element_id: 2, position_x: 380, position_y: 200, name: 'Web App', kind: 'service', description: 'React single-page application', technology: 'React', url: null, logo_url: "https://tldiagram.com/app/icons/react.png", technology_connectors: [], tags: ['frontend'], has_view: true, view_label: null },
36
+ { id: 103, view_id: 1, element_id: 3, position_x: 680, position_y: 200, name: 'API Gateway', kind: 'service', description: 'REST API gateway', technology: 'Go', url: null, logo_url: "https://tldiagram.com/app/icons/golang.png", technology_connectors: [], tags: ['backend'], has_view: false, view_label: null },
37
+ { id: 104, view_id: 1, element_id: 4, position_x: 380, position_y: 400, name: 'Auth Service', kind: 'service', description: 'Handles authentication & sessions', technology: 'Auth0', url: null, logo_url: "https://tldiagram.com/app/icons/auth0.png", technology_connectors: [], tags: ['backend'], has_view: false, view_label: null },
38
+ { id: 105, view_id: 1, element_id: 9, position_x: 380, position_y: 0, name: 'CDN', kind: 'service', description: 'Content delivery network', technology: 'Cloudflare', url: null, logo_url: "https://tldiagram.com/app/icons/cloudflare.png", technology_connectors: [], tags: ['external', 'infrastructure'], has_view: false, view_label: null },
39
+ { id: 106, view_id: 1, element_id: 10, position_x: 680, position_y: 0, name: 'Stripe', kind: 'service', description: 'Payment', technology: 'Stripe', url: null, logo_url: "https://tldiagram.com/app/icons/stripe.png", technology_connectors: [], tags: ['external', 'billing'], has_view: false, view_label: null },
40
+ ],
41
+ 2: [
42
+ { id: 201, view_id: 2, element_id: 5, position_x: 80, position_y: 200, name: 'Frontend', kind: 'service', description: 'React frontend bundle', technology: 'React', url: null, logo_url: "https://tldiagram.com/app/icons/react.png", technology_connectors: [], tags: ['frontend'], has_view: false, view_label: null },
43
+ { id: 202, view_id: 2, element_id: 6, position_x: 380, position_y: 200, name: 'Backend', kind: 'service', description: 'Core business logic API', technology: 'Go', url: null, logo_url: "https://tldiagram.com/app/icons/golang.png", technology_connectors: [], tags: ['backend'], has_view: false, view_label: null },
44
+ { id: 203, view_id: 2, element_id: 7, position_x: 680, position_y: 200, name: 'PostgreSQL', kind: 'database', description: 'Primary relational database', technology: 'PostgreSQL', url: null, logo_url: "https://tldiagram.com/app/icons/postgresql.png", technology_connectors: [], tags: ['data'], has_view: false, view_label: null },
45
+ { id: 204, view_id: 2, element_id: 8, position_x: 680, position_y: 400, name: 'Redis Cache', kind: 'database', description: 'In-memory cache and session store', technology: 'Redis', url: null, logo_url: "https://tldiagram.com/app/icons/redis.png", technology_connectors: [], tags: ['data'], has_view: false, view_label: null },
46
+ ],
47
+ }
48
+
49
+ export const DEMO_CONNECTORS: ViewConnectors = {
50
+ 1: [
51
+ { id: 1001, view_id: 1, source_element_id: 1, target_element_id: 2, label: 'Uses', description: null, relationship: null, direction: 'forward', style: 'bezier', url: null, source_handle: 'right', target_handle: 'left', created_at: NOW, updated_at: NOW },
52
+ { id: 1002, view_id: 1, source_element_id: 2, target_element_id: 3, label: 'API calls', description: null, relationship: null, direction: 'forward', style: 'bezier', url: null, source_handle: 'right', target_handle: 'left', created_at: NOW, updated_at: NOW },
53
+ { id: 1003, view_id: 1, source_element_id: 2, target_element_id: 4, label: 'Auth', description: null, relationship: null, direction: 'forward', style: 'bezier', url: null, source_handle: 'bottom', target_handle: 'top', created_at: NOW, updated_at: NOW },
54
+ { id: 1004, view_id: 1, source_element_id: 2, target_element_id: 9, label: 'Serves via', description: null, relationship: null, direction: 'backward', style: 'bezier', url: null, source_handle: 'top', target_handle: 'bottom', created_at: NOW, updated_at: NOW },
55
+ { id: 1005, view_id: 1, source_element_id: 3, target_element_id: 10, label: 'Billing', description: null, relationship: null, direction: 'both', style: 'bezier', url: null, source_handle: 'top', target_handle: 'bottom', created_at: NOW, updated_at: NOW },
56
+ ],
57
+ 2: [
58
+ { id: 2001, view_id: 2, source_element_id: 5, target_element_id: 6, label: 'HTTP/JSON', description: null, relationship: null, direction: 'forward', style: 'bezier', url: null, source_handle: 'right', target_handle: 'left', created_at: NOW, updated_at: NOW },
59
+ { id: 2002, view_id: 2, source_element_id: 6, target_element_id: 7, label: 'Reads / Writes', description: null, relationship: null, direction: 'forward', style: 'bezier', url: null, source_handle: 'right', target_handle: 'left', created_at: NOW, updated_at: NOW },
60
+ { id: 2003, view_id: 2, source_element_id: 6, target_element_id: 8, label: 'Cache', description: null, relationship: null, direction: 'forward', style: 'bezier', url: null, source_handle: 'bottom', target_handle: 'left', created_at: NOW, updated_at: NOW },
61
+ ],
62
+ }
63
+
64
+ export const DEMO_LAYERS: Record<number, ViewLayer[]> = {
65
+ 1: [],
66
+ 2: [],
67
+ }