@dxos/react-ui-canvas 0.13.0 → 0.14.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 (341) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/index.mjs +9044 -1135
  3. package/dist/lib/index.mjs.map +1 -1
  4. package/dist/types/src/components/About/About.d.ts +13 -0
  5. package/dist/types/src/components/About/About.d.ts.map +1 -0
  6. package/dist/types/src/components/About/About.stories.d.ts +7 -0
  7. package/dist/types/src/components/About/About.stories.d.ts.map +1 -0
  8. package/dist/types/src/components/About/index.d.ts +2 -0
  9. package/dist/types/src/components/About/index.d.ts.map +1 -0
  10. package/dist/types/src/components/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  11. package/dist/types/src/components/ControlFrame/ControlFrame.d.ts +8 -2
  12. package/dist/types/src/components/ControlFrame/ControlFrame.d.ts.map +1 -1
  13. package/dist/types/src/components/Layers/Layers.d.ts +30 -0
  14. package/dist/types/src/components/Layers/Layers.d.ts.map +1 -0
  15. package/dist/types/src/components/Layers/Layers.stories.d.ts +11 -0
  16. package/dist/types/src/components/Layers/Layers.stories.d.ts.map +1 -0
  17. package/dist/types/src/components/Layers/index.d.ts +2 -0
  18. package/dist/types/src/components/Layers/index.d.ts.map +1 -0
  19. package/dist/types/src/components/Palette/Palette.d.ts +20 -4
  20. package/dist/types/src/components/Palette/Palette.d.ts.map +1 -1
  21. package/dist/types/src/components/Palette/Palette.stories.d.ts +22 -0
  22. package/dist/types/src/components/Palette/Palette.stories.d.ts.map +1 -0
  23. package/dist/types/src/components/PartEditor/PartEditor.d.ts.map +1 -1
  24. package/dist/types/src/components/Properties/AlignField.d.ts +23 -0
  25. package/dist/types/src/components/Properties/AlignField.d.ts.map +1 -0
  26. package/dist/types/src/components/Properties/ClassField.d.ts +23 -0
  27. package/dist/types/src/components/Properties/ClassField.d.ts.map +1 -0
  28. package/dist/types/src/components/Properties/FontField.d.ts +7 -0
  29. package/dist/types/src/components/Properties/FontField.d.ts.map +1 -0
  30. package/dist/types/src/components/Properties/LayerField.d.ts +17 -0
  31. package/dist/types/src/components/Properties/LayerField.d.ts.map +1 -0
  32. package/dist/types/src/components/Properties/Properties.d.ts +27 -3
  33. package/dist/types/src/components/Properties/Properties.d.ts.map +1 -1
  34. package/dist/types/src/components/Properties/Properties.stories.d.ts +20 -0
  35. package/dist/types/src/components/Properties/Properties.stories.d.ts.map +1 -0
  36. package/dist/types/src/components/Properties/SceneField.d.ts +8 -0
  37. package/dist/types/src/components/Properties/SceneField.d.ts.map +1 -0
  38. package/dist/types/src/components/Properties/StyleGrid.d.ts +15 -5
  39. package/dist/types/src/components/Properties/StyleGrid.d.ts.map +1 -1
  40. package/dist/types/src/components/Properties/StyleGrid.stories.d.ts +7 -0
  41. package/dist/types/src/components/Properties/StyleGrid.stories.d.ts.map +1 -0
  42. package/dist/types/src/components/SceneLayer/SceneLayer.d.ts +31 -7
  43. package/dist/types/src/components/SceneLayer/SceneLayer.d.ts.map +1 -1
  44. package/dist/types/src/components/SceneView/Dock.d.ts +22 -0
  45. package/dist/types/src/components/SceneView/Dock.d.ts.map +1 -0
  46. package/dist/types/src/components/SceneView/Dock.stories.d.ts +15 -0
  47. package/dist/types/src/components/SceneView/Dock.stories.d.ts.map +1 -0
  48. package/dist/types/src/components/SceneView/SceneView.d.ts +33 -7
  49. package/dist/types/src/components/SceneView/SceneView.d.ts.map +1 -1
  50. package/dist/types/src/components/SceneView/SceneView.stories.d.ts +16 -6
  51. package/dist/types/src/components/SceneView/SceneView.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/SceneView/SceneViewContext.d.ts +36 -4
  53. package/dist/types/src/components/SceneView/SceneViewContext.d.ts.map +1 -1
  54. package/dist/types/src/components/SceneView/Scored.stories.d.ts +4 -4
  55. package/dist/types/src/components/SceneView/Scored.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/SceneView/usePointerMachine.d.ts +3 -1
  57. package/dist/types/src/components/SceneView/usePointerMachine.d.ts.map +1 -1
  58. package/dist/types/src/components/SceneView/useSceneCamera.d.ts +2 -2
  59. package/dist/types/src/components/SceneView/useSceneCamera.d.ts.map +1 -1
  60. package/dist/types/src/components/SceneView/useSceneClipboard.d.ts.map +1 -1
  61. package/dist/types/src/components/SceneView/useSceneKeys.d.ts.map +1 -1
  62. package/dist/types/src/components/SceneView/useSceneNavigation.d.ts +7 -4
  63. package/dist/types/src/components/SceneView/useSceneNavigation.d.ts.map +1 -1
  64. package/dist/types/src/components/Toolbar/Toolbar.d.ts +2 -0
  65. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  66. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  67. package/dist/types/src/components/index.d.ts +2 -0
  68. package/dist/types/src/components/index.d.ts.map +1 -1
  69. package/dist/types/src/hooks/useWheel.d.ts +5 -0
  70. package/dist/types/src/hooks/useWheel.d.ts.map +1 -1
  71. package/dist/types/src/index.d.ts +4 -1
  72. package/dist/types/src/index.d.ts.map +1 -1
  73. package/dist/types/src/model/atoms.d.ts +21 -3
  74. package/dist/types/src/model/atoms.d.ts.map +1 -1
  75. package/dist/types/src/model/projection.d.ts.map +1 -1
  76. package/dist/types/src/model/projections/constrained.d.ts +2 -1
  77. package/dist/types/src/model/projections/constrained.d.ts.map +1 -1
  78. package/dist/types/src/model/projections/dynamic.d.ts.map +1 -1
  79. package/dist/types/src/model/projections/lattice.d.ts.map +1 -1
  80. package/dist/types/src/model/registry.d.ts +21 -3
  81. package/dist/types/src/model/registry.d.ts.map +1 -1
  82. package/dist/types/src/model/store.d.ts +10 -2
  83. package/dist/types/src/model/store.d.ts.map +1 -1
  84. package/dist/types/src/model/types.d.ts +699 -338
  85. package/dist/types/src/model/types.d.ts.map +1 -1
  86. package/dist/types/src/playwright/SceneManager.d.ts +1 -1
  87. package/dist/types/src/playwright/SceneManager.d.ts.map +1 -1
  88. package/dist/types/src/utils/builder.d.ts +22 -41
  89. package/dist/types/src/utils/builder.d.ts.map +1 -1
  90. package/dist/types/src/utils/camera.d.ts +19 -10
  91. package/dist/types/src/utils/camera.d.ts.map +1 -1
  92. package/dist/types/src/utils/clipboard.d.ts +4 -2
  93. package/dist/types/src/utils/clipboard.d.ts.map +1 -1
  94. package/dist/types/src/utils/diagram.d.ts.map +1 -1
  95. package/dist/types/src/utils/group.d.ts +14 -0
  96. package/dist/types/src/utils/group.d.ts.map +1 -0
  97. package/dist/types/src/utils/group.test.d.ts +2 -0
  98. package/dist/types/src/utils/group.test.d.ts.map +1 -0
  99. package/dist/types/src/utils/gutter-route.d.ts +7 -0
  100. package/dist/types/src/utils/gutter-route.d.ts.map +1 -1
  101. package/dist/types/src/utils/hit.d.ts +3 -20
  102. package/dist/types/src/utils/hit.d.ts.map +1 -1
  103. package/dist/types/src/utils/index.d.ts +3 -0
  104. package/dist/types/src/utils/index.d.ts.map +1 -1
  105. package/dist/types/src/utils/lattice.d.ts +5 -0
  106. package/dist/types/src/utils/lattice.d.ts.map +1 -1
  107. package/dist/types/src/utils/layers.d.ts +35 -0
  108. package/dist/types/src/utils/layers.d.ts.map +1 -0
  109. package/dist/types/src/utils/layers.test.d.ts +2 -0
  110. package/dist/types/src/utils/layers.test.d.ts.map +1 -0
  111. package/dist/types/src/utils/parts.d.ts +25 -9
  112. package/dist/types/src/utils/parts.d.ts.map +1 -1
  113. package/dist/types/src/utils/ports.d.ts +2 -0
  114. package/dist/types/src/utils/ports.d.ts.map +1 -1
  115. package/dist/types/src/utils/properties.d.ts +4 -3
  116. package/dist/types/src/utils/properties.d.ts.map +1 -1
  117. package/dist/types/src/utils/route.d.ts +5 -0
  118. package/dist/types/src/utils/route.d.ts.map +1 -1
  119. package/dist/types/src/utils/scenes.d.ts +14 -0
  120. package/dist/types/src/utils/scenes.d.ts.map +1 -0
  121. package/dist/types/src/utils/scenes.test.d.ts +2 -0
  122. package/dist/types/src/utils/scenes.test.d.ts.map +1 -0
  123. package/dist/types/src/utils/shapes.d.ts +23 -9
  124. package/dist/types/src/utils/shapes.d.ts.map +1 -1
  125. package/dist/types/src/utils/style.d.ts +29 -6
  126. package/dist/types/src/utils/style.d.ts.map +1 -1
  127. package/dist/types/src/utils/style.test.d.ts +2 -0
  128. package/dist/types/src/utils/style.test.d.ts.map +1 -0
  129. package/dist/types/src/utils/testing.d.ts +2 -2
  130. package/dist/types/src/utils/testing.d.ts.map +1 -1
  131. package/dist/types/src/utils/undo.d.ts +15 -4
  132. package/dist/types/src/utils/undo.d.ts.map +1 -1
  133. package/dist/types/tsconfig.tsbuildinfo +1 -1
  134. package/package.json +20 -26
  135. package/src/components/About/About.stories.tsx +32 -0
  136. package/src/components/About/About.tsx +38 -0
  137. package/src/components/About/index.ts +5 -0
  138. package/src/components/Breadcrumbs/Breadcrumbs.tsx +17 -3
  139. package/src/components/ControlFrame/ControlFrame.tsx +138 -82
  140. package/src/components/Grid/Grid.stories.tsx +1 -1
  141. package/src/components/Layers/Layers.stories.tsx +131 -0
  142. package/src/components/Layers/Layers.tsx +216 -0
  143. package/src/components/Layers/index.ts +5 -0
  144. package/src/components/Palette/Palette.stories.tsx +135 -0
  145. package/src/components/Palette/Palette.tsx +230 -39
  146. package/src/components/PartEditor/PartEditor.tsx +4 -3
  147. package/src/components/Properties/AlignField.tsx +117 -0
  148. package/src/components/Properties/ClassField.tsx +44 -0
  149. package/src/components/Properties/FontField.tsx +73 -0
  150. package/src/components/Properties/LayerField.tsx +61 -0
  151. package/src/components/Properties/Properties.stories.tsx +113 -0
  152. package/src/components/Properties/Properties.tsx +240 -60
  153. package/src/components/Properties/SceneField.tsx +22 -0
  154. package/src/components/Properties/StyleGrid.stories.tsx +50 -0
  155. package/src/components/Properties/StyleGrid.tsx +54 -26
  156. package/src/components/SceneLayer/SceneLayer.tsx +497 -188
  157. package/src/components/SceneView/Constrained.stories.tsx +1 -1
  158. package/src/components/SceneView/Dock.stories.tsx +95 -0
  159. package/src/components/SceneView/Dock.tsx +146 -0
  160. package/src/components/SceneView/Dynamic.stories.tsx +1 -1
  161. package/src/components/SceneView/SceneView.stories.tsx +170 -18
  162. package/src/components/SceneView/SceneView.tsx +565 -151
  163. package/src/components/SceneView/SceneViewContext.ts +23 -2
  164. package/src/components/SceneView/Scored.stories.tsx +11 -11
  165. package/src/components/SceneView/usePointerMachine.ts +80 -20
  166. package/src/components/SceneView/useSceneCamera.ts +15 -8
  167. package/src/components/SceneView/useSceneClipboard.ts +4 -0
  168. package/src/components/SceneView/useSceneKeys.ts +6 -4
  169. package/src/components/SceneView/useSceneNavigation.ts +44 -33
  170. package/src/components/Toolbar/Toolbar.stories.tsx +14 -15
  171. package/src/components/Toolbar/Toolbar.tsx +15 -4
  172. package/src/components/index.ts +2 -0
  173. package/src/hooks/useWheel.ts +35 -0
  174. package/src/index.ts +4 -3
  175. package/src/model/atoms.ts +27 -3
  176. package/src/model/projection.ts +5 -0
  177. package/src/model/projections/constrained.test.ts +18 -10
  178. package/src/model/projections/constrained.ts +19 -8
  179. package/src/model/projections/dynamic.ts +5 -2
  180. package/src/model/projections/lattice.ts +15 -3
  181. package/src/model/registry.test.ts +14 -9
  182. package/src/model/registry.ts +39 -34
  183. package/src/model/store.ts +12 -2
  184. package/src/model/types.ts +124 -36
  185. package/src/playwright/SceneManager.ts +2 -2
  186. package/src/playwright/create.spec.ts +5 -3
  187. package/src/playwright/demo.spec.ts +2 -2
  188. package/src/playwright/lattice.spec.ts +4 -5
  189. package/src/playwright/scene.spec.ts +27 -25
  190. package/src/utils/builder.test.ts +46 -9
  191. package/src/utils/builder.ts +42 -18
  192. package/src/utils/camera.test.ts +22 -51
  193. package/src/utils/camera.ts +39 -32
  194. package/src/utils/clipboard.test.ts +23 -2
  195. package/src/utils/clipboard.ts +8 -4
  196. package/src/utils/diagram.test.ts +3 -1
  197. package/src/utils/diagram.ts +3 -25
  198. package/src/utils/group.test.ts +69 -0
  199. package/src/utils/group.ts +94 -0
  200. package/src/utils/gutter-route.test.ts +49 -0
  201. package/src/utils/gutter-route.ts +142 -16
  202. package/src/utils/hit.test.ts +4 -38
  203. package/src/utils/hit.ts +4 -26
  204. package/src/utils/index.ts +3 -0
  205. package/src/utils/lattice.ts +7 -1
  206. package/src/utils/layers.test.ts +139 -0
  207. package/src/utils/layers.ts +175 -0
  208. package/src/utils/parts.test.ts +66 -32
  209. package/src/utils/parts.ts +63 -41
  210. package/src/utils/ports.ts +7 -4
  211. package/src/utils/properties.test.ts +23 -6
  212. package/src/utils/properties.ts +66 -16
  213. package/src/utils/route.test.ts +51 -2
  214. package/src/utils/route.ts +133 -23
  215. package/src/utils/scenes.test.ts +38 -0
  216. package/src/utils/scenes.ts +54 -0
  217. package/src/utils/shapes.test.ts +33 -8
  218. package/src/utils/shapes.ts +51 -35
  219. package/src/utils/style.test.ts +54 -0
  220. package/src/utils/style.ts +153 -40
  221. package/src/utils/testing.test.ts +3 -3
  222. package/src/utils/testing.ts +21 -30
  223. package/src/utils/undo.test.ts +25 -2
  224. package/src/utils/undo.ts +50 -13
  225. package/dist/lib/chunk-Grid.mjs +0 -99
  226. package/dist/lib/chunk-Grid.mjs.map +0 -1
  227. package/dist/lib/scene.mjs +0 -6835
  228. package/dist/lib/scene.mjs.map +0 -1
  229. package/dist/lib/types.mjs +0 -16
  230. package/dist/lib/types.mjs.map +0 -1
  231. package/dist/types/src/archive/components/Canvas/Canvas.d.ts +0 -15
  232. package/dist/types/src/archive/components/Canvas/Canvas.d.ts.map +0 -1
  233. package/dist/types/src/archive/components/Canvas/Canvas.stories.d.ts +0 -18
  234. package/dist/types/src/archive/components/Canvas/Canvas.stories.d.ts.map +0 -1
  235. package/dist/types/src/archive/components/Canvas/index.d.ts +0 -2
  236. package/dist/types/src/archive/components/Canvas/index.d.ts.map +0 -1
  237. package/dist/types/src/archive/components/CellGrid/CellGrid.d.ts +0 -21
  238. package/dist/types/src/archive/components/CellGrid/CellGrid.d.ts.map +0 -1
  239. package/dist/types/src/archive/components/CellGrid/CellGrid.stories.d.ts +0 -21
  240. package/dist/types/src/archive/components/CellGrid/CellGrid.stories.d.ts.map +0 -1
  241. package/dist/types/src/archive/components/CellGrid/headers/Ruler.d.ts +0 -15
  242. package/dist/types/src/archive/components/CellGrid/headers/Ruler.d.ts.map +0 -1
  243. package/dist/types/src/archive/components/CellGrid/headers/TrackHeader.d.ts +0 -19
  244. package/dist/types/src/archive/components/CellGrid/headers/TrackHeader.d.ts.map +0 -1
  245. package/dist/types/src/archive/components/CellGrid/headers/index.d.ts +0 -3
  246. package/dist/types/src/archive/components/CellGrid/headers/index.d.ts.map +0 -1
  247. package/dist/types/src/archive/components/CellGrid/index.d.ts +0 -6
  248. package/dist/types/src/archive/components/CellGrid/index.d.ts.map +0 -1
  249. package/dist/types/src/archive/components/CellGrid/input/index.d.ts +0 -3
  250. package/dist/types/src/archive/components/CellGrid/input/index.d.ts.map +0 -1
  251. package/dist/types/src/archive/components/CellGrid/input/pointer.d.ts +0 -33
  252. package/dist/types/src/archive/components/CellGrid/input/pointer.d.ts.map +0 -1
  253. package/dist/types/src/archive/components/CellGrid/input/wheel.d.ts +0 -14
  254. package/dist/types/src/archive/components/CellGrid/input/wheel.d.ts.map +0 -1
  255. package/dist/types/src/archive/components/CellGrid/render/index.d.ts +0 -3
  256. package/dist/types/src/archive/components/CellGrid/render/index.d.ts.map +0 -1
  257. package/dist/types/src/archive/components/CellGrid/render/overlay-layer.d.ts +0 -21
  258. package/dist/types/src/archive/components/CellGrid/render/overlay-layer.d.ts.map +0 -1
  259. package/dist/types/src/archive/components/CellGrid/render/static-layer.d.ts +0 -36
  260. package/dist/types/src/archive/components/CellGrid/render/static-layer.d.ts.map +0 -1
  261. package/dist/types/src/archive/components/CellGrid/state/atoms.d.ts +0 -23
  262. package/dist/types/src/archive/components/CellGrid/state/atoms.d.ts.map +0 -1
  263. package/dist/types/src/archive/components/CellGrid/state/index.d.ts +0 -4
  264. package/dist/types/src/archive/components/CellGrid/state/index.d.ts.map +0 -1
  265. package/dist/types/src/archive/components/CellGrid/state/types.d.ts +0 -39
  266. package/dist/types/src/archive/components/CellGrid/state/types.d.ts.map +0 -1
  267. package/dist/types/src/archive/components/CellGrid/state/viewport.d.ts +0 -52
  268. package/dist/types/src/archive/components/CellGrid/state/viewport.d.ts.map +0 -1
  269. package/dist/types/src/archive/components/CellGrid/state/viewport.test.d.ts +0 -2
  270. package/dist/types/src/archive/components/CellGrid/state/viewport.test.d.ts.map +0 -1
  271. package/dist/types/src/archive/components/FPS.d.ts +0 -9
  272. package/dist/types/src/archive/components/FPS.d.ts.map +0 -1
  273. package/dist/types/src/archive/components/Grid/Grid.d.ts +0 -6
  274. package/dist/types/src/archive/components/Grid/Grid.d.ts.map +0 -1
  275. package/dist/types/src/archive/components/Grid/index.d.ts +0 -2
  276. package/dist/types/src/archive/components/Grid/index.d.ts.map +0 -1
  277. package/dist/types/src/archive/components/index.d.ts +0 -5
  278. package/dist/types/src/archive/components/index.d.ts.map +0 -1
  279. package/dist/types/src/archive/hooks/index.d.ts +0 -5
  280. package/dist/types/src/archive/hooks/index.d.ts.map +0 -1
  281. package/dist/types/src/archive/hooks/projection.d.ts +0 -60
  282. package/dist/types/src/archive/hooks/projection.d.ts.map +0 -1
  283. package/dist/types/src/archive/hooks/useCanvasContext.d.ts +0 -13
  284. package/dist/types/src/archive/hooks/useCanvasContext.d.ts.map +0 -1
  285. package/dist/types/src/archive/hooks/useDrag.d.ts +0 -6
  286. package/dist/types/src/archive/hooks/useDrag.d.ts.map +0 -1
  287. package/dist/types/src/archive/hooks/useWheel.d.ts +0 -8
  288. package/dist/types/src/archive/hooks/useWheel.d.ts.map +0 -1
  289. package/dist/types/src/archive/index.d.ts +0 -5
  290. package/dist/types/src/archive/index.d.ts.map +0 -1
  291. package/dist/types/src/archive/types.d.ts +0 -19
  292. package/dist/types/src/archive/types.d.ts.map +0 -1
  293. package/dist/types/src/archive/util/index.d.ts +0 -4
  294. package/dist/types/src/archive/util/index.d.ts.map +0 -1
  295. package/dist/types/src/archive/util/svg-path.d.ts +0 -4
  296. package/dist/types/src/archive/util/svg-path.d.ts.map +0 -1
  297. package/dist/types/src/archive/util/svg.d.ts +0 -32
  298. package/dist/types/src/archive/util/svg.d.ts.map +0 -1
  299. package/dist/types/src/archive/util/svg.stories.d.ts +0 -15
  300. package/dist/types/src/archive/util/svg.stories.d.ts.map +0 -1
  301. package/dist/types/src/archive/util/util.d.ts +0 -17
  302. package/dist/types/src/archive/util/util.d.ts.map +0 -1
  303. package/dist/types/src/scene.d.ts +0 -5
  304. package/dist/types/src/scene.d.ts.map +0 -1
  305. package/src/archive/components/Canvas/Canvas.stories.tsx +0 -111
  306. package/src/archive/components/Canvas/Canvas.tsx +0 -87
  307. package/src/archive/components/Canvas/index.ts +0 -5
  308. package/src/archive/components/CellGrid/CellGrid.stories.tsx +0 -239
  309. package/src/archive/components/CellGrid/CellGrid.tsx +0 -270
  310. package/src/archive/components/CellGrid/headers/Ruler.tsx +0 -71
  311. package/src/archive/components/CellGrid/headers/TrackHeader.tsx +0 -58
  312. package/src/archive/components/CellGrid/headers/index.ts +0 -6
  313. package/src/archive/components/CellGrid/index.ts +0 -9
  314. package/src/archive/components/CellGrid/input/index.ts +0 -6
  315. package/src/archive/components/CellGrid/input/pointer.ts +0 -236
  316. package/src/archive/components/CellGrid/input/wheel.ts +0 -68
  317. package/src/archive/components/CellGrid/render/index.ts +0 -6
  318. package/src/archive/components/CellGrid/render/overlay-layer.ts +0 -66
  319. package/src/archive/components/CellGrid/render/static-layer.ts +0 -112
  320. package/src/archive/components/CellGrid/state/atoms.ts +0 -43
  321. package/src/archive/components/CellGrid/state/index.ts +0 -7
  322. package/src/archive/components/CellGrid/state/types.ts +0 -40
  323. package/src/archive/components/CellGrid/state/viewport.test.ts +0 -50
  324. package/src/archive/components/CellGrid/state/viewport.ts +0 -94
  325. package/src/archive/components/FPS.tsx +0 -98
  326. package/src/archive/components/Grid/Grid.tsx +0 -17
  327. package/src/archive/components/Grid/index.ts +0 -5
  328. package/src/archive/components/index.ts +0 -8
  329. package/src/archive/hooks/index.ts +0 -8
  330. package/src/archive/hooks/projection.tsx +0 -156
  331. package/src/archive/hooks/useCanvasContext.ts +0 -32
  332. package/src/archive/hooks/useDrag.tsx +0 -96
  333. package/src/archive/hooks/useWheel.tsx +0 -80
  334. package/src/archive/index.ts +0 -8
  335. package/src/archive/types.ts +0 -14
  336. package/src/archive/util/index.ts +0 -7
  337. package/src/archive/util/svg-path.ts +0 -13
  338. package/src/archive/util/svg.stories.tsx +0 -46
  339. package/src/archive/util/svg.tsx +0 -128
  340. package/src/archive/util/util.ts +0 -50
  341. package/src/scene.ts +0 -9
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/archive/hooks/projection.tsx","../../src/archive/hooks/useCanvasContext.ts","../../src/archive/hooks/useDrag.tsx","../../src/archive/util/svg-path.ts","../../src/archive/util/svg.tsx","../../src/archive/util/util.ts","../../src/archive/hooks/useWheel.tsx","../../src/archive/components/Canvas/Canvas.tsx","../../src/archive/components/CellGrid/state/viewport.ts","../../src/archive/components/CellGrid/headers/Ruler.tsx","../../src/archive/components/CellGrid/headers/TrackHeader.tsx","../../src/archive/components/CellGrid/input/pointer.ts","../../src/archive/components/CellGrid/input/wheel.ts","../../src/archive/components/CellGrid/render/overlay-layer.ts","../../src/archive/components/CellGrid/render/static-layer.ts","../../src/archive/components/CellGrid/CellGrid.tsx","../../src/archive/components/CellGrid/state/atoms.ts","../../src/archive/components/FPS.tsx","../../src/archive/components/Grid/Grid.tsx"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { easeSinOut, interpolate, interpolateObject, transition } from 'd3';\nimport {\n type Matrix,\n applyToPoints,\n compose,\n identity,\n inverse,\n scale as scaleMatrix,\n translate as translateMatrix,\n} from 'transformation-matrix';\n\nimport { type Dimension, type Point } from '../types.ts';\n\nexport const defaultOrigin: Point = { x: 0, y: 0 };\n\n// TODO(burdon): Rotation also?\nexport type ProjectionState = {\n scale: number;\n offset: Point;\n};\n\n/**\n * Maps between screen and model coordinates.\n */\nexport interface Projection {\n get bounds(): Dimension;\n get scale(): number;\n get offset(): Point;\n\n /**\n * Maps the model space to the screen offset (from the top-left of the element).\n */\n toScreen(points: Point[]): Point[];\n\n /**\n * Maps the pointer coordinate (from the top-left of the element) to the model space.\n */\n toModel(points: Point[]): Point[];\n}\n\nexport class ProjectionMapper implements Projection {\n private _bounds: Dimension = { width: 0, height: 0 };\n private _scale: number = 1;\n private _offset: Point = defaultOrigin;\n private _toScreen: Matrix = identity();\n private _toModel: Matrix = identity();\n\n constructor(bounds?: Dimension, scale?: number, offset?: Point) {\n if (bounds && scale && offset) {\n this.update(bounds, scale, offset);\n }\n }\n\n update(bounds: Dimension, scale: number, offset: Point): this {\n this._bounds = bounds;\n this._scale = scale;\n this._offset = offset;\n this._toScreen = compose(\n // NOTE: Order is important.\n translateMatrix(this._offset.x, this._offset.y),\n scaleMatrix(this._scale),\n // TODO(burdon): Flip.\n // flipX(),\n );\n this._toModel = inverse(this._toScreen);\n return this;\n }\n\n get bounds() {\n return this._bounds;\n }\n\n get scale() {\n return this._scale;\n }\n\n get offset() {\n return this._offset;\n }\n\n toScreen(points: Point[]): Point[] {\n return applyToPoints(this._toScreen, points);\n }\n\n toModel(points: Point[]): Point[] {\n return applyToPoints(this._toModel, points);\n }\n}\n\n/**\n * Maintain position while zooming.\n */\nexport const getZoomTransform = ({\n scale,\n offset,\n pos,\n newScale,\n}: ProjectionState & { pos: Point; newScale: number }): ProjectionState => {\n return {\n scale: newScale,\n offset: {\n x: pos.x - (pos.x - offset.x) * (newScale / scale),\n y: pos.y - (pos.y - offset.y) * (newScale / scale),\n },\n };\n};\n\n/**\n * Zoom while keeping the specified position in place.\n */\n// TODO(burdon): Convert to object.\nexport const zoomInPlace = (\n setTransform: (state: ProjectionState) => void,\n pos: Point,\n offset: Point,\n current: number,\n next: number,\n delay = 200,\n) => {\n const is = interpolate(current, next);\n transition()\n .ease(easeSinOut)\n .duration(delay)\n .tween('zoom', () => (t) => {\n const newScale = is(t);\n setTransform(getZoomTransform({ scale: current, newScale, offset, pos }));\n });\n};\n\nconst noop = () => {};\n\n/**\n * Zoom to new scale and position.\n */\n// TODO(burdon): Convert to object.\nexport const zoomTo = (\n setTransform: (state: ProjectionState) => void,\n current: ProjectionState,\n next: ProjectionState,\n delay = 200,\n cb = noop,\n) => {\n const is = interpolateObject({ scale: current.scale, ...current.offset }, { scale: next.scale, ...next.offset });\n transition()\n .ease(easeSinOut)\n .duration(delay)\n .tween('zoom', () => (t) => {\n const { scale, x, y } = is(t);\n setTransform({ scale, offset: { x, y } });\n })\n .on('end', cb);\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type CSSProperties, type Dispatch, type SetStateAction, createContext, useContext } from 'react';\n\nimport { raise } from '@dxos/debug';\n\nimport { type Projection, type ProjectionState } from './projection.tsx';\n\n// Kept out of the canvas components: react-refresh only fast-refreshes a module whose exports are all\n// components, so a context and hook exported beside one force a full page reload on every edit.\n\nexport type CanvasContext = ProjectionState & {\n root: HTMLDivElement;\n ready: boolean;\n width: number;\n height: number;\n styles: CSSProperties;\n projection: Projection;\n setProjection: Dispatch<SetStateAction<ProjectionState>>;\n};\n\n/**\n * @internal\n */\n// TODO(burdon): Use `createContext` from `@dxos/react-hooks`?\nexport const CanvasContext = createContext<CanvasContext | null>(null);\n\nexport const useCanvasContext = (): CanvasContext => {\n return useContext(CanvasContext) ?? raise(new Error('Missing CanvasContext'));\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { bind } from 'bind-event-listener';\nimport { useEffect, useRef } from 'react';\n\nimport { useCanvasContext } from './useCanvasContext.ts';\n\nexport type DragOptions = {\n // TODO(burdon): Add constraints?\n};\n\n/**\n * Handle drag events to update the transform state (offset).\n */\nexport const useDrag = (_options: DragOptions = {}) => {\n const { root, setProjection } = useCanvasContext();\n\n // Track drag state.\n const state = useRef<{\n panning: boolean;\n x: number;\n y: number;\n }>({ panning: false, x: 0, y: 0 });\n\n useEffect(() => {\n if (!root) {\n return;\n }\n\n // TODO(burdon): Use d3-drag?\n return bind(root, {\n type: 'pointerdown',\n listener: (ev: PointerEvent) => {\n // Only left click.\n if (ev.button !== 0) {\n return;\n }\n\n if (ev.defaultPrevented) {\n return;\n }\n\n if (ev.target !== root || ev.shiftKey) {\n return;\n }\n\n // Check if clicking on an interactive element?\n // For now, assume if it bubbled to root, it's fair game unless prevented.\n\n ev.preventDefault(); // Prevent text selection.\n root.setPointerCapture(ev.pointerId);\n state.current = { panning: true, x: ev.clientX, y: ev.clientY };\n\n const moveUnbind = bind(root, {\n type: 'pointermove',\n listener: (ev: PointerEvent) => {\n if (!state.current.panning) {\n return;\n }\n\n // Calculate delta.\n const dx = ev.clientX - state.current.x;\n const dy = ev.clientY - state.current.y;\n\n state.current.x = ev.clientX;\n state.current.y = ev.clientY;\n\n setProjection((prev) => ({\n ...prev,\n offset: {\n x: prev.offset.x + dx,\n y: prev.offset.y + dy,\n },\n }));\n },\n });\n\n const upUnbind = bind(root, {\n type: 'pointerup',\n listener: (ev: PointerEvent) => {\n state.current.panning = false;\n root.releasePointerCapture(ev.pointerId);\n moveUnbind();\n upUnbind();\n // Clean up lostpointercapture as well?\n },\n });\n\n // Handle cancellation/lost capture just in case?\n // Using setPointerCapture usually handles this well on the element.\n },\n });\n }, [root]);\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { type Point } from '../types.ts';\n\n// Kept out of `svg.tsx`: react-refresh only fast-refreshes a module whose exports are all components,\n// so a helper exported beside them forces a full page reload on every edit.\n\n/** https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths */\nexport const createPath = (points: Point[], join = false) => {\n return ['M', points.map(({ x, y }) => `${x},${y}`).join(' L '), join ? 'Z' : ''].join(' ');\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { type PropsWithChildren, type SVGProps } from 'react';\n\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type Dimension, type Point } from '../types.ts';\nimport { createPath } from './svg-path.ts';\n\n// Refs\n// - https://airbnb.io/visx/gallery\n// - https://github.com/tldraw/tldraw/blob/main/packages/editor/src/lib/primitives/Vec.ts\n\n/**\n * https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths\n * NOTE: Leave space around shape for line width.\n */\nexport const Markers = ({ id = 'dx-marker', classNames }: Util.ThemedClassName<{ id?: string }>) => {\n return (\n <>\n <Arrow id={`${id}-arrow-start`} dir='start' classNames={classNames} />\n <Arrow id={`${id}-arrow-end`} dir='end' classNames={classNames} />\n <Arrow id={`${id}-triangle-start`} dir='start' closed classNames={classNames} />\n <Arrow id={`${id}-triangle-end`} dir='end' closed classNames={classNames} />\n <Marker id={`${id}-circle`} pos={{ x: 8, y: 8 }} size={{ width: 16, height: 16 }}>\n <circle cx={8} cy={8} r={5} stroke={'context-stroke'} className={mx(classNames)} />\n </Marker>\n </>\n );\n};\n\nexport type MarkerProps = SVGProps<SVGMarkerElement> &\n PropsWithChildren<\n Util.ThemedClassName<{\n id: string;\n pos: Point;\n size: Dimension;\n fill?: boolean;\n }>\n >;\n\n/**\n * https://www.w3.org/TR/SVG2/painting.html#Markers\n */\nexport const Marker = ({\n id,\n className,\n children,\n pos: { x: refX, y: refY },\n size: { width: markerWidth, height: markerHeight },\n fill,\n ...rest\n}: MarkerProps) => (\n <marker\n id={id}\n className={className}\n {...{\n refX,\n refY,\n markerWidth,\n markerHeight,\n markerUnits: 'strokeWidth',\n orient: 'auto',\n ...rest,\n }}\n >\n {children}\n </marker>\n);\n\nexport const Arrow = ({\n classNames,\n id,\n size = 16,\n dir = 'end',\n closed = false,\n}: Util.ThemedClassName<{ id: string; size?: number; dir?: 'start' | 'end'; closed?: boolean }>) => (\n <Marker\n id={id}\n size={{ width: size, height: size }}\n pos={dir === 'end' ? { x: size, y: size / 2 } : { x: 0, y: size / 2 }}\n >\n <path\n fill={closed ? undefined : 'none'}\n stroke={'context-stroke'}\n className={mx(classNames)}\n d={createPath(\n dir === 'end'\n ? [\n { x: 1, y: 1 },\n { x: size, y: size / 2 },\n { x: 1, y: size - 1 },\n ]\n : [\n { x: size - 1, y: 1 },\n { x: 0, y: size / 2 },\n { x: size - 1, y: size - 1 },\n ],\n closed,\n )}\n />\n </Marker>\n);\n\nexport const GridPattern = ({\n classNames,\n id,\n size,\n offset,\n}: Util.ThemedClassName<{ id: string; size: number; offset: Point }>) => (\n <pattern\n id={id}\n x={(size / 2 + offset.x) % size}\n y={(size / 2 + offset.y) % size}\n width={size}\n height={size}\n patternUnits='userSpaceOnUse'\n >\n {/* TODO(burdon): vars. */}\n <g className={mx(classNames)}>\n <line x1={0} y1={size / 2} x2={size} y2={size / 2} />\n <line x1={size / 2} y1={0} x2={size / 2} y2={size} />\n </g>\n </pattern>\n);\n","//\n// Copyright 2024 DXOS.org\n//\n\nlet logged = false;\n\n/**\n * Get the relative point of the cursor.\n * NOTE: ev.offset returns the position relative to the target.\n */\nexport const getRelativePoint = (el: HTMLElement, ev: MouseEvent) => {\n const rect = el.getBoundingClientRect();\n return { x: ev.clientX - rect.x, y: ev.clientY - rect.top };\n};\n\n/**\n *\n */\n// TODO(burdon): Factor out.\nexport const testId = <ID = string>(id: ID, inspect = false) => {\n if (inspect) {\n if (!logged) {\n // eslint-disable-next-line no-console\n console.log('Open storybook in expanded window;\\nthen run INSPECT()');\n logged = true;\n }\n\n (window as any).INSPECT = () => {\n const el = document.querySelector(`[data-test-id=\"${id}\"]`);\n (window as any).inspect(el);\n // eslint-disable-next-line no-console\n console.log(el);\n };\n }\n\n return { [DATA_TEST_ID]: id };\n};\n\nexport const inspectElement = (el: Element) => {\n (window as any).INSPECT = () => {\n (window as any).inspect(el);\n (window as any).element = el;\n // eslint-disable-next-line no-console\n console.log('Open storybook in expanded window;\\nthen run INSPECT()');\n // eslint-disable-next-line no-console\n console.log(el);\n };\n};\n\nexport const DATA_TEST_ID = 'data-test-id';\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport { bindAll } from 'bind-event-listener';\nimport { useEffect } from 'react';\n\nimport { getRelativePoint } from '../util/index.ts';\nimport { getZoomTransform } from './projection.tsx';\nimport { useCanvasContext } from './useCanvasContext.ts';\n\nexport type WheelOptions = {\n zoom?: boolean;\n};\n\nconst defaultOptions: WheelOptions = {\n zoom: true,\n};\n\n/**\n * Handle wheel events to update the transform state (zoom and offset).\n */\nexport const useWheel = (options: WheelOptions = defaultOptions) => {\n const { root, setProjection } = useCanvasContext();\n useEffect(() => {\n if (!root) {\n return;\n }\n\n return bindAll(root, [\n {\n type: 'wheel',\n options: { capture: true, passive: false },\n listener: (ev: WheelEvent) => {\n const zooming = isWheelZooming(ev);\n\n ev.preventDefault();\n if (zooming && !options.zoom) {\n return;\n }\n\n // Zoom or pan.\n if (ev.ctrlKey) {\n if (!root) {\n return;\n }\n\n // Keep centered while zooming.\n setProjection(({ scale, offset }) => {\n const pos = getRelativePoint(root, ev);\n const scaleSensitivity = 0.01;\n const newScale = scale * Math.exp(-ev.deltaY * scaleSensitivity);\n return getZoomTransform({ scale, offset, newScale, pos });\n });\n } else {\n setProjection(({ scale, offset: { x, y } }) => {\n return {\n scale,\n offset: {\n x: x - ev.deltaX,\n y: y - ev.deltaY,\n },\n };\n });\n }\n },\n },\n ]);\n }, [root]);\n};\n\nconst isWheelZooming = (ev: WheelEvent): boolean => {\n // Check for ctrl/cmd key + wheel action.\n if (ev.ctrlKey || ev.metaKey) {\n // Some browsers use deltaY, others deltaZ for zoom.\n return Math.abs(ev.deltaY) > 0 || Math.abs(ev.deltaZ) > 0;\n }\n\n return false;\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport React, {\n type CSSProperties,\n type HTMLAttributes,\n type PropsWithChildren,\n forwardRef,\n useEffect,\n useImperativeHandle,\n useMemo,\n useState,\n} from 'react';\nimport { useResizeDetector } from 'react-resize-detector';\n\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { CanvasContext, ProjectionMapper, type ProjectionState, defaultOrigin } from '../../hooks/index.ts';\n\nexport interface CanvasController {\n setProjection(projection: ProjectionState): Promise<void>;\n}\n\nexport type CanvasProps = Util.ThemedClassName<\n PropsWithChildren<Partial<ProjectionState> & HTMLAttributes<HTMLDivElement>>\n>;\n\n/**\n * Root canvas component.\n * Manages CSS projection.\n */\nexport const Canvas = forwardRef<CanvasController, CanvasProps>(\n ({ children, classNames, scale: scaleProp = 1, offset: offsetProp = defaultOrigin, ...props }, forwardedRef) => {\n // Size.\n const { ref, width = 0, height = 0 } = useResizeDetector();\n\n // Ready when initially resized.\n const [ready, setReady] = useState(false);\n\n // Projection.\n const [{ scale, offset }, setProjection] = useState<ProjectionState>({ scale: scaleProp, offset: offsetProp });\n useEffect(() => {\n if (width && height && offset === defaultOrigin) {\n setProjection({ scale, offset: { x: width / 2, y: height / 2 } });\n }\n }, [width, height, scale, offset]);\n\n // Projection mapper.\n const projection = useMemo(() => new ProjectionMapper(), []);\n useEffect(() => {\n projection.update({ width, height }, scale, offset);\n if (offset !== defaultOrigin) {\n setReady(true);\n }\n }, [projection, scale, offset, width, height]);\n\n // CSS transforms.\n const styles = useMemo<CSSProperties>(() => {\n return {\n // NOTE: Order is important.\n transform: `translate(${offset.x}px, ${offset.y}px) scale(${scale})`,\n visibility: width && height ? 'visible' : 'hidden',\n };\n }, [scale, offset]);\n\n // Controller.\n useImperativeHandle(forwardedRef, () => {\n return {\n setProjection: async (projection: ProjectionState) => {\n setProjection(projection);\n },\n };\n }, [ref]);\n\n return (\n <CanvasContext.Provider\n value={{ root: ref.current, ready, width, height, scale, offset, styles, projection, setProjection }}\n >\n <div {...props} className={mx('dx-cover overflow-hidden', classNames)} ref={ref}>\n {ready ? children : null}\n </div>\n </CanvasContext.Provider>\n );\n },\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type { Cell, CellCoord, Headers, Viewport } from './types.ts';\n\nexport const cellKey = (col: number, row: number): string => `${col},${row}`;\n\nexport const cellWidth = (viewport: Viewport): number => viewport.baseCellWidth * viewport.zoomX;\n\n/**\n * Convert a cell's world coordinates to screen-space pixel rectangle (relative to canvas origin).\n */\nexport const worldToScreen = (\n viewport: Viewport,\n headers: Headers,\n coord: { col: number; row: number; length?: number },\n): { x: number; y: number; w: number; h: number } => {\n const w = cellWidth(viewport);\n return {\n x: headers.left + coord.col * w - viewport.scrollX,\n y: headers.top + coord.row * viewport.cellHeight - viewport.scrollY,\n w: (coord.length ?? 1) * w,\n h: viewport.cellHeight,\n };\n};\n\n/**\n * Convert screen-space pixels (relative to canvas origin) to fractional cell coordinates.\n */\nexport const screenToWorld = (\n viewport: Viewport,\n headers: Headers,\n point: { x: number; y: number },\n): { col: number; row: number } => {\n const w = cellWidth(viewport);\n return {\n col: (point.x - headers.left + viewport.scrollX) / w,\n row: (point.y - headers.top + viewport.scrollY) / viewport.cellHeight,\n };\n};\n\nexport const hitTestCell = (\n viewport: Viewport,\n headers: Headers,\n point: { x: number; y: number },\n): CellCoord | null => {\n if (point.x < headers.left || point.y < headers.top) {\n return null;\n }\n const { col, row } = screenToWorld(viewport, headers, point);\n if (col < 0 || row < 0) {\n return null;\n }\n return { col: Math.floor(col), row: Math.floor(row) };\n};\n\n/**\n * Compute the inclusive range of cell coordinates intersecting the visible content rect.\n */\nexport const visibleCellRange = (\n viewport: Viewport,\n headers: Headers,\n size: { width: number; height: number },\n): { minCol: number; maxCol: number; minRow: number; maxRow: number } => {\n const w = cellWidth(viewport);\n const innerW = Math.max(0, size.width - headers.left);\n const innerH = Math.max(0, size.height - headers.top);\n const minCol = Math.max(0, Math.floor(viewport.scrollX / w));\n const maxCol = Math.floor((viewport.scrollX + innerW) / w);\n const minRow = Math.max(0, Math.floor(viewport.scrollY / viewport.cellHeight));\n const maxRow = Math.floor((viewport.scrollY + innerH) / viewport.cellHeight);\n return { minCol, maxCol, minRow, maxRow };\n};\n\n/**\n * Iterate sparse cell map, yielding only cells whose horizontal extent intersects visible cols and whose row is visible.\n */\nexport const visibleCells = function* <T>(\n cells: ReadonlyMap<string, Cell<T>>,\n range: { minCol: number; maxCol: number; minRow: number; maxRow: number },\n): Generator<Cell<T>> {\n for (const cell of cells.values()) {\n if (cell.row < range.minRow || cell.row > range.maxRow) {\n continue;\n }\n const start = cell.col;\n const end = cell.col + cell.length - 1;\n if (end < range.minCol || start > range.maxCol) {\n continue;\n }\n yield cell;\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo } from 'react';\n\nimport { mx } from '@dxos/ui-theme';\n\nimport type { Headers, Viewport } from '../state/types.ts';\nimport { cellWidth } from '../state/viewport.ts';\n\nexport type RulerProps = {\n viewport: Viewport;\n headers: Headers;\n width: number;\n /** Number of columns to label between major ticks. */\n majorEvery?: number;\n classNames?: string;\n};\n\n/**\n * Frozen top ruler. Ticks reflect the current viewport scroll and zoom.\n */\nexport const Ruler = ({ viewport, headers, width, majorEvery = 4, classNames }: RulerProps) => {\n // Clamp to >= 1 — a zero or negative `majorEvery` makes `col % majorEvery`\n // NaN / always-zero and breaks major-tick detection.\n const safeMajorEvery = Math.max(1, Math.floor(majorEvery));\n const ticks = useMemo(() => {\n const w = cellWidth(viewport);\n if (w < 1 || width <= headers.left) {\n return [];\n }\n const innerWidth = width - headers.left;\n const startCol = Math.floor(viewport.scrollX / w);\n const endCol = Math.ceil((viewport.scrollX + innerWidth) / w);\n const result: Array<{ col: number; x: number; major: boolean }> = [];\n for (let col = startCol; col <= endCol; col++) {\n result.push({\n col,\n x: headers.left + col * w - viewport.scrollX,\n major: col % safeMajorEvery === 0,\n });\n }\n return result;\n }, [viewport, headers.left, width, safeMajorEvery]);\n\n return (\n <div\n className={mx(\n 'absolute top-0 left-0 right-0 border-b border-neutral-200 dark:border-neutral-700 bg-base-surface select-none overflow-hidden',\n classNames,\n )}\n style={{ height: headers.top }}\n >\n {ticks.map(({ col, x, major }) => (\n <div\n key={col}\n className={mx(\n 'absolute top-0 bottom-0 text-[10px] text-neutral-500 dark:text-neutral-400',\n major\n ? 'border-l border-neutral-400 dark:border-neutral-500'\n : 'border-l border-neutral-200 dark:border-neutral-700',\n )}\n style={{ transform: `translateX(${x}px)` }}\n >\n {major ? <span className='absolute left-1 top-0'>{col}</span> : null}\n </div>\n ))}\n </div>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { mx } from '@dxos/ui-theme';\n\nimport type { Headers, Row, Viewport } from '../state/types.ts';\n\nexport type TrackHeaderProps = {\n viewport: Viewport;\n headers: Headers;\n rows: ReadonlyArray<Row>;\n height: number;\n classNames?: string;\n};\n\n/**\n * Frozen left column listing row labels. Translates vertically in sync with viewport scroll.\n *\n * Row dividers and alternating shading intentionally MATCH the canvas — opaque borders\n * and opaque alternating fills make the labels look out of phase with the cell area\n * even when the y-positions align. We mirror the canvas's transparent-overlay model\n * here so the frozen column reads as a direct continuation of the grid.\n */\nexport const TrackHeader = ({ viewport, headers, rows, height, classNames }: TrackHeaderProps) => {\n return (\n <div\n className={mx(\n 'absolute left-0 border-r border-neutral-200 dark:border-neutral-700 select-none overflow-hidden',\n classNames,\n )}\n style={{ top: headers.top, width: headers.left, height: Math.max(0, height - headers.top) }}\n >\n <div style={{ transform: `translateY(${-viewport.scrollY}px)` }}>\n {rows.map((row, index) => (\n <div\n key={row.id}\n className='flex items-center px-2 text-xs text-neutral-700 dark:text-neutral-300'\n style={{\n height: viewport.cellHeight,\n // Match the canvas's row-band: a translucent gray overlay on odd rows,\n // transparent on even rows. The container's overall background bleeds\n // through, so the labels stay legible in both themes.\n backgroundColor: index % 2 === 0 ? 'transparent' : 'rgba(128, 128, 128, 0.08)',\n // Match the canvas gridline color (rgba(128, 128, 128, 0.25)). Use a\n // half-pixel inset to keep crisp single-pixel rendering on retina.\n boxShadow: 'inset 0 -1px 0 rgba(128, 128, 128, 0.25)',\n }}\n >\n {row.label ?? row.id}\n </div>\n ))}\n </div>\n </div>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport type { CellGridAtoms } from '../state/atoms.ts';\nimport type { Cell, CellCoord, Headers, SelectionRange, Tool } from '../state/types.ts';\nimport { cellKey, hitTestCell } from '../state/viewport.ts';\n\n/**\n * 'set' / 'unset' are idempotent — the receiver must add or remove the cell\n * regardless of current state. 'toggle' flips it. Drag operations always pick\n * a fixed mode (set or unset) based on the cell under the initial pointerdown\n * so the user paints a uniform stroke instead of flipping each cell.\n */\nexport type ToggleMode = 'set' | 'unset' | 'toggle';\n\nexport type PointerHandlers = {\n onCellToggle?: (coord: CellCoord, mode: ToggleMode) => void;\n onSelectionCommit?: (range: SelectionRange) => void;\n /** Called each time the draw cursor moves to a new cell (edit tool). */\n onDrawUpdate?: (startCoord: CellCoord, endCoord: CellCoord) => void;\n /** Called when the user releases after an edit-tool drag; caller commits the note. */\n onDrawCommit?: (startCoord: CellCoord, endCoord: CellCoord) => void;\n};\n\ntype DragState =\n | { kind: 'toggle'; mode: 'set' | 'unset'; touched: Set<string> }\n | { kind: 'draw'; startCoord: CellCoord; endCoord: CellCoord }\n | { kind: 'select'; origin: CellCoord }\n | { kind: 'pan'; lastX: number; lastY: number };\n\nexport type PointerControllerOptions<T> = {\n registry: Registry.AtomRegistry;\n atoms: CellGridAtoms<T>;\n headers: Headers;\n handlers: PointerHandlers;\n};\n\n/**\n * Attach pointer handlers to an element. Returns an unsubscribe.\n */\nexport const attachPointerHandlers = <T>(\n element: HTMLElement,\n { registry, atoms, headers, handlers }: PointerControllerOptions<T>,\n): (() => void) => {\n let drag: DragState | null = null;\n\n const local = (event: PointerEvent) => {\n const rect = element.getBoundingClientRect();\n return { x: event.clientX - rect.left, y: event.clientY - rect.top };\n };\n\n // setPointerCapture throws for synthetic / untrusted PointerEvents (e.g. those\n // dispatched by tests). Capture is a best-effort UX nicety — never let it abort\n // the click path.\n const tryCapture = (pointerId: number) => {\n try {\n element.setPointerCapture(pointerId);\n } catch {\n // Ignore — drag tracking still works without capture.\n }\n };\n\n const onPointerDown = (event: PointerEvent) => {\n // Middle-mouse or space-held pan: pan tool regardless of `tool` atom.\n if (event.button === 1 || (event.button === 0 && event.altKey)) {\n drag = { kind: 'pan', lastX: event.clientX, lastY: event.clientY };\n tryCapture(event.pointerId);\n event.preventDefault();\n return;\n }\n\n if (event.button !== 0) {\n return;\n }\n\n const viewport = registry.get(atoms.viewport);\n const point = local(event);\n const coord = hitTestCell(viewport, headers, point);\n if (!coord) {\n return;\n }\n\n const tool = registry.get(atoms.tool) as Tool;\n tryCapture(event.pointerId);\n\n switch (tool) {\n case 'toggle':\n case 'resize': {\n // Inspect the cells atom under the pointer to decide whether the gesture\n // is a paint (set) or an erase (unset). Subsequent drag movements apply the\n // same operation idempotently to every cell the cursor crosses.\n const cells = registry.get(atoms.cells) as ReadonlyMap<string, unknown>;\n const key = cellKey(coord.col, coord.row);\n const mode: 'set' | 'unset' = cells.has(key) ? 'unset' : 'set';\n handlers.onCellToggle?.(coord, mode);\n drag = { kind: 'toggle', mode, touched: new Set([key]) };\n break;\n }\n case 'edit': {\n // Start a draw gesture: track extent and fire preview/commit callbacks\n // instead of toggling individual cells. Constrained to the starting row.\n drag = { kind: 'draw', startCoord: coord, endCoord: coord };\n handlers.onDrawUpdate?.(coord, coord);\n break;\n }\n case 'delete': {\n // Always removes notes regardless of current cell state.\n const key = cellKey(coord.col, coord.row);\n handlers.onCellToggle?.(coord, 'unset');\n drag = { kind: 'toggle', mode: 'unset', touched: new Set([key]) };\n break;\n }\n case 'select': {\n drag = { kind: 'select', origin: coord };\n registry.set(atoms.selection, {\n range: { col0: coord.col, row0: coord.row, col1: coord.col, row1: coord.row },\n });\n break;\n }\n }\n };\n\n const onPointerMove = (event: PointerEvent) => {\n if (!drag) {\n return;\n }\n if (drag.kind === 'pan') {\n const dx = event.clientX - drag.lastX;\n const dy = event.clientY - drag.lastY;\n drag.lastX = event.clientX;\n drag.lastY = event.clientY;\n registry.update(atoms.viewport, (current) => ({\n ...current,\n scrollX: Math.max(0, current.scrollX - dx),\n scrollY: Math.max(0, current.scrollY - dy),\n }));\n return;\n }\n\n const viewport = registry.get(atoms.viewport);\n const coord = hitTestCell(viewport, headers, local(event));\n if (!coord) {\n return;\n }\n\n if (drag.kind === 'toggle') {\n // Apply the drag's chosen mode to every cell the cursor enters, across rows,\n // de-duplicating per cell so we don't fire the same coord twice.\n const key = cellKey(coord.col, coord.row);\n if (!drag.touched.has(key)) {\n drag.touched.add(key);\n handlers.onCellToggle?.(coord, drag.mode);\n }\n } else if (drag.kind === 'draw') {\n // Constrain to the starting row so the note stays at the same pitch.\n const constrainedCol = coord.col;\n if (constrainedCol !== drag.endCoord.col) {\n drag.endCoord = { col: constrainedCol, row: drag.startCoord.row };\n handlers.onDrawUpdate?.(drag.startCoord, drag.endCoord);\n }\n } else if (drag.kind === 'select') {\n registry.set(atoms.selection, {\n range: { col0: drag.origin.col, row0: drag.origin.row, col1: coord.col, row1: coord.row },\n });\n }\n };\n\n const releaseCapture = (event: PointerEvent) => {\n if (element.hasPointerCapture(event.pointerId)) {\n element.releasePointerCapture(event.pointerId);\n }\n };\n\n const onPointerUp = (event: PointerEvent) => {\n if (!drag) {\n return;\n }\n if (drag.kind === 'draw') {\n handlers.onDrawCommit?.(drag.startCoord, drag.endCoord);\n } else if (drag.kind === 'select') {\n const range = registry.get(atoms.selection).range;\n if (range) {\n handlers.onSelectionCommit?.(range);\n }\n }\n drag = null;\n releaseCapture(event);\n };\n\n // pointercancel signals an interrupted gesture (system gesture, palm rejection,\n // capture lost). Per the Pointer Events spec this should clean up local state\n // ONLY and not be treated as a successful completion — so we never commit a\n // selection from cancel.\n const onPointerCancel = (event: PointerEvent) => {\n drag = null;\n releaseCapture(event);\n };\n\n element.addEventListener('pointerdown', onPointerDown);\n element.addEventListener('pointermove', onPointerMove);\n element.addEventListener('pointerup', onPointerUp);\n element.addEventListener('pointercancel', onPointerCancel);\n\n return () => {\n element.removeEventListener('pointerdown', onPointerDown);\n element.removeEventListener('pointermove', onPointerMove);\n element.removeEventListener('pointerup', onPointerUp);\n element.removeEventListener('pointercancel', onPointerCancel);\n };\n};\n\n/**\n * Utility for consumers: toggle, set, or unset membership of a cell in the cells atom.\n */\nexport const toggleCell = <T>(\n registry: Registry.AtomRegistry,\n atoms: CellGridAtoms<T>,\n coord: CellCoord,\n factory: (coord: CellCoord) => Cell<T>,\n mode: ToggleMode = 'toggle',\n): void => {\n registry.update(atoms.cells, (current) => {\n const next = new Map(current);\n const key = cellKey(coord.col, coord.row);\n const exists = next.has(key);\n if (mode === 'set' || (mode === 'toggle' && !exists)) {\n next.set(key, factory(coord));\n } else if (mode === 'unset' || (mode === 'toggle' && exists)) {\n next.delete(key);\n }\n return next;\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport type { CellGridAtoms } from '../state/atoms.ts';\nimport type { Headers } from '../state/types.ts';\nimport { cellWidth } from '../state/viewport.ts';\n\nconst MIN_ZOOM = 0.25;\nconst MAX_ZOOM = 8;\n\nexport type WheelControllerOptions<T> = {\n registry: Registry.AtomRegistry;\n atoms: CellGridAtoms<T>;\n headers: Headers;\n};\n\n/**\n * Attach wheel handlers. Vertical wheel scrolls y; shift+wheel scrolls x;\n * cmd/ctrl+wheel zooms x around the cursor.\n */\nexport const attachWheelHandlers = <T>(\n element: HTMLElement,\n { registry, atoms, headers }: WheelControllerOptions<T>,\n): (() => void) => {\n const onWheel = (event: WheelEvent) => {\n if (event.ctrlKey || event.metaKey) {\n event.preventDefault();\n // Zoom around cursor x.\n const rect = element.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const factor = Math.exp(-event.deltaY / 200);\n registry.update(atoms.viewport, (current) => {\n const nextZoom = Math.max(MIN_ZOOM, Math.min(MAX_ZOOM, current.zoomX * factor));\n if (nextZoom === current.zoomX) {\n return current;\n }\n const w = cellWidth(current);\n const worldX = (x - headers.left + current.scrollX) / w;\n const nextW = current.baseCellWidth * nextZoom;\n const nextScrollX = Math.max(0, worldX * nextW - (x - headers.left));\n return { ...current, zoomX: nextZoom, scrollX: nextScrollX };\n });\n return;\n }\n\n const dx = event.shiftKey ? event.deltaY : event.deltaX;\n const dy = event.shiftKey ? 0 : event.deltaY;\n const current = registry.get(atoms.viewport);\n const nextScrollX = Math.max(0, current.scrollX + dx);\n const nextScrollY = Math.max(0, current.scrollY + dy);\n\n // Only consume the wheel event if we're actually scrolling within the grid.\n // When the user wheels up at the top (scrollY === 0 && dy < 0) or wheels left\n // at the left edge, let the event bubble to the parent so the page or\n // enclosing container can scroll instead of swallowing the gesture.\n if (nextScrollX === current.scrollX && nextScrollY === current.scrollY) {\n return;\n }\n event.preventDefault();\n registry.set(atoms.viewport, { ...current, scrollX: nextScrollX, scrollY: nextScrollY });\n };\n\n element.addEventListener('wheel', onWheel, { passive: false });\n return () => element.removeEventListener('wheel', onWheel);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type { Headers, Selection, Viewport } from '../state/types.ts';\nimport { cellWidth, worldToScreen } from '../state/viewport.ts';\n\nexport type OverlayStyle = {\n playhead: string;\n selectionFill: string;\n selectionStroke: string;\n};\n\nexport type DrawOverlayOptions = {\n ctx: CanvasRenderingContext2D;\n size: { width: number; height: number };\n viewport: Viewport;\n headers: Headers;\n selection: Selection;\n /** Playhead position in world units (col + fraction), or null when not playing. */\n playhead: number | null;\n style: OverlayStyle;\n};\n\nexport const drawOverlay = ({ ctx, size, viewport, headers, selection, playhead, style }: DrawOverlayOptions): void => {\n ctx.clearRect(0, 0, size.width, size.height);\n\n ctx.save();\n ctx.beginPath();\n ctx.rect(headers.left, headers.top, size.width - headers.left, size.height - headers.top);\n ctx.clip();\n\n // Selection rectangle.\n if (selection.range) {\n const { col0, row0, col1, row1 } = selection.range;\n const minCol = Math.min(col0, col1);\n const maxCol = Math.max(col0, col1);\n const minRow = Math.min(row0, row1);\n const maxRow = Math.max(row0, row1);\n const tl = worldToScreen(viewport, headers, { col: minCol, row: minRow });\n const br = worldToScreen(viewport, headers, { col: maxCol + 1, row: maxRow + 1 });\n ctx.fillStyle = style.selectionFill;\n ctx.fillRect(tl.x, tl.y, br.x - tl.x, br.y - tl.y);\n ctx.strokeStyle = style.selectionStroke;\n ctx.setLineDash([4, 3]);\n ctx.lineWidth = 1;\n ctx.strokeRect(tl.x + 0.5, tl.y + 0.5, br.x - tl.x - 1, br.y - tl.y - 1);\n ctx.setLineDash([]);\n }\n\n // Playhead.\n if (playhead !== null) {\n const w = cellWidth(viewport);\n const x = headers.left + playhead * w - viewport.scrollX;\n if (x >= headers.left && x <= size.width) {\n ctx.strokeStyle = style.playhead;\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.moveTo(x, headers.top);\n ctx.lineTo(x, size.height);\n ctx.stroke();\n }\n }\n\n ctx.restore();\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type { Cell, Headers, Row, Viewport } from '../state/types.ts';\nimport { cellWidth, visibleCellRange, visibleCells, worldToScreen } from '../state/viewport.ts';\n\nexport type RenderCellArgs<T> = {\n ctx: CanvasRenderingContext2D;\n x: number;\n y: number;\n w: number;\n h: number;\n cell: Cell<T>;\n};\n\nexport type RenderCell<T = unknown> = (args: RenderCellArgs<T>) => void;\n\nexport type StaticLayerStyle = {\n /** Grid line color, e.g. 'rgba(0,0,0,0.08)'. */\n gridLine: string;\n /** Row band fill (alternating), e.g. 'rgba(0,0,0,0.02)'. */\n rowBand?: string;\n background?: string;\n};\n\nexport type DrawCellsOptions<T> = {\n ctx: CanvasRenderingContext2D;\n size: { width: number; height: number };\n viewport: Viewport;\n headers: Headers;\n rows: ReadonlyArray<Row>;\n cells: ReadonlyMap<string, Cell<T>>;\n renderCell: RenderCell<T>;\n style: StaticLayerStyle;\n};\n\n/**\n * Paint the static layer: background, gridlines, alternating row bands, and cells.\n * Pure with respect to its inputs (writes only to the supplied ctx).\n */\nexport const drawCells = <T>({\n ctx,\n size,\n viewport,\n headers,\n rows,\n cells,\n renderCell,\n style,\n}: DrawCellsOptions<T>): void => {\n ctx.clearRect(0, 0, size.width, size.height);\n\n if (style.background) {\n ctx.fillStyle = style.background;\n ctx.fillRect(0, 0, size.width, size.height);\n }\n\n const range = visibleCellRange(viewport, headers, size);\n const w = cellWidth(viewport);\n const h = viewport.cellHeight;\n\n // Row bands. Paint odd rows so the stripe pattern matches the TrackHeader's\n // label backgrounds (which darken odd row indices) — keeps the frozen left\n // column and the cell area visually in lockstep.\n if (style.rowBand) {\n ctx.fillStyle = style.rowBand;\n for (let row = range.minRow; row <= Math.min(range.maxRow, rows.length - 1); row++) {\n if (row % 2 === 0) {\n continue;\n }\n const y = headers.top + row * h - viewport.scrollY;\n ctx.fillRect(headers.left, y, size.width - headers.left, h);\n }\n }\n\n // Gridlines.\n ctx.strokeStyle = style.gridLine;\n ctx.lineWidth = 1;\n ctx.beginPath();\n for (let col = range.minCol; col <= range.maxCol + 1; col++) {\n const x = Math.floor(headers.left + col * w - viewport.scrollX) + 0.5;\n if (x < headers.left) {\n continue;\n }\n ctx.moveTo(x, headers.top);\n ctx.lineTo(x, size.height);\n }\n for (let row = range.minRow; row <= Math.min(range.maxRow + 1, rows.length); row++) {\n const y = Math.floor(headers.top + row * h - viewport.scrollY) + 0.5;\n if (y < headers.top) {\n continue;\n }\n ctx.moveTo(headers.left, y);\n ctx.lineTo(size.width, y);\n }\n ctx.stroke();\n\n // Cells.\n ctx.save();\n ctx.beginPath();\n ctx.rect(headers.left, headers.top, size.width - headers.left, size.height - headers.top);\n ctx.clip();\n for (const cell of visibleCells(cells, range)) {\n if (cell.row >= rows.length) {\n continue;\n }\n const rect = worldToScreen(viewport, headers, cell);\n renderCell({ ctx, ...rect, cell });\n }\n ctx.restore();\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { RegistryContext } from '@effect/atom-react/RegistryContext';\nimport React, { useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport { useResizeDetector } from 'react-resize-detector';\n\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { Ruler, TrackHeader } from './headers/index.ts';\nimport { type PointerHandlers, attachPointerHandlers, attachWheelHandlers } from './input/index.ts';\nimport { type OverlayStyle, type RenderCell, type StaticLayerStyle, drawCells, drawOverlay } from './render/index.ts';\nimport type { CellGridAtoms } from './state/atoms.ts';\nimport type { Cell, Headers, Row } from './state/types.ts';\n\nexport type CellGridProps<T = unknown> = Util.ThemedClassName<\n PointerHandlers & {\n atoms: CellGridAtoms<T>;\n rows: ReadonlyArray<Row>;\n renderCell: RenderCell<T>;\n headers?: Partial<Headers> | false;\n staticStyle?: Partial<StaticLayerStyle>;\n overlayStyle?: Partial<OverlayStyle>;\n }\n>;\n\nconst defaultHeaders: Headers = { left: 80, top: 24 };\n\nconst defaultStaticStyle: StaticLayerStyle = {\n gridLine: 'rgba(128,128,128,0.25)',\n rowBand: 'rgba(128,128,128,0.06)',\n};\n\nconst defaultOverlayStyle: OverlayStyle = {\n playhead: 'rgb(220, 38, 38)',\n selectionFill: 'rgba(59, 130, 246, 0.15)',\n selectionStroke: 'rgb(59, 130, 246)',\n};\n\nconst setupCanvas = (canvas: HTMLCanvasElement, width: number, height: number): CanvasRenderingContext2D | null => {\n const dpr = window.devicePixelRatio || 1;\n canvas.width = Math.max(1, Math.floor(width * dpr));\n canvas.height = Math.max(1, Math.floor(height * dpr));\n canvas.style.width = `${width}px`;\n canvas.style.height = `${height}px`;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n return null;\n }\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n return ctx;\n};\n\n/**\n * Canvas-based 2D grid where cells contain pluggable shapes. Suitable for music sequencers,\n * time-series data viz, and similar workloads at ~1k visible cells per viewport.\n */\nexport const CellGrid = <T,>({\n atoms,\n rows,\n renderCell,\n headers: headersProp,\n staticStyle: staticStyleProp,\n overlayStyle: overlayStyleProp,\n classNames,\n onCellToggle,\n onSelectionCommit,\n onDrawUpdate,\n onDrawCommit,\n}: CellGridProps<T>) => {\n const registry = useContext(RegistryContext);\n\n const headers = useMemo<Headers>(() => {\n if (headersProp === false) {\n return { left: 0, top: 0 };\n }\n return { ...defaultHeaders, ...(headersProp ?? {}) };\n }, [headersProp]);\n\n const staticStyle = useMemo<StaticLayerStyle>(\n () => ({ ...defaultStaticStyle, ...(staticStyleProp ?? {}) }),\n [staticStyleProp],\n );\n const overlayStyle = useMemo<OverlayStyle>(\n () => ({ ...defaultOverlayStyle, ...(overlayStyleProp ?? {}) }),\n [overlayStyleProp],\n );\n\n const { ref: containerRef, width = 0, height = 0 } = useResizeDetector<HTMLDivElement>();\n const staticCanvasRef = useRef<HTMLCanvasElement>(null);\n const overlayCanvasRef = useRef<HTMLCanvasElement>(null);\n const overlayInputRef = useRef<HTMLDivElement>(null);\n\n const [staticCtx, setStaticCtx] = useState<CanvasRenderingContext2D | null>(null);\n const [overlayCtx, setOverlayCtx] = useState<CanvasRenderingContext2D | null>(null);\n\n // Track header rerenders for the React-side ruler/track-header.\n const [viewportState, setViewportState] = useState(() => registry.get(atoms.viewport));\n\n // Resize canvases on container resize.\n useEffect(() => {\n if (!width || !height) {\n return;\n }\n if (staticCanvasRef.current) {\n const ctx = setupCanvas(staticCanvasRef.current, width, height);\n setStaticCtx(ctx);\n }\n if (overlayCanvasRef.current) {\n const ctx = setupCanvas(overlayCanvasRef.current, width, height);\n setOverlayCtx(ctx);\n }\n }, [width, height]);\n\n // Mirror viewport into React state so headers re-render on scroll/zoom.\n useEffect(() => registry.subscribe(atoms.viewport, (next) => setViewportState(next)), [registry, atoms.viewport]);\n\n // Static-layer redraw on (cells, viewport, rows, headers, style, size) change.\n useEffect(() => {\n if (!staticCtx || !width || !height) {\n return;\n }\n let raf: number | null = null;\n const schedule = () => {\n if (raf !== null) {\n return;\n }\n raf = requestAnimationFrame(() => {\n raf = null;\n drawCells({\n ctx: staticCtx,\n size: { width, height },\n viewport: registry.get(atoms.viewport),\n headers,\n rows,\n cells: registry.get(atoms.cells),\n renderCell,\n style: staticStyle,\n });\n });\n };\n schedule();\n const unsubCells = registry.subscribe(atoms.cells, schedule);\n const unsubViewport = registry.subscribe(atoms.viewport, schedule);\n return () => {\n if (raf !== null) {\n cancelAnimationFrame(raf);\n }\n unsubCells();\n unsubViewport();\n };\n }, [staticCtx, width, height, registry, atoms.cells, atoms.viewport, headers, rows, renderCell, staticStyle]);\n\n // Overlay rAF loop while playhead or active selection drag.\n useEffect(() => {\n if (!overlayCtx || !width || !height) {\n return;\n }\n let raf: number | null = null;\n let stopped = false;\n\n const paint = () => {\n drawOverlay({\n ctx: overlayCtx,\n size: { width, height },\n viewport: registry.get(atoms.viewport),\n headers,\n selection: registry.get(atoms.selection),\n playhead: registry.get(atoms.playhead),\n style: overlayStyle,\n });\n };\n\n const isAnimating = () => registry.get(atoms.playhead) !== null;\n\n const loop = () => {\n if (stopped) {\n return;\n }\n paint();\n if (isAnimating()) {\n raf = requestAnimationFrame(loop);\n } else {\n raf = null;\n }\n };\n\n const kick = () => {\n paint();\n if (raf === null && isAnimating()) {\n raf = requestAnimationFrame(loop);\n }\n };\n\n kick();\n const unsubSelection = registry.subscribe(atoms.selection, () => paint());\n const unsubPlayhead = registry.subscribe(atoms.playhead, kick);\n const unsubViewport = registry.subscribe(atoms.viewport, () => paint());\n\n return () => {\n stopped = true;\n if (raf !== null) {\n cancelAnimationFrame(raf);\n }\n unsubSelection();\n unsubPlayhead();\n unsubViewport();\n };\n }, [overlayCtx, width, height, registry, atoms.selection, atoms.playhead, atoms.viewport, headers, overlayStyle]);\n\n // Input wiring. Keep the callbacks in a ref so the listener attachment is stable\n // across consumer re-renders — otherwise an in-progress drag is torn down when\n // the parent's onCellToggle identity changes (e.g. after the very mutation we\n // just triggered), and subsequent pointermove events see drag === null.\n const callbacksRef = useRef<PointerHandlers>({ onCellToggle, onSelectionCommit, onDrawUpdate, onDrawCommit });\n callbacksRef.current = { onCellToggle, onSelectionCommit, onDrawUpdate, onDrawCommit };\n useEffect(() => {\n const element = overlayInputRef.current;\n if (!element) {\n return;\n }\n const detachPointer = attachPointerHandlers(element, {\n registry,\n atoms,\n headers,\n handlers: {\n onCellToggle: (coord, mode) => callbacksRef.current.onCellToggle?.(coord, mode),\n onSelectionCommit: (range) => callbacksRef.current.onSelectionCommit?.(range),\n onDrawUpdate: (start, end) => callbacksRef.current.onDrawUpdate?.(start, end),\n onDrawCommit: (start, end) => callbacksRef.current.onDrawCommit?.(start, end),\n },\n });\n const detachWheel = attachWheelHandlers(element, { registry, atoms, headers });\n return () => {\n detachPointer();\n detachWheel();\n };\n }, [registry, atoms, headers]);\n\n return (\n <div ref={containerRef} className={mx('relative dx-fill overflow-hidden dx-base-surface', classNames)}>\n {/*\n Canvases are nudged up + left 1 CSS pixel so the gridlines (drawn at the TOP\n and LEFT edges of each cell) sit on top of the frozen header dividers — the\n TrackHeader's right border and bottom-row box-shadow, which both render 1px\n inside the box. Without this offset the canvas gridlines land 1px down/right\n of the header dividers and the columns read as misaligned.\n */}\n <canvas ref={staticCanvasRef} className='dx-cover pointer-events-none' style={{ top: -1, left: -1 }} />\n <canvas ref={overlayCanvasRef} className='dx-cover pointer-events-none' style={{ top: -1, left: -1 }} />\n <div\n ref={overlayInputRef}\n className='dx-cover touch-none'\n style={{ paddingLeft: headers.left, paddingTop: headers.top }}\n />\n {headers.top > 0 && <Ruler viewport={viewportState} headers={headers} width={width} />}\n {headers.left > 0 && <TrackHeader viewport={viewportState} headers={headers} rows={rows} height={height} />}\n {headers.top > 0 && headers.left > 0 && (\n <div\n className='absolute top-0 left-0 border-b border-r border-neutral-200 dark:border-neutral-700 bg-base-surface'\n style={{ width: headers.left, height: headers.top }}\n />\n )}\n </div>\n );\n};\n\nexport type { Cell };\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\n\nimport type { Cell, Selection, Tool, Viewport } from './types.ts';\n\nexport type CellGridAtoms<T = unknown> = {\n cells: Atom.Writable<ReadonlyMap<string, Cell<T>>>;\n viewport: Atom.Writable<Viewport>;\n selection: Atom.Writable<Selection>;\n playhead: Atom.Writable<number | null>;\n tool: Atom.Writable<Tool>;\n};\n\nexport type CellGridAtomsOptions = {\n cellWidth?: number;\n cellHeight?: number;\n};\n\nexport const defaultViewport = (options: CellGridAtomsOptions = {}): Viewport => ({\n scrollX: 0,\n scrollY: 0,\n baseCellWidth: options.cellWidth ?? 24,\n cellHeight: options.cellHeight ?? 24,\n zoomX: 1,\n});\n\n/**\n * Create a fresh set of atoms backing a CellGrid instance. Consumers may pass any of these as props\n * or substitute their own (e.g., a cells atom backed by ECHO).\n *\n * Atoms are marked keepAlive so they preserve state across transient unsubscribe windows (e.g. React\n * Strict Mode mount-unmount-remount). Consumers are responsible for the atoms' lifetime.\n */\nexport const createCellGridAtoms = <T = unknown>(options: CellGridAtomsOptions = {}): CellGridAtoms<T> => ({\n cells: Atom.keepAlive(Atom.make<ReadonlyMap<string, Cell<T>>>(new Map())),\n viewport: Atom.keepAlive(Atom.make<Viewport>(defaultViewport(options))),\n selection: Atom.keepAlive(Atom.make<Selection>({ range: null })),\n playhead: Atom.keepAlive(Atom.make<number | null>(null)),\n tool: Atom.keepAlive(Atom.make<Tool>('toggle')),\n});\n","//\n// Copyright 2024 DXOS.org\n// Adapted from: https://github.com/smplrspace/react-fps-stats\n//\n\nimport React, { useEffect, useReducer, useRef } from 'react';\n\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nexport type FPSProps = Util.ThemedClassName<{\n width?: number;\n height?: number;\n bar?: string;\n}>;\n\ntype State = {\n max: number;\n len: number;\n fps: number[];\n frames: number;\n prevTime: number;\n};\n\nconst SEC = 1_000;\n\nexport const FPS = ({ classNames, width = 60, height = 30, bar = 'bg-cyan-500' }: FPSProps) => {\n const [{ fps, max, len }, dispatch] = useReducer(\n (state: State) => {\n const currentTime = Date.now();\n if (currentTime > state.prevTime + SEC) {\n const nextFPS = [\n ...new Array(Math.floor((currentTime - state.prevTime - SEC) / SEC)).fill(0),\n Math.max(1, Math.round((state.frames * SEC) / (currentTime - state.prevTime))),\n ];\n return {\n max: Math.max(state.max, ...nextFPS),\n len: Math.min(state.len + nextFPS.length, width),\n fps: [...state.fps, ...nextFPS].slice(-width),\n frames: 1,\n prevTime: currentTime,\n };\n } else {\n return { ...state, frames: state.frames + 1 };\n }\n },\n {\n max: 0,\n len: 0,\n fps: [],\n frames: 0,\n prevTime: Date.now(),\n },\n );\n\n const requestRef = useRef<number | null>(null);\n const tick = () => {\n dispatch();\n requestRef.current = requestAnimationFrame(tick);\n };\n\n useEffect(() => {\n requestRef.current = requestAnimationFrame(tick);\n return () => {\n if (requestRef.current) {\n cancelAnimationFrame(requestRef.current);\n }\n };\n }, []);\n\n return (\n <div\n style={{ width: width + 6 }}\n className={mx(\n 'relative flex flex-col p-0.5',\n 'bg-base-surface text-xs text-fg-subtle font-thin pointer-events-none border border-separator',\n classNames,\n )}\n >\n <div>{fps[len - 1]} FPS</div>\n <div className='w-full relative' style={{ height }}>\n {fps.map((frame, i) => (\n <div\n key={`fps-${i}`}\n className={bar}\n style={{\n position: 'absolute',\n bottom: 0,\n right: `${len - 1 - i}px`,\n height: `${(height * frame) / max}px`,\n width: 1,\n }}\n />\n ))}\n </div>\n </div>\n );\n};\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport React from 'react';\n\nimport { GridComponent, type GridProps } from '../../../components/Grid/index.ts';\nimport { useCanvasContext } from '../../hooks/index.ts';\n\nexport type { GridProps };\nexport { GridComponent };\n\n// TODO(burdon): Use id of parent canvas.\nexport const Grid = (props: GridProps) => {\n const { scale, offset } = useCanvasContext();\n return <GridComponent {...props} scale={scale} offset={offset} />;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/components/About/About.tsx","../../src/components/Breadcrumbs/Breadcrumbs.tsx","../../src/utils/undo.ts","../../src/model/atoms.ts","../../src/model/node-def.ts","../../src/model/types.ts","../../src/utils/order.ts","../../src/utils/shapes.ts","../../src/utils/hit.ts","../../src/utils/ports.ts","../../src/utils/lattice.ts","../../src/utils/gutter-route.ts","../../src/utils/route.ts","../../src/components/ControlFrame/ControlFrame.tsx","../../src/components/Grid/Grid.tsx","../../src/components/LatticeGrid/LatticeGrid.tsx","../../src/components/Layers/Layers.tsx","../../src/utils/dnd.ts","../../src/components/Palette/Palette.tsx","../../src/components/PartEditor/PartEditor.tsx","../../src/hooks/useRegistry.ts","../../src/utils/layers.ts","../../src/utils/layout.ts","../../src/model/store.ts","../../src/model/projection.ts","../../src/hooks/useSceneProjection.ts","../../src/hooks/useViewport.ts","../../src/hooks/useWheel.ts","../../src/utils/camera.ts","../../src/utils/parts.ts","../../src/utils/style.ts","../../src/components/SceneLayer/SceneLayer.tsx","../../src/model/registry.ts","../../src/utils/properties.ts","../../src/components/Properties/AlignField.tsx","../../src/components/Properties/ClassField.tsx","../../src/components/Properties/FontField.tsx","../../src/components/Properties/LayerField.tsx","../../src/components/Properties/SceneField.tsx","../../src/components/Properties/StyleGrid.tsx","../../src/components/Properties/Properties.tsx","../../src/model/keys.ts","../../src/utils/clipboard.ts","../../src/utils/group.ts","../../src/utils/scenes.ts","../../src/components/Toolbar/Toolbar.tsx","../../src/components/SceneView/Dock.tsx","../../src/components/SceneView/SceneViewContext.ts","../../src/utils/resize.ts","../../src/components/SceneView/usePointerMachine.ts","../../src/components/SceneView/useSceneCamera.ts","../../src/components/SceneView/useSceneClipboard.ts","../../src/components/SceneView/useSceneKeys.ts","../../src/components/SceneView/useSceneNavigation.ts","../../src/components/SceneView/useSceneSnap.ts","../../src/components/SceneView/SceneView.tsx","../../src/model/projections/constrained.ts","../../src/model/projections/dynamic.ts","../../src/model/projections/lattice.ts","../../src/utils/builder.ts","../../src/utils/diagram.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { Fragment, type ReactNode } from 'react';\n\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as Typography from '@dxos/react-ui/Typography';\nimport type * as Util from '@dxos/react-ui/Util';\n\nexport type AboutStat = { id: string; label: string; value: ReactNode };\n\nexport type AboutProps = Util.ThemedClassName<{\n stats: readonly AboutStat[];\n}>;\n\n/** A two-column table of the drawing's figures, one per list-height row: a label and its value. */\nexport const About = ({ classNames, stats }: AboutProps) => (\n <Panel.Root classNames={classNames} data-testid='about'>\n <Panel.Body>\n <Layout.Container>\n <Layout.Grid cols={['fill', 'auto']}>\n {stats.map(({ id, label, value }) => (\n <Fragment key={id}>\n <Typography.Text tone='muted' truncate>\n {label}\n </Typography.Text>\n <Typography.Text classNames='text-end tabular-nums' data-testid={`about-${id}`}>\n {value}\n </Typography.Text>\n </Fragment>\n ))}\n </Layout.Grid>\n </Layout.Container>\n </Panel.Body>\n </Panel.Root>\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { Fragment } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\n\nimport { type SceneId } from '../../model/index.ts';\n\nexport type BreadcrumbsProps = {\n path: SceneId[];\n nameOf: (id: SceneId) => string;\n /** Jump to the scene at `index` of the path (drill-out by several levels at once). */\n onSelect: (index: number) => void;\n};\n\n// TODO(burdon): Reconcile with react-ui.\nexport const Breadcrumbs = ({ path, nameOf, onSelect }: BreadcrumbsProps) => (\n <nav className='flex items-center gap-1 text-sm font-mono'>\n {path.map((id, index) => (\n <Fragment key={`${index}:${id}`}>\n {index > 0 && <span className='text-fg-subtle'>›</span>}\n {/* The root is home whatever its scene is called. */}\n {index === 0 ? (\n <Button.Root\n variant='ghost'\n size='sm'\n iconOnly\n icon='ph--house--regular'\n label={nameOf(id)}\n disabled={index === path.length - 1}\n data-testid='breadcrumb-root'\n onClick={() => onSelect(index)}\n />\n ) : (\n <Button.Root variant='ghost' size='sm' disabled={index === path.length - 1} onClick={() => onSelect(index)}>\n {nameOf(id)}\n </Button.Root>\n )}\n </Fragment>\n ))}\n </nav>\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Undo as a per-view log of projection snapshots (§8): every `apply` that changes the model pushes the\n// snapshot taken before it, so the undo unit is the intent, whatever the projection made of it. The\n// snapshot is opaque to the view; each projection knows how to take and restore its own.\n//\n\nimport type * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { type Projection } from '../model/projection.ts';\nimport { type SceneMap, type SceneStore } from '../model/store.ts';\n\n/** Entries older than this are dropped rather than growing without bound. */\nexport const UNDO_LIMIT = 100;\n\n/**\n * One undo step: the projection's snapshot from before it, and, for a step that also added or removed scenes (a\n * group into a new scene), the store's scenes from before it, so undo takes the new scene away and redo returns it.\n */\nexport type UndoEntry = { model: unknown; scenes?: SceneMap };\n\nexport type UndoState = {\n /** Which projection the snapshots belong to; a different one starts an empty log. */\n key: string;\n past: UndoEntry[];\n future: UndoEntry[];\n};\n\nexport const emptyUndo = (key = ''): UndoState => ({ key, past: [], future: [] });\n\nconst stateFor = (registry: Registry.AtomRegistry, atom: Atom.Writable<UndoState>, key: string): UndoState => {\n const current = registry.get(atom);\n return current.key === key ? current : emptyUndo(key);\n};\n\n/**\n * The projection with `apply` recording into `atom` under `key`; a rejected intent (same snapshot\n * before and after) records nothing.\n */\nexport const withUndo = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n): Projection => ({\n ...projection,\n apply: (intent) => {\n const before = projection.snapshot();\n projection.apply(intent);\n if (projection.snapshot() === before) {\n return;\n }\n const state = stateFor(registry, atom, key);\n registry.set(atom, { key, past: [...state.past.slice(-(UNDO_LIMIT - 1)), { model: before }], future: [] });\n },\n});\n\n/** Marks the step just recorded as one that also changed the store's scenes, which were `scenes` before it. */\nexport const recordScenes = (\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n scenes: SceneMap,\n): void => {\n const state = stateFor(registry, atom, key);\n const last = state.past[state.past.length - 1];\n if (last) {\n registry.set(atom, { ...state, past: [...state.past.slice(0, -1), { ...last, scenes }] });\n }\n};\n\n/** Swaps the model (and the store's scenes, for a step that changed them) for `entry`, returning what it replaced. */\nconst swap = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n store: SceneStore | undefined,\n entry: UndoEntry,\n): UndoEntry => {\n const scenes = entry.scenes && store ? registry.get(store.scenes) : undefined;\n const replaced: UndoEntry = { model: projection.snapshot(), ...(scenes ? { scenes } : {}) };\n if (entry.scenes && store) {\n registry.set(store.scenes, entry.scenes);\n }\n projection.restore(entry.model);\n return replaced;\n};\n\nexport const undo = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n store?: SceneStore,\n): boolean => {\n const state = stateFor(registry, atom, key);\n const entry = state.past[state.past.length - 1];\n if (!entry) {\n return false;\n }\n const replaced = swap(projection, registry, store, entry);\n registry.set(atom, { key, past: state.past.slice(0, -1), future: [...state.future, replaced] });\n return true;\n};\n\nexport const redo = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n store?: SceneStore,\n): boolean => {\n const state = stateFor(registry, atom, key);\n const entry = state.future[state.future.length - 1];\n if (!entry) {\n return false;\n }\n const replaced = swap(projection, registry, store, entry);\n registry.set(atom, { key, past: [...state.past, replaced], future: state.future.slice(0, -1) });\n return true;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Per-view ephemeral state (§4): selection, hover, drag, camera and the scene path live in atoms\n// owned by the view, never in the model, so two views of one scene stay independent.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\n\nimport { type Clipboard } from '../utils/clipboard.ts';\nimport { type PartKey } from '../utils/parts.ts';\nimport { type UndoState, emptyUndo } from '../utils/undo.ts';\nimport {\n type Bounds,\n type Camera,\n type ElementId,\n type Endpoint,\n type LayerId,\n type LinkId,\n type LinkType,\n type NodeId,\n type NodeType,\n type Point,\n type SceneId,\n type Side,\n type Tool,\n} from './types.ts';\n\nexport type Handle = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';\n\n/**\n * The pointer machine's state. A node gesture (move, resize, create, a spline point) shows its geometry\n * snapped as it goes; a link band follows the pointer exactly and snaps once, as it lands.\n */\nexport type Drag =\n /** Screen-space pan; `last` is the previous pointer position. */\n | { kind: 'pan'; last: Point }\n /** Marquee in scene coordinates; shift adds the hits to the selection, alt subtracts them. */\n | { kind: 'marquee'; from: Point; to: Point; mode: 'replace' | 'add' | 'subtract' }\n /**\n * Moving the selection; `anchor` is the pressed node's top-left, which is what snaps to the grid,\n * and `delta` the resulting scene-space offset applied transiently to every selected node. With\n * `copy` (⌘ held) the originals stay and copies land at `delta` instead. `raw` is the pointer's own offset, which\n * the nodes follow while the drag is in flight; `delta` is where they land.\n */\n | { kind: 'move'; ids: NodeId[]; origin: Point; anchor: Point; delta: Point; raw?: Point; copy?: boolean }\n /** Resizing one node by a handle; `bounds` is the transient result. */\n | { kind: 'resize'; id: NodeId; handle: Handle; start: Bounds; bounds: Bounds }\n /**\n * Rubber band from a port, or from a free point under a link tool; `target` is set while hovering a\n * valid drop, and the link is then previewed as created.\n */\n | { kind: 'link'; type: LinkType; source: Endpoint; from: Point; fromSide: Side; to: Point; target?: Endpoint }\n /**\n * Drawing a new node with a tool. `dropped` marks one dragged in from the palette or a host's\n * draggable, which previews as its frame alone: the pointer already carries the drag's own preview.\n */\n | { kind: 'create'; type: NodeType; from: Point; to: Point; dropped?: boolean }\n /** Moving one control point of a spline; `points` is the transient list. */\n | { kind: 'point'; id: LinkId; index: number; points: Point[] }\n /** Re-attaching one end of a link; `fixed` is the other end's resolved port for the rubber band. */\n | { kind: 'end'; id: LinkId; end: 'source' | 'target'; fixed: Point; fixedSide: Side; to: Point; target?: Endpoint };\n\n/**\n * Whether a move has left where it was pressed: until it does, a press on a selected node is a click, and the\n * selection keeps its outline and handles rather than flickering off and on.\n */\nexport const isMoving = (drag: Drag | undefined): boolean =>\n drag?.kind === 'move' && drag.raw !== undefined && (drag.raw.x !== 0 || drag.raw.y !== 0);\n\nexport type HistoryEntry = { path: SceneId[]; camera: Camera };\n\nexport type ControlPointRef = { link: LinkId; index: number };\n\n/** The text part being edited in place (`parts.ts`). */\nexport type EditingPart = { id: NodeId; part: PartKey };\n\n/** Where the properties and layers panels sit: floating over the canvas, or docked in a column beside it. */\nexport type PanelMode = 'floating' | 'docked';\n\nexport type SceneViewAtoms = {\n camera: Atom.Writable<Camera>;\n path: Atom.Writable<SceneId[]>;\n selection: Atom.Writable<ReadonlySet<ElementId>>;\n hover: Atom.Writable<NodeId | undefined>;\n /** The link under the pointer, which shows its end handles as a selected one does. */\n linkHover: Atom.Writable<LinkId | undefined>;\n /** The layer new shapes and links go on; unset (or a layer the scene does not have), the top one. */\n layer: Atom.Writable<LayerId | undefined>;\n /** The selected control point of a selected spline, if any. */\n point: Atom.Writable<ControlPointRef | undefined>;\n tool: Atom.Writable<Tool>;\n /** The link type a port drag creates under the select tool (the last link tool picked). */\n linkType: Atom.Writable<LinkType>;\n /** Grid shown and moves/resizes snapped to it. */\n snap: Atom.Writable<boolean>;\n /** Guides shown: on a lattice, its cells. */\n guides: Atom.Writable<boolean>;\n /** On a lattice scene, snap lands on the lattice's cells rather than the basic grid. */\n lattice: Atom.Writable<boolean>;\n drag: Atom.Writable<Drag | undefined>;\n history: Atom.Writable<{ entries: HistoryEntry[]; index: number }>;\n /** Projection snapshots for undo and redo (`undo.ts`). */\n undo: Atom.Writable<UndoState>;\n /** The last cut or copied fragment (`clipboard.ts`). */\n clipboard: Atom.Writable<Clipboard | undefined>;\n editing: Atom.Writable<EditingPart | undefined>;\n /**\n * The node whose embedded content takes input (an editor in a frame), entered by clicking the node; any other\n * node's embedded content is inert, so a press anywhere on it selects and moves it.\n */\n active: Atom.Writable<NodeId | undefined>;\n /** Frames show their id, type and geometry. */\n debug: Atom.Writable<boolean>;\n};\n\n/**\n * Fresh atoms for one view. Marked keepAlive so they survive React strict-mode remounts; the owner\n * decides their lifetime.\n */\nexport const createSceneViewAtoms = (root: SceneId): SceneViewAtoms => ({\n camera: Atom.keepAlive(Atom.make<Camera>({ x: 0, y: 0, zoom: 1 })),\n path: Atom.keepAlive(Atom.make<SceneId[]>([root])),\n selection: Atom.keepAlive(Atom.make<ReadonlySet<ElementId>>(new Set<ElementId>())),\n hover: Atom.keepAlive(Atom.make<NodeId | undefined>(undefined)),\n linkHover: Atom.keepAlive(Atom.make<LinkId | undefined>(undefined)),\n layer: Atom.keepAlive(Atom.make<LayerId | undefined>(undefined)),\n point: Atom.keepAlive(Atom.make<ControlPointRef | undefined>(undefined)),\n tool: Atom.keepAlive(Atom.make<Tool>({ kind: 'select' })),\n linkType: Atom.keepAlive(Atom.make<LinkType>('curve')),\n snap: Atom.keepAlive(Atom.make<boolean>(true)),\n guides: Atom.keepAlive(Atom.make<boolean>(true)),\n lattice: Atom.keepAlive(Atom.make<boolean>(true)),\n drag: Atom.keepAlive(Atom.make<Drag | undefined>(undefined)),\n history: Atom.keepAlive(Atom.make<{ entries: HistoryEntry[]; index: number }>({ entries: [], index: -1 })),\n undo: Atom.keepAlive(Atom.make<UndoState>(emptyUndo())),\n clipboard: Atom.keepAlive(Atom.make<Clipboard | undefined>(undefined)),\n editing: Atom.keepAlive(Atom.make<EditingPart | undefined>(undefined)),\n active: Atom.keepAlive(Atom.make<NodeId | undefined>(undefined)),\n debug: Atom.keepAlive(Atom.make<boolean>(false)),\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\n// Kept apart from `registry.ts`, which imports the built-in node views: views look definitions up through\n// this module, so loading a view never has to load the registry that refers back to it.\n\nimport { type NodeDef, type NodeRegistry } from './registry.ts';\nimport { type Node } from './types.ts';\n\n/** The definition of a node's type, when the registry has it. */\nexport const nodeDef = (registry: NodeRegistry, node: Node): NodeDef | undefined => registry[node.type];\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Scene engine types (docs/DESIGN.md §4). Plain Effect schemas: no ECHO yet, so the same shapes wrap\n// into an ECHO type later without change. A diagram is one scene of typed nodes and typed links; every\n// node is a `NodeBase` (centre, size, ports, style) plus the properties its type adds, so the engine\n// works on the base and a host composes the scene schema from its own node types (decision 1).\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation } from '@dxos/echo';\nimport { HueAnnotationId, StepAnnotationId } from '@dxos/ui-types';\n\nexport const Point = Schema.Struct({ x: Schema.Number, y: Schema.Number });\nexport type Point = Schema.Schema.Type<typeof Point>;\n\nexport const Size = Schema.Struct({ width: Schema.Number, height: Schema.Number });\nexport type Size = Schema.Schema.Type<typeof Size>;\n\n/** Minor grid spacing in scene px (the finest line the grid draws at zoom 1). */\nexport const DEFAULT_GRID = 16;\n\n/** Major lines every N minor lines; the grid draws both and snapping uses the major one. */\nexport const MAJOR_GRID_RATIO = 4;\n\n/** Snap unit: nodes, layout defaults and scene bounds align to it. */\nexport const MAJOR_GRID = DEFAULT_GRID * MAJOR_GRID_RATIO;\n\n/** Two fields side by side in a form, rather than one row each. */\nconst pairLayout = (first: string, second: string) =>\n `<grid cols=\"2\" fixed=\"true\"><field name=\"${first}\"/><field name=\"${second}\"/></grid>`;\n\n/** A node coordinate as a form edits it: the stepper moves by one minor grid cell, as an arrow nudge does. */\nconst gridNumber = (title: string) => Schema.Number.annotate({ title, [StepAnnotationId]: DEFAULT_GRID });\n\n/** `Point` and `Size` for a node's own frame, laid out as one row each in the properties form. */\nconst NodeCenter = Schema.Struct({ x: gridNumber('X'), y: gridNumber('Y') }).pipe(\n Annotation.FormLayoutAnnotation.set({ [Annotation.DEFAULT_LAYOUT_NAME]: pairLayout('x', 'y') }),\n);\nconst NodeSize = Schema.Struct({ width: gridNumber('Width'), height: gridNumber('Height') }).pipe(\n Annotation.FormLayoutAnnotation.set({ [Annotation.DEFAULT_LAYOUT_NAME]: pairLayout('width', 'height') }),\n);\n\nexport const Bounds = Schema.Struct({\n x: Schema.Number,\n y: Schema.Number,\n width: Schema.Number,\n height: Schema.Number,\n});\nexport type Bounds = Schema.Schema.Type<typeof Bounds>;\n\n/** screen = (scene + {x, y}) * zoom */\nexport const Camera = Schema.Struct({ x: Schema.Number, y: Schema.Number, zoom: Schema.Number });\nexport type Camera = Schema.Schema.Type<typeof Camera>;\n\nexport type NodeId = string;\nexport type LinkId = string;\n/** A node or link id; the two namespaces never collide within a scene. */\nexport type ElementId = string;\nexport type SceneId = string;\nexport type PortId = string;\n\nexport const Side = Schema.Literals(['n', 'e', 's', 'w']);\nexport type Side = Schema.Schema.Type<typeof Side>;\n\n/** What a port takes: links leaving it, links arriving at it, or either (the default). */\nexport const PortDirection = Schema.Literals(['in', 'out', 'any']);\nexport type PortDirection = Schema.Schema.Type<typeof PortDirection>;\n\n/** An attachment point on a node's frame: a side, a 0..1 offset along it, and what it accepts. */\nexport const Port = Schema.Struct({\n id: Schema.String,\n side: Side,\n offset: Schema.Number,\n accepts: Schema.optional(PortDirection),\n});\nexport type Port = Schema.Schema.Type<typeof Port>;\n\n//\n// Nodes\n//\n\n/** The hues the style pickers offer, neutral first, then in hue order; any theme hue still renders on a node. */\nexport const STYLE_HUES = ['neutral', 'red', 'orange', 'amber', 'green', 'teal', 'sky', 'blue', 'violet'] as const;\nexport const StyleHue = Schema.Literals(STYLE_HUES);\nexport type StyleHue = Schema.Schema.Type<typeof StyleHue>;\n\n/** How strongly a hue fills a frame: 0 is an outline (transparent), 1 to 3 are stronger to lighter fills. */\nexport const NodeTone = Schema.Literals([0, 1, 2, 3]);\nexport type NodeTone = Schema.Schema.Type<typeof NodeTone>;\n\n/** The typefaces a shape's text may use: the theme's body face, or its fixed-width one. */\nexport const FONT_FAMILIES = ['default', 'monospace'] as const;\nexport type FontFamily = (typeof FONT_FAMILIES)[number];\n\n/** Where text sits across a shape, and down it. */\nexport const HORIZONTAL_ALIGNS = ['left', 'center', 'right'] as const;\nexport const VERTICAL_ALIGNS = ['top', 'middle', 'bottom'] as const;\nexport type HorizontalAlign = (typeof HORIZONTAL_ALIGNS)[number];\nexport type VerticalAlign = (typeof VERTICAL_ALIGNS)[number];\n\n/** How a line is drawn: a link's stroke, or a node's border. */\nexport const LINE_STYLES = ['solid', 'dashed', 'dotted'] as const;\n\n/**\n * The common base style every element shares, nodes and links alike: its colour and its line. Each kind extends it\n * (`NodeStyle`), and a selection of several kinds edits only what they share. One field object per property, so\n * the kinds declare the same field and the properties panel sees it as shared.\n */\nexport const lineStyleFields = {\n /** One of the theme's hues: a link's stroke; a node's fill, text and border together. */\n hue: Schema.optional(Schema.String.annotate({ title: 'Hue', [HueAnnotationId]: true })),\n /** Solid, dashed or dotted: a link's stroke, or a node's border. */\n lineStyle: Schema.optional(Schema.Literals(LINE_STYLES).annotate({ title: 'Line style' })),\n};\n\n/** A link's style: the common base, unset drawn neutral and solid. */\nexport const LineStyle = Schema.Struct(lineStyleFields);\nexport type LineStyle = Schema.Schema.Type<typeof LineStyle>;\n\n/**\n * The common base plus a frame and text: what a shape draws. A shape with more to style extends it\n * (`Schema.Struct({ ...styleFields, … })`).\n */\nexport const styleFields = {\n ...lineStyleFields,\n /** The hue's fill; unset is 2, the look a hue had before tones. */\n tone: Schema.optional(NodeTone),\n rounded: Schema.optional(Schema.Boolean),\n fill: Schema.optional(Schema.Boolean),\n border: Schema.optional(Schema.Boolean),\n /** A guide: drawn dashed and unfilled, an annotation rather than content. */\n guide: Schema.optional(Schema.Boolean),\n /** The face of the shape's text; unset is the theme's body face. */\n fontFamily: Schema.optional(Schema.Literals(FONT_FAMILIES).annotate({ title: 'Font' })),\n /** Text size in the node's own scene units (the editor offers a readable range; stored values are not checked). */\n fontSize: Schema.optional(Schema.Number.annotate({ title: 'Font size' })),\n /** Where the text sits across the shape; unset is the type's own (a label centres, a note starts at the left). */\n alignHorizontal: Schema.optional(Schema.Literals(HORIZONTAL_ALIGNS).annotate({ title: 'Horizontal' })),\n /** Where the text sits down the shape; unset is the type's own (a label is middled, a note starts at the top). */\n alignVertical: Schema.optional(Schema.Literals(VERTICAL_ALIGNS).annotate({ title: 'Vertical' })),\n};\n\n/** Presentation choices a node carries: the shape style. */\nexport const NodeStyle = Schema.Struct(styleFields);\nexport type NodeStyle = Schema.Schema.Type<typeof NodeStyle>;\n\n/** The fields every node type shares; a type's schema is `Schema.Struct({ ...nodeBase, type: Literal, ... })`. */\nexport const nodeBase = {\n id: Schema.String,\n /** Fractional z-order key (see `order.ts`). */\n z: Schema.String,\n locked: Schema.optional(Schema.Boolean),\n center: NodeCenter,\n /** The frame is `size` centred on `center`, whatever the type draws inside it. */\n size: NodeSize,\n /** Per-node ports; absent means the node type's definition supplies them (decision 12). */\n ports: Schema.optional(Schema.Array(Port)),\n /** Ports spread along each side, overriding the type's layout; ignored when the node carries `ports`. */\n portsPerSide: Schema.optional(Schema.Number.annotate({ title: 'Ports per side' })),\n /** A style class of the drawing (`StyleClass`) the node takes its look from; its own `style` wins over it. */\n /** The scene layer the element is on; unset, or naming no layer of the scene, it is on the bottom one. */\n layer: Schema.optional(Schema.String.annotate({ title: 'Layer' })),\n class: Schema.optional(Schema.String.annotate({ title: 'Class' })),\n style: Schema.optional(NodeStyle),\n};\n\n/** Any node as the engine sees it: the shared fields and a type name; the registry knows the rest. */\nexport const NodeBase = Schema.Struct({ type: Schema.String, ...nodeBase });\nexport type NodeBase = Schema.Schema.Type<typeof NodeBase>;\n\n/** The fields of the `box` prototype (a framed shape with a centred label), shared by the types built on it. */\nexport const boxFields = {\n label: Schema.optional(Schema.String),\n};\n\n/**\n * The core base every node falls back to: its frame, ports, style and `label`. A node whose type the registry does\n * not know (its plugin is off) is drawn and edited as this, a box showing its label, so a type that keeps its title\n * in `label` still reads as itself.\n */\nexport const BaseNode = Schema.Struct({ type: Schema.String, ...nodeBase, ...boxFields });\nexport type BaseNode = Schema.Schema.Type<typeof BaseNode>;\n\nexport const RectNode = Schema.Struct({\n type: Schema.Literal('rect'),\n ...nodeBase,\n ...boxFields,\n});\nexport type RectNode = Schema.Schema.Type<typeof RectNode>;\n\n/** An ellipse inscribed in the frame. */\nexport const EllipseNode = Schema.Struct({\n type: Schema.Literal('ellipse'),\n ...nodeBase,\n label: Schema.optional(Schema.String),\n});\nexport type EllipseNode = Schema.Schema.Type<typeof EllipseNode>;\n\n/** Free text on the canvas. Named for what it is, so a host may keep `text` for a type of its own. */\nexport const NoteNode = Schema.Struct({\n type: Schema.Literal('note'),\n ...nodeBase,\n text: Schema.String,\n});\nexport type NoteNode = Schema.Schema.Type<typeof NoteNode>;\n\n/** A frame onto the next depth: renders its child scene scaled into this node's bounds. */\nexport const FrameNode = Schema.Struct({\n type: Schema.Literal('frame'),\n ...nodeBase,\n ...boxFields,\n scene: Schema.String,\n /** Draw the child scene inside the frame rather than the label; unset, it does so while there is no label. */\n contents: Schema.optional(Schema.Boolean.annotate({ title: 'Show contents' })),\n});\nexport type FrameNode = Schema.Schema.Type<typeof FrameNode>;\n\n/** The engine's own node types. A host may add its own (decision 1); those are `NodeBase` to the engine. */\nexport const BuiltinNode = Schema.Union([RectNode, EllipseNode, NoteNode, FrameNode]);\nexport type BuiltinNode = Schema.Schema.Type<typeof BuiltinNode>;\nexport type BuiltinNodeType = BuiltinNode['type'];\nexport const NODE_TYPES: readonly BuiltinNodeType[] = ['rect', 'ellipse', 'note', 'frame'];\n\n/** A node of the scene: the engine handles any `NodeBase`; built-in code narrows with the guards below. */\nexport type Node = NodeBase;\n/** A node type name; the engine's own are `BuiltinNodeType`. */\nexport type NodeType = string;\n\n/** Narrows a node to one built-in type; sound because the registry maps each type name to one schema. */\nexport const isRectNode = (node: NodeBase): node is RectNode => node.type === 'rect';\nexport const isEllipseNode = (node: NodeBase): node is EllipseNode => node.type === 'ellipse';\nexport const isNoteNode = (node: NodeBase): node is NoteNode => node.type === 'note';\nexport const isFrameNode = (node: NodeBase): node is FrameNode => node.type === 'frame';\n/** A node built on the `box` prototype, carrying a centred, editable label. */\nexport const isBoxNode = (node: NodeBase): node is RectNode | FrameNode => isRectNode(node) || isFrameNode(node);\n/** Whether a frame draws its child scene: as set, else while it has no label to show instead. */\nexport const showsContents = (node: FrameNode): boolean => node.contents ?? node.label === undefined;\nexport const isBuiltinNode = (node: NodeBase): node is BuiltinNode => NODE_TYPES.some((type) => type === node.type);\n\n//\n// Links\n//\n\n/** A link end on a node; no `port` means automatic (the closest appropriate pair, recomputed on every projection). */\nexport const PortEndpoint = Schema.Struct({\n node: Schema.String,\n port: Schema.optional(Schema.String),\n});\nexport type PortEndpoint = Schema.Schema.Type<typeof PortEndpoint>;\n\n/** A free link end at a scene point (decision 3): an arrow or path that starts or ends on nothing. */\nexport const PointEndpoint = Schema.Struct({ point: Point });\nexport type PointEndpoint = Schema.Schema.Type<typeof PointEndpoint>;\n\nexport const Endpoint = Schema.Union([PortEndpoint, PointEndpoint]);\nexport type Endpoint = Schema.Schema.Type<typeof Endpoint>;\n\nexport const isPointEndpoint = (end: Endpoint): end is PointEndpoint => 'point' in end;\n/** The node an end is attached to; a free end has none. */\nexport const endpointNode = (end: Endpoint): NodeId | undefined => ('node' in end ? end.node : undefined);\n\n/** What is drawn at a link end. */\n/** An end marker: a filled `arrow`, a `circle`, or a hollow `triangle` (inheritance). */\nexport const Marker = Schema.Literals(['arrow', 'circle', 'triangle']);\nexport type Marker = Schema.Schema.Type<typeof Marker>;\n\n/** Markers at the source (`start`) and target (`end`) of a link. */\n/** A link's end markers; the properties form shows them side by side, as the two ends of the line. */\nexport const LinkEnds = Schema.Struct({\n start: Schema.optional(Marker),\n end: Schema.optional(Marker),\n}).pipe(Annotation.FormLayoutAnnotation.set({ [Annotation.DEFAULT_LAYOUT_NAME]: pairLayout('start', 'end') }));\nexport type LinkEnds = Schema.Schema.Type<typeof LinkEnds>;\n\n/**\n * A named look of a drawing, kept beside its scenes: the nodes and links naming it derive their `style` from it (a\n * link takes the common base, its colour and line style), so one class restyles both together.\n */\nexport const StyleClass = Schema.Struct({\n id: Schema.String,\n name: Schema.String,\n style: Schema.optional(NodeStyle),\n});\nexport type StyleClass = Schema.Schema.Type<typeof StyleClass>;\n\n/** A drawing's style classes by id. */\nexport type StyleMap = Readonly<Record<string, StyleClass>>;\n\nconst linkBase = {\n id: Schema.String,\n z: Schema.String,\n locked: Schema.optional(Schema.Boolean),\n source: Endpoint,\n target: Endpoint,\n /** End markers; an arrow at `end` reads as the link's direction. */\n ends: Schema.optional(LinkEnds),\n /** A caption drawn at the middle of the link's route. */\n text: Schema.optional(Schema.String.annotate({ title: 'Label' })),\n /** A style class of the drawing the link takes its style from; its own `style` wins over it. */\n /** The scene layer the element is on; unset, or naming no layer of the scene, it is on the bottom one. */\n layer: Schema.optional(Schema.String.annotate({ title: 'Layer' })),\n class: Schema.optional(Schema.String.annotate({ title: 'Class' })),\n style: Schema.optional(LineStyle),\n};\n\nexport const LineLink = Schema.Struct({ type: Schema.Literal('line'), ...linkBase });\nexport type LineLink = Schema.Schema.Type<typeof LineLink>;\n\n/** Cubic Bézier leaving each port along its side's normal. */\nexport const CurveLink = Schema.Struct({ type: Schema.Literal('curve'), ...linkBase });\nexport type CurveLink = Schema.Schema.Type<typeof CurveLink>;\n\n/** Smooth curve through the ports and the control `points` in between, in order. */\nexport const SplineLink = Schema.Struct({\n type: Schema.Literal('spline'),\n ...linkBase,\n points: Schema.Array(Point),\n});\nexport type SplineLink = Schema.Schema.Type<typeof SplineLink>;\n\n/**\n * Routed between its ends rather than drawn: a stub leaves each port along its side's normal and the\n * route joins the two. Nothing is stored, so the path follows the nodes as they move.\n */\nexport const SmartLink = Schema.Struct({ type: Schema.Literal('smart'), ...linkBase });\nexport type SmartLink = Schema.Schema.Type<typeof SmartLink>;\n\nexport const Link = Schema.Union([LineLink, CurveLink, SplineLink, SmartLink]);\nexport type Link = Schema.Schema.Type<typeof Link>;\nexport type LinkType = Link['type'];\nexport const LINK_TYPES: readonly LinkType[] = ['line', 'curve', 'spline', 'smart'];\n\nexport type Element = Node | Link;\n\n/** The markers a link draws. */\nexport const linkMarkers = (link: Link): LinkEnds => link.ends ?? {};\n\nexport const isNode = (element: Element): element is Node => 'center' in element;\nexport const isLink = (element: Element): element is Link => 'source' in element;\n\n//\n// Scene\n//\n\n/** A layer id, unique within its scene. */\nexport type LayerId = string;\n\n/**\n * A scene's layer: elements paint by their layer's order (`z`, bottom first), then by their own `z`. A hidden layer\n * is neither drawn nor hit. A scene with no layers has one, implicitly (`DEFAULT_LAYER`).\n */\nexport const Layer = Schema.Struct({\n id: Schema.String,\n name: Schema.String,\n /** Fractional order key (see `order.ts`): the bottom layer has the least. */\n z: Schema.String,\n hidden: Schema.optional(Schema.Boolean),\n});\nexport type Layer = Schema.Schema.Type<typeof Layer>;\n\n/**\n * The scene schema over a set of node schemas: a host composes it from its registry's types, so the\n * schema stays exact for every type while the engine only ever sees `NodeBase`.\n */\nexport const createSceneSchema = <const Nodes extends readonly Schema.Codec<NodeBase, unknown>[]>(nodes: Nodes) =>\n Schema.Struct({\n id: Schema.String,\n name: Schema.optional(Schema.String),\n nodes: Schema.Record(Schema.String, Schema.Union(nodes)),\n links: Schema.Record(Schema.String, Link),\n layers: Schema.optional(Schema.Record(Schema.String, Layer)),\n });\n\n/** The scene schema over the built-in node types. */\nexport const Scene = createSceneSchema([RectNode, EllipseNode, NoteNode, FrameNode]);\n\n/** The scene schema over any node with the shared fields: what the engine itself can validate for a host. */\nexport const OpenScene = createSceneSchema([NodeBase]);\nexport type Scene = {\n readonly id: SceneId;\n readonly name?: string;\n readonly nodes: Readonly<Record<NodeId, Node>>;\n readonly links: Readonly<Record<LinkId, Link>>;\n readonly layers?: Readonly<Record<LayerId, Layer>>;\n};\n\n/** A node or link of the scene by id. */\nexport const getElement = (scene: Scene, id: ElementId): Element | undefined => scene.nodes[id] ?? scene.links[id];\n\n/** Property edits: the shared fields typed, a type's own fields by name. */\nexport type NodeValues = Partial<Omit<NodeBase, 'id' | 'type'>> & { readonly [key: string]: unknown };\n/** Per link type, so a spline's `points` are among the values an `update` may set. */\ntype ValuesOf<T> = T extends unknown ? Partial<Omit<T, 'id' | 'type'>> : never;\nexport type LinkValues = ValuesOf<Link>;\n\n/**\n * What the surface asks of a projection (§3). The surface never writes coordinates itself: a\n * projection may apply, rewrite or reject each intent and then re-emits the positioned scene.\n */\nexport type Intent =\n | { kind: 'move'; ids: NodeId[]; delta: Point }\n | { kind: 'resize'; id: NodeId; bounds: Bounds }\n | { kind: 'link'; link: Link }\n | { kind: 'create'; node: Node }\n | { kind: 'delete'; ids: ElementId[] }\n | { kind: 'reorder'; id: ElementId; z: string }\n /** Property edits (label, text, geometry, control points); `id` and `type` never change. */\n | { kind: 'update'; id: ElementId; values: NodeValues | LinkValues }\n /**\n * Arrange the scene (or just `ids`, when the selection is what the user asked to tidy). An intent\n * rather than a view action, so a projection that owns its own positions may rewrite or refuse it.\n */\n | { kind: 'layout'; ids?: ElementId[] }\n /** Adds a layer, or replaces the one of its id (a rename, a visibility toggle, a move in the order). */\n | { kind: 'layer'; layer: Layer }\n /** Removes a layer and every element on it; the last layer of a scene stays. */\n | { kind: 'removeLayer'; id: LayerId }\n /** Several intents applied as one model change (one undo step), e.g. a paste. */\n | { kind: 'batch'; intents: Intent[] };\n\nexport type Capabilities = {\n move?: boolean;\n resize?: boolean;\n link?: boolean;\n create?: boolean;\n delete?: boolean;\n update?: boolean;\n layout?: boolean;\n};\n\n/** The active tool: a node type draws that node, a link type is what port drags create. */\nexport type Tool =\n | { kind: 'select' }\n | { kind: 'hand' }\n | { kind: 'node'; type: NodeType }\n | { kind: 'link'; type: LinkType };\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Fractional z-order keys: strings that sort lexicographically, with a key constructible between any\n// two, so a reorder touches one element instead of renumbering the scene (which would be a conflict\n// magnet once elements live in a CRDT map).\n//\n\nconst DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n\nexport type Ordered = { id: string; z: string };\n\n/**\n * A key strictly between `a` and `b` (each a base-62 fraction in (0, 1) without trailing zeros);\n * `undefined` stands for the open end on that side.\n */\nexport const between = (a?: string, b?: string): string => midpoint(a ?? '', b);\n\nconst midpoint = (a: string, b: string | undefined): string => {\n if (b !== undefined && a >= b) {\n throw new Error(`order: ${JSON.stringify(a)} >= ${JSON.stringify(b)}`);\n }\n if (a.endsWith('0') || b?.endsWith('0')) {\n throw new Error('order: trailing zero');\n }\n if (b !== undefined) {\n let prefix = 0;\n while (prefix < b.length && (a[prefix] ?? '0') === b[prefix]) {\n prefix++;\n }\n if (prefix > 0) {\n return b.slice(0, prefix) + midpoint(a.slice(prefix), b.slice(prefix));\n }\n }\n const digitA = a ? DIGITS.indexOf(a[0]) : 0;\n const digitB = b !== undefined ? DIGITS.indexOf(b[0]) : DIGITS.length;\n if (digitB - digitA > 1) {\n return DIGITS[Math.round((digitA + digitB) / 2)];\n }\n if (b !== undefined && b.length > 1) {\n return b[0];\n }\n return DIGITS[digitA] + midpoint(a.slice(1), undefined);\n};\n\n/** Elements in paint order (bottom first). */\nexport const sortByZ = <T extends Ordered>(elements: readonly T[]): T[] =>\n [...elements].sort((left, right) => (left.z < right.z ? -1 : left.z > right.z ? 1 : left.id < right.id ? -1 : 1));\n\n/** A key above every element, so a new one paints on top. */\nexport const topZ = (elements: readonly Ordered[]): string => {\n let max: string | undefined;\n for (const element of elements) {\n if (max === undefined || element.z > max) {\n max = element.z;\n }\n }\n return between(max, undefined);\n};\n\n/** Keys for `count` elements in paint order, evenly spread from the open bottom. */\nexport const initialKeys = (count: number): string[] => {\n const keys: string[] = [];\n let previous: string | undefined;\n for (let index = 0; index < count; index++) {\n previous = between(previous, undefined);\n keys.push(previous);\n }\n return keys;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Pure geometry of the node and link types (§4): every node's frame is its `size` centred on `center`,\n// so the engine needs no registry to place, hit or route any type; the built-in types' defaults and\n// display text live here too. Rendering lives in the registry.\n//\n\nimport {\n type Bounds,\n type BuiltinNode,\n type BuiltinNodeType,\n DEFAULT_GRID,\n type Endpoint,\n type Link,\n type LinkEnds,\n type LinkType,\n type LinkValues,\n MAJOR_GRID_RATIO,\n type Node,\n type Point,\n type Size,\n} from '../model/types.ts';\nimport { type PartField } from './parts.ts';\n\n/** Axis-aligned frame of a node: its size centred on its centre. */\nexport const nodeBounds = (node: Node): Bounds => ({\n x: node.center.x - node.size.width / 2,\n y: node.center.y - node.size.height / 2,\n width: node.size.width,\n height: node.size.height,\n});\n\nexport const nodeSize = (node: Node): Size => node.size;\n\n/** The node re-framed to `bounds`. */\nexport const resizeNode = <N extends Node>(node: N, bounds: Bounds): N => ({\n ...node,\n center: { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 },\n size: { width: bounds.width, height: bounds.height },\n});\n\n/** Scene px of one nominal unit (a major grid cell) at the default grid. */\nexport const DEFAULT_CELL = DEFAULT_GRID * MAJOR_GRID_RATIO;\n\n/** A nominal size (in major grid cells) in scene px, for a drawing whose major cell is `cell` px. */\nexport const nominalSize = (size: Size, cell: number = DEFAULT_CELL): Size => ({\n width: size.width * cell,\n height: size.height * cell,\n});\n\n/**\n * The built-in types' sizes when created, in nominal units: one unit is the drawing's major grid cell, so a\n * new shape scales with the drawing's grid.\n */\nexport const NOMINAL_SIZES: Record<BuiltinNodeType, Size> = {\n rect: { width: 2, height: 1 },\n ellipse: { width: 2, height: 2 },\n note: { width: 4, height: 2 },\n frame: { width: 4, height: 2 },\n};\n\n/** The built-in types' sizes in scene px, for fixtures and imports, whose layouts are written against them. */\nexport const DEFAULT_SIZES: Record<BuiltinNodeType, Size> = {\n rect: { width: 256, height: 256 },\n ellipse: { width: 256, height: 256 },\n note: { width: 256, height: 128 },\n frame: { width: 512, height: 256 },\n};\n\n/** The bounding box a new basic shape gets at the default grid. */\nexport const DEFAULT_SHAPE_SIZE: Size = DEFAULT_SIZES.rect;\n\nexport type CreateNodeProps = {\n type: BuiltinNodeType;\n id: string;\n z: string;\n center: Point;\n size?: Size;\n /** A frame's child scene id. */\n scene?: string;\n};\n\n/** A new built-in node of `type` with its type's default content; a host type creates through its `NodeDef`. */\nexport const createNode = ({\n type,\n id,\n z,\n center,\n size = DEFAULT_SIZES[type],\n scene,\n}: CreateNodeProps): BuiltinNode => {\n switch (type) {\n // A new box carries no label: a placeholder would have to be cleared before a real one is typed.\n case 'rect':\n return { type, id, z, center, size };\n case 'ellipse':\n return { type, id, z, center, size };\n case 'note':\n return { type, id, z, center, size, text: 'Note' };\n case 'frame':\n return { type, id, z, center, size, scene: scene ?? id };\n }\n};\n\n/** What a shape copy keeps of its own (the fresh node's) rather than the source's: identity, place and child scene. */\nconst OWN_FIELDS = new Set(['id', 'type', 'z', 'center', 'scene']);\n\n/**\n * A new shape like `source` (its size, look and ports) built on `fresh`, the type's own new node at the\n * new place: it keeps its own identity and child scene, and the type's text rather than the source's.\n */\nexport const cloneShape = (source: Node, fresh: Node, parts: readonly PartField[] = []): Node => {\n const text = new Set(parts.map(({ field }) => field));\n return {\n ...fresh,\n ...Object.fromEntries(Object.entries(source).filter(([key]) => !OWN_FIELDS.has(key) && !text.has(key))),\n };\n};\n\nexport type CreateLinkProps = {\n type: LinkType;\n id: string;\n z: string;\n source: Endpoint;\n target: Endpoint;\n /** Where a new spline gets its first control point; ignored by the other types. */\n midpoint?: Point;\n ends?: LinkEnds;\n};\n\n/** A new link of `type`; a spline starts with one control point so it is editable at once. */\nexport const createLink = ({ type, id, z, source, target, midpoint, ends }: CreateLinkProps): Link => {\n const base = { id, z, source, target, ...(ends ? { ends } : {}) };\n switch (type) {\n case 'line':\n case 'curve':\n case 'smart':\n return { type, ...base };\n case 'spline':\n return { type, ...base, points: midpoint ? [midpoint] : [] };\n }\n};\n\n/**\n * The `update` values that reverse a link: source and target swap while the markers stay at the start and\n * end, so an arrow comes to point the other way; a spline's control points run the other way, so the drawn\n * path keeps its shape.\n */\nexport const flipLink = (link: Link): LinkValues => ({\n source: link.target,\n target: link.source,\n ...(link.type === 'spline' ? { points: [...link.points].reverse() } : {}),\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Hit testing from the model in scene coordinates, never from `getClientRects`, so it is pure and the\n// same for every renderer.\n//\n\nimport { type Bounds, MAJOR_GRID, type Node, type Point, type Scene } from '../model/types.ts';\nimport { sortByZ } from './order.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport const BOUNDS_PADDING = MAJOR_GRID;\n\nexport const containsPoint = (bounds: Bounds, point: Point) =>\n point.x >= bounds.x &&\n point.x <= bounds.x + bounds.width &&\n point.y >= bounds.y &&\n point.y <= bounds.y + bounds.height;\n\nexport const intersects = (left: Bounds, right: Bounds) =>\n left.x < right.x + right.width &&\n left.x + left.width > right.x &&\n left.y < right.y + right.height &&\n left.y + left.height > right.y;\n\nexport const unionBounds = (list: readonly Bounds[]): Bounds | undefined => {\n if (list.length === 0) {\n return undefined;\n }\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const bounds of list) {\n minX = Math.min(minX, bounds.x);\n minY = Math.min(minY, bounds.y);\n maxX = Math.max(maxX, bounds.x + bounds.width);\n maxY = Math.max(maxY, bounds.y + bounds.height);\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n};\n\nexport const padBounds = (bounds: Bounds, padding: number): Bounds => ({\n x: bounds.x - padding,\n y: bounds.y - padding,\n width: bounds.width + 2 * padding,\n height: bounds.height + 2 * padding,\n});\n\nexport const boundsFromPoints = (from: Point, to: Point): Bounds => ({\n x: Math.min(from.x, to.x),\n y: Math.min(from.y, to.y),\n width: Math.abs(to.x - from.x),\n height: Math.abs(to.y - from.y),\n});\n\n/** Grow `bounds` outward to the nearest multiples of `unit`. */\nexport const alignBounds = (bounds: Bounds, unit: number): Bounds => {\n const x = Math.floor(bounds.x / unit) * unit;\n const y = Math.floor(bounds.y / unit) * unit;\n return {\n x,\n y,\n width: Math.ceil((bounds.x + bounds.width) / unit) * unit - x,\n height: Math.ceil((bounds.y + bounds.height) / unit) * unit - y,\n };\n};\n\nexport const nodeList = (scene: Scene): Node[] => Object.values(scene.nodes);\n\n/**\n * What a scene holds (decision 6): the union of its nodes plus padding, grown to the major grid. Fit and a\n * portal's preview frame it; an empty scene has none.\n */\nexport const contentBounds = (scene: Scene, padding = BOUNDS_PADDING, unit = MAJOR_GRID): Bounds | undefined => {\n const content = unionBounds(nodeList(scene).map(nodeBounds));\n return content ? alignBounds(padBounds(content, padding), unit) : undefined;\n};\n\n/** Topmost node under `point`, or none; `margin` widens every node, e.g. to reach its ports. */\nexport const hitTest = (scene: Scene, point: Point, margin = 0): Node | undefined => {\n const nodes = sortByZ(nodeList(scene));\n for (let index = nodes.length - 1; index >= 0; index--) {\n if (containsPoint(padBounds(nodeBounds(nodes[index]), margin), point)) {\n return nodes[index];\n }\n }\n return undefined;\n};\n\n/** Nodes whose bounds intersect `bounds` (marquee semantics). */\nexport const nodesIntersecting = (scene: Scene, bounds: Bounds): Node[] =>\n nodeList(scene).filter((node) => intersects(nodeBounds(node), bounds));\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Ports come from the node type's definition unless the node carries its own (decision 12). A link end\n// without a `port` is automatic: the closest pair is chosen from the two nodes' ports on every projection, so rearranging\n// the diagram re-attaches its links.\n//\n\nimport { nodeDef } from '../model/node-def.ts';\nimport { type NodeRegistry } from '../model/registry.ts';\nimport { type Bounds, type Node, type Point, type Port, type PortDirection, type Side } from '../model/types.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport const SIDES: readonly Side[] = ['n', 'e', 's', 'w'];\n\nexport const DEFAULT_PORTS_PER_SIDE = 3;\n\n/** The most ports a side may carry; a stored count is clamped to `1..MAX_PORTS_PER_SIDE` whole ports. */\nexport const MAX_PORTS_PER_SIDE = 9;\n\nconst clampPorts = (count: number) =>\n Number.isFinite(count) ? Math.min(MAX_PORTS_PER_SIDE, Math.max(1, Math.round(count))) : DEFAULT_PORTS_PER_SIDE;\n\n/**\n * The id of the `index`th port along `side`, counting from 1 at the side's start: `e1` is the top of the\n * east side, `s2` the middle of the south side. Pin a link end to one by naming `<node>#<portId>`.\n */\nexport const portId = (side: Side, index = 1): string => `${side}${index}`;\n\n/**\n * `count` ports spread evenly along each side, named by `portId`. Each side lists its centre port first\n * so an automatic link ties to the centre.\n */\nexport const sidePorts = (count = DEFAULT_PORTS_PER_SIDE): readonly Port[] => {\n const middle = (count + 1) / 2;\n const indices = Array.from({ length: count }, (_, index) => index + 1).sort(\n (left, right) => Math.abs(left - middle) - Math.abs(right - middle) || left - right,\n );\n return SIDES.flatMap((side) =>\n indices.map((index) => ({ id: portId(side, index), side, offset: index / (count + 1) })),\n );\n};\n\nexport const defaultPorts: readonly Port[] = sidePorts();\n\n/** How many ports a node spreads along each side: its own count, else its type's, else the default. */\nexport const portsPerSideOf = (registry: NodeRegistry, node: Node): number =>\n clampPorts(node.portsPerSide ?? nodeDef(registry, node)?.portsPerSide ?? DEFAULT_PORTS_PER_SIDE);\n\n/**\n * A node's ports: its own when it carries them, else its own `portsPerSide` spread along each side, else\n * its type's layout or count. Ports landing on the same point collapse to the first, so a definition\n * cannot stack two at one place.\n */\nexport const nodePorts = (registry: NodeRegistry, node: Node): readonly Port[] => {\n const def = nodeDef(registry, node);\n const ports =\n node.ports ??\n (node.portsPerSide !== undefined ? sidePorts(clampPorts(node.portsPerSide)) : undefined) ??\n def?.ports?.(node) ??\n sidePorts(def?.portsPerSide);\n const bounds = nodeBounds(node);\n const seen = new Set<string>();\n return ports.filter((port) => {\n const { x, y } = portPoint(bounds, port);\n const key = `${x},${y}`;\n if (seen.has(key)) {\n return false;\n }\n seen.add(key);\n return true;\n });\n};\n\n/** A port's point on the frame: exactly its offset along the side, whatever the grid. */\nexport const portPoint = (bounds: Bounds, port: Port): Point => {\n const along = (origin: number, length: number) => origin + length * port.offset;\n switch (port.side) {\n case 'n':\n return { x: along(bounds.x, bounds.width), y: bounds.y };\n case 's':\n return { x: along(bounds.x, bounds.width), y: bounds.y + bounds.height };\n case 'w':\n return { x: bounds.x, y: along(bounds.y, bounds.height) };\n case 'e':\n return { x: bounds.x + bounds.width, y: along(bounds.y, bounds.height) };\n }\n};\n\nconst OPPOSITE: Record<Side, Side> = { n: 's', s: 'n', e: 'w', w: 'e' };\n\nexport const oppositeSide = (side: Side): Side => OPPOSITE[side];\n\n/** Outward unit normal of a side. */\nexport const sideNormal = (side: Side): Point => {\n switch (side) {\n case 'n':\n return { x: 0, y: -1 };\n case 's':\n return { x: 0, y: 1 };\n case 'w':\n return { x: -1, y: 0 };\n case 'e':\n return { x: 1, y: 0 };\n }\n};\n\n/** Whether a port takes a link end of `direction` (`out` leaves it, `in` arrives); an unlabelled port takes either. */\nexport const portAccepts = (port: Port, direction: Exclude<PortDirection, 'any'>): boolean =>\n (port.accepts ?? 'any') === 'any' || port.accepts === direction;\n\nexport type PortTerminal = {\n bounds: Bounds;\n ports: readonly Port[];\n /** Pinned port id; absent means automatic. */\n port?: string;\n};\n\nexport type PortPair = { source: Port; target: Port };\n\nconst distance2 = (left: Point, right: Point) => (left.x - right.x) ** 2 + (left.y - right.y) ** 2;\n\n/**\n * The port pair joining two nodes: pinned ports are honoured, automatic ends take the port that\n * minimises the distance to the other end (ties broken by port order, so the result is stable). The\n * source end only leaves a port that accepts `out`, the target end only lands on one that accepts `in`.\n */\nexport const pairPorts = (source: PortTerminal, target: PortTerminal): PortPair | undefined => {\n const sources = portCandidates(source, 'out');\n const targets = portCandidates(target, 'in');\n if (sources.length === 0 || targets.length === 0) {\n return undefined;\n }\n let best: PortPair | undefined;\n let bestDistance = Infinity;\n for (const from of sources) {\n const fromPoint = portPoint(source.bounds, from);\n for (const to of targets) {\n const value = distance2(fromPoint, portPoint(target.bounds, to));\n if (value < bestDistance) {\n bestDistance = value;\n best = { source: from, target: to };\n }\n }\n }\n return best;\n};\n\n/** The port of `terminal` closest to `point` among those taking `direction`, for a link whose other end is free. */\nexport const nearestPort = (\n terminal: PortTerminal,\n point: Point,\n direction: Exclude<PortDirection, 'any'>,\n): Port | undefined => {\n let best: Port | undefined;\n let bestDistance = Infinity;\n for (const port of portCandidates(terminal, direction)) {\n const value = distance2(portPoint(terminal.bounds, port), point);\n if (value < bestDistance) {\n bestDistance = value;\n best = port;\n }\n }\n return best;\n};\n\n/** The ports an end may use: those accepting its direction, narrowed to the pinned one when it is among them. */\nexport const portCandidates = (\n { ports, port }: PortTerminal,\n direction: Exclude<PortDirection, 'any'>,\n): readonly Port[] => {\n const allowed = ports.filter((candidate) => portAccepts(candidate, direction));\n if (port === undefined) {\n return allowed;\n }\n const pinned = allowed.find((candidate) => candidate.id === port);\n // A pinned port the definition no longer has, or that refuses the end, falls back to automatic rather\n // than dropping the link.\n return pinned ? [pinned] : allowed;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Lattice mode geometry (docs/DESIGN.md §8b): shapes occupy whole cells of a coarse lattice, separated by\n// fixed gutters. A cell's pitch is a one-cell shape plus a gutter; a shape spans any whole number of cells\n// on each axis and covers the gutters between them, so every channel between shapes is one gutter wide.\n//\n\nimport { type Bounds, type ElementId, type Node } from '../model/types.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** The size of a one-cell shape and the gutter between shapes, in scene units. */\nexport type LatticeSpec = { width: number; height: number; gutterX: number; gutterY: number };\n\nexport const DEFAULT_LATTICE: LatticeSpec = { width: 256, height: 128, gutterX: 128, gutterY: 64 };\n\n/** A shape on the lattice: its first (top-left) cell and how many cells it spans on each axis. */\nexport type LatticeCell = { col: number; row: number; spanX: number; spanY: number };\n\nconst pitchX = (spec: LatticeSpec) => spec.width + spec.gutterX;\nconst pitchY = (spec: LatticeSpec) => spec.height + spec.gutterY;\n\n/** The nearest whole span (at least 1) for a frame `length` long, one cell being `cell` plus `gutter`. */\nconst spanOf = (length: number, cell: number, gutter: number): number =>\n Math.max(1, Math.round((length + gutter) / (cell + gutter)));\n\n/** The lattice cells nearest a frame: the nearest whole spans, placed so their centre is nearest the frame's. */\nexport const toCell = (bounds: Bounds, spec: LatticeSpec): LatticeCell => {\n const spanX = spanOf(bounds.width, spec.width, spec.gutterX);\n const spanY = spanOf(bounds.height, spec.height, spec.gutterY);\n return {\n // `+ 0` folds -0 into 0, so a cell just left of the origin is the same key as the origin's.\n col: Math.round((bounds.x + bounds.width / 2) / pitchX(spec) - (spanX - 1) / 2) + 0,\n row: Math.round((bounds.y + bounds.height / 2) / pitchY(spec) - (spanY - 1) / 2) + 0,\n spanX,\n spanY,\n };\n};\n\n/** The frame a lattice cell range draws: its spanned shapes and the gutters between them. */\nexport const cellBounds = ({ col, row, spanX, spanY }: LatticeCell, spec: LatticeSpec): Bounds => ({\n x: col * pitchX(spec) - spec.width / 2,\n y: row * pitchY(spec) - spec.height / 2,\n width: spanX * spec.width + (spanX - 1) * spec.gutterX,\n height: spanY * spec.height + (spanY - 1) * spec.gutterY,\n});\n\n/**\n * A cell range resized to the frame a handle drag left (`from` was the frame before): on each axis the\n * moved edge snaps to the nearest cell edge and the opposite edge stays where it was, so a dragged face\n * steps one cell at a time; the range never shrinks below one cell, and an axis with no moved edge keeps\n * its cells.\n */\nexport const resizeCell = (cell: LatticeCell, from: Bounds, to: Bounds, spec: LatticeSpec): LatticeCell => {\n const axis = (\n [fromLow, fromHigh, toLow, toHigh]: [number, number, number, number],\n first: number,\n span: number,\n size: number,\n pitch: number,\n ): [first: number, span: number] => {\n const last = first + span - 1;\n if (Math.abs(toLow - fromLow) > Math.abs(toHigh - fromHigh)) {\n // The low edge moved: the cell whose low edge (`k x pitch - size / 2`) is nearest, up to the last cell.\n const next = Math.min(last, Math.round((toLow + size / 2) / pitch));\n return [next, last - next + 1];\n }\n if (toHigh !== fromHigh) {\n // The high edge moved: the cell whose high edge (`k x pitch + size / 2`) is nearest, from the first cell.\n const next = Math.max(first, Math.round((toHigh - size / 2) / pitch));\n return [first, next - first + 1];\n }\n return [first, span];\n };\n const [col, spanX] = axis(\n [from.x, from.x + from.width, to.x, to.x + to.width],\n cell.col,\n cell.spanX,\n spec.width,\n pitchX(spec),\n );\n const [row, spanY] = axis(\n [from.y, from.y + from.height, to.y, to.y + to.height],\n cell.row,\n cell.spanY,\n spec.height,\n pitchY(spec),\n );\n return { col, row, spanX, spanY };\n};\n\n/** A frame snapped onto the lattice: the nearest whole spans at the nearest cells. */\nexport const quantize = (bounds: Bounds, spec: LatticeSpec): Bounds => cellBounds(toCell(bounds, spec), spec);\n\nconst cellKey = (col: number, row: number) => `${col},${row}`;\n\n/** Every lattice position a cell covers, as `col,row` keys. */\nexport const coveredCells = ({ col, row, spanX, spanY }: LatticeCell): string[] => {\n const keys: string[] = [];\n for (let x = col; x < col + spanX; x++) {\n for (let y = row; y < row + spanY; y++) {\n keys.push(cellKey(x, y));\n }\n }\n return keys;\n};\n\n/** Which node covers each lattice position, for the nodes not in `except` (those being moved or resized). */\nexport type Occupancy = ReadonlyMap<string, ElementId>;\n\n/**\n * Whether a node takes part in the lattice: a guide (a group's backdrop) or a bare caption annotates the shapes rather\n * than being one, so it neither snaps, occupies cells nor blocks a gutter route.\n */\nexport const onLattice = (node: Node): boolean => !node.style?.guide && node.style?.border !== false;\n\nexport const occupancy = (\n nodes: Iterable<Node>,\n spec: LatticeSpec,\n except: ReadonlySet<ElementId> = new Set(),\n): Occupancy => {\n const cells = new Map<string, ElementId>();\n for (const node of nodes) {\n if (!except.has(node.id) && onLattice(node)) {\n for (const key of coveredCells(toCell(nodeBounds(node), spec))) {\n cells.set(key, node.id);\n }\n }\n }\n return cells;\n};\n\n/** Whether a cell overlaps a position another node already covers. */\nexport const collides = (cell: LatticeCell, occupied: Occupancy): boolean =>\n coveredCells(cell).some((key) => occupied.has(key));\n\n/**\n * The free cell of the same span nearest `cell`, searched ring by ring outwards (by the larger of the\n * column and row distances, then by row and column so the result is deterministic); `cell` itself when it is free.\n */\nexport const nearestFree = (cell: LatticeCell, occupied: Occupancy, maxRadius = 64): LatticeCell | undefined => {\n for (let radius = 0; radius <= maxRadius; radius++) {\n for (let dy = -radius; dy <= radius; dy++) {\n for (let dx = -radius; dx <= radius; dx++) {\n if (Math.max(Math.abs(dx), Math.abs(dy)) !== radius) {\n continue;\n }\n const candidate = { ...cell, col: cell.col + dx, row: cell.row + dy };\n if (!collides(candidate, occupied)) {\n return candidate;\n }\n }\n }\n }\n return undefined;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Gutter routing for smart links on a lattice scene (docs/DESIGN.md §8b): each end leaves its port\n// straight out to the centre line of the gutter beside it, and the route between runs at right angles, with\n// as few bends as it can, along gutter centre lines and the lines through its own ports. A port line runs\n// straight through free cells, so a route detours into the gutters only around occupied ones; a gutter a\n// multi-cell shape spans is covered by the shape, so it is not a track.\n//\n\nimport { type Bounds, type Node, type Point } from '../model/types.ts';\nimport { type LatticeSpec, onLattice } from './lattice.ts';\nimport { sideNormal } from './ports.ts';\nimport { type RouteEnd } from './route.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** A bend costs as much as this much distance: turns dominate, length breaks ties. */\nconst TURN_COST = 100_000;\n\n/** Gutter lines beyond the ends and the shapes the search may use, so a route can go round the outermost. */\nconst MARGIN = 3;\n\nconst EPSILON = 1e-6;\n\n/** Whether an axis-aligned segment passes through a frame's interior (touching its edge does not count). */\nconst crosses = (from: Point, to: Point, bounds: Bounds): boolean => {\n const [left, right] = [Math.min(from.x, to.x), Math.max(from.x, to.x)];\n const [top, bottom] = [Math.min(from.y, to.y), Math.max(from.y, to.y)];\n return (\n left < bounds.x + bounds.width - EPSILON &&\n right > bounds.x + EPSILON &&\n top < bounds.y + bounds.height - EPSILON &&\n bottom > bounds.y + EPSILON\n );\n};\n\n/** Where an end meets the gutter beside its port: straight out along the side's normal, half a gutter. */\nconst gutterExit = (end: RouteEnd, spec: LatticeSpec): Point => {\n const normal = sideNormal(end.side);\n return { x: end.point.x + (normal.x * spec.gutterX) / 2, y: end.point.y + (normal.y * spec.gutterY) / 2 };\n};\n\n/** The gutter centre lines (`(k + 1/2) x pitch`) in `[low, high]`, widened by `MARGIN` lines either side. */\nconst gutterLines = (low: number, high: number, pitch: number): number[] => {\n const first = Math.floor(low / pitch - 0.5) - MARGIN;\n const last = Math.ceil(high / pitch - 0.5) + MARGIN;\n return Array.from({ length: last - first + 1 }, (_, index) => (first + index + 0.5) * pitch);\n};\n\ntype Region = { left: number; right: number; top: number; bottom: number };\n\n/**\n * The span the search covers: the ends, grown by every frame within `MARGIN` pitches of them, so a way round\n * an obstacle is in range while a distant shape adds no lines to the grid. `transitive` keeps growing by the\n * frames near the grown span until none is left, for the rare detour round a chain of abutting shapes.\n */\nconst searchRegion = (\n start: Point,\n end: Point,\n frames: readonly Bounds[],\n pitchX: number,\n pitchY: number,\n transitive: boolean,\n): Region => {\n const region: Region = {\n left: Math.min(start.x, end.x),\n right: Math.max(start.x, end.x),\n top: Math.min(start.y, end.y),\n bottom: Math.max(start.y, end.y),\n };\n const [reachX, reachY] = [MARGIN * pitchX, MARGIN * pitchY];\n const pending = new Set(frames);\n for (let grown = true; grown;) {\n grown = false;\n // A single pass measures nearness against the ends' span only, so one frame cannot pull in the next.\n const reach = { ...region };\n for (const frame of pending) {\n const span = transitive ? region : reach;\n const near =\n frame.x <= span.right + reachX &&\n frame.x + frame.width >= span.left - reachX &&\n frame.y <= span.bottom + reachY &&\n frame.y + frame.height >= span.top - reachY;\n if (near) {\n region.left = Math.min(region.left, frame.x);\n region.right = Math.max(region.right, frame.x + frame.width);\n region.top = Math.min(region.top, frame.y);\n region.bottom = Math.max(region.bottom, frame.y + frame.height);\n pending.delete(frame);\n grown = transitive;\n }\n }\n }\n return region;\n};\n\nconst sortedUnique = (values: number[]): number[] =>\n [...new Set(values.map((value) => Math.round(value * 1000) / 1000))].sort((left, right) => left - right);\n\ntype Axis = 'h' | 'v';\n\n/**\n * The polyline a smart link follows through the gutters, from `from`'s port to `to`'s: undefined when the\n * gutters offer no way round (the caller then falls back to the plain smart route).\n */\nexport const gutterRoute = (\n nodes: readonly Node[],\n spec: LatticeSpec,\n from: RouteEnd,\n to: RouteEnd,\n): Point[] | undefined => gutterRouteWithCost(nodes, spec, from, to)?.points;\n\n/** A gutter route and what it cost the search: `TURN_COST` a bend, plus its length. */\nexport type GutterRoute = { points: Point[]; cost: number };\n\n/** {@link gutterRoute} with its cost, so routes between different ports can be compared. */\nexport const gutterRouteWithCost = (\n nodes: readonly Node[],\n spec: LatticeSpec,\n from: RouteEnd,\n to: RouteEnd,\n): GutterRoute | undefined => {\n const [pitchX, pitchY] = [spec.width + spec.gutterX, spec.height + spec.gutterY];\n const start = gutterExit(from, spec);\n const end = gutterExit(to, spec);\n const frames = nodes.filter(onLattice).map(nodeBounds);\n // The local grid finds almost every route; only when it offers no way round does the search widen.\n const search = (transitive: boolean) =>\n searchGrid(from, to, start, end, frames, searchRegion(start, end, frames, pitchX, pitchY, transitive), spec);\n return search(false) ?? search(true);\n};\n\n/** Dijkstra over the gutter lines and port lines in `region`, from the gutter exit `start` to `end`. */\nconst searchGrid = (\n from: RouteEnd,\n to: RouteEnd,\n start: Point,\n end: Point,\n frames: readonly Bounds[],\n region: Region,\n spec: LatticeSpec,\n): GutterRoute | undefined => {\n const [pitchX, pitchY] = [spec.width + spec.gutterX, spec.height + spec.gutterY];\n const verticals = gutterLines(region.left, region.right, pitchX);\n const horizontals = gutterLines(region.top, region.bottom, pitchY);\n const xs = sortedUnique([...verticals, start.x, end.x]);\n const ys = sortedUnique([...horizontals, start.y, end.y]);\n const clear = (a: Point, b: Point) => !frames.some((frame) => crosses(a, b, frame));\n\n const indexOf = (values: number[], value: number) => values.indexOf(Math.round(value * 1000) / 1000);\n const [startI, startJ] = [indexOf(xs, start.x), indexOf(ys, start.y)];\n const [endI, endJ] = [indexOf(xs, end.x), indexOf(ys, end.y)];\n // The stub leaves along the side's normal, so the first run continuing that axis is not a bend.\n const axisOf = (end: RouteEnd): Axis => (end.side === 'e' || end.side === 'w' ? 'h' : 'v');\n\n // Dijkstra over (column, row, arriving axis), the open set a binary heap: a route is searched for each candidate\n // pair of ports, so each search must be cheap.\n type State = { i: number; j: number; axis: Axis };\n const key = ({ i, j, axis }: State) => `${i},${j},${axis}`;\n const cost = new Map<string, number>();\n const previous = new Map<string, State>();\n const open = new MinHeap<State>();\n const startState: State = { i: startI, j: startJ, axis: axisOf(from) };\n cost.set(key(startState), 0);\n open.push(startState, 0);\n let best: State | undefined;\n let bestCost = Infinity;\n while (open.size > 0) {\n const entry = open.pop();\n if (!entry) {\n break;\n }\n const current = entry.value;\n const currentCost = cost.get(key(current)) ?? Infinity;\n // A state queued again at a lower cost leaves its older entry behind; skip the stale one.\n if (entry.priority > currentCost) {\n continue;\n }\n if (currentCost >= bestCost) {\n break;\n }\n if (current.i === endI && current.j === endJ) {\n // Entering the target's stub off its axis is one more bend.\n const total = currentCost + (current.axis === axisOf(to) ? 0 : TURN_COST);\n if (total < bestCost) {\n bestCost = total;\n best = current;\n }\n continue;\n }\n const here = { x: xs[current.i], y: ys[current.j] };\n const steps: [number, number, Axis][] = [\n [current.i - 1, current.j, 'h'],\n [current.i + 1, current.j, 'h'],\n [current.i, current.j - 1, 'v'],\n [current.i, current.j + 1, 'v'],\n ];\n for (const [i, j, axis] of steps) {\n if (i < 0 || j < 0 || i >= xs.length || j >= ys.length) {\n continue;\n }\n const there = { x: xs[i], y: ys[j] };\n if (!clear(here, there)) {\n continue;\n }\n const next: State = { i, j, axis };\n const nextCost =\n currentCost + Math.abs(there.x - here.x) + Math.abs(there.y - here.y) + (axis === current.axis ? 0 : TURN_COST);\n if (nextCost < (cost.get(key(next)) ?? Infinity)) {\n cost.set(key(next), nextCost);\n previous.set(key(next), current);\n open.push(next, nextCost);\n }\n }\n }\n if (!best) {\n return undefined;\n }\n\n const corners: Point[] = [];\n for (let state: State | undefined = best; state; state = previous.get(key(state))) {\n corners.unshift({ x: xs[state.i], y: ys[state.j] });\n }\n return { points: collapse([from.point, ...corners, to.point]), cost: bestCost };\n};\n\n/** A binary min-heap of values by priority. */\nclass MinHeap<T> {\n #items: { value: T; priority: number }[] = [];\n\n get size(): number {\n return this.#items.length;\n }\n\n push(value: T, priority: number): void {\n const items = this.#items;\n items.push({ value, priority });\n for (let index = items.length - 1; index > 0;) {\n const parent = (index - 1) >> 1;\n if (items[parent].priority <= items[index].priority) {\n break;\n }\n [items[parent], items[index]] = [items[index], items[parent]];\n index = parent;\n }\n }\n\n pop(): { value: T; priority: number } | undefined {\n const items = this.#items;\n const top = items[0];\n const last = items.pop();\n if (items.length > 0 && last) {\n items[0] = last;\n for (let index = 0; ;) {\n const [left, right] = [index * 2 + 1, index * 2 + 2];\n let smallest = index;\n if (left < items.length && items[left].priority < items[smallest].priority) {\n smallest = left;\n }\n if (right < items.length && items[right].priority < items[smallest].priority) {\n smallest = right;\n }\n if (smallest === index) {\n break;\n }\n [items[smallest], items[index]] = [items[index], items[smallest]];\n index = smallest;\n }\n }\n return top;\n }\n}\n\n/** Drops repeated points and the middle of any three collinear ones, so only the real bends remain. */\nconst collapse = (points: Point[]): Point[] => {\n const unique = points.filter(\n (point, index) => index === 0 || point.x !== points[index - 1].x || point.y !== points[index - 1].y,\n );\n return unique.filter((point, index) => {\n if (index === 0 || index === unique.length - 1) {\n return true;\n }\n const [before, after] = [unique[index - 1], unique[index + 1]];\n return !((before.x === point.x && point.x === after.x) || (before.y === point.y && point.y === after.y));\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Link routes as SVG path data in scene coordinates, one per link type: `line` is straight, `curve`\n// leaves each port along its side's normal and bends toward the other end, `spline` is the polyline\n// through the link's control points with its corners rounded. `ortho` (phase 2) will come from\n// `@dxos/diagram`'s router.\n//\n\nimport { Nudge } from '@dxos/diagram';\n\nimport { type NodeRegistry } from '../model/registry.ts';\nimport {\n DEFAULT_GRID,\n type Endpoint,\n type Link,\n MAJOR_GRID,\n type Node,\n type Point,\n type Port,\n type PortEndpoint,\n type Scene,\n type Side,\n isPointEndpoint,\n} from '../model/types.ts';\nimport { gutterRoute, gutterRouteWithCost } from './gutter-route.ts';\nimport { type LatticeSpec } from './lattice.ts';\nimport {\n type PortTerminal,\n nearestPort,\n nodePorts,\n pairPorts,\n portCandidates,\n portPoint,\n sideNormal,\n} from './ports.ts';\nimport { nodeBounds } from './shapes.ts';\n\nconst MIN_TANGENT = 40;\nconst TANGENT_RATIO = 0.4;\n\n/**\n * How far a rounded corner reaches back along each of its segments, in scene px: one minor grid cell, so\n * every corner of a route has the same radius (a gutter route's port stubs are half a gutter, two cells).\n */\nconst CORNER_RADIUS = DEFAULT_GRID;\n\n/** How far a smart link's stub leaves its port, in scene px (half a major cell). */\nconst SMART_STUB = MAJOR_GRID / 2;\n\n/**\n * A resolved link end. `free` marks a point end (one being dragged, or left on empty canvas): it has no port to\n * leave along, so a route runs straight to it rather than turning to its side's normal.\n */\nexport type RouteEnd = { point: Point; side: Side; free?: boolean };\n\nconst pt = ({ x, y }: Point) => `${x} ${y}`;\n\nexport const linePath = (from: Point, to: Point): string => `M ${pt(from)} L ${pt(to)}`;\n\nconst curveControls = (from: RouteEnd, to: RouteEnd): [Point, Point] => {\n const dx = to.point.x - from.point.x;\n const dy = to.point.y - from.point.y;\n const tangent = Math.max(MIN_TANGENT, Math.hypot(dx, dy) * TANGENT_RATIO);\n // A free end takes no tangent: its control point sits on the end, so the curve arrives straight at it.\n const control = (end: RouteEnd): Point => {\n const normal = sideNormal(end.side);\n return end.free ? end.point : { x: end.point.x + normal.x * tangent, y: end.point.y + normal.y * tangent };\n };\n return [control(from), control(to)];\n};\n\n/** Cubic Bézier whose control points sit `tangent` px out along each port's normal. */\nexport const curvePath = (from: RouteEnd, to: RouteEnd): string => {\n const [control1, control2] = curveControls(from, to);\n return `M ${pt(from.point)} C ${pt(control1)}, ${pt(control2)}, ${pt(to.point)}`;\n};\n\n/** Point on the curve at parameter `t`, for placing a label at the midpoint. */\nexport const curvePoint = (from: RouteEnd, to: RouteEnd, t: number): Point => {\n const [p1, p2] = curveControls(from, to);\n const p0 = from.point;\n const p3 = to.point;\n const u = 1 - t;\n return {\n x: u ** 3 * p0.x + 3 * u ** 2 * t * p1.x + 3 * u * t ** 2 * p2.x + t ** 3 * p3.x,\n y: u ** 3 * p0.y + 3 * u ** 2 * t * p1.y + 3 * u * t ** 2 * p2.y + t ** 3 * p3.y,\n };\n};\n\nconst distance = (from: Point, to: Point): number => Math.hypot(to.x - from.x, to.y - from.y);\n\n/** The point `length` along the way from `from` towards `to`, or `from` when the two coincide. */\nconst towards = (from: Point, to: Point, length: number): Point => {\n const span = distance(from, to);\n return span === 0\n ? from\n : { x: from.x + ((to.x - from.x) / span) * length, y: from.y + ((to.y - from.y) / span) * length };\n};\n\n/**\n * The polyline through every point with its corners rounded: each interior point becomes a quadratic\n * Bézier that takes the point as its control, so the route bends around a control point rather than\n * through it and a corner reads as a corner. The radius shrinks to half the shorter adjoining segment\n * where a point is close to its neighbours, so two corners never eat into each other.\n */\nexport const splinePath = (points: readonly Point[]): string => {\n if (points.length < 2) {\n return '';\n }\n const last = points.length - 1;\n const segments: string[] = [`M ${pt(points[0])}`];\n for (let index = 1; index < last; index++) {\n const previous = points[index - 1];\n const vertex = points[index];\n const next = points[index + 1];\n const radius = Math.min(CORNER_RADIUS, distance(previous, vertex) / 2, distance(vertex, next) / 2);\n segments.push(`L ${pt(towards(vertex, previous, radius))}`);\n segments.push(`Q ${pt(vertex)}, ${pt(towards(vertex, next, radius))}`);\n }\n segments.push(`L ${pt(points[last])}`);\n return segments.join(' ');\n};\n\n/** The path of a link between two resolved ends, by its type; on a lattice a smart link takes the gutters. */\nexport const linkPath = (link: Link, from: RouteEnd, to: RouteEnd, lattice?: LatticeRoute): string => {\n switch (link.type) {\n case 'line':\n return linePath(from.point, to.point);\n case 'curve':\n return curvePath(from, to);\n case 'spline':\n return splinePath([from.point, ...link.points, to.point]);\n case 'smart':\n // A free end (one being dragged) takes no gutter: the route runs straight to it.\n return splinePath(\n (lattice && !from.free && !to.free && gutterRoute(lattice.nodes, lattice.spec, from, to)) ||\n smartPoints(from, to),\n );\n default:\n // A link type this engine does not know (saved by a newer one) draws as the core base: a straight line.\n return linePath(from.point, to.point);\n }\n};\n\n/** What gutter routing needs: the lattice and the nodes whose frames block it. */\nexport type LatticeRoute = { spec: LatticeSpec; nodes: readonly Node[] };\n\n/**\n * The polyline a smart link follows: a stub out of each port along its side's normal, then one segment\n * joining them. `splinePath` rounds where they meet, so a pair of facing ports reads as the elbow the\n * ports imply rather than a straight line cutting across their own nodes.\n */\nexport const smartPoints = (from: RouteEnd, to: RouteEnd): Point[] => {\n // A free end has no stub: the route runs straight to it.\n const stub = (end: RouteEnd): Point[] => {\n const normal = sideNormal(end.side);\n return end.free ? [] : [{ x: end.point.x + normal.x * SMART_STUB, y: end.point.y + normal.y * SMART_STUB }];\n };\n return [from.point, ...stub(from), ...stub(to).reverse(), to.point];\n};\n\nexport type LinkGeometry = { link: Link; path: string; source: RouteEnd; target: RouteEnd };\n\n/** The side of a free end: the one facing the other end, so the route leaves it toward that end. */\nexport const sideToward = (from: Point, to: Point): Side => {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n return Math.abs(dx) >= Math.abs(dy) ? (dx >= 0 ? 'e' : 'w') : dy >= 0 ? 's' : 'n';\n};\n\n/** A node end as the port picker sees it, or nothing when the node is gone. */\nconst terminalOf = (scene: Scene, registry: NodeRegistry, end: PortEndpoint): PortTerminal | undefined => {\n const node = scene.nodes[end.node];\n return node ? { bounds: nodeBounds(node), ports: nodePorts(registry, node), port: end.port } : undefined;\n};\n\nconst routeEnd = (terminal: PortTerminal, port: Port): RouteEnd => ({\n point: portPoint(terminal.bounds, port),\n side: port.side,\n});\n\n/** Port pairs searched per tier of fewest possible bends. */\nconst PAIRS_PER_TIER = 3;\n\n/**\n * The fewest bends any right-angled route between two ports could take: none when they face each other on one line,\n * one when their sides are perpendicular and each points toward the corner they share, otherwise at least two.\n */\nconst leastBends = (from: RouteEnd, to: RouteEnd): number => {\n const out = sideNormal(from.side);\n // A route arrives at its target moving against the target side's normal.\n const arrive = sideNormal(to.side);\n const [dx, dy] = [to.point.x - from.point.x, to.point.y - from.point.y];\n const ahead = (normal: Point, x: number, y: number) => normal.x * x + normal.y * y > 0;\n if (out.x === -arrive.x && out.y === -arrive.y) {\n const aligned = out.x !== 0 ? dy === 0 : dx === 0;\n return aligned && ahead(out, dx, dy) ? 0 : 2;\n }\n if (out.x * arrive.x + out.y * arrive.y === 0) {\n // The corner is where the source's line meets the target's.\n const corner = out.x !== 0 ? { x: to.point.x, y: from.point.y } : { x: from.point.x, y: to.point.y };\n const first = ahead(out, corner.x - from.point.x, corner.y - from.point.y);\n const second = ahead({ x: -arrive.x, y: -arrive.y }, to.point.x - corner.x, to.point.y - corner.y);\n return first && second ? 1 : 2;\n }\n return 2;\n};\n\n/**\n * The ends and gutter route of a smart link between two nodes on a lattice: of the pairs of side-centre ports (or the\n * pinned ones), the one whose route is cheapest, fewest bends first, so a link leaves straight down a free column\n * rather than from the nearest port round a corner. Pairs are tried nearest first, so a tie keeps the nearest.\n */\nconst latticeEnds = (\n scene: Scene,\n registry: NodeRegistry,\n link: Link,\n route: LatticeRoute,\n): { from: RouteEnd; to: RouteEnd; points: Point[] } | undefined => {\n if (link.type !== 'smart' || isPointEndpoint(link.source) || isPointEndpoint(link.target)) {\n return undefined;\n }\n const source = terminalOf(scene, registry, link.source);\n const target = terminalOf(scene, registry, link.target);\n if (!source || !target) {\n return undefined;\n }\n // A side's centre, where a side has one; a pinned port or a custom layout keeps what it offers.\n const centres = (ports: readonly Port[]) => {\n const middle = ports.filter((port) => port.offset === 0.5);\n return middle.length > 0 ? middle : ports;\n };\n const sources = centres(portCandidates(source, 'out'));\n const targets = centres(portCandidates(target, 'in'));\n // Fewest possible bends first, then nearest: the search stops once no pair left could bend less than the best found.\n const pairs = sources\n .flatMap((from) => targets.map((to) => ({ from: routeEnd(source, from), to: routeEnd(target, to) })))\n .map((pair) => ({\n ...pair,\n least: leastBends(pair.from, pair.to),\n distance: Math.hypot(pair.from.point.x - pair.to.point.x, pair.from.point.y - pair.to.point.y),\n }))\n .sort((left, right) => left.least - right.least || left.distance - right.distance);\n let best: { from: RouteEnd; to: RouteEnd; points: Point[]; bends: number } | undefined;\n // Within a tier only the nearest few are searched: a farther pair seldom routes better, and each search has a cost.\n const tried = new Map<number, number>();\n for (const pair of pairs) {\n if (best && pair.least >= best.bends) {\n break;\n }\n const count = tried.get(pair.least) ?? 0;\n if (count >= PAIRS_PER_TIER) {\n continue;\n }\n tried.set(pair.least, count + 1);\n const routed = gutterRouteWithCost(route.nodes, route.spec, pair.from, pair.to);\n // The route's points are its ends and its corners.\n const bends = routed ? routed.points.length - 2 : Infinity;\n if (routed && (!best || bends < best.bends)) {\n best = { from: pair.from, to: pair.to, points: routed.points, bends };\n }\n }\n return best;\n};\n\n/**\n * Resolve a link's ends and route it by its type: two node ends take the automatic (or pinned) port pair,\n * a node end facing a free point takes the port nearest that point, and two free points face each other.\n */\nexport const linkGeometry = (\n scene: Scene,\n registry: NodeRegistry,\n link: Link,\n lattice?: LatticeSpec,\n): LinkGeometry | undefined => {\n const route = lattice ? { spec: lattice, nodes: Object.values(scene.nodes) } : undefined;\n const routed = route && latticeEnds(scene, registry, link, route);\n if (routed) {\n return { link, path: splinePath(routed.points), source: routed.from, target: routed.to };\n }\n const ends = resolveEnds(scene, registry, link.source, link.target);\n if (!ends) {\n return undefined;\n }\n const [from, to] = ends;\n return { link, path: linkPath(link, from, to, route), source: from, target: to };\n};\n\nconst resolveEnds = (\n scene: Scene,\n registry: NodeRegistry,\n source: Endpoint,\n target: Endpoint,\n): [RouteEnd, RouteEnd] | undefined => {\n if (isPointEndpoint(source)) {\n if (isPointEndpoint(target)) {\n return [\n { point: source.point, side: sideToward(source.point, target.point), free: true },\n { point: target.point, side: sideToward(target.point, source.point), free: true },\n ];\n }\n const terminal = terminalOf(scene, registry, target);\n const port = terminal && nearestPort(terminal, source.point, 'in');\n if (!terminal || !port) {\n return undefined;\n }\n const to = routeEnd(terminal, port);\n return [{ point: source.point, side: sideToward(source.point, to.point), free: true }, to];\n }\n if (isPointEndpoint(target)) {\n const terminal = terminalOf(scene, registry, source);\n const port = terminal && nearestPort(terminal, target.point, 'out');\n if (!terminal || !port) {\n return undefined;\n }\n const from = routeEnd(terminal, port);\n return [from, { point: target.point, side: sideToward(target.point, from.point), free: true }];\n }\n const sourceTerminal = terminalOf(scene, registry, source);\n const targetTerminal = terminalOf(scene, registry, target);\n const pair = sourceTerminal && targetTerminal && pairPorts(sourceTerminal, targetTerminal);\n if (!sourceTerminal || !targetTerminal || !pair) {\n return undefined;\n }\n return [routeEnd(sourceTerminal, pair.source), routeEnd(targetTerminal, pair.target)];\n};\n\n/**\n * Every link's geometry, routed together: on a lattice scene the smart links take the gutters and are\n * then nudged apart (`@dxos/diagram`'s `Nudge`, one minor grid unit between lanes) so links sharing a\n * gutter run side by side in their own lanes, ordered so their turn-offs do not cross (DESIGN §8b).\n * Other links, and any scene without a lattice, route one by one as `linkGeometry` does.\n */\nexport const sceneLinkGeometry = (\n scene: Scene,\n registry: NodeRegistry,\n links: readonly Link[],\n lattice?: LatticeSpec,\n): LinkGeometry[] => {\n if (!lattice) {\n return links.flatMap((link) => linkGeometry(scene, registry, link) ?? []);\n }\n const nodes = Object.values(scene.nodes);\n const rect = (bounds: { x: number; y: number; width: number; height: number }) => ({\n x: bounds.x,\n y: bounds.y,\n w: bounds.width,\n h: bounds.height,\n });\n const frameOf = (end: Endpoint) => {\n const node = isPointEndpoint(end) ? undefined : scene.nodes[end.node];\n return node ? rect(nodeBounds(node)) : undefined;\n };\n const route = { spec: lattice, nodes };\n const routed = links.flatMap((link) => {\n const chosen = latticeEnds(scene, registry, link, route);\n if (chosen) {\n return [{ link, from: chosen.from, to: chosen.to, points: chosen.points }];\n }\n const ends = resolveEnds(scene, registry, link.source, link.target);\n if (!ends) {\n return [];\n }\n const [from, to] = ends;\n const points = link.type === 'smart' ? (gutterRoute(nodes, lattice, from, to) ?? smartPoints(from, to)) : undefined;\n return [{ link, from, to, points }];\n });\n const smart = routed.filter((entry) => entry.points !== undefined);\n const nudged = Nudge.nudge(\n smart.map(({ link, points }) => ({\n points: points ?? [],\n source: frameOf(link.source),\n target: frameOf(link.target),\n })),\n { spacing: DEFAULT_GRID, obstacles: nodes.map((node) => rect(nodeBounds(node))) },\n );\n const lanes = new Map(smart.map((entry, index) => [entry.link.id, nudged[index]]));\n return routed.map(({ link, from, to }) => {\n const points = lanes.get(link.id);\n if (!points || points.length < 2) {\n return { link, path: linkPath(link, from, to), source: from, target: to };\n }\n // A nudged port may slide along its side, so the ends are read back from the lane.\n const source = { point: points[0], side: from.side };\n const target = { point: points[points.length - 1], side: to.side };\n return { link, path: splinePath(points), source, target };\n });\n};\n\n/** Index at which a new control point at `point` keeps the polyline `ends`+`points` in order. */\nexport const insertIndex = (from: Point, points: readonly Point[], to: Point, point: Point): number => {\n const polyline = [from, ...points, to];\n let best = 0;\n let bestDistance = Infinity;\n for (let index = 0; index < polyline.length - 1; index++) {\n const distance = segmentDistance(polyline[index], polyline[index + 1], point);\n if (distance < bestDistance) {\n bestDistance = distance;\n best = index;\n }\n }\n return best;\n};\n\nconst segmentDistance = (a: Point, b: Point, p: Point): number => {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const length2 = dx * dx + dy * dy;\n const t = length2 === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / length2));\n return Math.hypot(a.x + t * dx - p.x, a.y + t * dy - p.y);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Overlay in scene coordinates (§7 layer 3): selection outlines, resize handles, ports, link end and\n// control points, the marquee and the link rubber band. Sizes are divided by zoom because the parent\n// transform scales the SVG.\n//\n\nimport React, { memo } from 'react';\n\nimport { mx } from '@dxos/ui-theme';\n\nimport { type ControlPointRef, type Drag, type Handle, isMoving } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type NodeRegistry } from '../../model/registry.ts';\nimport {\n type Bounds,\n type Capabilities,\n type ElementId,\n type Endpoint,\n type Link,\n type LinkId,\n type Node,\n type Point,\n type Port,\n type Scene,\n type SplineLink,\n endpointNode,\n isPointEndpoint,\n} from '../../model/types.ts';\nimport { boundsFromPoints } from '../../utils/hit.ts';\nimport { type LatticeSpec } from '../../utils/lattice.ts';\nimport { nodePorts, oppositeSide, portPoint } from '../../utils/ports.ts';\nimport { curvePath, linkGeometry, sceneLinkGeometry } from '../../utils/route.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\n\nconst HANDLES: readonly Handle[] = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];\n\nexport const handlePoint = (bounds: Bounds, handle: Handle): Point => {\n const x = handle.includes('w')\n ? bounds.x\n : handle.includes('e')\n ? bounds.x + bounds.width\n : bounds.x + bounds.width / 2;\n const y = handle.includes('n')\n ? bounds.y\n : handle.includes('s')\n ? bounds.y + bounds.height\n : bounds.y + bounds.height / 2;\n return { x, y };\n};\n\nconst cursorFor = (handle: Handle) =>\n ({ n: 'ns', s: 'ns', e: 'ew', w: 'ew', ne: 'nesw', sw: 'nesw', nw: 'nwse', se: 'nwse' })[handle] + '-resize';\n\nexport type LinkEnd = 'source' | 'target';\n\nexport type ControlFrameProps = {\n scene: Scene;\n registry: NodeRegistry;\n /** What the view may do: no handle is drawn for a gesture that could not apply. */\n capabilities: Capabilities;\n selection: ReadonlySet<ElementId>;\n hover?: ElementId;\n /** The link under the pointer: it shows its end handles, as a selected link does. */\n hoveredLink?: LinkId;\n /** The pointer entered or left a hovered link's handles, which keeps the link hovered while on them. */\n onLinkHover?: (id: LinkId | undefined) => void;\n selectedPoint?: ControlPointRef;\n zoom: number;\n drag?: Drag;\n /** The bounds a create gesture in flight would land, drawn as a provisional frame. */\n createFrame?: Bounds;\n /** Where the nodes of a move in flight will land, drawn under them as they follow the pointer. */\n landing?: readonly Bounds[];\n /** The gesture in flight would be refused (an overlap on the lattice): its outlines turn red. */\n blocked?: boolean;\n /** The scene's lattice, so a selected smart link's handles sit on its gutter route. */\n lattice?: LatticeSpec;\n onHandlePointerDown?: (node: Node, handle: Handle, event: React.PointerEvent) => void;\n onPortPointerDown?: (node: Node, port: Port, event: React.PointerEvent) => void;\n onEndPointerDown?: (link: Link, end: LinkEnd, event: React.PointerEvent) => void;\n onPointPointerDown?: (link: SplineLink, index: number, event: React.PointerEvent) => void;\n /** `index` is where in the link's points a control point at `point` would be inserted. */\n onMidpointPointerDown?: (link: SplineLink, index: number, point: Point, event: React.PointerEvent) => void;\n onPointContextMenu?: (link: SplineLink, index: number, event: React.MouseEvent) => void;\n};\n\n/** The midpoint of every span of a spline's polyline, each with the index a control point there takes. */\nconst midpoints = (source: Point, points: readonly Point[], target: Point) => {\n const vertices = [source, ...points, target];\n return vertices.slice(1).map((vertex, index) => ({\n index,\n point: { x: (vertices[index].x + vertex.x) / 2, y: (vertices[index].y + vertex.y) / 2 },\n }));\n};\n\nexport const ControlFrame = memo(\n ({\n scene,\n registry,\n capabilities,\n selection,\n hover,\n hoveredLink,\n onLinkHover,\n selectedPoint,\n zoom,\n drag,\n createFrame,\n landing,\n blocked,\n lattice,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n }: ControlFrameProps) => {\n const unit = 1 / Math.max(zoom, 0.05);\n const handleSize = 8 * unit;\n const portRadius = 5 * unit;\n const midpointRadius = 4 * unit;\n // A move in flight shows the shapes themselves: no outlines or handles, just where they will land.\n const chrome = isMoving(drag) ? [] : [...selection];\n const selectedNodes = chrome.map((id) => scene.nodes[id]).filter((node) => node !== undefined);\n const selectedLinks = chrome.map((id) => scene.links[id]).filter((link) => link !== undefined);\n const linkUnder = hoveredLink && !selection.has(hoveredLink) ? scene.links[hoveredLink] : undefined;\n // A hovered link shows the handles of a selected one; only its ends, its control points stay a selection's.\n const lanes =\n lattice && (selectedLinks.length > 0 || linkUnder !== undefined)\n ? new Map(\n sceneLinkGeometry(scene, registry, Object.values(scene.links), lattice).map((geometry) => [\n geometry.link.id,\n geometry,\n ]),\n )\n : undefined;\n const single = selectedNodes.length === 1 ? selectedNodes[0] : undefined;\n // Only the node under the pointer: every node's ports at once is a field of dots that hides the\n // diagram the user is drawing, and a link can start from a body now, so they are a refinement\n // rather than the only way in.\n const portNodes = new Set<Node>();\n const hovered = hover ? scene.nodes[hover] : undefined;\n // A selected node shows its handles instead: ports on the same frame crowd them and the label.\n if (hovered && capabilities.link && !selection.has(hovered.id)) {\n portNodes.add(hovered);\n }\n // Pointer capture during a link drag suppresses hover, so the drop target shows its ports itself.\n const dropNode = (drag?.kind === 'link' || drag?.kind === 'end') && drag.target && endpointNode(drag.target);\n const dropTarget = dropNode ? scene.nodes[dropNode] : undefined;\n if (dropTarget) {\n portNodes.add(dropTarget);\n }\n // The end a link drag holds still shows its ports too, a new link's source as an existing link's far end.\n const draggedLink = drag?.kind === 'end' ? scene.links[drag.id] : undefined;\n const fixedEnd =\n drag?.kind === 'link'\n ? drag.source\n : draggedLink && drag?.kind === 'end'\n ? drag.end === 'source'\n ? draggedLink.target\n : draggedLink.source\n : undefined;\n const fixedNode = fixedEnd && endpointNode(fixedEnd);\n const anchor = fixedNode ? scene.nodes[fixedNode] : undefined;\n if (anchor) {\n portNodes.add(anchor);\n }\n const marquee = drag?.kind === 'marquee' ? boundsFromPoints(drag.from, drag.to) : undefined;\n // The layer draws every provisional link that will land (over a target, or free-ended); the band is only\n // a port drag over free space, where dropping would create a node rather than a free end.\n const band =\n drag?.kind === 'link' && !drag.target && !isPointEndpoint(drag.source)\n ? { from: { point: drag.from, side: drag.fromSide }, to: drag.to }\n : undefined;\n\n /** A link's end handles, and a selected spline's control points; a hovered link shows only its ends. */\n const linkHandles = (link: Link, hoverOnly: boolean) => {\n // On a lattice the handles sit on the link's lane, which depends on the links around it.\n const geometry = capabilities.update\n ? (lanes?.get(link.id) ?? linkGeometry(scene, registry, link, lattice))\n : undefined;\n if (!geometry) {\n return null;\n }\n const points =\n link.type === 'spline' ? (drag?.kind === 'point' && drag.id === link.id ? drag.points : link.points) : [];\n const ends: [LinkEnd, Point][] = [\n ['source', geometry.source.point],\n ['target', geometry.target.point],\n ];\n return (\n <g key={link.id}>\n {ends.map(([end, point]) => (\n <circle\n key={end}\n cx={point.x}\n cy={point.y}\n r={portRadius}\n className={mx(\n 'stroke-focus pointer-events-auto cursor-move hover:fill-focus',\n drag?.kind === 'end' && drag.id === link.id && drag.end === end ? 'fill-focus' : 'fill-base-surface',\n )}\n strokeWidth={unit}\n onPointerDown={(event) => onEndPointerDown?.(link, end, event)}\n onPointerEnter={hoverOnly ? () => onLinkHover?.(link.id) : undefined}\n onPointerLeave={hoverOnly ? () => onLinkHover?.(undefined) : undefined}\n />\n ))}\n {/* Midpoints first, so a control point wins wherever the two land on each other. */}\n {!hoverOnly &&\n link.type === 'spline' &&\n midpoints(geometry.source.point, points, geometry.target.point).map(({ index, point }) => (\n <circle\n key={`midpoint-${index}`}\n cx={point.x}\n cy={point.y}\n r={midpointRadius}\n className='fill-focus/40 pointer-events-auto cursor-copy hover:fill-focus'\n onPointerDown={(event) => onMidpointPointerDown?.(link, index, point, event)}\n />\n ))}\n {link.type === 'spline' &&\n points.map((point, index) => (\n <rect\n key={index}\n x={point.x - handleSize / 2}\n y={point.y - handleSize / 2}\n width={handleSize}\n height={handleSize}\n transform={`rotate(45 ${point.x} ${point.y})`}\n className={mx(\n 'stroke-focus pointer-events-auto cursor-move hover:fill-focus',\n selectedPoint?.link === link.id && selectedPoint.index === index ? 'fill-focus' : 'fill-base-surface',\n )}\n strokeWidth={unit}\n onPointerDown={(event) => onPointPointerDown?.(link, index, event)}\n onContextMenu={(event) => onPointContextMenu?.(link, index, event)}\n />\n ))}\n </g>\n );\n };\n\n return (\n <svg className='absolute overflow-visible pointer-events-none' width={1} height={1}>\n {selectedNodes.map((node) => {\n const bounds = nodeBounds(node);\n return (\n <rect\n key={node.id}\n x={bounds.x}\n y={bounds.y}\n width={bounds.width}\n height={bounds.height}\n className={mx('fill-none', blocked ? 'stroke-error-border' : 'stroke-focus')}\n strokeWidth={unit}\n data-blocked={blocked || undefined}\n />\n );\n })}\n {[...portNodes].map((node) => {\n const bounds = nodeBounds(node);\n return nodePorts(registry, node).map((port) => {\n const point = portPoint(bounds, port);\n // Filled while it is an end of the drag in progress: the source, or the port it would drop on.\n const isEnd = (end: Endpoint | undefined) =>\n end !== undefined && !isPointEndpoint(end) && end.node === node.id && end.port === port.id;\n const active = isEnd(fixedEnd) || ((drag?.kind === 'link' || drag?.kind === 'end') && isEnd(drag.target));\n return (\n <circle\n key={`${node.id}/${port.id}`}\n cx={point.x}\n cy={point.y}\n r={portRadius}\n className={mx(\n 'stroke-focus pointer-events-auto cursor-crosshair hover:fill-focus',\n active ? 'fill-focus' : 'fill-base-surface',\n )}\n strokeWidth={unit}\n onPointerDown={(event) => onPortPointerDown?.(node, port, event)}\n />\n );\n });\n })}\n {/* A hovered link's ends go under a node's handles, so a resize handle on the same point still wins. */}\n {linkUnder && linkHandles(linkUnder, true)}\n {/* Handles after the ports so a handle wins where a port sits on the same point (a side centre). */}\n {single && capabilities.resize && nodeDef(registry, single)?.resizable && !single.locked && (\n <g>\n {HANDLES.map((handle) => {\n const point = handlePoint(nodeBounds(single), handle);\n return (\n <rect\n key={handle}\n x={point.x - handleSize / 2}\n y={point.y - handleSize / 2}\n width={handleSize}\n height={handleSize}\n className='fill-base-surface stroke-focus pointer-events-auto'\n strokeWidth={unit}\n style={{ cursor: cursorFor(handle) }}\n onPointerDown={(event) => onHandlePointerDown?.(single, handle, event)}\n />\n );\n })}\n </g>\n )}\n {/* A link's end and control-point handles all move it, so they follow the `update` capability together. */}\n {selectedLinks.map((link) => linkHandles(link, false))}\n {band && (\n <path\n d={curvePath(band.from, { point: band.to, side: oppositeSide(band.from.side), free: true })}\n className='fill-none stroke-focus'\n strokeWidth={2 * unit}\n strokeDasharray={`${6 * unit} ${4 * unit}`}\n />\n )}\n {/* A link end over empty canvas carries a connection circle, as an end on a port does. */}\n {(drag?.kind === 'link' || drag?.kind === 'end') && !drag.target && (\n <circle\n data-testid='free-end'\n cx={drag.to.x}\n cy={drag.to.y}\n r={portRadius}\n className='fill-focus stroke-focus pointer-events-none'\n strokeWidth={unit}\n />\n )}\n {marquee && (\n <rect\n x={marquee.x}\n y={marquee.y}\n width={marquee.width}\n height={marquee.height}\n className='fill-focus/10 stroke-focus'\n strokeWidth={unit}\n />\n )}\n {landing?.map((frame, index) => (\n <rect\n key={index}\n data-testid='landing-frame'\n x={frame.x}\n y={frame.y}\n width={frame.width}\n height={frame.height}\n className={mx('fill-none', blocked ? 'stroke-error-border' : 'stroke-focus')}\n data-blocked={blocked || undefined}\n strokeWidth={unit}\n strokeDasharray={`${4 * unit} ${4 * unit}`}\n />\n ))}\n {createFrame && (\n <rect\n data-testid='create-frame'\n x={createFrame.x}\n y={createFrame.y}\n width={createFrame.width}\n height={createFrame.height}\n className={blocked ? 'fill-error-surface stroke-error-border' : 'fill-focus/10 stroke-focus'}\n data-blocked={blocked || undefined}\n strokeWidth={unit}\n />\n )}\n </svg>\n );\n },\n);\n\nControlFrame.displayName = 'ControlFrame';\n","//\n// Copyright 2024 DXOS.org\n//\n\nimport React, { forwardRef, useId, useMemo } from 'react';\n\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type Point } from '../../model/types.ts';\n\nconst gridRatios = [1 / 4, 1, 4, 16];\n\nconst defaultGridSize = 16;\nconst defaultOffset: Point = { x: 0, y: 0 };\nconst defaultRange = [defaultGridSize, 128] as const;\n\nconst createId = (parent: string, grid: number) => `dx-canvas-grid-${parent}-${grid}`;\n\n/**\n * A level's line opacity from its on-screen spacing alone: faint at the finest drawn spacing, a step\n * darker per fourfold. A level then fades in as the view zooms rather than popping, and a scene swap\n * that keeps every spacing (drilling through a grid-aligned portal) keeps every line as it was. The\n * step is small and the ceiling low: the grid is a guide under the diagram, so the coarse levels in\n * particular must not read as content.\n */\nconst levelOpacity = (size: number, min: number) => Math.min(0.12, 0.04 + (0.02 * Math.log(size / min)) / Math.log(4));\n\nexport type GridProps = Util.ThemedClassName<{\n size?: number;\n scale?: number;\n offset?: Point;\n showAxes?: boolean;\n /** Grid levels as multiples of `size`, finest first. */\n ratios?: readonly number[];\n /** On-screen cell size (px) outside which a level is not drawn. */\n range?: readonly [min: number, max: number];\n}>;\n\n/** Multi-level grid in screen space, fed the camera's scale and offset. */\nexport const GridComponent = forwardRef<SVGSVGElement, GridProps>(\n (\n {\n size: gridSize = defaultGridSize,\n scale = 1,\n offset = defaultOffset,\n showAxes = true,\n ratios = gridRatios,\n range = defaultRange,\n classNames,\n },\n forwardedRef,\n ) => {\n const svgRef = Hooks.useForwardedRef(forwardedRef);\n const { width = 0, height = 0 } = svgRef.current?.getBoundingClientRect() ?? {};\n\n const instanceId = useId();\n const [min, max] = range;\n const grids = useMemo(\n () =>\n ratios\n .map((ratio) => ({ id: ratio, size: ratio * gridSize * scale }))\n .filter(({ size }) => size >= min && size <= max),\n [ratios, gridSize, scale, min, max],\n );\n\n return (\n <svg\n data-testid='dx-canvas-grid'\n ref={svgRef}\n // `dx-cover` (absolute inset-0) does not stretch a replaced <svg> element — without an explicit\n // size it falls back to the intrinsic 300x150, clipping the 100%-sized grid rects. Force full size.\n className={mx(\n 'dx-cover w-full h-full pointer-events-none touch-none select-none',\n 'stroke-neutral-500',\n classNames,\n )}\n >\n {/* NOTE: The pattern is offset so that the middle of the pattern aligns with the grid. */}\n <defs>\n {grids.map(({ id, size }) => (\n <GridPattern key={id} id={createId(instanceId, id)} offset={offset} size={size} />\n ))}\n </defs>\n {showAxes && (\n <>\n <line x1={0} y1={offset.y} x2={width} y2={offset.y} className='stroke-neutral-500 opacity-40' />\n <line x1={offset.x} y1={0} x2={offset.x} y2={height} className='stroke-neutral-500 opacity-40' />\n </>\n )}\n <g>\n {grids.map(({ id, size }) => (\n <rect\n key={id}\n opacity={levelOpacity(size, min)}\n fill={`url(#${createId(instanceId, id)})`}\n width='100%'\n height='100%'\n />\n ))}\n </g>\n </svg>\n );\n },\n);\n\nGridComponent.displayName = 'GridComponent';\n\n/** One grid level as an SVG pattern of crossing lines, offset so a line sits on the origin. */\nconst GridPattern = ({ id, size, offset }: { id: string; size: number; offset: Point }) => (\n <pattern\n id={id}\n x={(size / 2 + offset.x) % size}\n y={(size / 2 + offset.y) % size}\n width={size}\n height={size}\n patternUnits='userSpaceOnUse'\n >\n <line x1={0} y1={size / 2} x2={size} y2={size / 2} />\n <line x1={size / 2} y1={0} x2={size / 2} y2={size} />\n </pattern>\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { memo } from 'react';\n\nimport { type Bounds } from '../../model/types.ts';\nimport { type LatticeSpec, cellBounds } from '../../utils/lattice.ts';\n\n/** Above this many cells the lattice reads as texture rather than places, so it is not drawn. */\nconst MAX_CELLS = 4096;\n\nexport type LatticeGridProps = {\n spec: LatticeSpec;\n /** The scene area to cover, in scene units. */\n bounds: Bounds;\n /** One screen pixel in scene units, so the outline stays a hairline at any zoom. */\n unit: number;\n};\n\n/**\n * The cells of a lattice scene (DESIGN §8b), drawn in scene coordinates as faint one-cell frames, so the\n * places a shape can land and the gutters between them are visible before anything is dropped.\n */\nexport const LatticeGrid = memo(({ spec, bounds, unit }: LatticeGridProps) => {\n const [pitchX, pitchY] = [spec.width + spec.gutterX, spec.height + spec.gutterY];\n const [fromCol, toCol] = [Math.floor(bounds.x / pitchX), Math.ceil((bounds.x + bounds.width) / pitchX)];\n const [fromRow, toRow] = [Math.floor(bounds.y / pitchY), Math.ceil((bounds.y + bounds.height) / pitchY)];\n if ((toCol - fromCol + 1) * (toRow - fromRow + 1) > MAX_CELLS) {\n return null;\n }\n\n const cells: Bounds[] = [];\n for (let row = fromRow; row <= toRow; row++) {\n for (let col = fromCol; col <= toCol; col++) {\n cells.push(cellBounds({ col, row, spanX: 1, spanY: 1 }, spec));\n }\n }\n\n return (\n <svg className='absolute overflow-visible pointer-events-none' width={1} height={1} data-testid='lattice-grid'>\n {cells.map((cell) => (\n <rect\n key={`${cell.x},${cell.y}`}\n x={cell.x}\n y={cell.y}\n width={cell.width}\n height={cell.height}\n className='fill-none stroke-separator'\n strokeWidth={unit}\n strokeDasharray={`${4 * unit} ${4 * unit}`}\n />\n ))}\n </svg>\n );\n});\n\nLatticeGrid.displayName = 'LatticeGrid';\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useMemo, useState } from 'react';\n\nimport { OrderedList } from '@dxos/react-ui-list';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Editable from '@dxos/react-ui/Editable';\nimport * as Menu from '@dxos/react-ui/Menu';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport type * as Util from '@dxos/react-ui/Util';\n\nimport { type Layer, type LayerId } from '../../model/types.ts';\n\nexport type LayersPanelProps = Util.ThemedClassName<{\n /** The scene's layers, bottom first (`sceneLayers`); the panel lists them top first, as they stack. */\n layers: readonly Layer[];\n /** The selected layers; the top-most of them is the one new shapes go on. */\n selected?: readonly LayerId[];\n readonly?: boolean;\n onSelectedChange?: (ids: LayerId[]) => void;\n /** Shows or hides a layer. */\n onToggle?: (id: LayerId) => void;\n onRename?: (id: LayerId, name: string) => void;\n /** Moves a layer to `index` in the bottom-first order. */\n onMove?: (id: LayerId, index: number) => void;\n /** Adds a layer; the panel opens the name of the one whose id it returns. */\n onCreate?: () => LayerId | void;\n /** Removes the selected layers and their shapes; offered while at least one layer would remain. */\n onDelete?: (ids: LayerId[]) => void;\n /** Merges the selected layers into the top-most of them; offered while two or more are selected. */\n onMerge?: (ids: LayerId[], into: LayerId) => void;\n /** Whether the panel is docked beside the canvas. */\n docked?: boolean;\n}>;\n\ntype LayerNameProps = {\n layer: Layer;\n readonly?: boolean;\n editing: boolean;\n onEditingChange: (editing: boolean) => void;\n onRename?: (name: string) => void;\n};\n\n/**\n * A layer's name, edited in place on a double-click (`Editable`: the input takes the preview's cell, so the row does\n * not move). Enter or leaving it commits, Escape keeps the old name. It is the row's text part, so it carries that\n * part's class for the row's layout.\n */\nconst LayerName = ({ layer, readonly, editing, onEditingChange, onRename }: LayerNameProps) => (\n <Editable.Root\n classNames='dx-listbox-item-text'\n value={layer.name}\n activation='dblclick'\n editing={editing}\n onEditingChange={onEditingChange}\n disabled={readonly || !onRename}\n onValueChange={(next) => {\n const name = next.trim();\n if (name && name !== layer.name) {\n onRename?.(name);\n }\n }}\n >\n <Editable.Preview data-testid={`layer-name-${layer.id}`} />\n <Editable.Input\n aria-label='Layer name'\n data-testid={`layer-input-${layer.id}`}\n // While a name is typed, the list's keys (typeahead, arrows, selection) must not take its keys; otherwise the\n // list keeps them, so the arrows move between rows.\n onKeyDown={(event) => event.stopPropagation()}\n />\n </Editable.Root>\n);\n\n/**\n * A scene's layers, top first as they stack: the active one is selected, each shows or hides from its eye, renames on\n * a double-click and reorders by its handle. The toolbar adds a layer, deletes the active one, and merges it down.\n */\nexport const LayersPanel = ({\n classNames,\n layers,\n selected: selectedProp,\n readonly,\n onSelectedChange,\n onToggle,\n onRename,\n onMove,\n onCreate,\n onDelete,\n onMerge,\n docked = false,\n}: LayersPanelProps) => {\n const items = useMemo(() => [...layers].reverse(), [layers]);\n // The row whose name is open; a new layer opens its own, so it is named as it is made.\n const [editingId, setEditingId] = useState<LayerId>();\n // Bottom first, as `layers`, so the last is the top-most selected.\n const selected = useMemo(\n () => layers.filter((layer) => selectedProp?.includes(layer.id)).map((layer) => layer.id),\n [layers, selectedProp],\n );\n const top = selected[selected.length - 1];\n return (\n <Panel.Root classNames={classNames} data-testid='layers'>\n <Panel.Header asChild>\n <Toolbar.Root data-testid='layers-toolbar'>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--plus--regular'\n label='Add layer'\n disabled={readonly || !onCreate}\n data-testid='layers-create'\n onClick={() => {\n const id = onCreate?.();\n if (id) {\n setEditingId(id);\n }\n }}\n />\n {/* The rarer, destructive edits wait in a menu at the toolbar's end. */}\n <Toolbar.Separator variant='gap' />\n <Menu.Root positioning={{ placement: 'bottom-end', gutter: 4 }}>\n <Menu.Trigger asChild>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--dots-three-vertical--regular'\n label='Layer actions'\n disabled={readonly}\n data-testid='layers-menu'\n />\n </Menu.Trigger>\n <Menu.Content>\n <Menu.Item\n item={{ value: 'merge', label: 'Merge layers', icon: 'ph--arrow-line-down--regular' }}\n disabled={!onMerge || selected.length < 2}\n data-testid='layers-merge'\n onSelect={() => top && onMerge?.(selected, top)}\n />\n <Menu.Item\n item={{ value: 'delete', label: 'Delete layers', icon: 'ph--trash--regular' }}\n disabled={!onDelete || selected.length === 0 || selected.length >= layers.length}\n data-testid='layers-delete'\n onSelect={() => onDelete?.(selected)}\n />\n </Menu.Content>\n </Menu.Root>\n </Toolbar.Root>\n </Panel.Header>\n <Panel.Body>\n <OrderedList.Root\n items={items}\n getLabel={(layer) => layer.name}\n readonly={readonly || !onMove}\n multiple\n value={selected}\n onValueChange={(ids) => onSelectedChange?.(ids)}\n // The list is top first; the order the model keeps is bottom first.\n onMove={(from, to) => onMove?.(items[from].id, items.length - 1 - to)}\n >\n {({ items }) => (\n <OrderedList.Content\n // Docked, the dock scrolls the panels together, so the list keeps no scroll of its own (it would hold the wheel).\n scroll={!docked}\n // Rows run edge to edge, with no gutter around them.\n gutter='none'\n aria-label='Layers'\n onKeyDown={(event) => {\n // Enter on the list (as well as selecting the highlighted row) opens that row's name.\n if (event.key !== 'Enter' || event.target !== event.currentTarget || readonly || !onRename) {\n return;\n }\n const active = event.currentTarget.getAttribute('aria-activedescendant');\n const id = active ? event.currentTarget.ownerDocument.getElementById(active)?.dataset.value : undefined;\n if (id) {\n setEditingId(id);\n }\n }}\n >\n {items.map((layer) => (\n <OrderedList.Item key={layer.id} id={layer.id} data-testid={`layer-${layer.id}`}>\n <OrderedList.DragHandle />\n <LayerName\n layer={layer}\n readonly={readonly}\n editing={editingId === layer.id}\n onEditingChange={(editing) =>\n setEditingId((current) => (editing ? layer.id : current === layer.id ? undefined : current))\n }\n onRename={(name) => onRename?.(layer.id, name)}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon={layer.hidden ? 'ph--eye-slash--regular' : 'ph--eye--regular'}\n label={layer.hidden ? 'Show layer' : 'Hide layer'}\n disabled={readonly || !onToggle}\n data-testid={`layer-toggle-${layer.id}`}\n onClick={(event) => {\n // The row's own click selects it; showing or hiding a layer leaves the selection alone.\n event.stopPropagation();\n onToggle?.(layer.id);\n }}\n />\n </OrderedList.Item>\n ))}\n </OrderedList.Content>\n )}\n </OrderedList.Root>\n </Panel.Body>\n </Panel.Root>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The drag payload a node type travels as between the palette (or a host's own draggable) and the\n// canvas drop target (DESIGN.md §8 \"external drag-in\"); internal gestures stay pointer-driven.\n//\n\nimport { type NodeType } from '../model/types.ts';\n\nconst NODE_DRAG_TYPE = 'dx-canvas/node';\n\n/** The pragmatic-dnd data of a drag that creates a node of `type` where it drops. */\nexport const nodeDragData = (type: NodeType): Record<string, unknown> => ({ type: NODE_DRAG_TYPE, node: type });\n\n/** The node type a drag carries, or nothing when the drag is not one of ours. */\nexport const nodeDragType = (data: Record<string | symbol, unknown>): NodeType | undefined =>\n data.type === NODE_DRAG_TYPE && typeof data.node === 'string' ? data.node : undefined;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';\nimport React, { type RefObject, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Icon from '@dxos/react-ui/Icon';\nimport * as Popover from '@dxos/react-ui/Popover';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type LinkRegistry, type NodeRegistry } from '../../model/registry.ts';\nimport { type Capabilities, type Tool } from '../../model/types.ts';\nimport { nodeDragData } from '../../utils/dnd.ts';\n\ntype Entry = { tool: Tool; icon: string; label: string; key?: string };\n\nconst BASE: Entry[] = [\n { tool: { kind: 'select' }, icon: 'ph--cursor--regular', label: 'Select', key: 'V' },\n { tool: { kind: 'hand' }, icon: 'ph--hand--regular', label: 'Pan', key: 'H' },\n];\n\n/** A run of palette entries; a group of node types may fold into one flyout button when the rail runs out of room. */\nexport type PaletteGroup = { name: string; entries: Entry[]; collapsible: boolean };\n\n/** Node types by their `group`, in registry order; types without one share the first, unnamed group. */\nconst nodeGroups = (nodes: NodeRegistry): PaletteGroup[] => {\n const groups = new Map<string, Entry[]>();\n for (const def of Object.values(nodes)) {\n const name = def.group ?? '';\n groups.set(name, [\n ...(groups.get(name) ?? []),\n { tool: { kind: 'node' as const, type: def.type }, icon: def.icon, label: def.name, key: def.key },\n ]);\n }\n return [...groups.entries()].map(([name, entries]) => ({ name, entries, collapsible: entries.length > 1 }));\n};\n\n/**\n * Palette groups: the fixed tools, then the node types by group, then a link per link type; a group the projection\n * cannot apply (`create`, `link`) is left out rather than offered and silently dropped. Only node groups fold.\n */\nexport const paletteGroups = (nodes: NodeRegistry, links: LinkRegistry, capabilities: Capabilities): PaletteGroup[] =>\n [\n { name: 'Tools', entries: BASE, collapsible: false },\n ...(capabilities.create ? nodeGroups(nodes) : []),\n {\n name: 'Links',\n entries: capabilities.link\n ? Object.values(links).map((def) => ({\n tool: { kind: 'link' as const, type: def.type },\n icon: def.icon,\n label: def.name,\n key: def.key,\n }))\n : [],\n collapsible: false,\n },\n ].filter((group) => group.entries.length > 0);\n\n/** Palette entries by group, flat within each. */\nexport const paletteEntries = (nodes: NodeRegistry, links: LinkRegistry, capabilities: Capabilities): Entry[][] =>\n paletteGroups(nodes, links, capabilities).map((group) => group.entries);\n\nexport const sameTool = (left: Tool, right: Tool): boolean =>\n left.kind === right.kind && ('type' in left ? left.type === ('type' in right ? right.type : undefined) : true);\n\nexport const toolForKey = (\n nodes: NodeRegistry,\n links: LinkRegistry,\n capabilities: Capabilities,\n key: string,\n): Tool | undefined =>\n paletteEntries(nodes, links, capabilities)\n .flat()\n .find((entry) => entry.key !== undefined && entry.key === key.toUpperCase())?.tool;\n\nexport type PaletteProps = {\n tool: Tool;\n nodes: NodeRegistry;\n links: LinkRegistry;\n capabilities: Capabilities;\n /**\n * Folds each group of node types into one flyout button: `auto` (the default) does so only when the flat rail would\n * not fit the space below it, so a small registry keeps every tool one click away.\n */\n collapse?: 'auto' | boolean;\n /** How a folded group lists its tools: one per row with its name (the default), or a grid of icons. */\n flyout?: 'list' | 'grid';\n onToolChange: (tool: Tool) => void;\n};\n\n/** The height the rail would take flat: each button, the gaps between them, and each group's padding and divider. */\nconst flatHeight = (groups: readonly PaletteGroup[], button: number): number =>\n groups.reduce((height, group) => height + group.entries.length * (button + 4) - 4 + 9, 0);\n\n/**\n * Whether the rail folds its node groups: always, never, or (`auto`) when the flat rail would overflow its parent,\n * which the host sizes to the room the rail may take (`SceneView.Palette` spans from below the navigation to above\n * the bottom bars); re-measured as that resizes.\n */\nconst useCollapsed = (\n ref: RefObject<HTMLDivElement | null>,\n groups: readonly PaletteGroup[],\n collapse: PaletteProps['collapse'],\n) => {\n const [overflows, setOverflows] = useState(false);\n useLayoutEffect(() => {\n const element = ref.current;\n const host = element?.parentElement;\n if (collapse !== 'auto' || !element || !host) {\n return;\n }\n const measure = () => {\n const button = element.querySelector('button')?.getBoundingClientRect().height ?? 32;\n setOverflows(flatHeight(groups, button) > host.clientHeight);\n };\n measure();\n const observer = new ResizeObserver(measure);\n observer.observe(host);\n return () => observer.disconnect();\n }, [ref, groups, collapse]);\n return collapse === 'auto' ? overflows : collapse;\n};\n\n/**\n * Tool palette: a click picks the tool; a node type can also be dragged onto the canvas, which creates\n * it where it drops (the canvas is a pragmatic-dnd drop target for `nodeDragData`). With many types the node\n * groups fold into flyouts (`collapse`), each showing its active or last-used tool.\n */\nexport const Palette = ({\n tool,\n nodes,\n links,\n capabilities,\n collapse = 'auto',\n flyout = 'list',\n onToolChange,\n}: PaletteProps) => {\n const ref = useRef<HTMLDivElement>(null);\n const groups = useMemo(() => paletteGroups(nodes, links, capabilities), [nodes, links, capabilities]);\n const collapsed = useCollapsed(ref, groups, collapse);\n return (\n <div\n ref={ref}\n // The host's frame spans the room the rail may take and lets the canvas below it take the pointer.\n className='flex flex-col w-fit rounded-sm bg-modal-surface border border-separator divide-y divide-separator pointer-events-auto'\n data-testid='palette'\n data-collapsed={collapsed || undefined}\n >\n {groups.map((group) =>\n collapsed && group.collapsible ? (\n <div key={group.name} className='flex flex-col p-1'>\n <PaletteFlyout group={group} tool={tool} layout={flyout} onToolChange={onToolChange} />\n </div>\n ) : (\n <div key={group.name} className='flex flex-col gap-1 p-1'>\n {group.entries.map((entry) => (\n <PaletteButton\n key={entry.label}\n entry={entry}\n active={sameTool(tool, entry.tool)}\n onToolChange={onToolChange}\n />\n ))}\n </div>\n ),\n )}\n </div>\n );\n};\n\n/** How long the pointer rests on a folded group before its tools open. */\nconst HOVER_OPEN_MS = 500;\n/** How long the tools stay open after the pointer leaves, so it can cross the gap between the rail and the grid. */\nconst HOVER_CLOSE_MS = 250;\n\n/**\n * Opens after the pointer rests on the trigger, and closes once it has left both the trigger and the content. `hovered`\n * is how it opened, so the content can leave focus where it is.\n */\nconst useHoverOpen = (setOpen: (open: boolean, hovered?: boolean) => void) => {\n const timer = useRef<ReturnType<typeof setTimeout>>(undefined);\n useEffect(() => () => clearTimeout(timer.current), []);\n return useMemo(\n () => ({\n enter: () => {\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setOpen(true, true), HOVER_OPEN_MS);\n },\n keep: () => clearTimeout(timer.current),\n leave: () => {\n clearTimeout(timer.current);\n timer.current = setTimeout(() => setOpen(false), HOVER_CLOSE_MS);\n },\n }),\n [setOpen],\n );\n};\n\ntype PaletteFlyoutProps = {\n group: PaletteGroup;\n tool: Tool;\n layout: NonNullable<PaletteProps['flyout']>;\n onToolChange: (tool: Tool) => void;\n};\n\n/**\n * A folded group: its active (else last-used, else first) tool as one button, picked with a click, and a corner\n * chevron (or a hover) opening the group's tools beside the rail, as a list or a grid (`layout`).\n */\nconst PaletteFlyout = ({ group, tool, layout, onToolChange }: PaletteFlyoutProps) => {\n const [open, setOpenState] = useState(false);\n // Opened by a hover, the list takes no focus (a pointer user would see a focus ring on the first row); opened from\n // the chevron (a click or the keyboard), it does, so arrows move through it.\n const [hovered, setHovered] = useState(false);\n const setOpen = useCallback((next: boolean, byHover = false) => {\n setHovered(next && byHover);\n setOpenState(next);\n }, []);\n const hover = useHoverOpen(setOpen);\n const [lastUsed, setLastUsed] = useState<Entry>(group.entries[0]);\n const active = group.entries.find((entry) => sameTool(tool, entry.tool));\n // A tool picked from elsewhere (its key, the grid) becomes the group's face, so the rail shows what is in use.\n useEffect(() => {\n if (active) {\n setLastUsed(active);\n }\n }, [active]);\n const shown = active ?? lastUsed;\n return (\n <Popover.Root\n open={open}\n autoFocus={!hovered}\n onOpenChange={({ open }) => setOpen(open)}\n positioning={{ placement: 'right-start' }}\n >\n <Popover.Anchor asChild>\n <div\n className='relative'\n data-testid={`palette-group-${group.name}`}\n onPointerEnter={hover.enter}\n onPointerLeave={hover.leave}\n >\n <PaletteButton entry={shown} active={active !== undefined} onToolChange={onToolChange} />\n <Popover.Trigger asChild>\n <button\n type='button'\n aria-label={`${group.name} tools`}\n className='absolute bottom-0 right-0 flex size-3 items-end justify-end text-fg-subtle hover:text-fg'\n data-testid={`palette-group-${group.name}-open`}\n >\n <Icon.Icon icon='ph--caret-right--fill' size='xs' />\n </button>\n </Popover.Trigger>\n </div>\n </Popover.Anchor>\n <Popover.Content onPointerEnter={hover.keep} onPointerLeave={hover.leave}>\n <div\n className={mx(\n layout === 'list'\n ? 'flex flex-col items-stretch gap-1 p-1'\n : 'grid grid-cols-[repeat(3,min-content)] gap-1 p-1',\n )}\n data-testid={`palette-group-${group.name}-tools`}\n >\n {group.entries.map((entry) => (\n <PaletteButton\n key={entry.label}\n entry={entry}\n labelled={layout === 'list'}\n active={sameTool(tool, entry.tool)}\n onToolChange={(next) => {\n onToolChange(next);\n setOpen(false);\n }}\n />\n ))}\n </div>\n </Popover.Content>\n </Popover.Root>\n );\n};\n\nconst PaletteButton = ({\n entry,\n active,\n labelled,\n onToolChange,\n}: {\n entry: Entry;\n active: boolean;\n /** Shows the tool's name beside its icon (a flyout's list), rather than the icon alone. */\n labelled?: boolean;\n onToolChange: (tool: Tool) => void;\n}) => {\n const ref = useRef<HTMLButtonElement>(null);\n const nodeType = entry.tool.kind === 'node' ? entry.tool.type : undefined;\n useEffect(() => {\n if (!ref.current || nodeType === undefined) {\n return;\n }\n return draggable({\n element: ref.current,\n getInitialData: () => nodeDragData(nodeType),\n // The canvas draws a ghost of the node that will land, so the browser's image of the icon is noise.\n onGenerateDragPreview: ({ nativeSetDragImage }) => disableNativeDragPreview({ nativeSetDragImage }),\n });\n }, [nodeType]);\n return (\n <Button.Root\n ref={ref}\n variant='ghost'\n iconOnly={!labelled}\n icon={entry.icon}\n label={labelled ? entry.label : entry.key ? `${entry.label} (${entry.key})` : entry.label}\n classNames={mx(labelled && 'w-full justify-start', active && 'bg-primary-500/20')}\n data-testid={`palette-${entry.key ?? ('type' in entry.tool ? entry.tool.type : entry.tool.kind)}`}\n onClick={() => onToolChange(entry.tool)}\n />\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// A node's text part: static text, or, while it is the part being edited, an in-place editor over the\n// same box. Enter commits (Mod-Enter in a multi-line part, where Enter breaks the line), Escape rejects,\n// and leaving the editor commits. Pointer and key events stay inside so the canvas neither drags nor\n// handles shortcuts while the user types.\n//\n\nimport { Prec } from '@codemirror/state';\nimport { EditorView, keymap } from '@codemirror/view';\nimport React, { type PropsWithChildren, useRef } from 'react';\n\nimport { useTextEditor } from '@dxos/react-ui-editor';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { createBasicExtensions, createThemeExtensions } from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type PartEditing, type PartKey } from '../../utils/parts.ts';\n\nexport type TextPartProps = Util.ThemedClassName<\n PropsWithChildren<{\n part: PartKey;\n /** The part's current text, which the editor starts from. */\n text: string;\n editing?: PartEditing;\n }>\n>;\n\n/** Renders `children` as the part's text, or the editor when `editing` names this part. */\nexport const TextPart = ({ classNames, part, text, editing, children }: TextPartProps) =>\n editing?.part === part ? (\n <PartEditor classNames={classNames} part={part} text={text} editing={editing} />\n ) : (\n <div className={mx(classNames)} data-part={part}>\n {/* The text's own box, which a part's layout may pad (its line boxes, not the part's frame). */}\n <span className='inline-block'>{children}</span>\n </div>\n );\n\ntype PartEditorProps = Util.ThemedClassName<{ part: PartKey; text: string; editing: PartEditing }>;\n\nconst stop = (event: React.SyntheticEvent) => event.stopPropagation();\n\nconst PartEditor = ({ classNames, part, text, editing }: PartEditorProps) => {\n const themeMode = Hooks.useThemeMode();\n const multiline = editing.multiline;\n // Commit or cancel once: the editor unmounts on either, and its focus loss must not commit again.\n const done = useRef(false);\n const finish = (action: () => void) => {\n if (!done.current) {\n done.current = true;\n action();\n }\n };\n const { parentRef, focusAttributes } = useTextEditor(\n () => ({\n id: `part-${part}`,\n initialValue: text,\n autoFocus: true,\n selectionEnd: true,\n extensions: [\n createBasicExtensions({ lineWrapping: true, history: false, search: false }),\n createThemeExtensions({\n themeMode,\n // Content height, not full height, so the part's own layout places the editor where it puts the\n // static text (a label centred in its cell).\n slots: { editor: { className: 'w-full max-h-full [&>.cm-scroller]:scrollbar-none' } },\n }),\n // The part's own leading, not the editor theme's, so the lines do not shift when editing starts.\n Prec.highest(EditorView.theme({ '.cm-scroller, .cm-content, .cm-line': { lineHeight: 'inherit' } })),\n EditorView.focusChangeEffect.of((state, focusing) => {\n if (!focusing) {\n finish(() => editing.commit(state.doc.toString()));\n }\n return null;\n }),\n Prec.highest(\n keymap.of([\n {\n key: 'Enter',\n run: (view) => {\n if (multiline) {\n view.dispatch(view.state.replaceSelection('\\n'));\n } else {\n finish(() => editing.commit(view.state.doc.toString()));\n }\n return true;\n },\n },\n {\n key: 'Mod-Enter',\n run: (view) => {\n finish(() => editing.commit(view.state.doc.toString()));\n return true;\n },\n },\n {\n key: 'Escape',\n run: () => {\n finish(() => editing.cancel());\n return true;\n },\n },\n ]),\n ),\n ],\n }),\n [part, text, multiline, themeMode, editing],\n );\n\n return (\n <div\n ref={parentRef}\n {...focusAttributes}\n className={mx('select-text cursor-text', classNames)}\n data-part={part}\n data-testid='part-editor'\n onPointerDown={stop}\n onDoubleClick={stop}\n onKeyDown={stop}\n />\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { RegistryContext } from '@effect/atom-react/RegistryContext';\nimport { useContext } from 'react';\n\n/** The view's atom registry; components read atoms through `useAtomValue` and write through this. */\nexport const useRegistry = () => useContext(RegistryContext);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Scene layers: every node and link is on exactly one, the layers are ordered, and a hidden one is neither drawn nor\n// hit. A scene that names no layers has one, implicitly, which the first layer edit makes real.\n//\n\nimport {\n type Element,\n type Intent,\n type Layer,\n type LayerId,\n type Link,\n type Node,\n type Scene,\n endpointNode,\n} from '../model/types.ts';\nimport { between, sortByZ } from './order.ts';\n\n/** The layer of a scene that names none: every element is on it. */\nexport const DEFAULT_LAYER: Layer = { id: 'layer', name: 'Layer 1', z: between() };\n\n/** A scene's layers, bottom first; a scene with none has the implicit `DEFAULT_LAYER`. */\nexport const sceneLayers = (scene: Scene): Layer[] => {\n const layers = sortByZ(Object.values(scene.layers ?? {}));\n return layers.length > 0 ? layers : [DEFAULT_LAYER];\n};\n\n/** The layer an element is on: its own, else (unset, or a layer the scene does not have) the bottom one. */\nexport const elementLayer = (element: Element, layers: readonly Layer[]): LayerId =>\n element.layer !== undefined && layers.some((layer) => layer.id === element.layer)\n ? element.layer\n : (layers[0]?.id ?? DEFAULT_LAYER.id);\n\n/** The layer new elements go on: the active one when the scene has it, else the top layer. */\nexport const activeLayer = (scene: Scene, active: LayerId | undefined): LayerId => {\n const layers = sceneLayers(scene);\n return layers.find((layer) => layer.id === active)?.id ?? layers[layers.length - 1].id;\n};\n\n/** Nodes in paint order: by their layer's order, then by their own `z`. */\nexport const layerOrder = (nodes: readonly Node[], layers: readonly Layer[]): Node[] => {\n const rank = new Map(layers.map((layer, index) => [layer.id, index]));\n const rankOf = (node: Node) => rank.get(elementLayer(node, layers)) ?? 0;\n return sortByZ(nodes).sort((left, right) => rankOf(left) - rankOf(right));\n};\n\n/**\n * The scene as drawn and hit: without the elements of hidden layers, or the links to a node that is hidden. The same\n * scene when no layer is hidden, so a memo over it holds.\n */\nexport const visibleScene = (scene: Scene): Scene => {\n const layers = sceneLayers(scene);\n const hidden = new Set(layers.filter((layer) => layer.hidden).map((layer) => layer.id));\n if (hidden.size === 0) {\n return scene;\n }\n const nodes = Object.fromEntries(\n Object.entries(scene.nodes).filter(([, node]) => !hidden.has(elementLayer(node, layers))),\n );\n const shown = (link: Link) =>\n !hidden.has(elementLayer(link, layers)) &&\n [link.source, link.target].every((end) => {\n const node = endpointNode(end);\n return node === undefined || nodes[node] !== undefined;\n });\n const links = Object.fromEntries(Object.entries(scene.links).filter(([, link]) => shown(link)));\n return { ...scene, nodes, links };\n};\n\n/** The scene's layers as a record, the implicit layer made real so a new layer does not take its elements. */\nconst layerRecord = (scene: Scene): Record<LayerId, Layer> =>\n scene.layers && Object.keys(scene.layers).length > 0 ? { ...scene.layers } : { [DEFAULT_LAYER.id]: DEFAULT_LAYER };\n\n/**\n * The scene with its layers named and every element on one by name: an element with no layer, or one the scene does not\n * have, takes the layer it is drawn on (`elementLayer`). The same scene when nothing changes, so a memo over it holds.\n */\nexport const pinLayers = (scene: Scene): Scene => {\n const layers = sceneLayers(scene);\n const pin = <T extends Element>(record: Record<string, T>): Record<string, T> | undefined => {\n const loose = Object.values(record).filter((element) => element.layer !== elementLayer(element, layers));\n return loose.length === 0\n ? undefined\n : {\n ...record,\n ...Object.fromEntries(\n loose.map((element) => [element.id, { ...element, layer: elementLayer(element, layers) }]),\n ),\n };\n };\n const named = scene.layers && Object.keys(scene.layers).length > 0;\n const nodes = pin(scene.nodes);\n const links = pin(scene.links);\n return named && !nodes && !links\n ? scene\n : { ...scene, layers: layerRecord(scene), nodes: nodes ?? scene.nodes, links: links ?? scene.links };\n};\n\n/** Applies a layer intent to the scene (`reduceIntent` delegates here). */\nexport const reduceLayerIntent = (scene: Scene, intent: Extract<Intent, { kind: 'layer' | 'removeLayer' }>): Scene => {\n if (intent.kind === 'layer') {\n // Pinned first: an element without a layer is on the bottom one, so a layer added below would otherwise take it.\n const pinned = pinLayers(scene);\n return { ...pinned, layers: { ...layerRecord(pinned), [intent.layer.id]: intent.layer } };\n }\n const layers = sceneLayers(scene);\n if (layers.length < 2 || !layers.some((layer) => layer.id === intent.id)) {\n return scene;\n }\n const { [intent.id]: _, ...rest } = layerRecord(scene);\n // The elements on the removed layer go with it; `elementLayer` is read against the layers before the removal.\n const keep = (element: Element) => elementLayer(element, layers) !== intent.id;\n const nodes = Object.fromEntries(Object.entries(scene.nodes).filter(([, node]) => keep(node)));\n const links = Object.fromEntries(\n Object.entries(scene.links).filter(\n ([, link]) =>\n keep(link) &&\n [link.source, link.target].every((end) => {\n const node = endpointNode(end);\n return node === undefined || nodes[node] !== undefined;\n }),\n ),\n );\n return { ...scene, nodes, links, layers: rest };\n};\n\n/** A new layer below the others, so it ends the top-first list, named after the first `Layer <n>` not taken. */\nexport const createLayer = (scene: Scene, id: LayerId): Layer => {\n const layers = sceneLayers(scene);\n const names = new Set(layers.map((layer) => layer.name));\n let index = layers.length + 1;\n while (names.has(`Layer ${index}`)) {\n index++;\n }\n return { id, name: `Layer ${index}`, z: between(undefined, layers[0]?.z) };\n};\n\n/** The layer moved to `index` in the bottom-first order. */\nexport const moveLayer = (scene: Scene, id: LayerId, index: number): Layer | undefined => {\n const layers = sceneLayers(scene);\n const layer = layers.find((candidate) => candidate.id === id);\n if (!layer) {\n return undefined;\n }\n const others = layers.filter((candidate) => candidate.id !== id);\n return { ...layer, z: between(others[index - 1]?.z, others[index]?.z) };\n};\n\n/**\n * Merging layers into `into`, as one batch: the elements of every layer in `from` move onto `into`, keeping their own\n * order, and those layers are removed. None unless `into` and at least one other of `from` are layers of the scene.\n */\nexport const mergeLayersIntent = (scene: Scene, from: readonly LayerId[], into: LayerId): Intent | undefined => {\n const layers = sceneLayers(scene);\n const ids = new Set(layers.map((layer) => layer.id));\n const merged = new Set(from.filter((id) => id !== into && ids.has(id)));\n if (!ids.has(into) || merged.size === 0) {\n return undefined;\n }\n const moved = [...Object.values(scene.nodes), ...Object.values(scene.links)].filter((element) =>\n merged.has(elementLayer(element, layers)),\n );\n return {\n kind: 'batch',\n intents: [\n // The implicit layer is made real first, so the elements left on it keep it once the others are gone.\n ...(scene.layers ? [] : layers.map((layer): Intent => ({ kind: 'layer', layer }))),\n ...moved.map((element): Intent => ({ kind: 'update', id: element.id, values: { layer: into } })),\n ...[...merged].map((id): Intent => ({ kind: 'removeLayer', id })),\n ],\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Auto layout (MIGRATION.md M4): the scene's own nodes arranged into ranked rows along its links,\n// through `@dxos/diagram`'s ranking — the same engine the dynamic projection lays its graph out with,\n// rather than a second one. Unlike the editor's `@antv` layout this keeps each node: its type, its\n// size and its content are untouched and only the centre moves, so laying out is an arrangement of\n// the diagram rather than a replacement of it.\n//\n\nimport { Layout } from '@dxos/diagram';\n\nimport { type ElementId, MAJOR_GRID, type Point, type Scene, type Size, endpointNode } from '../model/types.ts';\n\nexport type LayoutOptions = {\n /** Gap between rows and between the columns within a row, in scene px. */\n gap?: Size;\n /** Where the arrangement's top-left corner goes. */\n origin?: Point;\n};\n\nconst DEFAULTS: Required<LayoutOptions> = {\n gap: { width: MAJOR_GRID * 2, height: MAJOR_GRID * 2 },\n origin: { x: MAJOR_GRID * 2, y: MAJOR_GRID * 2 },\n};\n\n/**\n * The scene with its nodes ranked into rows: a node sits one row below its deepest predecessor, and\n * the nodes of a row are laid left to right in their current left-to-right order, so an arrangement a\n * user has already tidied along a row survives. Rows are as tall as their tallest node and columns as\n * wide as their widest, so mixed sizes never overlap. Everything lands on the major grid.\n *\n * `ids`, when given, narrows what moves: the rest of the scene stays exactly where it is, which is how\n * \"lay out the selection\" differs from \"lay out the board\".\n */\nexport const layoutScene = (scene: Scene, ids?: readonly ElementId[], options: LayoutOptions = {}): Scene => {\n const { gap, origin } = { ...DEFAULTS, ...options };\n const subject = new Set(ids ?? Object.keys(scene.nodes));\n const moving = Object.values(scene.nodes).filter((node) => subject.has(node.id) && !node.locked);\n if (moving.length === 0) {\n return scene;\n }\n\n const known = new Set(moving.map(({ id }) => id));\n const edges = Object.values(scene.links)\n .map((link) => ({ from: endpointNode(link.source) ?? '', to: endpointNode(link.target) ?? '' }))\n .filter(({ from, to }) => known.has(from) && known.has(to));\n // Sorted, so the ranking (and with it the arrangement) does not depend on the map's insertion order.\n const ordered = [...moving].sort((left, right) => (left.id < right.id ? -1 : 1));\n const ranks = Layout.rank(\n ordered.map(({ id }) => id),\n edges,\n );\n\n const rows = new Map<number, typeof ordered>();\n for (const node of ordered) {\n const rank = ranks.get(node.id) ?? 0;\n rows.set(rank, [...(rows.get(rank) ?? []), node]);\n }\n\n const centers = new Map<string, Point>();\n let top = origin.y;\n for (const rank of [...rows.keys()].sort((left, right) => left - right)) {\n // Their current order along the row, so a row the user has already arranged keeps its reading order.\n const members = [...(rows.get(rank) ?? [])].sort((left, right) => left.center.x - right.center.x);\n const height = Math.max(...members.map(({ size }) => size.height));\n let left = origin.x;\n for (const node of members) {\n centers.set(node.id, snap({ x: left + node.size.width / 2, y: top + height / 2 }));\n left += node.size.width + gap.width;\n }\n top += height + gap.height;\n }\n\n const nodes = { ...scene.nodes };\n let changed = false;\n for (const [id, center] of centers) {\n const node = nodes[id];\n if (node.center.x !== center.x || node.center.y !== center.y) {\n nodes[id] = { ...node, center };\n changed = true;\n }\n }\n return changed ? { ...scene, nodes } : scene;\n};\n\nconst snap = ({ x, y }: Point): Point => ({\n x: Math.round(x / MAJOR_GRID) * MAJOR_GRID,\n y: Math.round(y / MAJOR_GRID) * MAJOR_GRID,\n});\n\nexport type GridExtent = { columns: number; rows: number };\n\n/**\n * Where the first slot's centre goes for a grid of `extent` equal slots, `size` each and `pitch` apart,\n * placed so the whole arrangement straddles the origin. A slot spans an odd number of major cells, so\n * its run's exact midpoint falls half a cell off the grid; the leading edge is rounded to the grid\n * instead, which keeps every slot snapped at the cost of the arrangement sitting up to half a cell off\n * centre.\n */\nexport const centeredOrigin = (extent: GridExtent, pitch: Size, size: Size): Point => ({\n x: leadingEdge(extent.columns, pitch.width, size.width) + size.width / 2,\n y: leadingEdge(extent.rows, pitch.height, size.height) + size.height / 2,\n});\n\nconst leadingEdge = (count: number, pitch: number, extent: number): number =>\n Math.round(-(Math.max(count - 1, 0) * pitch + extent) / 2 / MAJOR_GRID) * MAJOR_GRID;\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Scene store seam: scenes by id behind atoms, so a view subscribes to exactly the scene it shows and\n// an ECHO-backed store (phase 3) can replace the in-memory one without touching the surface.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { type Scene, type SceneId, type StyleMap } from './types.ts';\n\nexport type SceneMap = Readonly<Record<SceneId, Scene>>;\n\nexport type SceneStore = {\n /** Every scene, keyed by id. Written through the registry. */\n readonly scenes: Atom.Writable<SceneMap>;\n /** Derived atom for one scene; stable per id so subscriptions do not churn. */\n scene: (id: SceneId) => Atom.Atom<Scene | undefined>;\n /** The drawing's style classes; a store without them offers none. */\n readonly styles?: Atom.Writable<StyleMap>;\n};\n\n/** A store held in memory, which always keeps style classes. */\nexport type MemorySceneStore = SceneStore & { readonly styles: Atom.Writable<StyleMap> };\n\nexport const createMemoryStore = (initial: readonly Scene[] = [], initialStyles: StyleMap = {}): MemorySceneStore => {\n const styles = Atom.keepAlive(Atom.make<StyleMap>(initialStyles));\n const scenes = Atom.keepAlive(Atom.make<SceneMap>(Object.fromEntries(initial.map((scene) => [scene.id, scene]))));\n const derived = new Map<SceneId, Atom.Atom<Scene | undefined>>();\n return {\n scenes,\n styles,\n scene: (id) => {\n let atom = derived.get(id);\n if (!atom) {\n atom = Atom.keepAlive(Atom.make((get) => get(scenes)[id]));\n derived.set(id, atom);\n }\n return atom;\n },\n };\n};\n\n/** Replace one scene in the store (a no-op when the updater returns the same object). */\nexport const updateScene = (\n registry: Registry.AtomRegistry,\n store: SceneStore,\n id: SceneId,\n update: (scene: Scene) => Scene,\n): void => {\n const scenes = registry.get(store.scenes);\n const current = scenes[id];\n if (!current) {\n return;\n }\n const next = update(current);\n if (next !== current) {\n registry.set(store.scenes, { ...scenes, [id]: next });\n }\n};\n\nexport const putScene = (registry: Registry.AtomRegistry, store: SceneStore, scene: Scene): void => {\n registry.set(store.scenes, { ...registry.get(store.scenes), [scene.id]: scene });\n};\n\n/** No classes: what a store without `styles` reads as. */\nexport const NO_STYLES: Atom.Atom<StyleMap> = Atom.keepAlive(Atom.make<StyleMap>({}));\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The projection seam (docs/DESIGN.md §3): the only thing the surface knows. It reads a positioned\n// scene and sends intents; the projection owns the drawing model and decides what an intent means.\n// `freehand` is the identity projection: intents write coordinates straight into the scene.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\nimport * as Schema from 'effect/Schema';\n\nimport { type LatticeSpec } from '../utils/lattice.ts';\nimport { reduceLayerIntent } from '../utils/layers.ts';\nimport { layoutScene } from '../utils/layout.ts';\nimport { resizeNode } from '../utils/shapes.ts';\nimport { type SceneStore, putScene, updateScene } from './store.ts';\nimport {\n type Capabilities,\n type Intent,\n type Link,\n type Node,\n OpenScene,\n type Scene,\n type SceneId,\n endpointNode,\n} from './types.ts';\n\nexport type Projection = {\n /** Positioned nodes and links; re-emitted on every model change. */\n readonly scene: Atom.Atom<Scene>;\n /** May apply, partially apply, rewrite the model, or reject. */\n apply: (intent: Intent) => void;\n readonly capabilities: Capabilities;\n /**\n * The model as an opaque immutable value, identical (`===`) when nothing changed, so the view can\n * keep an undo log without knowing what the model is (`undo.ts`).\n */\n snapshot: () => unknown;\n restore: (snapshot: unknown) => void;\n /**\n * What `apply` would make of `intent`, without applying it: the rewritten intent, or undefined when it\n * would be refused. Absent means intents apply as given. Previews of a gesture in flight read it, so a\n * drag shows where the drop will land.\n */\n constrain?: (intent: Intent) => Intent | undefined;\n /** The lattice the projection keeps shapes on, for the grid layer that draws it (DESIGN §8b). */\n lattice?: LatticeSpec;\n};\n\nconst EMPTY: Scene = { id: '', nodes: {}, links: {} };\n\n/** Freehand semantics as a pure reducer, so it is testable and reusable by other projections. */\nexport const reduceIntent = (scene: Scene, intent: Intent): Scene => {\n switch (intent.kind) {\n case 'move': {\n const nodes = { ...scene.nodes };\n let changed = false;\n for (const id of intent.ids) {\n const node = nodes[id];\n if (node && !node.locked) {\n nodes[id] = { ...node, center: { x: node.center.x + intent.delta.x, y: node.center.y + intent.delta.y } };\n changed = true;\n }\n }\n return changed ? { ...scene, nodes } : scene;\n }\n\n case 'resize': {\n const node = scene.nodes[intent.id];\n if (!node || node.locked) {\n return scene;\n }\n return { ...scene, nodes: { ...scene.nodes, [intent.id]: resizeNode(node, intent.bounds) } };\n }\n\n case 'link': {\n const { link } = intent;\n // Every node end must exist, and a link never joins a node to itself; free ends need nothing.\n const nodes = [link.source, link.target].map(endpointNode);\n if (nodes.some((id) => id !== undefined && scene.nodes[id] === undefined)) {\n return scene;\n }\n if (nodes[0] !== undefined && nodes[0] === nodes[1]) {\n return scene;\n }\n return { ...scene, links: { ...scene.links, [link.id]: link } };\n }\n\n case 'create': {\n return { ...scene, nodes: { ...scene.nodes, [intent.node.id]: intent.node } };\n }\n\n case 'delete': {\n const ids = new Set(intent.ids);\n const nodes: Record<string, Node> = {};\n for (const node of Object.values(scene.nodes)) {\n if (!ids.has(node.id)) {\n nodes[node.id] = node;\n }\n }\n const links: Record<string, Link> = {};\n for (const link of Object.values(scene.links)) {\n // A link loses its meaning with either end, so it goes too.\n if (\n !ids.has(link.id) &&\n !ids.has(endpointNode(link.source) ?? '') &&\n !ids.has(endpointNode(link.target) ?? '')\n ) {\n links[link.id] = link;\n }\n }\n return { ...scene, nodes, links };\n }\n\n case 'reorder': {\n const node = scene.nodes[intent.id];\n if (node) {\n return node.z === intent.z\n ? scene\n : { ...scene, nodes: { ...scene.nodes, [intent.id]: { ...node, z: intent.z } } };\n }\n const link = scene.links[intent.id];\n if (link) {\n return link.z === intent.z\n ? scene\n : { ...scene, links: { ...scene.links, [intent.id]: { ...link, z: intent.z } } };\n }\n return scene;\n }\n\n case 'layout':\n return layoutScene(scene, intent.ids);\n\n case 'batch':\n return intent.intents.reduce(reduceIntent, scene);\n\n case 'layer':\n case 'removeLayer':\n return reduceLayerIntent(scene, intent);\n\n case 'update': {\n const node = scene.nodes[intent.id];\n if (node) {\n const next = Object.assign({}, node, intent.values, { id: node.id, type: node.type });\n return { ...scene, nodes: { ...scene.nodes, [intent.id]: next } };\n }\n const link = scene.links[intent.id];\n if (link) {\n const next = Object.assign({}, link, intent.values, { id: link.id, type: link.type });\n return { ...scene, links: { ...scene.links, [intent.id]: next } };\n }\n return scene;\n }\n }\n};\n\nexport type FreehandProjectionOptions = {\n registry: Registry.AtomRegistry;\n store: SceneStore;\n sceneId: SceneId;\n /**\n * Whether a constraining projection (the lattice) applies its constraint now; the view passes its snap\n * toggle. Read per intent, so turning it off frees the next gesture without rebuilding the projection.\n */\n constrained?: () => boolean;\n};\n\nexport const freehandCapabilities: Capabilities = {\n move: true,\n resize: true,\n link: true,\n create: true,\n delete: true,\n update: true,\n layout: true,\n};\n\n/** What a read-only view may do: look, select and navigate, nothing that reaches the model. */\nexport const readonlyCapabilities: Capabilities = {\n move: false,\n resize: false,\n link: false,\n create: false,\n delete: false,\n update: false,\n layout: false,\n};\n\n/** Identity projection over the store: what the surface asks for is what the model becomes. */\nexport const createFreehandProjection = ({ registry, store, sceneId }: FreehandProjectionOptions): Projection => ({\n scene: Atom.keepAlive(Atom.make((get) => get(store.scene(sceneId)) ?? EMPTY)),\n apply: (intent) => updateScene(registry, store, sceneId, (scene) => reduceIntent(scene, intent)),\n capabilities: freehandCapabilities,\n snapshot: () => registry.get(store.scene(sceneId)),\n restore: (snapshot) => {\n // A host's nodes are `NodeBase` to the engine, so a snapshot is checked against the open schema.\n if (Schema.is(OpenScene)(snapshot)) {\n putScene(registry, store, snapshot);\n }\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport { useMemo } from 'react';\n\nimport { type SceneViewAtoms } from '../model/atoms.ts';\nimport { type FreehandProjectionOptions, type Projection, createFreehandProjection } from '../model/projection.ts';\nimport { type SceneStore } from '../model/store.ts';\nimport { withUndo } from '../utils/undo.ts';\nimport { useRegistry } from './useRegistry.ts';\n\nexport type UseSceneProjectionOptions = {\n store: SceneStore;\n atoms: SceneViewAtoms;\n createProjection?: (options: FreehandProjectionOptions) => Projection;\n /**\n * A host-owned projection, already obtained from this hook, used for every scene on the path: for a host\n * that owns one scene and its side effects and shares the projection with the view.\n */\n projection?: Projection;\n};\n\n/**\n * The projection of the scene at the head of the view's path, recording into the view's undo log;\n * shared by the view and its panels so every edit is undoable.\n */\nexport const useSceneProjection = ({\n store,\n atoms,\n createProjection = createFreehandProjection,\n projection,\n}: UseSceneProjectionOptions): Projection => {\n const registry = useRegistry();\n const path = useAtomValue(atoms.path);\n const sceneId = path[path.length - 1];\n return useMemo(\n () =>\n projection ??\n withUndo(\n createProjection({\n registry,\n store,\n sceneId,\n // Snap lands on the lattice only while both snap and the lattice toggle are on.\n constrained: () => registry.get(atoms.snap) && registry.get(atoms.lattice),\n }),\n registry,\n atoms.undo,\n sceneId,\n ),\n [projection, createProjection, registry, store, sceneId, atoms.undo, atoms.snap, atoms.lattice],\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useLayoutEffect, useState } from 'react';\n\nimport { type Size } from '../model/types.ts';\n\n/**\n * Content size of an element, tracked with a ResizeObserver. Measured in a layout effect so the\n * first paint already knows the size: a passive measurement paints one unfitted frame first.\n */\nexport const useViewport = (ref: RefObject<HTMLElement | null>): Size => {\n const [viewport, setViewport] = useState<Size>({ width: 0, height: 0 });\n useLayoutEffect(() => {\n const element = ref.current;\n if (!element) {\n return;\n }\n const update = (width: number, height: number) =>\n setViewport((current) => (current.width === width && current.height === height ? current : { width, height }));\n update(element.clientWidth, element.clientHeight);\n const observer = new ResizeObserver(([entry]) => {\n const { width, height } = entry.contentRect;\n update(width, height);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref]);\n return viewport;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useEffect } from 'react';\n\nexport type WheelHandler = (event: WheelEvent, pointer: { x: number; y: number }) => void;\n\n/**\n * Marks content whose own scrolling takes the wheel rather than the canvas panning: a floating panel over the canvas\n * (the properties form), or a host's content embedded in a node (an object's surface in a frame).\n */\nexport const SCENE_OVERLAY_ATTRIBUTE = 'data-scene-overlay';\n\nconst SCROLLS = /(auto|scroll)/;\n\n/** Whether an element from `target` up to `overlay` scrolls, so the wheel is its own rather than the canvas's. */\nconst scrollsWithin = (target: Element, overlay: Element): boolean => {\n for (let element: Element | null = target; element; element = element.parentElement) {\n const { overflowX, overflowY } = getComputedStyle(element);\n if (\n (SCROLLS.test(overflowY) && element.scrollHeight > element.clientHeight) ||\n (SCROLLS.test(overflowX) && element.scrollWidth > element.clientWidth)\n ) {\n return true;\n }\n if (element === overlay) {\n return false;\n }\n }\n return false;\n};\n\n/** Non-passive wheel listener with the pointer in element coordinates, so the page never scrolls. */\nexport const useWheel = (ref: RefObject<HTMLElement | null>, handler: WheelHandler) => {\n useEffect(() => {\n const element = ref.current;\n if (!element) {\n return;\n }\n const onWheel = (event: WheelEvent) => {\n const target = event.target instanceof Element ? event.target : null;\n const overlay = target?.closest(`[${SCENE_OVERLAY_ATTRIBUTE}]`);\n // Content embedded in a node with nothing to scroll (a card that fits its frame) still lets the canvas pan.\n if (target && overlay && (!overlay.closest('[data-node-id]') || scrollsWithin(target, overlay))) {\n // A pinch over a panel still must not zoom the page; a scroll is the panel's own.\n if (event.ctrlKey || event.metaKey) {\n event.preventDefault();\n }\n return;\n }\n event.preventDefault();\n const rect = element.getBoundingClientRect();\n handler(event, { x: event.clientX - rect.left, y: event.clientY - rect.top });\n };\n element.addEventListener('wheel', onWheel, { passive: false });\n return () => element.removeEventListener('wheel', onWheel);\n }, [ref, handler]);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Camera math (docs/DESIGN.md §5): per-scene coordinates, one CSS transform for the camera, and the\n// portal mapping that lets a camera be re-expressed in a child scene's space so drill-in is seamless.\n//\n\nimport { interpolateZoom } from 'd3';\n\nimport { type Bounds, type Camera, type Node, type Point, type Size } from '../model/types.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport const MIN_ZOOM = 1 / 32;\nexport const MAX_ZOOM = 32;\n\n/** True size: one scene px is one screen px, at every level. Fit never zooms past it. */\nexport const NOMINAL_ZOOM = 1;\n\nexport const clampZoom = (zoom: number) => Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));\n\nexport const sceneToScreen = (camera: Camera, point: Point): Point => ({\n x: (point.x + camera.x) * camera.zoom,\n y: (point.y + camera.y) * camera.zoom,\n});\n\nexport const screenToScene = (camera: Camera, point: Point): Point => ({\n x: point.x / camera.zoom - camera.x,\n y: point.y / camera.zoom - camera.y,\n});\n\n/** Change zoom while keeping the scene point under `screen` fixed. */\nexport const zoomAt = (camera: Camera, screen: Point, zoom: number): Camera => {\n const clamped = clampZoom(zoom);\n const anchor = screenToScene(camera, screen);\n return { zoom: clamped, x: screen.x / clamped - anchor.x, y: screen.y / clamped - anchor.y };\n};\n\nexport const panBy = (camera: Camera, delta: Point): Camera => ({\n ...camera,\n x: camera.x + delta.x,\n y: camera.y + delta.y,\n});\n\nexport const cameraTransform = (camera: Camera) => `scale(${camera.zoom}) translate(${camera.x}px, ${camera.y}px)`;\n\nexport const boundsCenter = (bounds: Bounds): Point => ({\n x: bounds.x + bounds.width / 2,\n y: bounds.y + bounds.height / 2,\n});\n\nexport const screenBounds = (camera: Camera, bounds: Bounds): Bounds => {\n const origin = sceneToScreen(camera, bounds);\n return { ...origin, width: bounds.width * camera.zoom, height: bounds.height * camera.zoom };\n};\n\n/**\n * Camera that centres `bounds` in the viewport at the largest zoom that fits it with `inset` px around,\n * never above `maxZoom` (a small region is centred rather than blown up past it).\n */\nexport const fitBounds = (bounds: Bounds, viewport: Size, inset = 0, maxZoom = MAX_ZOOM): Camera => {\n const zoom = clampZoom(\n Math.min(maxZoom, viewport.width / (bounds.width + 2 * inset), viewport.height / (bounds.height + 2 * inset)),\n );\n return {\n zoom,\n x: viewport.width / (2 * zoom) - (bounds.x + bounds.width / 2),\n y: viewport.height / (2 * zoom) - (bounds.y + bounds.height / 2),\n };\n};\n\n/** Uniform scale that maps a child-space region into the portal node (letterboxed). */\nexport const portalScale = (portal: Node, region: Bounds) => {\n const { width, height } = nodeBounds(portal);\n return Math.min(width / region.width, height / region.height);\n};\n\n/**\n * The frame a portal gives its child: the child-space region, of the portal's proportions, that maps onto\n * the portal's box. It is the child's content (`child`) centred in the smallest such region that holds it,\n * and never smaller than the box itself, so the preview shrinks a large scene to fit but never magnifies a\n * small one. Every scene keeps its own scale: the frame only says where the child sits under the portal,\n * and entering it maps the camera through the frame, so a shape is the same size at the same zoom on any\n * level. An empty child is the box itself, centred on its origin.\n */\nexport const portalFrame = (portal: Node, child: Bounds | undefined): Bounds => {\n const { width, height } = nodeBounds(portal);\n const content = child ?? { x: 0, y: 0, width: 0, height: 0 };\n const factor = Math.max(1, content.width / width, content.height / height);\n const frame = { width: width * factor, height: height * factor };\n return {\n x: content.x + (content.width - frame.width) / 2,\n y: content.y + (content.height - frame.height) / 2,\n ...frame,\n };\n};\n\n/** Child-scene CSS transform inside a portal node whose own origin is the node's top-left. */\nexport const portalTransform = (portal: Node, frame: Bounds) => {\n const scale = portalScale(portal, frame);\n return `scale(${scale}) translate(${-frame.x}px, ${-frame.y}px)`;\n};\n\n/**\n * Re-express a parent-space camera in child-scene space so the swap is visually seamless:\n * screen = (parentPoint + cam) * zoom and parentPoint = portalOrigin + (childPoint - childOrigin) * s.\n */\nexport const enterPortal = (camera: Camera, portal: Node, child: Bounds): Camera => {\n const scale = portalScale(portal, child);\n const origin = nodeBounds(portal);\n return {\n zoom: camera.zoom * scale,\n x: (origin.x - child.x * scale + camera.x) / scale,\n y: (origin.y - child.y * scale + camera.y) / scale,\n };\n};\n\n/** Inverse of `enterPortal`. */\nexport const exitPortal = (camera: Camera, portal: Node, child: Bounds): Camera => {\n const scale = portalScale(portal, child);\n const origin = nodeBounds(portal);\n return {\n zoom: camera.zoom / scale,\n x: camera.x * scale - origin.x + child.x * scale,\n y: camera.y * scale - origin.y + child.y * scale,\n };\n};\n\n/** A portal filling this share of the viewport (on its tighter axis) leaves the rest of its layer fully shown… */\nconst FADE_START = 0.25;\n/** …and this share hides it: zooming into a portal fades out what is around it, and zooming out fades it back. */\nconst FADE_END = 0.75;\n\n/**\n * The opacity of a layer around a portal, from how much of the viewport the portal fills on its tighter axis:\n * 1 while it is small, falling to 0 as it grows towards filling the view. A wheel zoom, a drill-in and a\n * drill-out all move the camera, so all three fade alike.\n */\nexport const layerOpacity = (camera: Camera, bounds: Bounds, viewport: Size): number => {\n if (viewport.width === 0 || viewport.height === 0) {\n return 1;\n }\n const fill = Math.min((bounds.width * camera.zoom) / viewport.width, (bounds.height * camera.zoom) / viewport.height);\n return Math.min(1, Math.max(0, (FADE_END - fill) / (FADE_END - FADE_START)));\n};\n\n/** Fraction of the viewport covered by the bounds' screen rectangle. */\nexport const coverage = (camera: Camera, bounds: Bounds, viewport: Size) => {\n if (viewport.width === 0 || viewport.height === 0) {\n return 0;\n }\n const rect = screenBounds(camera, bounds);\n const width = Math.max(0, Math.min(rect.x + rect.width, viewport.width) - Math.max(rect.x, 0));\n const height = Math.max(0, Math.min(rect.y + rect.height, viewport.height) - Math.max(rect.y, 0));\n return (width * height) / (viewport.width * viewport.height);\n};\n\n// van Wijk & Nuij: the camera is (centre, visible width) so a zoom-out-then-in trajectory falls out of d3.\nconst toView = (camera: Camera, viewport: Size): [number, number, number] => [\n viewport.width / (2 * camera.zoom) - camera.x,\n viewport.height / (2 * camera.zoom) - camera.y,\n viewport.width / camera.zoom,\n];\n\nconst fromView = ([cx, cy, width]: [number, number, number], viewport: Size): Camera => {\n const zoom = viewport.width / width;\n return { zoom, x: viewport.width / (2 * zoom) - cx, y: viewport.height / (2 * zoom) - cy };\n};\n\nexport const MIN_ANIMATION_MS = 250;\nexport const MAX_ANIMATION_MS = 800;\n\n/** How long a drill in or out takes, either way, so entering and leaving a scene feel the same. */\nexport const DRILL_ANIMATION_MS = 1000;\n\n/** Animate between cameras, over `fixedDuration` ms or a time fitted to the distance; returns a cancel function. */\nexport const animateCamera = (\n from: Camera,\n to: Camera,\n viewport: Size,\n apply: (camera: Camera) => void,\n done?: () => void,\n fixedDuration?: number,\n): (() => void) => {\n const interpolate = interpolateZoom(toView(from, viewport), toView(to, viewport));\n const duration = fixedDuration ?? Math.min(MAX_ANIMATION_MS, Math.max(MIN_ANIMATION_MS, interpolate.duration));\n const start = performance.now();\n let frame = 0;\n const tick = (now: number) => {\n const t = Math.min(1, (now - start) / duration);\n const eased = t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;\n apply(fromView(interpolate(eased), viewport));\n if (t < 1) {\n frame = requestAnimationFrame(tick);\n } else {\n done?.();\n }\n };\n frame = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(frame);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Text parts of a node: the properties a node type renders as text and lets the user edit in place. Each\n// type declares its parts in its registry definition, so a type a host adds edits the same way as a built-in\n// one. A part is named by the property it edits; a `lines` part reads and writes a list one entry per line.\n//\n\nimport { nodeDef } from '../model/node-def.ts';\nimport { type NodeRegistry } from '../model/registry.ts';\nimport { type Node, type NodeValues } from '../model/types.ts';\n\n/** A part's name: the node property it edits. */\nexport type PartKey = string;\n\n/** A text property of a node type, as its definition declares it. */\nexport type PartField = {\n /** The node property the part edits. */\n field: PartKey;\n /** A list of strings, one per line; implies `multiline`. */\n lines?: boolean;\n /** Enter breaks the line and Mod-Enter commits, rather than Enter committing. */\n multiline?: boolean;\n};\n\n/** A part edited in place: which one, and how the editor hands its result back. */\nexport type PartEditing = {\n part: PartKey;\n multiline: boolean;\n commit: (text: string) => void;\n cancel: () => void;\n};\n\nconst toLines = (text: string): string[] =>\n text\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n\n/** The core base's one part: the label a node of an unknown type is edited by (see `BaseNode`). */\nconst BASE_PARTS: readonly PartField[] = [{ field: 'label' }];\n\n/** The parts a node's type declares; a type the registry does not know has the core base's label. */\nexport const nodeParts = (registry: NodeRegistry, node: Node): readonly PartField[] => {\n const def = nodeDef(registry, node);\n return def ? (def.parts ?? []) : BASE_PARTS;\n};\n\nconst partOf = (registry: NodeRegistry, node: Node, part: PartKey): PartField | undefined =>\n nodeParts(registry, node).find(({ field }) => field === part);\n\n/** Whether the part takes several lines. */\nexport const isMultiline = (part: PartField): boolean => part.lines === true || part.multiline === true;\n\n/** The part's text, or none when the node's type has no such part. */\nexport const partText = (registry: NodeRegistry, node: Node, part: PartKey): string | undefined => {\n const field = partOf(registry, node, part);\n if (!field) {\n return undefined;\n }\n const value: unknown = Reflect.get(node, field.field);\n if (field.lines) {\n return Array.isArray(value) ? value.filter((line) => typeof line === 'string').join('\\n') : '';\n }\n return typeof value === 'string' ? value : '';\n};\n\n/** The `update` values that set the part's text, or none when the node's type has no such part. */\nexport const partValues = (registry: NodeRegistry, node: Node, part: PartKey, text: string): NodeValues | undefined => {\n const field = partOf(registry, node, part);\n if (!field) {\n return undefined;\n }\n return { [field.field]: field.lines ? toLines(text) : text };\n};\n\n/** A node's main text: its first part's, which a diagram or a DSL export shows as the node's name. */\nexport const nodeTitle = (registry: NodeRegistry, node: Node): string | undefined => {\n const [first] = nodeParts(registry, node);\n return first ? partText(registry, node, first.field) : undefined;\n};\n\n/** The node with its main text (its first part) set; a type without parts is returned as is. */\nexport const withTitle = <N extends Node>(registry: NodeRegistry, node: N, text: string): N => {\n const [first] = nodeParts(registry, node);\n return first ? { ...node, ...partValues(registry, node, first.field, text) } : node;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The frame classes a node's `style` resolves to. Tailwind only emits classes it can read verbatim, so\n// every hue is spelled out here rather than composed from the hue name.\n//\n\nimport {\n type HorizontalAlign,\n type Link,\n type Node,\n type NodeStyle,\n type NodeTone,\n STYLE_HUES,\n type StyleHue,\n type StyleMap,\n type VerticalAlign,\n isEllipseNode,\n isFrameNode,\n showsContents,\n} from '../model/types.ts';\n\nexport type HueClasses = { surface: string; text: string; border: string };\n\nconst HUES: Record<string, HueClasses> = {\n neutral: { surface: 'bg-neutral-surface', text: 'text-neutral-fg', border: 'border-neutral-border' },\n red: { surface: 'bg-red-surface', text: 'text-red-fg', border: 'border-red-border' },\n orange: { surface: 'bg-orange-surface', text: 'text-orange-fg', border: 'border-orange-border' },\n amber: { surface: 'bg-amber-surface', text: 'text-amber-fg', border: 'border-amber-border' },\n yellow: { surface: 'bg-yellow-surface', text: 'text-yellow-fg', border: 'border-yellow-border' },\n lime: { surface: 'bg-lime-surface', text: 'text-lime-fg', border: 'border-lime-border' },\n green: { surface: 'bg-green-surface', text: 'text-green-fg', border: 'border-green-border' },\n emerald: { surface: 'bg-emerald-surface', text: 'text-emerald-fg', border: 'border-emerald-border' },\n teal: { surface: 'bg-teal-surface', text: 'text-teal-fg', border: 'border-teal-border' },\n cyan: { surface: 'bg-cyan-surface', text: 'text-cyan-fg', border: 'border-cyan-border' },\n sky: { surface: 'bg-sky-surface', text: 'text-sky-fg', border: 'border-sky-border' },\n blue: { surface: 'bg-blue-surface', text: 'text-blue-fg', border: 'border-blue-border' },\n indigo: { surface: 'bg-indigo-surface', text: 'text-indigo-fg', border: 'border-indigo-border' },\n violet: { surface: 'bg-violet-surface', text: 'text-violet-fg', border: 'border-violet-border' },\n purple: { surface: 'bg-purple-surface', text: 'text-purple-fg', border: 'border-purple-border' },\n fuchsia: { surface: 'bg-fuchsia-surface', text: 'text-fuchsia-fg', border: 'border-fuchsia-border' },\n pink: { surface: 'bg-pink-surface', text: 'text-pink-fg', border: 'border-pink-border' },\n rose: { surface: 'bg-rose-surface', text: 'text-rose-fg', border: 'border-rose-border' },\n};\n\nexport const TONES: readonly NodeTone[] = [0, 1, 2, 3];\n\n/** What each tone is called, for labels. */\nexport const TONE_NAMES: Record<NodeTone, string> = { 0: 'outline', 1: 'strong', 2: 'medium', 3: 'light' };\n\n/** The tone a hue without one draws at: the look a hue had before tones. */\nexport const DEFAULT_TONE: NodeTone = 2;\n\ntype ToneClasses = { surface: string; text: string };\n\n/**\n * The fills either side of a hue's `surface` role (its 400): the scale's 500 under light text (tone 1), and its\n * 300 under its darkest text (tone 3). Tone 2 is the role pair in `HUES`; tone 0 has no fill.\n */\nconst TONE_FILLS: Record<StyleHue, Record<'strong' | 'light', ToneClasses>> = {\n neutral: {\n light: { surface: 'bg-neutral-300', text: 'text-neutral-900' },\n strong: { surface: 'bg-neutral-500', text: 'text-neutral-50' },\n },\n red: {\n light: { surface: 'bg-red-300', text: 'text-red-900' },\n strong: { surface: 'bg-red-500', text: 'text-neutral-50' },\n },\n orange: {\n light: { surface: 'bg-orange-300', text: 'text-orange-900' },\n strong: { surface: 'bg-orange-500', text: 'text-neutral-50' },\n },\n amber: {\n light: { surface: 'bg-amber-300', text: 'text-amber-900' },\n strong: { surface: 'bg-amber-500', text: 'text-neutral-50' },\n },\n green: {\n light: { surface: 'bg-green-300', text: 'text-green-900' },\n strong: { surface: 'bg-green-500', text: 'text-neutral-50' },\n },\n teal: {\n light: { surface: 'bg-teal-300', text: 'text-teal-900' },\n strong: { surface: 'bg-teal-500', text: 'text-neutral-50' },\n },\n sky: {\n light: { surface: 'bg-sky-300', text: 'text-sky-900' },\n strong: { surface: 'bg-sky-500', text: 'text-neutral-50' },\n },\n blue: {\n light: { surface: 'bg-blue-300', text: 'text-blue-900' },\n strong: { surface: 'bg-blue-500', text: 'text-neutral-50' },\n },\n violet: {\n light: { surface: 'bg-violet-300', text: 'text-violet-900' },\n strong: { surface: 'bg-violet-500', text: 'text-neutral-50' },\n },\n};\n\nconst isStyleHue = (hue: string | undefined): hue is StyleHue => STYLE_HUES.some((candidate) => candidate === hue);\n\n/** The default look: the base surface, the base text and the separator border. */\nconst DEFAULT: HueClasses = { surface: 'bg-base-surface', text: '', border: 'border-separator' };\n\n/**\n * The classes a hue at a tone draws with. Every tone keeps the hue's border; tone 0 drops the fill and\n * keeps the default text, and a tone a hue has no fills for draws as `medium` (its role pair).\n */\nexport const hueClasses = (hue: string | undefined, tone: NodeTone = DEFAULT_TONE): HueClasses => {\n const base = (hue && HUES[hue]) || DEFAULT;\n if (!hue || base === DEFAULT) {\n return base;\n }\n if (tone === 0) {\n return { surface: 'bg-transparent', text: '', border: base.border };\n }\n if ((tone === 1 || tone === 3) && isStyleHue(hue)) {\n return { ...TONE_FILLS[hue][tone === 1 ? 'strong' : 'light'], border: base.border };\n }\n return base;\n};\n\n/** `base` with every field `own` sets over it; an `undefined` field of `own` is unset, so it leaves the base's. */\nconst overlay = <T extends object>(base: T | undefined, own: T | undefined): T | undefined => {\n if (!base || !own) {\n return own ?? base;\n }\n const merged = { ...base };\n for (const [key, value] of Object.entries(own)) {\n if (value !== undefined) {\n Reflect.set(merged, key, value);\n }\n }\n return merged;\n};\n\n/** A node as drawn: its class's style under its own (`StyleClass`). */\nexport const classedNode = (node: Node, styles: StyleMap | undefined): Node => {\n const style = node.class ? styles?.[node.class]?.style : undefined;\n return style ? { ...node, style: overlay(style, node.style) } : node;\n};\n\n/** A link as drawn: its class's colour and line style under its own. */\nexport const classedLink = (link: Link, styles: StyleMap | undefined): Link => {\n const style = link.class ? styles?.[link.class]?.style : undefined;\n // A link draws only the common base (`LineStyle`) of its class's style.\n return style ? { ...link, style: overlay({ hue: style.hue, lineStyle: style.lineStyle }, link.style) } : link;\n};\n\n/**\n * A node's style with the defaults the frame draws spelled out: an unset `fill` or `border` is drawn, so\n * the properties panel must show it as on rather than as an unset (off) toggle.\n */\nexport const resolveStyle = (style: NodeStyle = {}): NodeStyle => ({\n ...style,\n fill: style.fill ?? true,\n border: style.border ?? true,\n});\n\n/**\n * Frame classes for a node: fill and text colour, border and corner radius from its style; a guide is\n * dashed and unfilled.\n */\nexport const frameClasses = (node: Node, selected: boolean, hovered = false): string[] => {\n const style = resolveStyle(node.style);\n const hue = hueClasses(style.hue, style.tone);\n const filled = style.fill && !style.guide;\n // A scene shape drawing its contents is a window onto another canvas, so it is opaque even in outline: the\n // grid behind it would read as part of the child scene.\n const opaque = isFrameNode(node) && showsContents(node);\n const clear = !filled || hue.surface === 'bg-transparent';\n const surface = opaque && clear ? 'bg-base-surface' : filled ? hue.surface : '';\n return [\n surface,\n // A guide's hue marks its edge (a group's backdrop); its title reads in the default text colour.\n style.guide ? '' : hue.text,\n selected\n ? 'border-focus'\n : hovered\n ? 'border-focus/50'\n : // A frame always shows its edge: it bounds a scene or an embedded object, which has none of its own.\n style.border === false && !style.guide && !isFrameNode(node)\n ? 'border-transparent'\n : hue.border,\n style.guide || style.lineStyle === 'dashed' ? 'border-dashed' : style.lineStyle === 'dotted' ? 'border-dotted' : '',\n isEllipseNode(node) ? 'rounded-[50%]' : style.rounded ? 'rounded-2xl' : 'rounded-sm',\n ];\n};\n\nexport type LineClasses = { stroke: string; fill: string };\n\n/** A link's stroke and its end markers' fill, in the hue's border colour so a link matches a node of its hue. */\nconst LINE_CLASSES: Record<StyleHue, LineClasses> = {\n neutral: { stroke: 'stroke-neutral-border', fill: 'fill-neutral-border' },\n red: { stroke: 'stroke-red-border', fill: 'fill-red-border' },\n orange: { stroke: 'stroke-orange-border', fill: 'fill-orange-border' },\n amber: { stroke: 'stroke-amber-border', fill: 'fill-amber-border' },\n green: { stroke: 'stroke-green-border', fill: 'fill-green-border' },\n teal: { stroke: 'stroke-teal-border', fill: 'fill-teal-border' },\n sky: { stroke: 'stroke-sky-border', fill: 'fill-sky-border' },\n blue: { stroke: 'stroke-blue-border', fill: 'fill-blue-border' },\n violet: { stroke: 'stroke-violet-border', fill: 'fill-violet-border' },\n};\n\n/** The default line: the grey every link drew before lines took a hue. */\nconst DEFAULT_LINE: LineClasses = { stroke: 'stroke-neutral-500', fill: 'fill-neutral-500' };\n\nexport const lineClasses = (hue: string | undefined): LineClasses =>\n isStyleHue(hue) ? LINE_CLASSES[hue] : DEFAULT_LINE;\n\n/**\n * Splits an edit of a classed element's look (`edited`, against what the panel `shown`): every field that changed\n * goes to the class, so each element of the class derives it, and the element drops its own value for that field,\n * which would otherwise hide the class's.\n */\nexport const splitClassEdit = <T extends object>(\n shown: object | undefined,\n edited: unknown,\n classLook: T,\n own: T | undefined,\n): { classLook: T; own: T | undefined } => {\n const nextClass = { ...classLook };\n const nextOwn = own ? { ...own } : undefined;\n if (typeof edited === 'object' && edited !== null) {\n for (const [key, value] of Object.entries(edited)) {\n if (Reflect.get(shown ?? {}, key) !== value) {\n Reflect.set(nextClass, key, value);\n if (nextOwn) {\n Reflect.deleteProperty(nextOwn, key);\n }\n }\n }\n }\n return { classLook: nextClass, own: nextOwn };\n};\n\nconst HORIZONTAL_CLASSES: Record<HorizontalAlign, string> = {\n left: 'items-start text-left',\n center: 'items-center text-center',\n right: 'items-end text-right',\n};\n\nconst VERTICAL_CLASSES: Record<VerticalAlign, string> = {\n top: 'justify-start',\n middle: 'justify-center',\n bottom: 'justify-end',\n};\n\n/**\n * Classes placing a text part in its shape by the style's alignment, else by the type's own (`defaults`): the part\n * is a column, so `justify` places it down the shape and `items` across it.\n */\nexport const alignClasses = (\n style: NodeStyle | undefined,\n defaults: { horizontal: HorizontalAlign; vertical: VerticalAlign },\n): string =>\n `flex flex-col ${HORIZONTAL_CLASSES[style?.alignHorizontal ?? defaults.horizontal]} ${\n VERTICAL_CLASSES[style?.alignVertical ?? defaults.vertical]\n }`;\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Renders one scene's nodes and links in scene coordinates under the camera transform (§7). Nodes are\n// HTML so they can host live content; links are one SVG per scene; live portals nest another layer.\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport React, {\n type CSSProperties,\n Fragment,\n createContext,\n memo,\n useContext,\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport { mx } from '@dxos/ui-theme';\n\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type NodeRegistry, type NodeViewProps } from '../../model/registry.ts';\nimport { NO_STYLES, type SceneStore } from '../../model/store.ts';\nimport {\n type ElementId,\n type LineStyle,\n type Link,\n type LinkId,\n MAJOR_GRID_RATIO,\n type Marker,\n type Node,\n type NodeId,\n type Scene,\n type StyleMap,\n isFrameNode,\n isNoteNode,\n linkMarkers,\n showsContents,\n} from '../../model/types.ts';\nimport { portalFrame, portalScale, portalTransform } from '../../utils/camera.ts';\nimport { contentBounds } from '../../utils/hit.ts';\nimport { type LatticeSpec } from '../../utils/lattice.ts';\nimport { elementLayer, sceneLayers, visibleScene } from '../../utils/layers.ts';\nimport { sortByZ } from '../../utils/order.ts';\nimport { type PartEditing, type PartKey, isMultiline, nodeParts } from '../../utils/parts.ts';\nimport { sceneLinkGeometry } from '../../utils/route.ts';\nimport { DEFAULT_CELL, nodeBounds } from '../../utils/shapes.ts';\nimport { alignClasses, classedLink, classedNode, frameClasses, lineClasses } from '../../utils/style.ts';\nimport { TextPart } from '../PartEditor/PartEditor.tsx';\n\n/** Screen px below which a portal shows only its title; above it a portal showing its contents mounts the child live. */\nexport const DOT_PX = 40;\n/** Default for `liveDepth`: root plus this many live nested levels (decision 10). */\nexport const MAX_LIVE_DEPTH = 1;\n/** Hysteresis at the tier boundaries so a portal does not flicker while zooming across one. */\nconst TIER_HYSTERESIS = 0.1;\n\nexport type Tier = 'dot' | 'preview' | 'live';\n\nexport const tierFor = (node: Node, zoom: number, depth: number, liveDepth: number, previous?: Tier): Tier => {\n const { width, height } = nodeBounds(node);\n const px = Math.min(width, height) * zoom;\n const dot = previous === 'dot' ? DOT_PX * (1 + TIER_HYSTERESIS) : DOT_PX * (1 - TIER_HYSTERESIS);\n if (px < dot) {\n return 'dot';\n }\n // Past `liveDepth` the child is summarised rather than mounted, which bounds how many scenes render live.\n return depth >= liveDepth ? 'preview' : 'live';\n};\n\nexport type ElementHandlers = {\n onNodePointerDown?: (node: Node, event: React.PointerEvent) => void;\n onLinkPointerDown?: (link: Link, event: React.PointerEvent) => void;\n onLinkDoubleClick?: (link: Link, event: React.MouseEvent) => void;\n onLinkContextMenu?: (link: Link, event: React.MouseEvent) => void;\n /** The in-place editor of `part` finished with `text` (commit) or was dismissed (cancel). */\n onPartCommit?: (node: Node, part: PartKey, text: string) => void;\n onPartCancel?: () => void;\n /** The pointer entered a link (its id) or left it (`undefined`). */\n onLinkHover?: (id: LinkId | undefined) => void;\n /** A node's own open control was pressed (a portal's zoom-in icon). */\n onNodeOpen?: (node: Node) => void;\n};\n\nexport type SceneLayerProps = {\n store: SceneStore;\n scene: Scene;\n registry: NodeRegistry;\n /** Effective screen zoom of this layer (camera zoom × portal scales). */\n zoom: number;\n depth: number;\n liveDepth: number;\n selected?: ReadonlySet<ElementId>;\n /** The selection is drawn as it looks, without its outline (a move in flight shows the shapes themselves). */\n plain?: boolean;\n hover?: NodeId;\n /** The link under the pointer, outlined as a hovered shape is. */\n hoveredLink?: LinkId;\n /** The portal a drill-in is animating into, while it is. */\n opening?: ElementId;\n /** The portal filling most of the view, and the opacity of everything else on the layer as it does. */\n focus?: { id: ElementId; opacity: number };\n /** The text part being edited in place, if any. */\n editing?: { id: NodeId; part: PartKey };\n /** The node whose embedded content takes input. */\n active?: NodeId;\n /** A node drawn as a preview of what a gesture will create: translucent, dashed, and not pressable. */\n ghost?: NodeId;\n /** Frames show their id, type and geometry. */\n debug?: boolean;\n /** Absent on nested (read-only) layers. */\n handlers?: ElementHandlers;\n /** The scene's lattice, when it has one: smart links route through its gutters. */\n lattice?: LatticeSpec;\n /** Scene px of one nominal unit (the drawing's major grid cell); a nested layer inherits its parent's. */\n cell?: number;\n};\n\nexport const SceneLayer = memo(\n ({\n store,\n scene: sceneProp,\n registry,\n zoom,\n depth,\n liveDepth,\n selected,\n plain,\n hover,\n hoveredLink,\n opening,\n focus,\n editing,\n active,\n ghost,\n debug,\n handlers,\n lattice: latticeProp,\n cell: cellProp,\n }: SceneLayerProps) => {\n const inherited = useContext(CellContext);\n const cell = cellProp ?? inherited;\n // A nested scene (a frame's contents, a drill-in in flight) routes on its parent's lattice, so its links do not\n // jump onto the gutters when it settles as the root.\n const inheritedLattice = useContext(LatticeContext);\n const lattice = latticeProp ?? inheritedLattice;\n // A hidden layer's elements are not drawn (nor, for the root, hit: the view hit-tests the same visible scene).\n const scene = useMemo(() => visibleScene(sceneProp), [sceneProp]);\n const links = useMemo(\n () => sceneLinkGeometry(scene, registry, sortByZ(Object.values(scene.links)), lattice),\n [scene, registry, lattice],\n );\n // Paint order is the layers', bottom first: each layer's links, then its nodes, then its links' ends, so an upper\n // layer covers a lower one whole. Within a layer it is z, with the selection on top: a selected node is being\n // worked on and must not hide under a neighbour, while the model's order stays what the user arranged.\n const groups = useMemo(() => {\n const layers = sceneLayers(scene);\n const nodes = sortByZ(Object.values(scene.nodes));\n return layers.map((layer) => {\n const onLayer = nodes.filter((node) => elementLayer(node, layers) === layer.id);\n return {\n layer,\n nodes: selected?.size\n ? [...onLayer.filter((node) => !selected.has(node.id)), ...onLayer.filter((node) => selected.has(node.id))]\n : onLayer,\n links: links.filter(({ link }) => elementLayer(link, layers) === layer.id),\n };\n });\n }, [scene, links, selected]);\n // Each element is drawn with its class's look under its own; the handlers still get the element as stored.\n const styles = useAtomValue(store.styles ?? NO_STYLES);\n const lines = useMemo(\n () => new Map(links.map(({ link }) => [link.id, classedLink(link, styles).style])),\n [links, styles],\n );\n const unit = 1 / Math.max(zoom, 0.05);\n const linkWidth = LINK_WIDTH * lineWeight(depth, zoom);\n // Everything but the portal being zoomed into fades with the zoom (see `layerOpacity`).\n const fadeStyle: CSSProperties | undefined = focus && focus.opacity < 1 ? { opacity: focus.opacity } : undefined;\n // One set of end markers per line colour in use, sized in scene units so they scale with the nodes they join.\n const markerId = useId();\n const lineHues = useMemo(() => [...new Set([...lines.values()].map((line) => line?.hue))], [lines]);\n const markerUrl = (marker: Marker | undefined, end: 'start' | 'end', hue: string | undefined) =>\n marker ? `url(#${markerId}-${hue ?? 'default'}-${marker}-${end})` : undefined;\n\n return (\n <CellContext.Provider value={cell}>\n <LatticeContext.Provider value={lattice}>\n <svg className='absolute overflow-visible pointer-events-none' style={fadeStyle} width={1} height={1}>\n <defs>\n {lineHues.map((hue) => (\n <Markers\n key={hue ?? 'default'}\n id={`${markerId}-${hue ?? 'default'}`}\n cell={cell}\n hue={hue}\n width={linkWidth}\n />\n ))}\n </defs>\n </svg>\n {groups.map((group) => (\n <Fragment key={group.layer.id}>\n <svg className='absolute overflow-visible pointer-events-none' style={fadeStyle} width={1} height={1}>\n {group.links.map(({ link, path }) => (\n <g key={link.id}>\n {/* A wide transparent twin makes the thin stroke easy to press. */}\n {handlers && (\n <path\n d={path}\n className='fill-none stroke-transparent pointer-events-auto cursor-pointer'\n style={{ pointerEvents: 'stroke' }}\n strokeWidth={12 * unit}\n onPointerDown={(event) => handlers.onLinkPointerDown?.(link, event)}\n onPointerEnter={() => handlers.onLinkHover?.(link.id)}\n onPointerLeave={() => handlers.onLinkHover?.(undefined)}\n onDoubleClick={(event) => handlers.onLinkDoubleClick?.(link, event)}\n onContextMenu={(event) => handlers.onLinkContextMenu?.(link, event)}\n />\n )}\n <path\n d={path}\n className={mx(\n 'fill-none',\n plain\n ? lineClasses(lines.get(link.id)?.hue).stroke\n : selected?.has(link.id)\n ? 'stroke-focus'\n : hoveredLink === link.id\n ? 'stroke-focus/50'\n : lineClasses(lines.get(link.id)?.hue).stroke,\n )}\n strokeWidth={linkWidth}\n strokeDasharray={dashArray(lines.get(link.id)?.lineStyle, linkWidth)}\n strokeLinecap={lines.get(link.id)?.lineStyle === 'dotted' ? 'round' : undefined}\n data-link-id={link.id}\n />\n {link.text && <LinkText path={path} text={link.text} />}\n </g>\n ))}\n </svg>\n {group.nodes.map((node) => (\n <NodeFrame\n key={node.id}\n store={store}\n scene={scene}\n registry={registry}\n node={node}\n styles={styles}\n zoom={zoom}\n depth={depth}\n liveDepth={liveDepth}\n selected={!plain && (selected?.has(node.id) ?? false)}\n hovered={hover === node.id}\n opening={opening === node.id}\n fade={focus && focus.id !== node.id ? fadeStyle : undefined}\n chromeFade={focus?.id === node.id ? fadeStyle : undefined}\n editingPart={editing?.id === node.id ? editing.part : undefined}\n active={active === node.id}\n ghost={ghost === node.id}\n debug={debug}\n handlers={handlers}\n />\n ))}\n {/* The ends paint over the layer's nodes, so an end centred on a node's edge shows whole. */}\n <svg className='absolute overflow-visible pointer-events-none' style={fadeStyle} width={1} height={1}>\n {group.links.map(({ link, path }) => (\n <path\n key={link.id}\n d={path}\n className='fill-none stroke-none'\n markerStart={markerUrl(linkMarkers(link).start, 'start', lines.get(link.id)?.hue)}\n markerEnd={markerUrl(linkMarkers(link).end, 'end', lines.get(link.id)?.hue)}\n />\n ))}\n </svg>\n </Fragment>\n ))}\n </LatticeContext.Provider>\n </CellContext.Provider>\n );\n },\n);\n\nSceneLayer.displayName = 'SceneLayer';\n\n/** The width of a node frame's border, which a nested scene drawn inside it steps out over. */\nconst FRAME_BORDER = '--scene-frame-border' as const;\n\n/** A link's stroke, in scene units like a node's 2px border, so a link keeps its weight beside the shapes at any zoom. */\nconst LINK_WIDTH = 2;\n\n/** The most a nested scene's lines thicken by. */\nconst MAX_LINE_WEIGHT = 2;\n\n/**\n * How much thicker a layer draws its lines: a scene seen inside another is small, so its borders and links thicken,\n * up to double, as it shrinks; at its own size (as it is drilled into) it is back to 1, so nothing jumps at the swap.\n */\nexport const lineWeight = (depth: number, zoom: number): number =>\n depth > 0 ? Math.min(MAX_LINE_WEIGHT, Math.max(1, 1 / Math.max(zoom, 0.05))) : 1;\n\n/** Scene px of a nominal unit for the layers below a `SceneLayer` given one, so nested scenes draw alike. */\nconst CellContext = createContext(DEFAULT_CELL);\n\n/** The lattice smart links route on, inherited by nested layers. */\nconst LatticeContext = createContext<LatticeSpec | undefined>(undefined);\n\n/** The scene's minor grid, in px, on each node frame for the text inside it. */\nconst MINOR_GRID = '--dx-minor-grid';\n\n/**\n * A text part covers the frame from its outer edge, border included, so its lines start on the grid the frame's edge is\n * on rather than a border width inside it.\n */\n// Spelled out, not built from `FRAME_BORDER`: Tailwind only emits classes it can read verbatim.\n// The text's own box is flush with the frame's edge and pads its text a grid unit either side; its lines need no\n// padding above or below, being on the grid already.\nconst TEXT_BOX = 'absolute inset-[calc(-1*var(--scene-frame-border,2px))] [&>span]:px-(--dx-minor-grid)';\n\n/** A line is a whole number of minor grid units tall, the text centred in it, so lines of text sit on the grid. */\nconst LINE_ON_GRID = mx(\n // Important: a size class (`text-lg`) carries its own leading, which would otherwise win.\n '[--dx-line:round(up,1.25em,var(--dx-minor-grid))] leading-(--dx-line)!',\n);\n\n/** A line pattern's dashes in scene units, relative to the stroke; a dot is a zero-length dash with a round cap. */\nconst dashArray = (dash: LineStyle['lineStyle'], width = LINK_WIDTH): string | undefined =>\n dash === 'dashed' ? `${4 * width} ${3 * width}` : dash === 'dotted' ? `0 ${2.5 * width}` : undefined;\n\n/** Bounding box of every end, in nominal units: a quarter of a major grid cell. */\nconst END_BOX = 0.25;\n\n/** The end markers, one per kind and end: a start marker points back along the path, an end marker along it. */\nconst Markers = ({ id, cell, hue, width }: { id: string; cell: number; hue: string | undefined; width: number }) => {\n const line = lineClasses(hue);\n // Each end fills a box of `END_BOX` nominal units, so it scales with the grid and the shapes it joins: the\n // arrow and the triangle 10 of their 12 view units, the circle 8 of its 10.\n const box = END_BOX * cell;\n const arrow = box;\n const triangle = (box * 12) / 10;\n const circle = (box * 10) / 8;\n // An outline matches the line's width, in its marker's view units.\n const outline = (size: number, view: number) => (width * view) / size;\n const ends = ['start', 'end'] as const;\n return (\n <>\n {ends.map((end) => (\n <marker\n key={`arrow-${end}`}\n id={`${id}-arrow-${end}`}\n viewBox='-1 -1 12 12'\n refX={10}\n refY={5}\n markerWidth={(arrow * 12) / 10}\n markerHeight={(arrow * 12) / 10}\n markerUnits='userSpaceOnUse'\n orient={end === 'start' ? 'auto-start-reverse' : 'auto'}\n >\n {/* An open arrowhead: two strokes, not a filled head. */}\n <path\n d='M 0 0 L 10 5 L 0 10'\n className={mx('fill-none', line.stroke)}\n strokeWidth={outline((arrow * 12) / 10, 12)}\n strokeLinecap='round'\n strokeLinejoin='round'\n />\n </marker>\n ))}\n {/* Inheritance (UML generalization): a triangle filled with the canvas, so the line stops at its base. */}\n {ends.map((end) => (\n <marker\n key={`triangle-${end}`}\n id={`${id}-triangle-${end}`}\n viewBox='-1 -1 12 12'\n refX={10}\n refY={5}\n markerWidth={triangle}\n markerHeight={triangle}\n markerUnits='userSpaceOnUse'\n orient={end === 'start' ? 'auto-start-reverse' : 'auto'}\n >\n <path\n d='M 0 0 L 10 5 L 0 10 z'\n className={mx('fill-base-surface', line.stroke)}\n strokeWidth={outline(triangle, 12)}\n />\n </marker>\n ))}\n {/* A circle centred on the connection point, filled with the canvas so the line stops at its rim. */}\n {ends.map((end) => (\n <marker\n key={`circle-${end}`}\n id={`${id}-circle-${end}`}\n viewBox='0 0 10 10'\n refX={5}\n refY={5}\n markerWidth={circle}\n markerHeight={circle}\n markerUnits='userSpaceOnUse'\n >\n <circle\n cx={5}\n cy={5}\n r={4}\n className={mx('fill-base-surface', line.stroke)}\n strokeWidth={outline(circle, 10)}\n />\n </marker>\n ))}\n </>\n );\n};\n\ntype LinkTextProps = { path: string; text: string };\n\n/** A caption's backdrop margin around its text, in scene units. */\nconst LINK_TEXT_PAD = { x: 8, y: 2 };\n\n/** A link's caption at the middle of its route, over a halo of the canvas so it reads where it crosses lines. */\nconst LinkText = ({ path, text }: LinkTextProps) => {\n const ref = useRef<SVGPathElement>(null);\n const textRef = useRef<SVGTextElement>(null);\n const [at, setAt] = useState<{ x: number; y: number }>();\n const [box, setBox] = useState<{ x: number; y: number; width: number; height: number }>();\n // The route is only known as drawn: its midpoint is measured along the path, not between its ends.\n useLayoutEffect(() => {\n const element = ref.current;\n if (element) {\n const { x, y } = element.getPointAtLength(element.getTotalLength() / 2);\n setAt({ x, y });\n }\n }, [path]);\n // The backdrop fits the text as set, so it is measured once the text is placed.\n useLayoutEffect(() => {\n const element = textRef.current;\n if (element && at) {\n const { x, y, width, height } = element.getBBox();\n setBox({\n x: x - LINK_TEXT_PAD.x,\n y: y - LINK_TEXT_PAD.y,\n width: width + LINK_TEXT_PAD.x * 2,\n height: height + LINK_TEXT_PAD.y * 2,\n });\n }\n }, [at, text]);\n return (\n <>\n <path ref={ref} d={path} className='fill-none stroke-none' />\n {at && (\n <>\n {/* Opaque, so the caption reads over the lines it sits on. */}\n {box && <rect {...box} rx={box.height / 2} className='fill-base-surface' data-link-text-box />}\n <text\n ref={textRef}\n x={at.x}\n y={at.y}\n textAnchor='middle'\n dominantBaseline='central'\n className='fill-fg-muted text-sm'\n data-link-text\n >\n {text}\n </text>\n </>\n )}\n </>\n );\n};\n\ntype NodeFrameProps = Omit<NodeViewProps, 'editing'> & {\n hovered?: boolean;\n editingPart?: PartKey;\n ghost?: boolean;\n debug?: boolean;\n handlers?: ElementHandlers;\n /** The fade while another node is zoomed into. */\n fade?: CSSProperties;\n /** The fade of this node's own frame (fill and border) while it is zoomed into; its contents stay. */\n chromeFade?: CSSProperties;\n /** The drawing's style classes, under the node's own style. */\n styles?: StyleMap;\n};\n\n/** Positions a node, owns its frame styling and pointer events; the node definition renders the body. */\nconst NodeFrame = memo(\n ({ handlers, hovered, editingPart, ghost, debug, fade, chromeFade, styles, ...props }: NodeFrameProps) => {\n const { node, registry, selected } = props;\n const cell = useContext(CellContext);\n const drawn = useMemo(() => classedNode(node, styles), [node, styles]);\n const bounds = nodeBounds(node);\n const interactive = handlers !== undefined && !ghost;\n // A type the registry does not know is drawn as the core base: a box with its label.\n const def = nodeDef(registry, node);\n const Component = def?.component ?? BoxNodeView;\n const Toolbar = interactive ? def?.toolbar : undefined;\n const editing = useMemo<PartEditing | undefined>(\n () =>\n editingPart && handlers\n ? {\n part: editingPart,\n multiline: nodeParts(registry, node).some((part) => part.field === editingPart && isMultiline(part)),\n commit: (text) => handlers.onPartCommit?.(node, editingPart, text),\n cancel: () => handlers.onPartCancel?.(),\n }\n : undefined,\n [editingPart, handlers, node, registry],\n );\n const onOpen = useMemo(\n () => (interactive && handlers.onNodeOpen ? () => handlers.onNodeOpen?.(node) : undefined),\n [interactive, handlers, node],\n );\n // Being zoomed into, the frame becomes the child scene's canvas, so it drops its fill (the first class)\n // at once and keeps only its own border, not the selection's or the hover's.\n // `fontSize` is inherited by every text part, so an override set on the node reaches the label,\n // the class compartments and the editor alike; unset, the parts keep their own theme sizes.\n // The frame's border is 2px, thickened with the layer's lines (`lineWeight`); fading, it is padding instead.\n const border = 2 * lineWeight(props.depth, props.zoom);\n const thick = border !== 2;\n const frameStyle: CSSProperties & Record<`--${string}`, string> = {\n left: bounds.x,\n top: bounds.y,\n width: bounds.width,\n height: bounds.height,\n fontSize: drawn.style?.fontSize,\n [FRAME_BORDER]: chromeFade ? '0px' : `${border}px`,\n [MINOR_GRID]: `${cell / MAJOR_GRID_RATIO}px`,\n ...(thick ? (chromeFade ? { padding: border } : { borderWidth: border }) : {}),\n ...fade,\n };\n const frameLook = props.opening ? frameClasses(drawn, false).slice(1) : frameClasses(drawn, selected, hovered);\n return (\n <>\n <div\n className={mx(\n 'absolute box-border overflow-hidden',\n // Fading, the border becomes padding of the same width so the contents stay put.\n ...(chromeFade ? ['p-0.5 isolate'] : ['border-2', ...frameLook]),\n // Every text part inherits the face, as it does `fontSize`.\n drawn.style?.fontFamily === 'monospace' && 'font-mono',\n interactive && !node.locked && 'cursor-grab',\n ghost && 'opacity-50 border-dashed pointer-events-none',\n )}\n style={frameStyle}\n data-node-id={node.id}\n data-ghost={ghost || undefined}\n onPointerDown={\n interactive\n ? (event) => {\n // React bubbles a portal's events through the tree: a press in a menu the node's content opened is\n // not a press on the node.\n if (event.target instanceof Element && event.currentTarget.contains(event.target)) {\n handlers.onNodePointerDown?.(node, event);\n }\n }\n : undefined\n }\n >\n {/* Fading, the frame's fill and border are drawn behind the contents so they fade without them. */}\n {chromeFade && (\n <div\n aria-hidden\n className={mx('dx-cover -z-10 border-2 pointer-events-none', ...frameLook)}\n style={thick ? { ...chromeFade, borderWidth: border } : chromeFade}\n />\n )}\n <Component {...props} node={drawn} editing={editing} onOpen={onOpen} />\n {debug && (\n <div\n className='absolute top-0 left-0 px-1 text-[10px] leading-4 font-mono whitespace-nowrap bg-modal-surface text-fg-muted pointer-events-none'\n data-testid='node-debug'\n >\n {node.id} · {node.type} · {bounds.x},{bounds.y} {bounds.width}×{bounds.height} · z {node.z}\n </div>\n )}\n </div>\n {Toolbar && (\n // Outside the frame, which clips its contents; scaled back to screen size from its bottom-right corner. Its\n // own width (`w-max`): near the layer's edge an absolute box would shrink to the space left. Shown with the\n // frame's hover or selection, and kept while the pointer crosses onto it.\n <div\n className={mx(\n 'absolute flex w-max pb-1 transition-opacity',\n hovered || selected ? 'opacity-100' : 'opacity-0 hover:opacity-100',\n )}\n style={{\n left: bounds.x + bounds.width,\n top: bounds.y,\n transform: `translate(-100%, -100%) scale(${1 / Math.max(props.zoom, 0.05)})`,\n transformOrigin: 'bottom right',\n ...fade,\n }}\n data-testid='node-toolbar'\n onPointerDown={(event) => event.stopPropagation()}\n onDoubleClick={(event) => event.stopPropagation()}\n >\n <Toolbar {...props} node={drawn} editing={editing} onOpen={onOpen} />\n </div>\n )}\n </>\n );\n },\n);\n\nNodeFrame.displayName = 'NodeFrame';\n\n/**\n * A part's own size class, or nothing when the node overrides `fontSize`: a Tailwind size wins over the\n * inherited value, so the override only reaches the text if the class is left off.\n */\nconst sizeClass = (node: Node, className: string) => (node.style?.fontSize === undefined ? className : undefined);\n\ntype LabelPartProps = Pick<NodeViewProps, 'node' | 'editing'> & { label: string };\n\n/** The centred, editable label of a box (and an ellipse). */\nconst LabelPart = ({ node, editing, label }: LabelPartProps) => (\n <TextPart\n part='label'\n text={label}\n editing={editing}\n classNames={mx(\n TEXT_BOX,\n 'whitespace-pre-wrap',\n LINE_ON_GRID,\n alignClasses(node.style, { horizontal: 'center', vertical: 'middle' }),\n sizeClass(node, 'text-lg'),\n )}\n >\n {label}\n </TextPart>\n);\n\n/** A node's core-base `label`, read from any type: a type the registry does not know still carries it. */\nconst baseLabel = (node: Node): string => {\n const label: unknown = Reflect.get(node, 'label');\n return typeof label === 'string' ? label : '';\n};\n\nconst LabelNodeView = ({ node, editing }: NodeViewProps) => (\n <LabelPart node={node} editing={editing} label={baseLabel(node)} />\n);\n\n/** The `box` prototype's body: its centred label. */\nexport const BoxNodeView = LabelNodeView;\n\nexport const EllipseNodeView = LabelNodeView;\n\n/** A node whose type the registry does not know: its frame and type name, so the scene still reads. */\nexport const UnknownNodeView = ({ node }: NodeViewProps) => (\n <div className='dx-cover flex items-center justify-center text-xs text-fg-muted'>{node.type}</div>\n);\n\nexport const NoteNodeView = ({ node, editing }: NodeViewProps) => {\n const text = isNoteNode(node) ? node.text : '';\n return (\n <TextPart\n part='text'\n text={text}\n editing={editing}\n classNames={mx(\n TEXT_BOX,\n 'whitespace-pre-wrap',\n LINE_ON_GRID,\n alignClasses(node.style, { horizontal: 'left', vertical: 'top' }),\n )}\n >\n {text}\n </TextPart>\n );\n};\n\n/**\n * A frame over a child scene: the centred label, or with `contents` the child drawn inside the frame (a\n * preview, then the live scene as it grows on screen), and a zoom-in control at the top-right.\n */\nexport const FrameNodeView = (props: NodeViewProps) => {\n const { node, store, registry, zoom, depth, liveDepth, opening, editing, onOpen } = props;\n const child = useAtomValue(store.scene(isFrameNode(node) ? node.scene : ''));\n const contents = opening || (isFrameNode(node) && showsContents(node));\n // Being entered, the portal is already the child scene on the canvas: live.\n const tier = !child ? 'dot' : opening ? 'live' : tierFor(node, zoom, depth, liveDepth);\n const bounds = useMemo(() => (child ? portalFrame(node, contentBounds(child)) : undefined), [node, child]);\n const title = (isFrameNode(node) ? node.label : undefined) ?? child?.name ?? child?.id ?? '';\n // Too small to show anything inside (or with no child yet), it reads as a closed scene: frame and title.\n if (!contents || tier === 'dot') {\n return (\n <>\n <LabelPart node={node} editing={editing} label={title} />\n {onOpen && <OpenControl onOpen={onOpen} />}\n </>\n );\n }\n return (\n <div className='dx-cover'>\n {tier === 'preview' && child && (\n <div className='dx-cover flex flex-col items-center justify-center gap-1 pointer-events-none'>\n <span className='text-lg'>{title}</span>\n <span>\n {Object.keys(child.nodes).length} nodes · {Object.keys(child.links).length} links\n </span>\n </div>\n )}\n {tier === 'live' &&\n child &&\n bounds && (\n // The nested layer is read-only: only the root scene receives handlers.\n // Pulled out by the frame's border, so the child's origin is the node's corner as\n // `portalTransform` and `enterPortal` assume; inside the padding box it sat a border in and\n // the scene jumped by that at the drill-in swap. The width is the frame's own (`FRAME_BORDER`),\n // since a fading frame trades its border for padding.\n <div\n className='absolute pointer-events-none'\n style={{\n top: `calc(-1 * var(${FRAME_BORDER}, 2px))`,\n left: `calc(-1 * var(${FRAME_BORDER}, 2px))`,\n transform: portalTransform(node, bounds),\n transformOrigin: '0 0',\n }}\n >\n <SceneLayer\n store={store}\n scene={child}\n registry={registry}\n zoom={zoom * portalScale(node, bounds)}\n depth={depth + 1}\n liveDepth={liveDepth}\n />\n </div>\n )}\n {/* The preview centres the title already; the live scene fills the frame, so it names it in the corner. */}\n {!opening && tier === 'live' && (\n <span className='absolute top-1 left-2 text-xs text-fg-subtle pointer-events-none'>{title}</span>\n )}\n {!opening && onOpen && <OpenControl onOpen={onOpen} />}\n </div>\n );\n};\n\nexport type OpenControlProps = { label?: string; onOpen: () => void };\n\n/** The open control at a frame's top-right; it takes the press, so it neither drags nor selects the node. */\nexport const OpenControl = ({ label = 'Open scene', onOpen }: OpenControlProps) => (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrows-out--regular'\n label={label}\n classNames='absolute top-1 right-1'\n data-testid='portal-open'\n onPointerDown={(event) => event.stopPropagation()}\n onDoubleClick={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n onOpen();\n }}\n />\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Node and link type definitions (decision 12): what a type's schema is, what it renders, where its\n// ports are, how it may be manipulated, and how the palette presents it. Per type, not per instance, so\n// the data stays small and ports come for free; a node may still carry its own `ports`. A host composes\n// its own registry (and with `createSceneSchema` its scene schema) from the built-ins and its types.\n//\n// A type may be built on a prototype (`extends`): it inherits every definition field it leaves unset, so\n// shapes that look and behave alike share one definition and differ only where they say so. Prototypes\n// are resolved once, when the registry is created, so a lookup is still one record read.\n//\n\nimport type * as Schema from 'effect/Schema';\nimport { type ComponentType } from 'react';\n\nimport { type FormFieldMap } from '@dxos/react-ui-form';\n\nimport { BoxNodeView, EllipseNodeView, FrameNodeView, NoteNodeView } from '../components/SceneLayer/SceneLayer.tsx';\nimport { type PartEditing, type PartField } from '../utils/parts.ts';\nimport { NOMINAL_SIZES, createNode } from '../utils/shapes.ts';\nimport { type SceneStore } from './store.ts';\nimport {\n EllipseNode,\n FrameNode,\n type LinkType,\n type Node,\n type NodeBase,\n type NodeType,\n NoteNode,\n type Point,\n type Port,\n RectNode,\n type Scene,\n type Size,\n} from './types.ts';\n\nexport type NodeViewProps = {\n node: Node;\n scene: Scene;\n store: SceneStore;\n registry: NodeRegistry;\n /** Effective screen zoom of the layer (camera zoom × portal scales), for level-of-detail choices. */\n zoom: number;\n /** Nesting depth of the layer; 0 is the root. */\n depth: number;\n /** Nested levels below the root that may mount live (decision 10). */\n liveDepth: number;\n selected: boolean;\n /** The view is being zoomed into: a portal shows its child plainly, as the child will look once entered. */\n opening?: boolean;\n /** The text part of this node being edited in place, with the editor's callbacks. */\n editing?: PartEditing;\n /** The node's embedded content takes input (`SceneViewAtoms.active`); otherwise it should be inert. */\n active?: boolean;\n /** Opens the node (drills into a portal); absent where the layer is read-only. */\n onOpen?: () => void;\n};\n\nexport type CreateProps = { id: string; z: string; center: Point; size: Size };\n\nexport type NodeDef = {\n type: NodeType;\n name: string;\n icon: string;\n /** Palette shortcut; a registry of many types leaves most without one. */\n key?: string;\n /** Palette group; types without one share the default group. */\n group?: string;\n /** The type's schema; the host's scene schema is the union of its registry's (`createSceneSchema`). */\n schema: Schema.Codec<NodeBase, unknown>;\n component: ComponentType<NodeViewProps>;\n /** A new node of the type with its default content, for the palette tool and drop-on-canvas. */\n create: (props: CreateProps) => Node;\n /** Size when created, in nominal units: one unit is the drawing's major grid cell. */\n defaultSize: Size;\n /** Explicit port layout; absent, the type gets `portsPerSide` ports spread along each side. */\n ports?: (node: Node) => readonly Port[];\n /** Defaults to `DEFAULT_PORTS_PER_SIDE`. */\n portsPerSide?: number;\n resizable?: boolean;\n minSize?: Size;\n maxSize?: Size;\n /** Double-click opens the node (a frame drills in; a text node edits, later). */\n openable?: boolean;\n /**\n * The host's own way to open this node, when it has one (a frame showing an object rather than a scene):\n * opening calls it instead of drilling in, and auto-drill passes the node by.\n */\n hostOpen?: (node: Node) => (() => void) | undefined;\n /**\n * Controls floating above the node, flush with its right edge and at screen size, so they neither cover the node's\n * content nor scale with the camera; renders nothing when it returns `null`.\n */\n toolbar?: ComponentType<NodeViewProps>;\n /** The text properties edited in place, in order; the first is the node's main text. */\n parts?: readonly PartField[];\n /** Properties-panel renderers for this type's fields, by path (e.g. a list as lines). */\n fields?: FormFieldMap;\n};\n\n/**\n * A node type as declared: a `NodeDef` whose fields may be left to its prototype. A prototype (a spec in\n * `prototypes`) is never a type of its own: it is not in the registry, the palette or the scene schema.\n */\nexport type NodeDefSpec = Partial<Omit<NodeDef, 'type'>> & {\n /** The prototype this type inherits unset fields from. */\n extends?: string;\n};\n\n/**\n * A registry from type specs and the prototypes they extend: each type takes its own fields over its\n * prototype's, recursively. Throws when a type names a missing prototype, a cycle, or ends up without a\n * field every type needs.\n */\nexport const createNodeRegistry = (\n types: Readonly<Record<NodeType, NodeDefSpec>>,\n prototypes: Readonly<Record<string, NodeDefSpec>> = {},\n): NodeRegistry => {\n const inherit = (spec: NodeDefSpec, chain: readonly string[]): NodeDefSpec => {\n if (spec.extends === undefined) {\n return spec;\n }\n if (chain.includes(spec.extends)) {\n throw new Error(`Node prototype cycle: ${[...chain, spec.extends].join(' -> ')}`);\n }\n const prototype = prototypes[spec.extends];\n if (!prototype) {\n throw new Error(`Unknown node prototype: ${spec.extends}`);\n }\n const { extends: _, ...own } = spec;\n return { ...inherit(prototype, [...chain, spec.extends]), ...own };\n };\n return Object.fromEntries(\n Object.entries(types).map(([type, spec]) => {\n const { extends: _, ...resolved } = inherit(spec, [type]);\n const { name, icon, schema, component, create, defaultSize } = resolved;\n if (!name || !icon || !schema || !component || !create || !defaultSize) {\n throw new Error(`Node type ${type} is missing a required field`);\n }\n const def: NodeDef = { ...resolved, type, name, icon, schema, component, create, defaultSize };\n return [type, def];\n }),\n );\n};\n\nexport type LinkDef = {\n type: LinkType;\n name: string;\n icon: string;\n key: string;\n};\n\nexport type NodeRegistry = Readonly<Record<NodeType, NodeDef>>;\nexport type LinkRegistry = Readonly<Record<LinkType, LinkDef>>;\n\nconst MIN_SIZE: Size = { width: 64, height: 32 };\n\n/**\n * A framed shape with a centred, editable label: resizable, with ports spread along every side. The\n * built-in rectangle and frame are both boxes; a host type can extend it too.\n */\nexport const boxPrototype: NodeDefSpec = {\n component: BoxNodeView,\n parts: [{ field: 'label' }],\n defaultSize: NOMINAL_SIZES.rect,\n resizable: true,\n minSize: MIN_SIZE,\n};\n\nexport const defaultNodePrototypes: Readonly<Record<string, NodeDefSpec>> = { box: boxPrototype };\n\nexport const defaultNodeTypes: Readonly<Record<NodeType, NodeDefSpec>> = {\n rect: {\n extends: 'box',\n name: 'Rectangle',\n icon: 'ph--rectangle--regular',\n key: 'R',\n schema: RectNode,\n create: (props) => createNode({ type: 'rect', ...props }),\n },\n ellipse: {\n name: 'Ellipse',\n icon: 'ph--circle--regular',\n key: 'E',\n schema: EllipseNode,\n component: EllipseNodeView,\n create: (props) => createNode({ type: 'ellipse', ...props }),\n defaultSize: NOMINAL_SIZES.ellipse,\n // Only the side centres of the frame lie on the curve.\n portsPerSide: 1,\n parts: [{ field: 'label' }],\n resizable: true,\n minSize: MIN_SIZE,\n },\n\n note: {\n name: 'Note',\n icon: 'ph--text-t--regular',\n key: 'T',\n schema: NoteNode,\n component: NoteNodeView,\n parts: [{ field: 'text', multiline: true }],\n create: (props) => createNode({ type: 'note', ...props }),\n defaultSize: NOMINAL_SIZES.note,\n resizable: true,\n minSize: MIN_SIZE,\n },\n frame: {\n extends: 'box',\n name: 'Frame',\n icon: 'ph--frame-corners--regular',\n key: 'F',\n schema: FrameNode,\n component: FrameNodeView,\n create: (props) => createNode({ type: 'frame', ...props }),\n defaultSize: NOMINAL_SIZES.frame,\n minSize: { width: 96, height: 60 },\n openable: true,\n },\n};\n\nexport const defaultNodeRegistry: NodeRegistry = createNodeRegistry(defaultNodeTypes, defaultNodePrototypes);\n\nexport const defaultLinkRegistry: LinkRegistry = {\n line: { type: 'line', name: 'Line', icon: 'ph--line-segment--regular', key: 'L' },\n curve: { type: 'curve', name: 'Curve', icon: 'ph--bezier-curve--regular', key: 'K' },\n spline: { type: 'spline', name: 'Spline', icon: 'ph--wave-sine--regular', key: 'P' },\n smart: { type: 'smart', name: 'Smart line', icon: 'ph--flow-arrow--regular', key: 'O' },\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Editing several elements in one form: the properties every selected type declares alike, the values\n// they share (and the paths they disagree on), and the patch an edit makes to each element.\n//\n\nimport * as Schema from 'effect/Schema';\nimport * as SchemaAST from 'effect/SchemaAST';\n\nimport { getChecks, getPropertySignatures } from '@dxos/effect/SchemaAST';\n\ntype Values = Readonly<Record<string, unknown>>;\n\n/** A record of fields to merge into; an instance (an ECHO `Ref`, a date) is a value, compared and kept whole. */\nconst isPlainObject = (value: unknown): value is Values => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n return prototype === Object.prototype || prototype === null;\n};\n\nconst isOptional = (ast: SchemaAST.AST) => ast.context?.isOptional ?? false;\n\n/** A check as comparable data: the filter and its payload (`isBetween` with its bounds), if it declares them. */\nconst checkKey = (check: SchemaAST.Check<any>): string | undefined => {\n const representation = check.annotations?.representation;\n return representation === undefined ? undefined : JSON.stringify(representation);\n};\n\n/** Whether two types carry the same checks, so a value one accepts the other does too. */\nconst sameChecks = (left: SchemaAST.AST, right: SchemaAST.AST): boolean => {\n const [leftChecks, rightChecks] = [getChecks(left), getChecks(right)];\n // A check that declares no representation cannot be compared, so only the same check matches it.\n const same = (check: SchemaAST.Check<any>, other: SchemaAST.Check<any>) => {\n const key = checkKey(check);\n return check === other || (key !== undefined && key === checkKey(other));\n };\n return (\n leftChecks.length === rightChecks.length && leftChecks.every((check, index) => same(check, rightChecks[index]))\n );\n};\n\n/**\n * Whether two property types describe the same values, so one field can edit both. Separately declared\n * types compare by structure and by their checks: `locked` on a node and on a link is the same optional\n * boolean, but numbers bounded differently are not, since the form validates against only one of them.\n */\nexport const sameType = (left: SchemaAST.AST, right: SchemaAST.AST): boolean => {\n if (left === right) {\n return true;\n }\n if (left._tag !== right._tag || isOptional(left) !== isOptional(right) || !sameChecks(left, right)) {\n return false;\n }\n if (left._tag === 'Literal' && right._tag === 'Literal') {\n return left.literal === right.literal;\n }\n if (left._tag === 'Union' && right._tag === 'Union') {\n return sameList(left.types, right.types);\n }\n if (left._tag === 'Arrays' && right._tag === 'Arrays') {\n return sameList(left.elements, right.elements) && sameList(left.rest, right.rest);\n }\n if (left._tag === 'Objects' && right._tag === 'Objects') {\n const others = new Map(right.propertySignatures.map((property) => [property.name, property.type]));\n return (\n left.propertySignatures.length === right.propertySignatures.length &&\n left.propertySignatures.every((property) => {\n const other = others.get(property.name);\n return other !== undefined && sameType(property.type, other);\n })\n );\n }\n return true;\n};\n\nconst sameList = (left: readonly SchemaAST.AST[], right: readonly SchemaAST.AST[]) =>\n left.length === right.length && left.every((type, index) => sameType(type, right[index]));\n\n/**\n * What two property types share: the type itself when they are the same, and for two structs (a node's style and a\n * link's, say) the struct of the fields they declare alike, recursively; none when they share nothing.\n */\nconst commonType = (left: SchemaAST.AST, right: SchemaAST.AST): SchemaAST.AST | undefined => {\n if (sameType(left, right)) {\n return left;\n }\n // An optional struct is a union with `undefined`: intersect member by member.\n if (left._tag === 'Union' && right._tag === 'Union' && left.types.length === right.types.length) {\n const types = left.types.map((type, index) => commonType(type, right.types[index]));\n return types.every((type) => type !== undefined)\n ? new SchemaAST.Union(\n types.flatMap((type) => (type ? [type] : [])),\n left.options,\n left.annotations,\n left.checks,\n left.encoding,\n left.context,\n left.encodingChecks,\n )\n : undefined;\n }\n if (left._tag !== 'Objects' || right._tag !== 'Objects' || isOptional(left) !== isOptional(right)) {\n return undefined;\n }\n const shared = left.propertySignatures.flatMap((property) => {\n const other = right.propertySignatures.find((candidate) => candidate.name === property.name);\n const type = other && commonType(property.type, other.type);\n return type ? [new SchemaAST.PropertySignature(property.name, type)] : [];\n });\n return shared.length > 0\n ? new SchemaAST.Objects(\n shared,\n left.indexSignatures,\n left.annotations,\n left.checks,\n left.encoding,\n left.context,\n left.encodingChecks,\n )\n : undefined;\n};\n\n/**\n * The properties every schema declares alike, as one struct over the first schema's declarations, a struct\n * property narrowed to the fields every schema's declares alike; `undefined` when they share none. One schema is\n * its own common schema.\n */\nexport const commonSchema = (schemas: readonly Schema.Codec<any, any>[]): Schema.Codec<any, any> | undefined => {\n const [first, ...rest] = schemas;\n if (!first) {\n return undefined;\n }\n const shared = getPropertySignatures(first.ast).flatMap((property) => {\n let type: SchemaAST.AST | undefined = property.type;\n for (const schema of rest) {\n const other = getPropertySignatures(schema.ast).find((candidate) => candidate.name === property.name);\n type = type && other ? commonType(type, other.type) : undefined;\n }\n return type ? [new SchemaAST.PropertySignature(property.name, type)] : [];\n });\n return shared.length > 0 ? Schema.make<Schema.Codec<any, any>>(new SchemaAST.Objects(shared, [])) : undefined;\n};\n\nconst equal = (left: unknown, right: unknown): boolean => {\n if (left === right) {\n return true;\n }\n if (Array.isArray(left) && Array.isArray(right)) {\n return left.length === right.length && left.every((value, index) => equal(value, right[index]));\n }\n if (isPlainObject(left) && isPlainObject(right)) {\n const keys = new Set([...Object.keys(left), ...Object.keys(right)]);\n return [...keys].every((key) => equal(left[key], right[key]));\n }\n return false;\n};\n\nexport type MergedValues = {\n /** The shared value at every path; where the objects disagree, the first object's, so the form still validates. */\n values: Values;\n /** Json-paths (`style.hue`) whose value differs between the objects. */\n mixed: Set<string>;\n};\n\n/** Merges the objects' `keys` for one form, descending into nested objects so a struct is mixed field by field. */\nexport const mergeValues = (objects: readonly Values[], keys: readonly PropertyKey[]): MergedValues => {\n const mixed = new Set<string>();\n const merge = (sources: readonly Values[], names: readonly string[], prefix: string): Values =>\n Object.fromEntries(\n names.flatMap((name) => {\n const path = prefix ? `${prefix}.${name}` : name;\n const values = sources.map((source) => source[name]);\n if (values.every(isPlainObject)) {\n const nested = [...new Set(values.flatMap((value) => Object.keys(value)))];\n return [[name, merge(values, nested, path)]];\n }\n if (!values.every((value) => equal(value, values[0]))) {\n mixed.add(path);\n }\n const value = values.find((value) => value !== undefined);\n return value === undefined ? [] : [[name, value]];\n }),\n );\n const names = keys.filter((key): key is string => typeof key === 'string');\n return { values: merge(objects, names, ''), mixed };\n};\n\nconst getIn = (value: unknown, path: readonly string[]): unknown =>\n path.reduce<unknown>((current, key) => (isPlainObject(current) ? current[key] : undefined), value);\n\nconst setIn = (value: unknown, path: readonly string[], next: unknown): unknown => {\n const [head, ...rest] = path;\n if (head === undefined) {\n return next;\n }\n const current = isPlainObject(value) ? value : {};\n return { ...current, [head]: setIn(current[head], rest, next) };\n};\n\n/**\n * The top-level values an edit writes to one element: each changed json-path set to the form's value,\n * leaving the element's other nested fields (the rest of its `style`) as they were.\n */\nexport const patchValues = (element: Values, values: Values, paths: readonly string[]): Record<string, unknown> => {\n const patch: Record<string, unknown> = {};\n for (const path of paths) {\n const [head, ...rest] = path.split('.');\n patch[head] = setIn(head in patch ? patch[head] : element[head], rest, getIn(values, path.split('.')));\n }\n return patch;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport type * as SchemaAST from 'effect/SchemaAST';\nimport React from 'react';\n\nimport { Form, type FormFieldRenderer, useFormFieldState } from '@dxos/react-ui-form';\nimport * as Layout from '@dxos/react-ui/Layout';\nimport * as ToggleGroup from '@dxos/react-ui/ToggleGroup';\n\nimport { type HorizontalAlign, NodeStyle, type VerticalAlign } from '../../model/types.ts';\n\nexport type IconToggleOption<T extends string> = { value: T; icon: string; label: string };\n\nexport type IconToggleProps<T extends string> = {\n label: string;\n options: readonly IconToggleOption<T>[];\n value?: T;\n readonly?: boolean;\n onValueChange: (value: T) => void;\n};\n\n/** One choice of a few, each an icon: a single-select toggle group whose pressed item is the value. */\nexport const IconToggle = <T extends string>({\n label,\n options,\n value,\n readonly,\n onValueChange,\n}: IconToggleProps<T>) => (\n <ToggleGroup.Root\n type='single'\n value={value ?? ''}\n aria-label={label}\n onValueChange={(next) => {\n // Pressing the pressed item releases it in the group; the value stays what it was.\n const option = options.find((candidate) => candidate.value === next);\n if (option) {\n onValueChange(option.value);\n }\n }}\n >\n {options.map((option) => (\n <ToggleGroup.Item\n key={option.value}\n value={option.value}\n variant='ghost'\n icon={option.icon}\n iconOnly\n label={option.label}\n disabled={readonly}\n data-testid={`align-${option.value}`}\n />\n ))}\n </ToggleGroup.Root>\n);\n\nconst HORIZONTAL: readonly IconToggleOption<HorizontalAlign>[] = [\n { value: 'left', icon: 'ph--align-left-simple--regular', label: 'Align left' },\n { value: 'center', icon: 'ph--align-center-vertical-simple--regular', label: 'Align centre' },\n { value: 'right', icon: 'ph--align-right-simple--regular', label: 'Align right' },\n];\n\nconst VERTICAL: readonly IconToggleOption<VerticalAlign>[] = [\n { value: 'top', icon: 'ph--align-top-simple--regular', label: 'Align top' },\n { value: 'middle', icon: 'ph--align-center-horizontal-simple--regular', label: 'Align middle' },\n { value: 'bottom', icon: 'ph--align-bottom-simple--regular', label: 'Align bottom' },\n];\n\n/**\n * The text alignment, rendered at `style.alignHorizontal`: the horizontal and vertical toggles side by side in one\n * row (`style.alignVertical` is hidden). Each writes only its own path, so an edit across a selection leaves each\n * element's other style values.\n */\nexport const AlignField: FormFieldRenderer = ({ jsonPath, readonly }) => {\n const stylePath = (jsonPath ?? 'style.alignHorizontal').split('.').slice(0, -1);\n const horizontalField = useFormFieldState('AlignField', [...stylePath, 'alignHorizontal']);\n const verticalField = useFormFieldState('AlignField', [...stylePath, 'alignVertical']);\n const horizontal = HORIZONTAL.find((option) => option.value === horizontalField.getValue())?.value;\n const vertical = VERTICAL.find((option) => option.value === verticalField.getValue())?.value;\n // A pick is a commit: a toggle never blurs, so it commits itself.\n const pick = (field: typeof horizontalField, ast: SchemaAST.AST, value: string) => {\n field.onValueChange(ast, value);\n field.onBlur();\n };\n return (\n <Layout.Container\n layout='row'\n gutter='inherit'\n align='start'\n gap='md'\n columns='repeat(2, minmax(0, 1fr))'\n // The properties panel is narrow, and the two toggles fit side by side there, so the row never stacks.\n fixed\n >\n <Form.Field path={jsonPath} label='Horizontal' readonly={readonly}>\n <IconToggle\n label='Horizontal alignment'\n options={HORIZONTAL}\n value={horizontal}\n readonly={!!readonly}\n onValueChange={(next) => pick(horizontalField, NodeStyle.fields.alignHorizontal.ast, next)}\n />\n </Form.Field>\n <Form.Field path={[...stylePath, 'alignVertical'].join('.')} label='Vertical' readonly={readonly}>\n <IconToggle\n label='Vertical alignment'\n options={VERTICAL}\n value={vertical}\n readonly={!!readonly}\n onValueChange={(next) => pick(verticalField, NodeStyle.fields.alignVertical.ast, next)}\n />\n </Form.Field>\n </Layout.Container>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { createContext, useContext, useMemo } from 'react';\n\nimport { Form, type FormFieldRenderer, SelectControl } from '@dxos/react-ui-form';\n\nimport { type StyleMap } from '../../model/types.ts';\n\n/** The drawing's style classes, for the class field; unset when the host offers none, so the field is hidden. */\nexport const StyleClassesContext = createContext<StyleMap | undefined>(undefined);\n\n/** The select's value for no class: a select item needs a non-empty value. */\nconst NO_CLASS = '-';\n\n/** An element's style class: one of the drawing's, or none, leaving only its own style. */\nexport const ClassField: FormFieldRenderer = ({ type, label, jsonPath, readonly, getValue, onValueChange, onBlur }) => {\n const styles = useContext(StyleClassesContext);\n const items = useMemo(\n () => [\n { value: NO_CLASS, label: 'None' },\n ...Object.values(styles ?? {})\n .map((styleClass) => ({ value: styleClass.id, label: styleClass.name }))\n .sort((left, right) => left.label.localeCompare(right.label)),\n ],\n [styles],\n );\n const value: unknown = getValue();\n return (\n <Form.Field path={jsonPath} label={label} readonly={readonly}>\n <SelectControl\n items={items}\n value={typeof value === 'string' ? value : NO_CLASS}\n readonly={readonly}\n onValueChange={(next) => {\n // A choice is a commit: the select never blurs, so it commits itself.\n onValueChange(type, next === NO_CLASS ? undefined : next);\n onBlur();\n }}\n />\n </Form.Field>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { Form, type FormFieldRenderer, SelectControl, useFormFieldState } from '@dxos/react-ui-form';\nimport * as Input from '@dxos/react-ui/Input';\nimport * as Layout from '@dxos/react-ui/Layout';\n\nimport { FONT_FAMILIES, type FontFamily, NodeStyle } from '../../model/types.ts';\n\nconst FAMILY_LABELS: Record<FontFamily, string> = { default: 'Default', monospace: 'Monospace' };\n\nconst FAMILIES = FONT_FAMILIES.map((value) => ({ value, label: FAMILY_LABELS[value] }));\n\n/** The editor's readable range; stored sizes outside it are kept, not checked. */\nconst FONT_SIZE = { min: 8, max: 80, step: 1 };\n\n/**\n * The text face and size, rendered at `style.fontFamily`: the two side by side in one row (`style.fontSize` is\n * hidden). Each writes only its own path, so an edit across a selection leaves each element's other style values.\n */\nexport const FontField: FormFieldRenderer = ({ jsonPath, readonly }) => {\n const stylePath = (jsonPath ?? 'style.fontFamily').split('.').slice(0, -1);\n const familyField = useFormFieldState('FontField', [...stylePath, 'fontFamily']);\n const sizeField = useFormFieldState('FontField', [...stylePath, 'fontSize']);\n const family: unknown = familyField.getValue();\n const size: unknown = sizeField.getValue();\n return (\n <Layout.Container\n layout='row'\n gutter='inherit'\n align='start'\n gap='md'\n columns='repeat(2, minmax(0, 1fr))'\n // The properties panel is narrow, and the two controls fit side by side there, so the row never stacks.\n fixed\n >\n <Form.Field path={jsonPath} label='Font' readonly={readonly}>\n <SelectControl\n items={FAMILIES}\n value={typeof family === 'string' ? family : 'default'}\n readonly={readonly}\n onValueChange={(next) => {\n const fontFamily = FONT_FAMILIES.find((family) => family === next);\n // The body face is the default, so it is stored as unset; a pick never blurs, so it commits itself.\n familyField.onValueChange(\n NodeStyle.fields.fontFamily.ast,\n fontFamily === 'default' ? undefined : fontFamily,\n );\n familyField.onBlur();\n }}\n />\n </Form.Field>\n <Form.Field path={[...stylePath, 'fontSize'].join('.')} label='Font size' readonly={readonly}>\n <Input.Number\n disabled={!!readonly}\n {...FONT_SIZE}\n formatOptions={{ maximumFractionDigits: 0 }}\n value={typeof size === 'number' ? String(size) : ''}\n onValueChange={(_, fontSize) => {\n if (!Number.isNaN(fontSize)) {\n // A stepper press never blurs, so each value commits itself.\n sizeField.onValueChange(NodeStyle.fields.fontSize.ast, fontSize);\n sizeField.onBlur();\n }\n }}\n />\n </Form.Field>\n </Layout.Container>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\nimport React, { createContext, useContext, useMemo } from 'react';\n\nimport { Form, type FormFieldRenderer, SelectControl, useFormFieldState } from '@dxos/react-ui-form';\nimport * as Layout from '@dxos/react-ui/Layout';\n\nimport { type Layer } from '../../model/types.ts';\nimport { ClassField, StyleClassesContext } from './ClassField.tsx';\n\n/** The scene's layers, bottom first, for the layer field. */\nexport const LayersContext = createContext<readonly Layer[]>([]);\n\n/** The layer an element is on: one of the scene's, listed top first as they stack. */\nexport const LayerField: FormFieldRenderer = ({ type, label, jsonPath, readonly, getValue, onValueChange, onBlur }) => {\n const layers = useContext(LayersContext);\n const items = useMemo(() => [...layers].reverse().map((layer) => ({ value: layer.id, label: layer.name })), [layers]);\n const value: unknown = getValue();\n return (\n <Form.Field path={jsonPath} label={label} readonly={readonly}>\n <SelectControl\n items={items}\n value={typeof value === 'string' ? value : undefined}\n readonly={readonly}\n onValueChange={(next) => {\n // A choice is a commit: the select never blurs, so it commits itself.\n onValueChange(type, next);\n onBlur();\n }}\n />\n </Form.Field>\n );\n};\n\n/**\n * The layer and the style class side by side in one row, rendered at `layer` (`class` is hidden); the class select\n * only while the host offers classes.\n */\nexport const LayerClassField: FormFieldRenderer = (props) => {\n const styles = useContext(StyleClassesContext);\n const classField = useFormFieldState('LayerClassField', ['class']);\n return (\n <Layout.Container\n layout='row'\n gutter='inherit'\n align='start'\n gap='md'\n columns='repeat(2, minmax(0, 1fr))'\n // The properties panel is narrow, and the two selects fit side by side there, so the row never stacks.\n fixed\n >\n <LayerField {...props} />\n {styles && (\n <ClassField {...classField} type={Schema.String.ast} label='Class' jsonPath='class' readonly={props.readonly} />\n )}\n </Layout.Container>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { createContext, useContext } from 'react';\n\nimport { Form, type FormFieldRenderer, SelectField } from '@dxos/react-ui-form';\n\nimport { type SceneOption } from '../../utils/scenes.ts';\n\n/** The scenes a selected scene shape may open, as the panel's host lists them (`sceneOptions`). */\nexport const SceneOptionsContext = createContext<readonly SceneOption[]>([]);\n\n/** A scene shape's `scene`: which scene of this drawing it opens, so several shapes may open one scene. */\nexport const SceneField: FormFieldRenderer = (props) => {\n const options = useContext(SceneOptionsContext);\n return (\n <Form.Field path={props.jsonPath} label={props.label} readonly={props.readonly}>\n <SelectField {...props} options={[...options]} />\n </Form.Field>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { Form, type FormFieldRenderer, useFormFieldState } from '@dxos/react-ui-form';\nimport * as ToggleGroup from '@dxos/react-ui/ToggleGroup';\nimport { mx } from '@dxos/ui-theme';\n\nimport { NodeStyle, type NodeTone, STYLE_HUES, type StyleHue } from '../../model/types.ts';\nimport { DEFAULT_TONE, TONE_NAMES, TONES, hueClasses } from '../../utils/style.ts';\n\nexport type StyleChoice = { hue: StyleHue; tone: NodeTone };\n\nconst SEPARATOR = ':';\n\nconst choiceKey = ({ hue, tone }: StyleChoice) => `${hue}${SEPARATOR}${tone}`;\n\nconst parseChoice = (key: string): StyleChoice | undefined => {\n const [hue, tone] = key.split(SEPARATOR);\n const styleHue = STYLE_HUES.find((candidate) => candidate === hue);\n const nodeTone = TONES.find((candidate) => String(candidate) === tone);\n return styleHue !== undefined && nodeTone !== undefined ? { hue: styleHue, tone: nodeTone } : undefined;\n};\n\nconst capitalize = (text: string) => text.charAt(0).toUpperCase() + text.slice(1);\n\n/** The pressed item keeps the panel's background; the selection is drawn around the swatch instead. */\nconst ITEM_CLASSES = 'min-w-0 px-0 aria-checked:bg-transparent aria-checked:hover:bg-hover-surface';\n\nexport type StyleGridProps = {\n hue?: string;\n /** Unset is the default tone, as the frame draws it. */\n tone?: NodeTone;\n /** Several nodes disagree: no swatch is selected until one is picked. */\n indeterminate?: boolean;\n readonly?: boolean;\n /** The rows offered; all tones by default, or one row (e.g. a line's outline colour only). */\n tones?: readonly NodeTone[];\n onValueChange: (choice: StyleChoice) => void;\n};\n\n/**\n * Each offered hue in a column and its tones down the rows, every swatch drawn with the classes the node\n * itself would take, so a pick is a preview. A hue the grid does not offer, or none, selects nothing.\n */\nexport const StyleGrid = ({\n hue,\n tone = DEFAULT_TONE,\n indeterminate,\n readonly,\n tones = TONES,\n onValueChange,\n}: StyleGridProps) => {\n const selected = indeterminate || !hue ? '' : `${hue}${SEPARATOR}${tone}`;\n return (\n <ToggleGroup.Root\n type='single'\n classNames='grid grid-cols-9 gap-1'\n value={selected}\n aria-label='Style'\n data-testid='style-grid'\n onValueChange={(next) => {\n // Pressing the selected swatch again deselects it in the group; the style keeps its value.\n const choice = parseChoice(next);\n if (choice) {\n onValueChange(choice);\n }\n }}\n >\n {tones.flatMap((rowTone) =>\n STYLE_HUES.map((columnHue) => {\n const key = choiceKey({ hue: columnHue, tone: rowTone });\n const classes = hueClasses(columnHue, rowTone);\n return (\n <ToggleGroup.Item\n key={key}\n value={key}\n variant='ghost'\n classNames={ITEM_CLASSES}\n disabled={readonly}\n data-style-option={key}\n >\n <span\n role='img'\n aria-label={`${capitalize(columnHue)}, ${TONE_NAMES[rowTone]}`}\n className={mx(\n 'size-5 rounded-xs border-2',\n classes.surface,\n classes.border,\n selected === key && 'outline-2 outline-offset-2 outline-primary-500',\n )}\n />\n </ToggleGroup.Item>\n );\n }),\n )}\n </ToggleGroup.Root>\n );\n};\n\n/** The outline row alone: a link takes a hue but no fill, so its colour is the hue's border. */\nconst OUTLINE_TONES: readonly NodeTone[] = [0];\n\nexport type StyleFieldOptions = {\n /** Offer the fill rows (tones 1–3) as well as the outline; a link, or a selection with one, has no fill. */\n fills: boolean;\n};\n\n/**\n * The properties panel's style picker, rendered at `style.hue`, for every kind of element: with `fills`, one pick\n * sets the hue and its tone together (a node); without, the outline row sets the hue alone (a link, or a\n * selection mixing kinds, which edits only the style they share).\n */\nexport const createStyleField = ({ fills }: StyleFieldOptions): FormFieldRenderer => {\n const StyleField: FormFieldRenderer = ({ label, jsonPath, readonly, indeterminate, getValue, onBlur }) => {\n // Hue and tone change together, so the pick writes their parent once; two field writes would race.\n const stylePath = (jsonPath ?? 'style.hue').split('.').slice(0, -1);\n const styleField = useFormFieldState('StyleField', stylePath);\n const style: NodeStyle = styleField.getValue() ?? {};\n return (\n <Form.Field path={jsonPath} label={label} readonly={readonly}>\n <StyleGrid\n hue={getValue()}\n tone={fills ? style.tone : 0}\n tones={fills ? TONES : OUTLINE_TONES}\n indeterminate={indeterminate}\n readonly={!!readonly}\n onValueChange={({ hue, tone }) => {\n // A pick is a commit: the grid never blurs, so it commits itself.\n styleField.onValueChange(NodeStyle.ast, fills ? { ...style, hue, tone } : { ...style, hue });\n onBlur();\n }}\n />\n </Form.Field>\n );\n };\n return StyleField;\n};\n\n/** The style picker with its fill rows: a node's, or a selection of nodes. */\nexport const StyleGridField = createStyleField({ fills: true });\n\n/** The style picker's outline row alone: a link's, or a selection with a link in it. */\nexport const OutlineStyleField = createStyleField({ fills: false });\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Property panel for the selection: a schema-driven form over the properties every selected element\n// declares alike (one element: its whole schema; a node's from its registry definition), so every field\n// a type has is editable without a per-type form. Values the elements disagree on show as mixed; an edit\n// writes only the changed fields, to every element, as one batch of `update` intents.\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport type * as Atom from 'effect/reactivity/Atom';\nimport type * as Schema from 'effect/Schema';\nimport React, { useCallback, useMemo } from 'react';\n\nimport { type Database } from '@dxos/echo';\nimport {\n Form,\n type FormFieldMap,\n type FormFieldOverride,\n type FormFieldRenderer,\n type FormUpdateMeta,\n type RefFieldDataProps,\n} from '@dxos/react-ui-form';\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Input from '@dxos/react-ui/Input';\nimport * as Panel from '@dxos/react-ui/Panel';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport type * as Util from '@dxos/react-ui/Util';\n\nimport { useRegistry } from '../../hooks/index.ts';\nimport { SCENE_OVERLAY_ATTRIBUTE } from '../../hooks/useWheel.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type NodeRegistry, defaultNodeRegistry } from '../../model/registry.ts';\nimport { NO_STYLES } from '../../model/store.ts';\nimport {\n BaseNode,\n CurveLink,\n type Element,\n type Layer,\n LineLink,\n type LinkType,\n type Node,\n type NodeStyle,\n SmartLink,\n SplineLink,\n type StyleClass,\n type StyleMap,\n getElement,\n isFrameNode,\n isLink,\n isNoteNode,\n showsContents,\n} from '../../model/types.ts';\nimport { elementLayer, sceneLayers } from '../../utils/layers.ts';\nimport { MAX_PORTS_PER_SIDE, portsPerSideOf } from '../../utils/ports.ts';\nimport { commonSchema, mergeValues, patchValues } from '../../utils/properties.ts';\nimport { type SceneOption } from '../../utils/scenes.ts';\nimport { flipLink } from '../../utils/shapes.ts';\nimport { classedLink, classedNode, resolveStyle, splitClassEdit } from '../../utils/style.ts';\nimport { AlignField } from './AlignField.tsx';\nimport { StyleClassesContext } from './ClassField.tsx';\nimport { FontField } from './FontField.tsx';\nimport { LayerClassField, LayersContext } from './LayerField.tsx';\nimport { SceneField, SceneOptionsContext } from './SceneField.tsx';\nimport { OutlineStyleField, StyleGridField } from './StyleGrid.tsx';\n\n/** Identity, ordering and geometry lists are the surface's, not the user's. */\nconst HIDDEN = ['id', 'type', 'z', 'ports', 'points', 'source', 'target'];\n\n/**\n * A string list as one entry per line: a UML compartment reads as a block of text, so a textarea\n * beats the generic array field's row of inputs. Blank lines survive while typing (they round-trip\n * through split/join) and are dropped on blur, when the form saves.\n */\nexport const LinesField: FormFieldRenderer = ({ type, label, jsonPath, readonly, getValue, onValueChange, onBlur }) => {\n const lines: string[] = getValue() ?? [];\n return (\n <Form.Field path={jsonPath} label={label} readonly={readonly}>\n <Input.Textarea\n rows={4}\n classNames='font-mono'\n disabled={!!readonly}\n value={lines.join('\\n')}\n onChange={(event) => onValueChange(type, event.target.value.split('\\n'))}\n onBlur={(event) => {\n onValueChange(\n type,\n lines.map((line) => line.trim()).filter((line) => line.length > 0),\n );\n onBlur(event);\n }}\n />\n </Form.Field>\n );\n};\n\n/** Renderers by field path the panel always uses (the style grid); node types add their own (`NodeDef.fields`). */\nexport const DEFAULT_FIELDS: FormFieldMap = {\n 'style.hue': StyleGridField,\n 'style.alignHorizontal': AlignField,\n 'style.fontFamily': FontField,\n 'scene': SceneField,\n 'layer': LayerClassField,\n};\n\nconst LINK_SCHEMAS: Record<LinkType, Schema.Codec<any, any>> = {\n line: LineLink,\n curve: CurveLink,\n spline: SplineLink,\n smart: SmartLink,\n};\n\n/** An element's own schema; a type the registry does not know gets the core base's (`BaseNode`, or a line). */\nconst schemaOf = (nodes: NodeRegistry, element: Element): Schema.Codec<any, any> =>\n isLink(element) ? (LINK_SCHEMAS[element.type] ?? LineLink) : (nodeDef(nodes, element)?.schema ?? BaseNode);\n\n/** Where a type places its text unless styled otherwise: a note from the top left, a label in the middle. */\nconst textAlign = (node: Node): Pick<NodeStyle, 'alignHorizontal' | 'alignVertical'> =>\n isNoteNode(node)\n ? { alignHorizontal: 'left', alignVertical: 'top' }\n : { alignHorizontal: 'center', alignVertical: 'middle' };\n\n/**\n * What the form shows for an element: what the view draws, so its class's look, an unset fill, border or Show\n * contents read as they look and an unset port count as the type's.\n */\nconst formValues = (\n nodes: NodeRegistry,\n element: Element,\n styles: StyleMap,\n layers: readonly Layer[],\n): Record<string, unknown> =>\n isLink(element)\n ? { ...element, layer: elementLayer(element, layers), style: classedLink(element, styles).style }\n : {\n ...element,\n layer: elementLayer(element, layers),\n style: { ...textAlign(element), ...resolveStyle(classedNode(element, styles).style) },\n portsPerSide: portsPerSideOf(nodes, element),\n ...(isFrameNode(element) ? { contents: showsContents(element) } : {}),\n };\n\n/**\n * How the panel presents fields. Ranges are the editor's, not the model's: a check on the stored schema would\n * make a record outside them (an older or imported scene) fail validation and drop out of the scene. The style\n * grid at `style.hue` also sets `style.tone`, which has no field of its own.\n */\nconst FIELD_OVERRIDES: Record<string, FormFieldOverride> = {\n 'style.hue': { label: 'Style' },\n 'style.tone': { hidden: true },\n 'style.alignVertical': { hidden: true },\n 'style.fontSize': { hidden: true },\n 'portsPerSide': { min: 1, max: MAX_PORTS_PER_SIDE, step: 1 },\n 'scene': { label: 'Scene' },\n 'layer': { label: 'Layer' },\n};\n\nconst plural = (count: number, noun: string) => `${count} ${noun}${count === 1 ? '' : 's'}`;\n\n/** The selection by kind, e.g. \"3 nodes, 2 links\". */\nconst describeSelection = (elements: readonly Element[]) => {\n const links = elements.filter(isLink).length;\n const nodes = elements.length - links;\n return [nodes > 0 && plural(nodes, 'node'), links > 0 && plural(links, 'link')].filter(Boolean).join(', ');\n};\n\nexport type PropertiesProps = Util.ThemedClassName<{\n projection: Projection;\n atoms: SceneViewAtoms;\n nodes?: NodeRegistry;\n fields?: FormFieldMap;\n /** Show the fields without letting them change; also implied by a projection that cannot `update`. */\n readonly?: boolean;\n /** The database a reference field picks from; without it reference fields are read-only. */\n db?: Database.Database;\n /** Narrows a reference field's candidates (e.g. to objects of one kind). */\n getOptions?: RefFieldDataProps['getOptions'];\n /** A host's per-selection field overrides (e.g. a field it allows only in some states), over the panel's own. */\n overrides?: (elements: readonly Element[]) => Record<string, FormFieldOverride>;\n /** The scenes a scene shape may open (`sceneOptions`); without them its scene is not editable here. */\n sceneOptions?: readonly SceneOption[];\n /** The drawing's style classes (`SceneStore.styles`); without them elements take no class. */\n styles?: Atom.Writable<StyleMap>;\n /** Moves the selection into a new scene (`groupIntoScene`); offered for a selection of several elements. */\n onGroup?: () => void;\n /** Whether the panel is docked beside the canvas. */\n docked?: boolean;\n}>;\n\nexport const Properties = ({\n classNames,\n projection,\n atoms,\n nodes = defaultNodeRegistry,\n fields,\n readonly: readonlyProp = false,\n db,\n getOptions,\n overrides,\n sceneOptions,\n styles,\n onGroup,\n docked = false,\n}: PropertiesProps) => {\n const registry = useRegistry();\n const scene = useAtomValue(projection.scene);\n const selection = useAtomValue(atoms.selection);\n const elements = useMemo(() => [...selection].flatMap((id) => getElement(scene, id) ?? []), [scene, selection]);\n const readonly = readonlyProp || !projection.capabilities.update;\n const styleMap = useAtomValue(styles ?? NO_STYLES);\n const layers = useMemo(() => sceneLayers(scene), [scene]);\n\n // Keyed by the selected types, so the schema (and the form built on it) holds while values change under it.\n const typesKey = [...new Set(elements.map((element) => element.type))].sort().join();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const schema = useMemo(() => commonSchema(elements.map((element) => schemaOf(nodes, element))), [typesKey, nodes]);\n const { values, fieldOverrides } = useMemo(() => {\n const shown = elements.map((element) => formValues(nodes, element, styleMap, layers));\n const { values, mixed } = mergeValues(shown, Object.keys(shown[0] ?? {}));\n // A value the elements disagree on shows as indeterminate until it is edited, then applies to all of them.\n const fieldOverrides: Record<string, FormFieldOverride> = {\n ...FIELD_OVERRIDES,\n ...(sceneOptions ? {} : { scene: { hidden: true } }),\n // The class is edited in the layer's row (`LayerClassField`).\n class: { hidden: true },\n ...overrides?.(elements),\n };\n for (const path of mixed) {\n fieldOverrides[path] = { ...fieldOverrides[path], indeterminate: true };\n }\n return { values, fieldOverrides };\n }, [elements, nodes, overrides, sceneOptions, styles, styleMap, layers]);\n\n const onSave = useCallback(\n (values: Record<string, unknown>, { changed }: FormUpdateMeta<Record<string, unknown>>) => {\n const paths = Object.keys(changed).filter((path) => changed[path as keyof typeof changed]);\n // A classed element's look is its class's: an edit of it restyles the class, and so every element deriving it.\n const classes: Record<string, StyleClass> = {};\n const intents = elements.map((element) => {\n const shown = formValues(nodes, element, styleMap, layers);\n const patch = patchValues(shown, values, paths);\n const styleClass = styles && element.class ? (classes[element.class] ?? styleMap[element.class]) : undefined;\n // Taking a class drops the element's own look, so it derives the class's whole rather than in part.\n if (typeof patch.class === 'string') {\n return { kind: 'update' as const, id: element.id, values: { ...patch, style: undefined } };\n }\n if (!styleClass || !('style' in patch)) {\n return { kind: 'update' as const, id: element.id, values: patch };\n }\n // A link's look is the common base of its class's style; a node's, the whole of it.\n const look = isLink(element)\n ? classedLink(element, styleMap).style\n : resolveStyle(classedNode(element, styleMap).style);\n const split = splitClassEdit(look, patch.style, styleClass.style ?? {}, element.style);\n classes[styleClass.id] = { ...styleClass, style: split.classLook };\n return { kind: 'update' as const, id: element.id, values: { ...patch, style: split.own } };\n });\n if (styles && Object.keys(classes).length > 0) {\n registry.set(styles, { ...styleMap, ...classes });\n }\n projection.apply({ kind: 'batch', intents });\n },\n [projection, elements, nodes, styles, styleMap, layers, registry],\n );\n\n // A new class takes the selected element's look, and the element then follows it rather than carrying its own.\n const single = elements.length === 1 ? elements[0] : undefined;\n const onCreateClass = useCallback(() => {\n if (!styles || !single) {\n return;\n }\n const id = `class-${crypto.randomUUID()}`;\n const name = `Class ${Object.keys(styleMap).length + 1}`;\n const style = isLink(single) ? classedLink(single, styleMap).style : classedNode(single, styleMap).style;\n const styleClass: StyleClass = { id, name, ...(style ? { style } : {}) };\n registry.set(styles, { ...styleMap, [id]: styleClass });\n projection.apply({ kind: 'update', id: single.id, values: { class: id, style: undefined } });\n }, [styles, single, styleMap, registry, projection]);\n\n // Reverses every selected link (source and target swap; an arrow comes to point the other way), as one batch.\n const links = useMemo(() => elements.filter(isLink), [elements]);\n const onFlip = useCallback(() => {\n projection.apply({\n kind: 'batch',\n intents: links.map((link) => ({ kind: 'update' as const, id: link.id, values: flipLink(link) })),\n });\n // A spline's control points run the other way after a flip, so a selected point's index names another one.\n registry.set(atoms.point, undefined);\n }, [projection, links, registry, atoms.point]);\n\n // The selected node types' own renderers over the panel's; a host's `fields` win over both. One style picker for\n // every kind: its fill rows only when every element is a node, since a link has a colour but no fill.\n const fieldMap = useMemo(\n () => ({\n ...DEFAULT_FIELDS,\n ...(elements.some(isLink) ? { 'style.hue': OutlineStyleField } : {}),\n ...Object.assign(\n {},\n ...elements.map((element) => (isLink(element) ? {} : (nodeDef(nodes, element)?.fields ?? {}))),\n ),\n ...fields,\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [typesKey, nodes, fields],\n );\n\n if (elements.length === 0) {\n return (\n <Panel.Root classNames={classNames} data-testid='properties' {...{ [SCENE_OVERLAY_ATTRIBUTE]: true }}>\n <Panel.Body>\n <p className='p-2 text-sm text-fg-muted'>Select a node or link to edit its properties.</p>\n </Panel.Body>\n </Panel.Root>\n );\n }\n\n const summary = elements.length > 1 && `${describeSelection(elements)}${schema ? '' : ' — no shared properties'}`;\n return (\n <Panel.Root classNames={classNames} data-testid='properties' {...{ [SCENE_OVERLAY_ATTRIBUTE]: true }}>\n <Panel.Header asChild>\n <Toolbar.Root data-testid='properties-toolbar'>\n {onGroup && elements.length > 1 && elements.some((element) => !isLink(element)) && (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--frame-corners--regular'\n label='New scene from selection'\n disabled={readonly}\n data-testid='properties-group'\n onClick={onGroup}\n />\n )}\n {styles && single && (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--swatches--regular'\n label='New class from selection'\n disabled={readonly}\n data-testid='properties-new-class'\n onClick={onCreateClass}\n />\n )}\n {links.length > 0 && links.length === elements.length && (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrows-left-right--regular'\n label='Flip direction'\n disabled={readonly}\n data-testid='properties-flip'\n onClick={onFlip}\n />\n )}\n </Toolbar.Root>\n </Panel.Header>\n <Panel.Body>\n {schema && (\n <LayersContext.Provider value={layers}>\n <StyleClassesContext.Provider value={styles ? styleMap : undefined}>\n <SceneOptionsContext.Provider value={sceneOptions ?? []}>\n <Form.Root\n key={[...selection].join()}\n schema={schema}\n values={values}\n fieldOverrides={fieldOverrides}\n fieldMap={fieldMap}\n db={db}\n getOptions={getOptions}\n readonly={readonly}\n autoSave\n onSave={onSave}\n >\n {/* Floating, the panel is as tall as its host and a long form scrolls inside it; docked, the dock scrolls\n the panels together, so the form keeps no scroll of its own (it would hold the wheel). */}\n <Form.Viewport scroll={!docked}>\n <Form.Content>\n <Form.Fields exclude={HIDDEN} />\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n </SceneOptionsContext.Provider>\n </StyleClassesContext.Provider>\n </LayersContext.Provider>\n )}\n </Panel.Body>\n <Panel.Footer classNames='text-center'>\n <span className='text-sm text-fg-muted' data-testid='properties-summary'>\n {summary}\n </span>\n </Panel.Footer>\n </Panel.Root>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The editor's keyboard bindings in one table, so the view matches events against it and the toolbar\n// and palette print the same shortcuts it honours. Tool keys (R, E, L, ...) live on the registry entries\n// and are matched by the palette; everything else is here.\n//\n\n/** One chord: `key` as `KeyboardEvent.key` (letters lower-case), with the modifiers it needs. */\nexport type KeyBinding = {\n key: string;\n /** The platform command key: Meta on macOS, Control elsewhere; either satisfies it. */\n meta?: boolean;\n /** Required when set; ignored when absent, so a chord may be held with or without Shift. */\n shift?: boolean;\n alt?: boolean;\n};\n\nexport type KeyAction =\n | 'cancel'\n | 'delete'\n | 'open'\n | 'fit'\n | 'fitSelection'\n | 'zoomReset'\n | 'back'\n | 'forward'\n | 'nudge'\n | 'copy'\n | 'cut'\n | 'paste'\n | 'undo'\n | 'redo'\n | 'selectAll'\n | 'snap'\n | 'guides'\n | 'lattice'\n | 'debug';\n\n/** Every action's chords; the first is the one shown in labels. */\nexport const KEY_BINDINGS: Record<KeyAction, KeyBinding[]> = {\n cancel: [{ key: 'Escape' }],\n delete: [{ key: 'Delete' }, { key: 'Backspace' }],\n open: [{ key: 'Enter' }],\n fit: [{ key: 'Home' }, { key: '!', shift: true }],\n fitSelection: [{ key: '@', shift: true }],\n zoomReset: [{ key: ')', shift: true }],\n back: [{ key: 'ArrowLeft', alt: true }],\n forward: [{ key: 'ArrowRight', alt: true }],\n nudge: [{ key: 'ArrowUp' }, { key: 'ArrowDown' }, { key: 'ArrowLeft' }, { key: 'ArrowRight' }],\n copy: [{ key: 'c', meta: true }],\n cut: [{ key: 'x', meta: true }],\n paste: [{ key: 'v', meta: true }],\n undo: [{ key: 'z', meta: true, shift: false }],\n redo: [{ key: 'z', meta: true, shift: true }],\n selectAll: [{ key: 'a', meta: true }],\n // Not with Shift: Shift+G is the lattice toggle.\n snap: [{ key: 'g', shift: false }],\n guides: [{ key: ';' }],\n lattice: [{ key: 'G', shift: true }],\n debug: [{ key: 'd' }],\n};\n\n/** The subset of a keyboard event the bindings read, so tests and non-React callers can pass a literal. */\nexport type KeyEventLike = {\n key: string;\n metaKey: boolean;\n ctrlKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n};\n\n/** The command modifier, held: the same test on a pointer event reveals a node's ports for linking. */\nexport const hasCommandKey = (event: { metaKey: boolean; ctrlKey: boolean }): boolean => event.metaKey || event.ctrlKey;\n\nexport const matchesBinding = (event: KeyEventLike, binding: KeyBinding): boolean => {\n const key =\n binding.key.length === 1 ? event.key.toLowerCase() === binding.key.toLowerCase() : event.key === binding.key;\n return (\n key &&\n hasCommandKey(event) === (binding.meta ?? false) &&\n event.altKey === (binding.alt ?? false) &&\n (binding.shift === undefined || event.shiftKey === binding.shift)\n );\n};\n\n/** The action an event asks for, if any; a plain letter that binds no action is left to the tool palette. */\nexport const keyAction = (event: KeyEventLike): KeyAction | undefined => {\n for (const [action, bindings] of Object.entries(KEY_BINDINGS)) {\n if (bindings.some((binding) => matchesBinding(event, binding))) {\n return action as KeyAction;\n }\n }\n return undefined;\n};\n\n/** A key that reaches the tool palette: no command or option modifier, so typing a tool letter is unambiguous. */\nexport const isToolKey = (event: KeyEventLike): boolean => !hasCommandKey(event) && !event.altKey;\n\nconst IS_MAC = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform);\n\nconst KEY_GLYPHS: Record<string, string> = {\n ArrowUp: '↑',\n ArrowDown: '↓',\n ArrowLeft: '←',\n ArrowRight: '→',\n Escape: 'Esc',\n Backspace: '⌫',\n Delete: '⌦',\n Enter: '↩',\n Home: 'Home',\n};\n\n/** The chord as a label reads it: modifiers in the platform's order, then the key. */\nexport const shortcutLabel = (binding: KeyBinding): string => {\n const key = KEY_GLYPHS[binding.key] ?? binding.key.toUpperCase();\n const modifiers = [\n binding.alt ? (IS_MAC ? '⌥' : 'Alt+') : '',\n binding.shift ? (IS_MAC ? '⇧' : 'Shift+') : '',\n binding.meta ? (IS_MAC ? '⌘' : 'Ctrl+') : '',\n ].join('');\n return `${modifiers}${key}`;\n};\n\n/** The label for an action's first chord. */\nexport const shortcutFor = (action: KeyAction): string => shortcutLabel(KEY_BINDINGS[action][0]);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Cut, copy and paste as pure functions over the model (§8): the clipboard holds a fragment of nodes\n// and the links between them; a paste mints fresh ids, offsets the fragment and returns one `batch`\n// intent so the projection applies it atomically and undo takes it back in one step.\n//\n\nimport {\n type Bounds,\n type ElementId,\n type Endpoint,\n type Intent,\n type LayerId,\n type Link,\n type Node,\n type Point,\n type Scene,\n isPointEndpoint,\n} from '../model/types.ts';\nimport { unionBounds } from './hit.ts';\nimport { between, topZ } from './order.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport type Clipboard = {\n nodes: Node[];\n /** Links whose both ends are in `nodes`. */\n links: Link[];\n /** How many times this fragment has been pasted, so each paste lands one step further. */\n pasted: number;\n};\n\n/** The selected nodes and the links joining them; a link is copied whether or not it was selected. */\nexport const copySelection = (scene: Scene, selection: Iterable<ElementId>): Clipboard | undefined => {\n const ids = new Set(selection);\n const nodes = Object.values(scene.nodes).filter((node) => ids.has(node.id));\n const nodeIds = new Set(nodes.map(({ id }) => id));\n // A link comes along when every node end is in the fragment and at least one end is (a free end travels\n // with the node it is drawn to); a link with two free ends comes only when it is selected itself.\n const inFragment = (end: Endpoint) => isPointEndpoint(end) || nodeIds.has(end.node);\n const attached = (end: Endpoint) => !isPointEndpoint(end) && nodeIds.has(end.node);\n const links = Object.values(scene.links).filter(\n (link) =>\n inFragment(link.source) &&\n inFragment(link.target) &&\n (ids.has(link.id) || attached(link.source) || attached(link.target)),\n );\n return nodes.length > 0 ? { nodes, links, pasted: 0 } : undefined;\n};\n\nexport const clipboardBounds = (clipboard: Clipboard): Bounds | undefined =>\n unionBounds(clipboard.nodes.map(nodeBounds));\n\nexport type PasteOptions = {\n clipboard: Clipboard;\n /** Scene-space offset applied to every node and control point. */\n offset: Point;\n createId: (prefix: string) => string;\n /** Z keys for the pasted nodes and links, above the scene. */\n nodeZ: (index: number) => string;\n linkZ: (index: number) => string;\n /** The layer the pasted elements go on; unset, each keeps its own. */\n layer?: LayerId;\n};\n\nexport type Paste = { intent: Intent; ids: ElementId[] };\n\n/** The batch that recreates the fragment with fresh ids at `offset`, and the ids it will create. */\nexport const pasteFragment = ({ clipboard, offset, createId, nodeZ, linkZ, layer }: PasteOptions): Paste => {\n const idMap = new Map<ElementId, ElementId>();\n const shift = (point: Point): Point => ({ x: point.x + offset.x, y: point.y + offset.y });\n const onLayer = layer !== undefined ? { layer } : {};\n const nodes: Node[] = clipboard.nodes.map((node, index) => {\n const id = createId(node.type);\n idMap.set(node.id, id);\n // A pasted portal shares the child scene: two portals to one scene are Muse \"linked cards\" (§4).\n return { ...node, ...onLayer, id, z: nodeZ(index), center: shift(node.center) };\n });\n const links: Link[] = clipboard.links.map((link, index) => {\n const id = createId(link.type);\n idMap.set(link.id, id);\n const remap = (end: Endpoint): Endpoint =>\n isPointEndpoint(end) ? { point: shift(end.point) } : { ...end, node: idMap.get(end.node) ?? end.node };\n const ends = { source: remap(link.source), target: remap(link.target) };\n return link.type === 'spline'\n ? { ...link, ...onLayer, id, z: linkZ(index), ...ends, points: link.points.map(shift) }\n : { ...link, ...onLayer, id, z: linkZ(index), ...ends };\n });\n return {\n intent: {\n kind: 'batch',\n intents: [\n ...nodes.map((node): Intent => ({ kind: 'create', node })),\n ...links.map((link): Intent => ({ kind: 'link', link })),\n ],\n },\n ids: [...nodes.map(({ id }) => id), ...links.map(({ id }) => id)],\n };\n};\n\n/**\n * The batch that copies the selected nodes (and the links between them) `offset` away, above everything\n * else, and the ids it creates; nothing when the selection holds no node.\n */\nexport const duplicateSelection = (\n scene: Scene,\n selection: Iterable<ElementId>,\n offset: Point,\n createId: (prefix: string) => string,\n): Paste | undefined => {\n const clipboard = copySelection(scene, selection);\n if (!clipboard) {\n return undefined;\n }\n let nodeZ = topZ(Object.values(scene.nodes));\n let linkZ = topZ(Object.values(scene.links));\n return pasteFragment({\n clipboard,\n offset,\n createId,\n nodeZ: () => (nodeZ = between(nodeZ, undefined)),\n linkZ: () => (linkZ = between(linkZ, undefined)),\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport {\n type Element,\n type ElementId,\n type Endpoint,\n type FrameNode,\n type Intent,\n type LayerId,\n type Link,\n type Scene,\n endpointNode,\n} from '../model/types.ts';\nimport { unionBounds } from './hit.ts';\nimport { elementLayer, sceneLayers } from './layers.ts';\nimport { topZ } from './order.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** What grouping a selection makes: the new scene, and the intents that replace the selection with its shape. */\nexport type SceneGroup = { child: Scene; intents: Intent[] };\n\n/** `end` moved onto the scene shape when it was on a grouped node; a port of the old node means nothing there. */\nconst reattach = (end: Endpoint, inside: ReadonlySet<string>, portal: string): Endpoint => {\n const node = endpointNode(end);\n return node !== undefined && inside.has(node) ? { node: portal } : end;\n};\n\n/**\n * Moves the selected nodes into a new scene `id`, opened by a scene shape of the same id where they were. A link\n * between two grouped nodes moves with them; one crossing out of the group stays here, re-attached to the shape.\n * The nodes keep their coordinates: the shape frames whatever the child holds. None when no node is selected, or\n * when a selected node is locked. The shape goes on `layer`; the new scene has the layers its elements were on.\n */\nexport const groupIntoScene = (\n scene: Scene,\n ids: Iterable<ElementId>,\n id: string,\n layer?: LayerId,\n): SceneGroup | undefined => {\n const selected = new Set(ids);\n const nodes = Object.values(scene.nodes).filter((node) => selected.has(node.id));\n const bounds = unionBounds(nodes.map(nodeBounds));\n // A locked node may not leave its scene, so a selection holding one is not grouped at all.\n if (nodes.length === 0 || !bounds || nodes.some((node) => node.locked)) {\n return undefined;\n }\n\n const inside = new Set(nodes.map((node) => node.id));\n const isInside = (end: Endpoint) => {\n const node = endpointNode(end);\n return node === undefined || inside.has(node);\n };\n const touches = (link: Link) => [link.source, link.target].some((end) => inside.has(endpointNode(end) ?? ''));\n const links = Object.values(scene.links).filter(touches);\n // A link with both ends in the group (a free end counts as either side) goes with it; the rest cross out.\n const moved = links.filter((link) => isInside(link.source) && isInside(link.target));\n const crossing = links.filter((link) => !moved.includes(link));\n\n const portal: FrameNode = {\n type: 'frame',\n id,\n z: topZ(Object.values(scene.nodes)),\n center: { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 },\n size: { width: bounds.width, height: bounds.height },\n scene: id,\n ...(layer !== undefined ? { layer } : {}),\n };\n // Each element names the layer it resolved to here, and the new scene has those layers, in their order.\n const layers = sceneLayers(scene);\n const placed = <T extends Element>(element: T): T => ({ ...element, layer: elementLayer(element, layers) });\n const childNodes = nodes.map(placed);\n const childLinks = moved.map(placed);\n const used = new Set([...childNodes, ...childLinks].map((element) => element.layer));\n return {\n child: {\n id,\n nodes: Object.fromEntries(childNodes.map((node) => [node.id, node])),\n links: Object.fromEntries(childLinks.map((link) => [link.id, link])),\n layers: Object.fromEntries(layers.filter((entry) => used.has(entry.id)).map((entry) => [entry.id, entry])),\n },\n intents: [\n { kind: 'create', node: portal },\n // Re-attached before the nodes go, since deleting a node takes the links on it.\n ...crossing.map((link): Intent => ({\n kind: 'update',\n id: link.id,\n values: { source: reattach(link.source, inside, id), target: reattach(link.target, inside, id) },\n })),\n { kind: 'delete', ids: [...inside] },\n ],\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type SceneMap } from '../model/store.ts';\nimport { type Scene, type SceneId, isFrameNode } from '../model/types.ts';\n\n/** A scene a scene shape may open, as the properties panel lists it. */\nexport type SceneOption = { value: SceneId; label: string };\n\n/** The scenes the shapes of `scene` open. */\nconst childScenes = (scene: Scene | undefined): SceneId[] =>\n scene ? Object.values(scene.nodes).flatMap((node) => (isFrameNode(node) ? [node.scene] : [])) : [];\n\n/** Whether `from`, or any scene it opens however deep, is one of `targets`. */\nconst reaches = (scenes: SceneMap, from: SceneId, targets: ReadonlySet<SceneId>): boolean => {\n const seen = new Set<SceneId>();\n const pending = [from];\n for (let id = pending.pop(); id !== undefined; id = pending.pop()) {\n if (targets.has(id)) {\n return true;\n }\n if (!seen.has(id)) {\n seen.add(id);\n pending.push(...childScenes(scenes[id]));\n }\n }\n return false;\n};\n\n/**\n * The scenes a shape in the scene at the head of `path` may open: any scene of the store, shared by as many shapes\n * as open it, except one that would open the path again, which would nest the scene in itself without end. An\n * unnamed scene reads as the label of a shape that opens it.\n */\nexport const sceneOptions = (\n scenes: SceneMap,\n path: readonly SceneId[],\n filter: (id: SceneId) => boolean = () => true,\n): SceneOption[] => {\n const ancestors = new Set(path);\n const labels = new Map<SceneId, string>();\n for (const scene of Object.values(scenes)) {\n for (const node of Object.values(scene.nodes)) {\n if (isFrameNode(node) && node.label && !labels.has(node.scene)) {\n labels.set(node.scene, node.label);\n }\n }\n }\n return Object.values(scenes)\n .filter((scene) => filter(scene.id) && !reaches(scenes, scene.id, ancestors))\n .map((scene) => ({ value: scene.id, label: scene.name ?? labels.get(scene.id) ?? scene.id }))\n .sort((left, right) => left.label.localeCompare(right.label));\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The optional editor toolbars (decision 5): every button is an action the view exposes, so a host may\n// render these bars, its own, or none; the palette stays a separate component. They are separate bars so\n// where a control sits says what it does: `NavigationToolbar` says where the view is in the scene tree,\n// `ActionToolbar` changes the scene, and `CameraToolbar` fits and zooms the view beside its own numbers.\n//\n\nimport React, { type ReactNode } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Menu from '@dxos/react-ui/Menu';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { shortcutFor } from '../../model/keys.ts';\nimport { type NodeRegistry } from '../../model/registry.ts';\nimport { type Capabilities, type NodeType, type SceneId } from '../../model/types.ts';\nimport { Breadcrumbs } from '../Breadcrumbs/Breadcrumbs.tsx';\n\n/** What the toolbars can ask of the view; a missing action hides or disables its control. */\nexport type ToolbarActions = {\n /** Navigation: the scene path, a name per scene, and drill-out by path index. */\n path: SceneId[];\n nameOf: (id: SceneId) => string;\n onPath: (index: number) => void;\n fit: () => void;\n /** Back to true size (100%), about the view's centre. */\n zoomReset: () => void;\n zoomIn: () => void;\n zoomOut: () => void;\n snap: boolean;\n toggleSnap: () => void;\n guides: boolean;\n toggleGuides: () => void;\n /** On a lattice scene: whether snap lands on the lattice rather than the basic grid; absent elsewhere. */\n lattice?: boolean;\n toggleLattice?: () => void;\n debug: boolean;\n toggleDebug: () => void;\n canUndo: boolean;\n canRedo: boolean;\n undo: () => void;\n redo: () => void;\n hasSelection: boolean;\n hasClipboard: boolean;\n cut: () => void;\n copy: () => void;\n paste: () => void;\n delete: () => void;\n /** A new node of `type` at the centre of the view. */\n create: (type: NodeType) => void;\n /** Auto layout; absent when the projection does not offer it (`Capabilities.layout`). */\n layout?: () => void;\n};\n\n// A bar fills the frame its host floats it in and scrolls what does not fit; the toolbar's own layout\n// supplies `overflow-x-auto scrollbar-none`, leaving no bar over the diagram.\nconst barClasses = 'w-full gap-1 px-2 py-1 rounded-sm bg-modal-surface border border-separator';\n\nconst readoutClasses = 'text-fg-muted font-mono text-sm whitespace-nowrap';\n\nexport type NavigationToolbarProps = Util.ThemedClassName<{\n actions: ToolbarActions;\n /** Trailing status, e.g. the depth readout. */\n children?: ReactNode;\n}>;\n\n/** Where the view is: the drilled path and the readout that follows it. */\nexport const NavigationToolbar = ({ classNames, actions, children }: NavigationToolbarProps) => {\n const { path } = actions;\n return (\n <Toolbar.Root size='sm' classNames={mx(barClasses, classNames)} data-testid='canvas-toolbar'>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrow-up--regular'\n label='Up'\n disabled={path.length < 2}\n data-testid='toolbar-up'\n onClick={() => actions.onPath(path.length - 2)}\n />\n <Breadcrumbs path={path} nameOf={actions.nameOf} onSelect={actions.onPath} />\n {children && (\n <>\n <Toolbar.Separator variant='line' />\n <Toolbar.Text classNames={readoutClasses}>{children}</Toolbar.Text>\n </>\n )}\n </Toolbar.Root>\n );\n};\n\nexport type CameraToolbarProps = Util.ThemedClassName<{ actions: ToolbarActions; children?: ReactNode }>;\n\n/** The camera: fit and zoom, beside its own numbers; nothing here changes the scene. */\nexport const CameraToolbar = ({ classNames, actions, children }: CameraToolbarProps) => {\n return (\n <Toolbar.Root size='sm' classNames={mx(barClasses, classNames)} data-testid='canvas-debug'>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrows-out--regular'\n label={`Fit (${shortcutFor('fit')})`}\n data-testid='toolbar-fit'\n onClick={actions.fit}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--number-square-one--regular'\n label={`Actual size (${shortcutFor('zoomReset')})`}\n data-testid='toolbar-zoom-reset'\n onClick={actions.zoomReset}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--magnifying-glass-plus--regular'\n label='Zoom in'\n data-testid='toolbar-zoom-in'\n onClick={actions.zoomIn}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--magnifying-glass-minus--regular'\n label='Zoom out'\n data-testid='toolbar-zoom-out'\n onClick={actions.zoomOut}\n />\n <Toolbar.Separator variant='line' />\n <Toolbar.Text classNames={readoutClasses}>{children}</Toolbar.Text>\n </Toolbar.Root>\n );\n};\n\nexport type ActionToolbarProps = Util.ThemedClassName<{\n actions: ToolbarActions;\n nodes: NodeRegistry;\n capabilities: Capabilities;\n}>;\n\n/** Everything that changes the scene, plus snap, history, clipboard, creation and debug. */\nexport const ActionToolbar = ({ classNames, actions, nodes, capabilities }: ActionToolbarProps) => {\n return (\n <Toolbar.Root size='sm' classNames={mx(barClasses, classNames)} data-testid='canvas-actions'>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--grid-four--regular'\n label={`Snap (${shortcutFor('snap')}): snap moves, resizes and new nodes to the major grid, or with the lattice on to its cells`}\n classNames={mx(actions.snap && 'bg-primary-500/20')}\n data-testid='toolbar-snap'\n onClick={actions.toggleSnap}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--frame-corners--regular'\n label={`Guides (${shortcutFor('guides')}): show the lattice cells`}\n classNames={mx(actions.guides && 'bg-primary-500/20')}\n data-testid='toolbar-guides'\n onClick={actions.toggleGuides}\n />\n {actions.toggleLattice && (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--squares-four--regular'\n label={`Lattice (${shortcutFor('lattice')}): snap to the lattice's cells rather than the basic grid`}\n classNames={mx(actions.lattice && 'bg-primary-500/20')}\n data-testid='toolbar-lattice'\n onClick={actions.toggleLattice}\n />\n )}\n <Toolbar.Separator variant='line' />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrow-u-up-left--regular'\n label={`Undo (${shortcutFor('undo')})`}\n disabled={!actions.canUndo}\n data-testid='undo'\n onClick={actions.undo}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrow-u-up-right--regular'\n label={`Redo (${shortcutFor('redo')})`}\n disabled={!actions.canRedo}\n data-testid='redo'\n onClick={actions.redo}\n />\n <Toolbar.Separator variant='line' />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--scissors--regular'\n label={`Cut (${shortcutFor('cut')})`}\n disabled={!actions.hasSelection || !capabilities.delete}\n data-testid='cut'\n onClick={actions.cut}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--copy--regular'\n label={`Copy (${shortcutFor('copy')})`}\n disabled={!actions.hasSelection}\n data-testid='copy'\n onClick={actions.copy}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--clipboard-text--regular'\n label={`Paste (${shortcutFor('paste')})`}\n disabled={!actions.hasClipboard || !capabilities.create}\n data-testid='paste'\n onClick={actions.paste}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--trash--regular'\n label={`Delete (${shortcutFor('delete')})`}\n disabled={!actions.hasSelection || !capabilities.delete}\n data-testid='toolbar-delete'\n onClick={actions.delete}\n />\n <Toolbar.Separator variant='line' />\n <Menu.Root positioning={{ placement: 'bottom-end', gutter: 4 }}>\n <Menu.Trigger asChild>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--plus--regular'\n label='Create a node at the centre of the view'\n disabled={!capabilities.create}\n data-testid='toolbar-create'\n />\n </Menu.Trigger>\n {/* Portalled: inside the bar's flex flow the items would sit under the readout and the canvas. */}\n <Menu.Content>\n {Object.values(nodes).map((def) => (\n <Menu.Item\n key={def.type}\n data-testid={`create-${def.type}`}\n onSelect={() => actions.create(def.type)}\n item={{ value: def.type, label: def.name }}\n />\n ))}\n </Menu.Content>\n </Menu.Root>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--tree-structure--regular'\n label={actions.layout ? 'Auto layout' : 'Auto layout (not offered by this projection)'}\n disabled={!actions.layout}\n data-testid='toolbar-layout'\n onClick={actions.layout}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--bug--regular'\n label={`Debug (${shortcutFor('debug')}): label every frame with its id, type and geometry`}\n classNames={mx(actions.debug && 'bg-primary-500/20')}\n data-testid='toolbar-debug'\n onClick={actions.toggleDebug}\n />\n </Toolbar.Root>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The dock: a column beside the canvas that panels move into when the view's panels are docked, one accordion\n// section per panel. A panel registers its section and portals itself into the section's slot.\n//\n\nimport React, {\n type PropsWithChildren,\n type ReactNode,\n type SyntheticEvent,\n createContext,\n useCallback,\n useContext,\n useLayoutEffect,\n useMemo,\n useState,\n} from 'react';\nimport { createPortal } from 'react-dom';\n\nimport * as Accordion from '@dxos/react-ui/Accordion';\nimport * as ScrollArea from '@dxos/react-ui/ScrollArea';\n\n/** A panel's section in the dock. */\nexport type DockSection = {\n id: string;\n title: string;\n icon: string;\n /** Sections stack by it, lowest first. */\n order: number;\n};\n\ntype DockContextValue = {\n sections: readonly DockSection[];\n slots: Readonly<Record<string, HTMLDivElement | null>>;\n closed: ReadonlySet<string>;\n register: (section: DockSection) => () => void;\n setSlot: (id: string, element: HTMLDivElement | null) => void;\n setClosed: (closed: ReadonlySet<string>) => void;\n};\n\nconst DockContext = createContext<DockContextValue | undefined>(undefined);\n\n/** Holds the docked sections and their slots for a view's `Dock` and its panels. */\nexport const DockProvider = ({ children }: PropsWithChildren) => {\n const [sections, setSections] = useState<DockSection[]>([]);\n const [slots, setSlots] = useState<Record<string, HTMLDivElement | null>>({});\n // Closed rather than open, so a section that docks later starts open.\n const [closed, setClosed] = useState<ReadonlySet<string>>(new Set());\n const register = useCallback((section: DockSection) => {\n setSections((current) =>\n [...current.filter((entry) => entry.id !== section.id), section].sort((left, right) => left.order - right.order),\n );\n return () => setSections((current) => current.filter((entry) => entry.id !== section.id));\n }, []);\n const setSlot = useCallback(\n (id: string, element: HTMLDivElement | null) =>\n setSlots((current) => (current[id] === element ? current : { ...current, [id]: element })),\n [],\n );\n const value = useMemo(\n () => ({ sections, slots, closed, register, setSlot, setClosed }),\n [sections, slots, closed, register, setSlot],\n );\n return <DockContext.Provider value={value}>{children}</DockContext.Provider>;\n};\n\n/** A section's slot; its ref callback is stable, since a new one each render would detach and reattach (a loop). */\nconst DockSlot = ({ id, setSlot }: { id: string; setSlot: DockContextValue['setSlot'] }) => {\n const ref = useCallback((element: HTMLDivElement | null) => setSlot(id, element), [id, setSlot]);\n return <div ref={ref} />;\n};\n\n/** Stops a docked panel's events at the dock: through the portal they would reach the canvas root (hover, menus). */\nconst stop = (event: SyntheticEvent) => event.stopPropagation();\n\n/**\n * The dock column: an accordion of the registered sections, any number open, each as tall as its panel, the column\n * scrolling them together. Nothing (and no space) while no panel is docked.\n */\nexport const Dock = () => {\n const dock = useContext(DockContext);\n if (!dock || dock.sections.length === 0) {\n return null;\n }\n const { sections, closed, setSlot, setClosed } = dock;\n return (\n // The column is the scroll area itself: each section is as tall as its panel, and it scrolls them together.\n <ScrollArea.Root\n classNames='w-80 shrink-0 border-l border-separator-subtle bg-base-surface'\n data-testid='scene-view-dock'\n >\n <ScrollArea.Viewport>\n <Accordion.Root\n border={false}\n onPointerDown={stop}\n onPointerMove={stop}\n onPointerUp={stop}\n onDoubleClick={stop}\n onContextMenu={stop}\n onKeyDown={stop}\n value={sections.filter((section) => !closed.has(section.id)).map((section) => section.id)}\n onValueChange={(open) =>\n setClosed(new Set(sections.filter((section) => !open.includes(section.id)).map((section) => section.id)))\n }\n >\n {sections.map((section) => (\n <Accordion.Item key={section.id} value={section.id} data-testid={`dock-section-${section.id}`}>\n {/* A distinct surface, so a section's header reads apart from its panel's own toolbar. */}\n <Accordion.ItemTrigger icon={section.icon} classNames='bg-group-surface'>\n {section.title}\n </Accordion.ItemTrigger>\n <Accordion.ItemContent>\n <DockSlot id={section.id} setSlot={setSlot} />\n </Accordion.ItemContent>\n </Accordion.Item>\n ))}\n </Accordion.Root>\n </ScrollArea.Viewport>\n </ScrollArea.Root>\n );\n};\n\n/**\n * Registers a section while `docked`, and renders `panel` into it: docked, the panel's portal into the dock (once its\n * slot mounts); floating, `null`, so the caller renders the panel where it floats.\n */\nexport const useDockSection = (section: DockSection, docked: boolean, panel: ReactNode): ReactNode | null => {\n const dock = useContext(DockContext);\n const { id, title, icon, order } = section;\n useLayoutEffect(() => {\n if (!dock || !docked) {\n return;\n }\n return dock.register({ id, title, icon, order });\n // `register` is stable; the section re-registers only when it changes.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [dock?.register, docked, id, title, icon, order]);\n if (!docked) {\n return null;\n }\n const slot = dock?.slots[id];\n return slot ? createPortal(panel, slot) : null;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type KeyboardEvent, type MouseEvent, type RefObject } from 'react';\n\nimport { createContext } from '@dxos/react-hooks';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport {\n type ControlPointRef,\n type Drag,\n type EditingPart,\n type PanelMode,\n type SceneViewAtoms,\n} from '../../model/atoms.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type LinkRegistry, type NodeRegistry } from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Bounds,\n type Camera,\n type Capabilities,\n type ElementId,\n type LinkId,\n type NodeId,\n type Scene,\n type SceneId,\n type Tool,\n} from '../../model/types.ts';\nimport { type Clipboard } from '../../utils/clipboard.ts';\nimport { type ElementHandlers } from '../SceneLayer/SceneLayer.tsx';\nimport { type ToolbarActions } from '../Toolbar/Toolbar.tsx';\nimport { type PointerMachine } from './usePointerMachine.ts';\nimport { type SceneCamera } from './useSceneCamera.ts';\nimport { type SceneClipboard } from './useSceneClipboard.ts';\nimport { type SceneNavigation } from './useSceneNavigation.ts';\n\n/**\n * What `SceneView.Root` composes and every part reads. The parts are a view onto one machine rather than\n * components with state of their own, so the whole of it is here rather than threaded part by part: a\n * toolbar and the canvas act on the same camera, the same selection and the same projection.\n */\nexport type SceneViewContextValue = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n store: SceneStore;\n projection: Projection;\n capabilities: Capabilities;\n /** The scene is only looked at: the parts that edit it (selection frame, ports, actions, properties) hide. */\n readonly: boolean;\n nodeRegistry: NodeRegistry;\n linkRegistry: LinkRegistry;\n\n /** The scene as stored, and as it is drawn while a gesture is in flight. */\n scene: Scene;\n displayScene: Scene;\n /** The gesture in flight would be refused by the projection (e.g. an overlap on the lattice). */\n blocked: boolean;\n /** The current scene's frame. */\n bounds: Bounds;\n /** The scene's frame and the visible viewport together, for the lattice cells. */\n latticeBounds: Bounds;\n path: SceneId[];\n camera: Camera;\n /** The zoom against this level's own 1:1 rather than the root's; display only. */\n /** The centre of the view in scene coordinates. */\n pointer: { x: number; y: number };\n /** Whether the viewport has been measured; the scene stays hidden until it has. */\n measured: boolean;\n /** One screen pixel in scene units, for chrome that should not grow with the camera. */\n frameUnit: number;\n /** The portal filling most of the view and the opacity of the rest of the layer around it (`layerOpacity`). */\n focus: { id: ElementId; opacity: number } | undefined;\n /** Minor grid spacing in scene px. */\n grid: number;\n snapEnabled: boolean;\n guides: boolean;\n /** On a lattice scene, snap lands on the lattice rather than the basic grid. */\n latticeOn: boolean;\n\n selection: ReadonlySet<ElementId>;\n hover: ElementId | undefined;\n selectedPoint: ControlPointRef | undefined;\n editing: EditingPart | undefined;\n /** The node whose embedded content takes input. */\n active: NodeId | undefined;\n clipboard: Clipboard | undefined;\n drag: Drag | undefined;\n tool: Tool;\n debug: boolean;\n /** Where the properties and layers panels sit. */\n panels: PanelMode;\n\n /** The bounds a create gesture would land, drawn whether or not the node itself previews. */\n createFrame: Bounds | undefined;\n /** Where the nodes of a move in flight will land, while they follow the pointer. */\n landing: readonly Bounds[] | undefined;\n handlers: ElementHandlers;\n /** The link under the pointer. */\n linkHover: LinkId | undefined;\n select: (ids: Iterable<ElementId>) => void;\n toolbarActions: ToolbarActions;\n} & Pick<SceneCamera, 'navigating' | 'opening'> &\n Pick<SceneNavigation, 'drillIn'> &\n Pick<SceneClipboard, 'copy' | 'cut' | 'paste'> &\n Pick<\n PointerMachine,\n | 'onBackgroundPointerDown'\n | 'onPointerMove'\n | 'onPointerUp'\n | 'onContextMenu'\n | 'cancelDrag'\n | 'updateHover'\n | 'onHandlePointerDown'\n | 'onPortPointerDown'\n | 'onEndPointerDown'\n | 'onPointPointerDown'\n | 'onMidpointPointerDown'\n | 'onPointContextMenu'\n | 'setTool'\n | 'removePoint'\n | 'menu'\n | 'closeMenu'\n | 'menuAnchorRef'\n > & {\n onDoubleClick: (event: MouseEvent) => void;\n onKeyDown: (event: KeyboardEvent) => void;\n rootRef: RefObject<HTMLDivElement | null>;\n };\n\nexport const [SceneViewProvider, useSceneViewContext] = createContext<SceneViewContextValue>('SceneView.Root');\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Resize geometry as a pure function of the start frame, the handle and the pointer offset, so the\n// view only feeds it the drag and the projection receives one `resize` intent.\n//\n\nimport { type Handle } from '../model/atoms.ts';\nimport { type Bounds, type Point, type Size } from '../model/types.ts';\n\nexport type ResizeOptions = {\n minSize: Size;\n maxSize?: Size;\n /** Both edges of a moved axis move by the same amount, so the centre stays put (shift-drag). */\n symmetric?: boolean;\n /** Snaps a moving edge; the fixed edge (or the centre when symmetric) never moves. */\n snap?: (value: number) => number;\n};\n\nconst identity = (value: number) => value;\n\n/** Resize by a handle: the moving edges land on `snap`, the opposite edges stay put, sizes clamp to the limits. */\nexport const resizeBounds = (\n start: Bounds,\n handle: Handle,\n delta: Point,\n { minSize, maxSize, symmetric = false, snap = identity }: ResizeOptions,\n): Bounds => {\n const horizontal = resizeAxis(\n { origin: start.x, length: start.width },\n { start: handle.includes('w'), end: handle.includes('e') },\n delta.x,\n { min: minSize.width, max: maxSize?.width, symmetric, snap },\n );\n const vertical = resizeAxis(\n { origin: start.y, length: start.height },\n { start: handle.includes('n'), end: handle.includes('s') },\n delta.y,\n { min: minSize.height, max: maxSize?.height, symmetric, snap },\n );\n return { x: horizontal.origin, y: vertical.origin, width: horizontal.length, height: vertical.length };\n};\n\ntype Axis = { origin: number; length: number };\ntype AxisOptions = { min: number; max?: number; symmetric: boolean; snap: (value: number) => number };\n\nconst resizeAxis = (\n axis: Axis,\n moving: { start: boolean; end: boolean },\n delta: number,\n { min, max, symmetric, snap }: AxisOptions,\n): Axis => {\n if (!moving.start && !moving.end) {\n return axis;\n }\n const center = axis.origin + axis.length / 2;\n let start = axis.origin;\n let end = axis.origin + axis.length;\n if (moving.end) {\n end = snap(end + delta);\n }\n if (moving.start) {\n start = snap(start + delta);\n }\n if (symmetric) {\n const half = moving.end ? end - center : center - start;\n const length = clamp(2 * half, min, max);\n return { origin: center - length / 2, length };\n }\n const length = clamp(end - start, min, max);\n return moving.start ? { origin: end - length, length } : { origin: start, length };\n};\n\nconst clamp = (value: number, min: number, max: number | undefined): number =>\n Math.min(Math.max(value, min), max ?? Infinity);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport {\n type MouseEvent,\n type MutableRefObject,\n type PointerEvent,\n type RefObject,\n useCallback,\n useRef,\n useState,\n} from 'react';\n\nimport { SCENE_OVERLAY_ATTRIBUTE, type useRegistry } from '../../hooks/index.ts';\nimport { type ControlPointRef, type Drag, type Handle, type SceneViewAtoms } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type CreateProps, type NodeRegistry } from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Camera,\n type Capabilities,\n type ElementId,\n type Endpoint,\n type Link,\n type Node,\n type NodeId,\n type NodeType,\n type Point,\n type Port,\n type Scene,\n type SplineLink,\n type Tool,\n endpointNode,\n isFrameNode,\n isPointEndpoint,\n} from '../../model/types.ts';\nimport { boundsCenter, panBy, screenToScene } from '../../utils/camera.ts';\nimport { duplicateSelection } from '../../utils/clipboard.ts';\nimport { boundsFromPoints, hitTest, nodesIntersecting } from '../../utils/hit.ts';\nimport { DEFAULT_LAYER, activeLayer } from '../../utils/layers.ts';\nimport { topZ } from '../../utils/order.ts';\nimport { nodePorts, portAccepts, portPoint } from '../../utils/ports.ts';\nimport { resizeBounds } from '../../utils/resize.ts';\nimport { insertIndex, linkGeometry, sideToward } from '../../utils/route.ts';\nimport { NOMINAL_SIZES, cloneShape, createLink, createNode, nodeBounds, nominalSize } from '../../utils/shapes.ts';\nimport { type LinkEnd, handlePoint } from '../ControlFrame/ControlFrame.tsx';\nimport { type SceneCamera } from './useSceneCamera.ts';\nimport { type SceneSnap } from './useSceneSnap.ts';\n\n/** How near a port the pointer must be, in screen px, for the port rather than the body to take a link. */\nconst PORT_SNAP_PX = 16;\n\n/** The node drawn as a preview during a create drag; it never reaches the model. */\nexport const PREVIEW_NODE_ID = 'preview-node';\n\nexport const createId = (prefix: string) => `${prefix}-${Math.random().toString(36).slice(2, 10)}`;\n\nconst distance = (left: Point, right: Point): [number, number] => [left.x - right.x, left.y - right.y];\n\n/**\n * Whether a link gesture has gone far enough to be a link: at least one grid cell (`minimum`, scene\n * units) from where it started. Short of that it is a click, so it neither previews nor lands.\n */\nexport const isLinkDrawn = ({ from, to }: { from: Point; to: Point }, minimum: number): boolean =>\n Math.hypot(to.x - from.x, to.y - from.y) >= minimum;\n\n/** Whether a link between two endpoints has a direction: either pinned port declares `in` or `out`. */\nconst isDirected = (scene: Scene, registry: NodeRegistry, source: Endpoint, target: Endpoint): boolean =>\n [source, target].some((end) => {\n if (isPointEndpoint(end)) {\n return false;\n }\n const node = scene.nodes[end.node];\n const port = node && nodePorts(registry, node).find((candidate) => candidate.id === end.port);\n return port !== undefined && port.accepts !== undefined && port.accepts !== 'any';\n });\n\nexport type ContextMenu = { at: Point; scene: Point; kind: 'point' | 'element' | 'canvas' };\n\nexport type UsePointerMachineOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n store: SceneStore;\n scene: Scene;\n nodeRegistry: NodeRegistry;\n projection: Projection;\n capabilities: Capabilities;\n camera: Camera;\n rootRef: RefObject<HTMLDivElement | null>;\n /** Set once the user takes the camera over, which stops the view re-fitting itself. */\n interactedRef: MutableRefObject<boolean>;\n select: (ids: Iterable<ElementId>) => void;\n /** Scene px of one nominal unit (the model's major grid cell), which a new node's default size is counted in. */\n cell: number;\n} & Pick<SceneCamera, 'setCamera' | 'cancelAnimation' | 'isNavigating'> &\n Pick<SceneSnap, 'minor' | 'major' | 'snap' | 'snapMinor'>;\n\nexport type PointerMachine = {\n /** Root element handlers. */\n onBackgroundPointerDown: (event: PointerEvent) => void;\n onPointerMove: (event: PointerEvent) => void;\n /** Ends the gesture in flight; `event` is the release (absent for a drop from outside the canvas). */\n onPointerUp: (event?: { clientX: number; clientY: number }) => void;\n onContextMenu: (event: MouseEvent) => void;\n /** A gesture abandoned (Escape, a drag leaving the canvas). */\n cancelDrag: () => void;\n updateHover: (point: Point | undefined) => void;\n\n /** Element handlers, threaded to the layer and the control frame. */\n onNodePointerDown: (node: Node, event: PointerEvent) => void;\n onLinkPointerDown: (link: Link, event: PointerEvent) => void;\n onLinkDoubleClick: (link: Link, event: MouseEvent) => void;\n onLinkContextMenu: (link: Link, event: MouseEvent) => void;\n onHandlePointerDown: (node: Node, handle: Handle, event: PointerEvent) => void;\n onPortPointerDown: (node: Node, port: Port, event: PointerEvent) => void;\n onEndPointerDown: (link: Link, end: LinkEnd, event: PointerEvent) => void;\n onPointPointerDown: (link: SplineLink, index: number, event: PointerEvent) => void;\n onMidpointPointerDown: (link: SplineLink, index: number, point: Point, event: PointerEvent) => void;\n onPointContextMenu: (link: SplineLink, index: number, event: MouseEvent) => void;\n\n setTool: (next: Tool) => void;\n setDrag: (next: Drag | undefined) => void;\n /** A pointer event's position in scene coordinates. */\n toScene: (event: { clientX: number; clientY: number }) => Point;\n removePoint: (point: ControlPointRef) => void;\n\n /** The node a create drag would make; the ghost, the frame and the drop all read it. */\n createdNode: (drag: Extract<Drag, { kind: 'create' }>, id: NodeId) => Node | undefined;\n commitCreated: (node: Node) => void;\n\n menu: ContextMenu | undefined;\n closeMenu: () => void;\n menuAnchorRef: RefObject<HTMLSpanElement | null>;\n};\n\n/**\n * Every gesture the canvas takes: what a press starts, what a move does to the drag in flight, and what a\n * release commits. The drag lives in an atom rather than in React state, so a handler reads the gesture it\n * is continuing rather than the one the last render closed over, and the view renders the drag by\n * projecting it onto a copy of the scene.\n */\nexport const usePointerMachine = ({\n registry,\n atoms,\n store,\n scene,\n nodeRegistry,\n projection,\n capabilities,\n camera,\n rootRef,\n interactedRef,\n select,\n setCamera,\n cancelAnimation,\n isNavigating,\n cell,\n minor,\n major,\n snap,\n snapMinor,\n}: UsePointerMachineOptions): PointerMachine => {\n const toScene = useCallback(\n (event: { clientX: number; clientY: number }): Point => {\n const rect = rootRef.current?.getBoundingClientRect();\n const camera = registry.get(atoms.camera);\n return screenToScene(camera, { x: event.clientX - (rect?.left ?? 0), y: event.clientY - (rect?.top ?? 0) });\n },\n [registry, atoms.camera, rootRef],\n );\n\n const setDrag = useCallback((next: Drag | undefined) => registry.set(atoms.drag, next), [registry, atoms.drag]);\n\n const setTool = useCallback(\n (next: Tool) => {\n registry.set(atoms.tool, next);\n if (next.kind === 'link') {\n registry.set(atoms.linkType, next.type);\n }\n // A creation tool is about what comes next, so the outgoing selection's outline and handles would\n // only sit over the drawing; the node the gesture makes becomes the selection.\n if (next.kind === 'node' || next.kind === 'link') {\n registry.set(atoms.selection, new Set<ElementId>());\n registry.set(atoms.point, undefined);\n }\n },\n [registry, atoms.tool, atoms.linkType, atoms.selection, atoms.point],\n );\n\n const startDrag = useCallback(\n (next: Drag, event: PointerEvent) => {\n interactedRef.current = true;\n cancelAnimation();\n // A gesture has no hover: the pointer is captured, so the highlight would stick to where it began.\n registry.set(atoms.hover, undefined);\n setDrag(next);\n rootRef.current?.setPointerCapture(event.pointerId);\n },\n [cancelAnimation, setDrag, interactedRef, rootRef, registry, atoms.hover],\n );\n\n const onBackgroundPointerDown = useCallback(\n (event: PointerEvent) => {\n if (event.target !== event.currentTarget) {\n return;\n }\n const currentTool = registry.get(atoms.tool);\n const point = toScene(event);\n if (event.button === 1 || currentTool.kind === 'hand') {\n startDrag({ kind: 'pan', last: { x: event.clientX, y: event.clientY } }, event);\n } else if (event.button !== 0) {\n return;\n } else if (currentTool.kind === 'node') {\n if (capabilities.create) {\n const from = { x: snap(point.x), y: snap(point.y) };\n startDrag({ kind: 'create', type: currentTool.type, from, to: from }, event);\n }\n } else if (currentTool.kind === 'link') {\n // A link tool on empty canvas draws a free-ended link (decision 3); dropping on a node attaches that end.\n if (capabilities.link) {\n startDrag(\n { kind: 'link', type: currentTool.type, source: { point }, from: point, fromSide: 'e', to: point },\n event,\n );\n }\n } else {\n const mode = event.altKey ? 'subtract' : event.shiftKey ? 'add' : 'replace';\n if (mode === 'replace') {\n select([]);\n }\n startDrag({ kind: 'marquee', from: point, to: point, mode }, event);\n }\n },\n [registry, atoms.tool, toScene, startDrag, select, capabilities.create, capabilities.link, snap],\n );\n\n /** Click selection shared by nodes and links: shift toggles, a plain click on an unselected element replaces. */\n const clickSelect = useCallback(\n (id: ElementId, event: PointerEvent): Set<ElementId> => {\n const current = registry.get(atoms.selection);\n const next = new Set(event.shiftKey ? current : current.has(id) ? current : []);\n if (event.shiftKey && current.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n select(next);\n return next;\n },\n [registry, atoms.selection, select],\n );\n\n /** Makes a node's embedded content live (`SceneViewAtoms.active`), when it has any. */\n const activate = useCallback(\n (id: NodeId) => {\n // Escaped: a host's node id may hold characters a selector would misread.\n if (rootRef.current?.querySelector(`[data-node-id=\"${CSS.escape(id)}\"] [${SCENE_OVERLAY_ATTRIBUTE}]`)) {\n registry.set(atoms.active, id);\n }\n },\n [rootRef, registry, atoms.active],\n );\n\n const onNodePointerDown = useCallback(\n (node: Node, event: PointerEvent) => {\n const currentTool = registry.get(atoms.tool);\n if ((currentTool.kind !== 'select' && currentTool.kind !== 'link') || event.button !== 0) {\n return;\n }\n event.stopPropagation();\n // With a link tool the body is a source like a port is, so a link can be drawn between two shapes\n // without aiming at their dots; the endpoint carries no port and routing picks the side.\n if (currentTool.kind === 'link' && capabilities.link) {\n const from = toScene(event);\n // The band leaves the side of the node the press is nearest; routing picks the real side on drop.\n const fromSide = sideToward(boundsCenter(nodeBounds(node)), from);\n startDrag({ kind: 'link', type: currentTool.type, source: { node: node.id }, from, fromSide, to: from }, event);\n return;\n }\n const next = clickSelect(node.id, event);\n // A press on the content of the active node (its own toolbar or editor) starts no move: the drag's pointer\n // capture would take the click from that content's controls. Inactive, the content is inert and the node moves.\n const embedded = event.target instanceof Element && event.target.closest(`[${SCENE_OVERLAY_ATTRIBUTE}]`);\n if (embedded && registry.get(atoms.active) === node.id) {\n return;\n }\n if (capabilities.move && !node.locked) {\n const { x, y } = nodeBounds(node);\n const ids = [...next].filter((id) => scene.nodes[id] !== undefined);\n startDrag(\n { kind: 'move', ids, origin: toScene(event), anchor: { x, y }, delta: { x: 0, y: 0 }, copy: event.metaKey },\n event,\n );\n } else if (next.size === 1) {\n // A node that cannot move has no drag to end in a click, so the press itself activates it.\n activate(node.id);\n }\n },\n [\n registry,\n atoms.tool,\n atoms.active,\n activate,\n clickSelect,\n capabilities.move,\n capabilities.link,\n scene.nodes,\n toScene,\n startDrag,\n ],\n );\n\n const onLinkPointerDown = useCallback(\n (link: Link, event: PointerEvent) => {\n const currentTool = registry.get(atoms.tool);\n if (currentTool.kind === 'hand' || event.button !== 0) {\n return;\n }\n event.stopPropagation();\n clickSelect(link.id, event);\n },\n [registry, atoms.tool, clickSelect],\n );\n\n const onHandlePointerDown = useCallback(\n (node: Node, handle: Handle, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.resize) {\n return;\n }\n event.stopPropagation();\n const start = nodeBounds(node);\n startDrag({ kind: 'resize', id: node.id, handle, start, bounds: start }, event);\n },\n [capabilities.resize, startDrag],\n );\n\n const onPortPointerDown = useCallback(\n (node: Node, port: Port, event: PointerEvent) => {\n // A link leaves a port that accepts `out`; an input-only port is a drop target, not a source.\n if (event.button !== 0 || !capabilities.link || !portAccepts(port, 'out')) {\n return;\n }\n event.stopPropagation();\n const from = portPoint(nodeBounds(node), port);\n const currentTool = registry.get(atoms.tool);\n const type = currentTool.kind === 'link' ? currentTool.type : registry.get(atoms.linkType);\n startDrag(\n { kind: 'link', type, source: { node: node.id, port: port.id }, from, fromSide: port.side, to: from },\n event,\n );\n },\n [capabilities.link, registry, atoms.tool, atoms.linkType, startDrag],\n );\n\n const removePoint = useCallback(\n ({ link: id, index }: ControlPointRef) => {\n const link = scene.links[id];\n if (link?.type === 'spline' && capabilities.update) {\n projection.apply({ kind: 'update', id, values: { points: link.points.filter((_, i) => i !== index) } });\n }\n registry.set(atoms.point, undefined);\n },\n [scene.links, capabilities.update, projection, registry, atoms.point],\n );\n\n /** A spline's control point: press selects it, drag moves it, alt-click removes it. */\n const onPointPointerDown = useCallback(\n (link: SplineLink, index: number, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n if (event.altKey) {\n removePoint({ link: link.id, index });\n return;\n }\n registry.set(atoms.point, { link: link.id, index });\n startDrag({ kind: 'point', id: link.id, index, points: [...link.points] }, event);\n },\n [capabilities.update, removePoint, registry, atoms.point, startDrag],\n );\n\n /** The midpoint of a span: pressing it adds a control point there and moves it in the same gesture. */\n const onMidpointPointerDown = useCallback(\n (link: SplineLink, index: number, point: Point, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n registry.set(atoms.point, { link: link.id, index });\n const points = [...link.points.slice(0, index), point, ...link.points.slice(index)];\n startDrag({ kind: 'point', id: link.id, index, points }, event);\n },\n [capabilities.update, registry, atoms.point, startDrag],\n );\n\n // The right-click menu opens at the pointer, anchored to an empty element parked under the cursor\n // (the menu positions itself at a real element); what it offers depends on what was pressed.\n const menuAnchorRef = useRef<HTMLSpanElement>(null);\n const [menu, setMenu] = useState<ContextMenu | undefined>(undefined);\n const closeMenu = useCallback(() => setMenu(undefined), []);\n const openMenu = useCallback(\n (event: MouseEvent, kind: ContextMenu['kind']) => {\n event.preventDefault();\n event.stopPropagation();\n const rect = rootRef.current?.getBoundingClientRect();\n setMenu({\n at: { x: event.clientX - (rect?.left ?? 0), y: event.clientY - (rect?.top ?? 0) },\n scene: toScene(event),\n kind,\n });\n },\n [toScene, rootRef],\n );\n\n const onPointContextMenu = useCallback(\n (link: SplineLink, index: number, event: MouseEvent) => {\n registry.set(atoms.point, { link: link.id, index });\n openMenu(event, 'point');\n },\n [registry, atoms.point, openMenu],\n );\n\n /** Right-click on an element adds it to the selection unless it is already in it, then offers edit actions. */\n const onElementContextMenu = useCallback(\n (id: ElementId, event: MouseEvent) => {\n if (!registry.get(atoms.selection).has(id)) {\n select([id]);\n }\n openMenu(event, 'element');\n },\n [registry, atoms.selection, select, openMenu],\n );\n\n const onLinkContextMenu = useCallback(\n (link: Link, event: MouseEvent) => onElementContextMenu(link.id, event),\n [onElementContextMenu],\n );\n\n const onContextMenu = useCallback(\n (event: MouseEvent) => {\n const node = hitTest(scene, toScene(event));\n if (node) {\n onElementContextMenu(node.id, event);\n } else {\n openMenu(event, 'canvas');\n }\n },\n [scene, toScene, onElementContextMenu, openMenu],\n );\n\n /** Dragging a link's end re-attaches it; the other end stays put and anchors the rubber band. */\n const onEndPointerDown = useCallback(\n (link: Link, end: LinkEnd, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n const geometry = linkGeometry(scene, nodeRegistry, link);\n if (!geometry) {\n return;\n }\n const other = end === 'source' ? geometry.target : geometry.source;\n const to = end === 'source' ? geometry.source.point : geometry.target.point;\n startDrag({ kind: 'end', id: link.id, end, fixed: other.point, fixedSide: other.side, to }, event);\n },\n [capabilities.update, scene, nodeRegistry, startDrag],\n );\n\n /** Double-click on a spline adds a control point there; other link types have no points to edit. */\n const onLinkDoubleClick = useCallback(\n (link: Link, event: MouseEvent) => {\n if (link.type !== 'spline' || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n const geometry = linkGeometry(scene, nodeRegistry, link);\n if (!geometry) {\n return;\n }\n const point = toScene(event);\n const index = insertIndex(geometry.source.point, link.points, geometry.target.point, point);\n const points = [\n ...link.points.slice(0, index),\n { x: snap(point.x), y: snap(point.y) },\n ...link.points.slice(index),\n ];\n projection.apply({ kind: 'update', id: link.id, values: { points } });\n select([link.id]);\n },\n [capabilities.update, scene, nodeRegistry, toScene, snap, projection, select],\n );\n\n /**\n * The drop target for a link end: over a node (with a port-sized margin), the port nearest the pointer\n * among those that accept the end (`in` for a target, `out` for a source); a node with none takes no drop.\n */\n const linkTarget = useCallback(\n (point: Point, exclude: NodeId | undefined, direction: 'in' | 'out'): Endpoint | undefined => {\n const reach = PORT_SNAP_PX / registry.get(atoms.camera).zoom;\n const node = hitTest(scene, point, reach);\n if (!node || node.id === exclude) {\n return undefined;\n }\n const boundsOf = nodeBounds(node);\n let nearest: Port | undefined;\n let best = Infinity;\n for (const candidate of nodePorts(nodeRegistry, node).filter((port) => portAccepts(port, direction))) {\n const value = Math.hypot(...distance(portPoint(boundsOf, candidate), point));\n if (value < best) {\n best = value;\n nearest = candidate;\n }\n }\n // A port claims the drop only while the pointer is within reach of it; anywhere else on the node\n // the link binds to the body, which is also what a node with no port accepting this end takes.\n return nearest && best <= reach ? { node: node.id, port: nearest.id } : { node: node.id };\n },\n [scene, registry, atoms.camera, nodeRegistry],\n );\n\n // Hover comes from the model with a margin, not from the node element, so it survives the pointer\n // crossing onto a port that sits on the frame edge.\n const updateHover = useCallback(\n (point: Point | undefined) => {\n const zoom = registry.get(atoms.camera).zoom;\n const next = point ? hitTest(scene, point, PORT_SNAP_PX / zoom)?.id : undefined;\n if (registry.get(atoms.hover) !== next) {\n registry.set(atoms.hover, next);\n }\n },\n [registry, atoms.camera, atoms.hover, scene],\n );\n\n const onPointerMove = useCallback(\n (event: PointerEvent) => {\n const current = registry.get(atoms.drag);\n if (!current) {\n if (!isNavigating()) {\n updateHover(toScene(event));\n }\n return;\n }\n switch (current.kind) {\n case 'pan': {\n const zoom = registry.get(atoms.camera).zoom;\n setCamera((camera) =>\n panBy(camera, { x: (event.clientX - current.last.x) / zoom, y: (event.clientY - current.last.y) / zoom }),\n );\n setDrag({ ...current, last: { x: event.clientX, y: event.clientY } });\n break;\n }\n case 'marquee':\n case 'create': {\n const point = toScene(event);\n setDrag({ ...current, to: current.kind === 'create' ? { x: snap(point.x), y: snap(point.y) } : point });\n break;\n }\n case 'move': {\n // Snap the pressed node's top-left to the minor grid; the selection moves by the same offset.\n const point = toScene(event);\n const raw = { x: point.x - current.origin.x, y: point.y - current.origin.y };\n setDrag({\n ...current,\n raw,\n delta: {\n x: snapMinor(current.anchor.x + raw.x) - current.anchor.x,\n y: snapMinor(current.anchor.y + raw.y) - current.anchor.y,\n },\n // Read on every move, so pressing or releasing ⌘ mid-drag switches between moving and copying.\n copy: event.metaKey && capabilities.create === true,\n });\n break;\n }\n case 'resize': {\n const point = toScene(event);\n const anchor = handlePoint(current.start, current.handle);\n const delta = { x: point.x - anchor.x, y: point.y - anchor.y };\n const node = scene.nodes[current.id];\n const def = node && nodeDef(nodeRegistry, node);\n const bounds = resizeBounds(current.start, current.handle, delta, {\n minSize: def?.minSize ?? { width: major, height: major },\n maxSize: def?.maxSize,\n symmetric: event.shiftKey,\n // The moving edge lands on the minor grid, as a move does: a node's size is no coarser than\n // its position, while a new node still arrives on the major one.\n snap: snapMinor,\n });\n setDrag({ ...current, bounds });\n break;\n }\n case 'link': {\n // The band follows the pointer exactly; it snaps as it lands (`settle`). A free source keeps\n // facing the far end.\n const point = toScene(event);\n const target = linkTarget(point, endpointNode(current.source), 'in');\n const fromSide = isPointEndpoint(current.source) ? sideToward(current.from, point) : current.fromSide;\n setDrag({ ...current, to: point, fromSide, target });\n break;\n }\n case 'point': {\n // A control point moves on the minor grid, as a node does; the double-click that adds one is a\n // creation and stays on the major grid.\n const point = toScene(event);\n const points = [...current.points];\n points[current.index] = { x: snapMinor(point.x), y: snapMinor(point.y) };\n setDrag({ ...current, points });\n break;\n }\n case 'end': {\n const point = toScene(event);\n const link = scene.links[current.id];\n const other = link ? endpointNode(current.end === 'source' ? link.target : link.source) : undefined;\n const target = linkTarget(point, other, current.end === 'source' ? 'out' : 'in');\n setDrag({ ...current, to: point, target });\n break;\n }\n }\n },\n [\n registry,\n atoms.drag,\n atoms.camera,\n setCamera,\n setDrag,\n toScene,\n snap,\n snapMinor,\n scene.nodes,\n scene.links,\n nodeRegistry,\n major,\n linkTarget,\n updateHover,\n isNavigating,\n capabilities.create,\n ],\n );\n\n /**\n * A link band follows the pointer exactly while it is drawn; this is where its free ends snap to the\n * major grid, once, as it lands. An end dropped on a node keeps the node.\n */\n const settle = useCallback(\n (current: Drag): Drag => {\n const snapPoint = (point: Point): Point => ({ x: snap(point.x), y: snap(point.y) });\n switch (current.kind) {\n case 'link': {\n const free = isPointEndpoint(current.source);\n const from = free ? snapPoint(current.from) : current.from;\n return {\n ...current,\n from,\n source: free ? { point: from } : current.source,\n to: current.target ? current.to : snapPoint(current.to),\n };\n }\n case 'end':\n return current.target ? current : { ...current, to: snapPoint(current.to) };\n default:\n return current;\n }\n },\n [snap],\n );\n\n // The node the current create gesture made, re-framed by every ghost frame and by the drop, so a\n // definition whose `create` has effects (a trigger mints an object) runs it once, for the node that lands.\n const pendingRef = useRef<{ type: NodeType; node: Node } | undefined>(undefined);\n\n /**\n * The node a create drag would make: what was drawn, or the type's default size at the press when the\n * drag was a click. Shared by the ghost preview and the drop, so the preview is what lands.\n */\n const createdNode = useCallback(\n (drag: Extract<Drag, { kind: 'create' }>, id: NodeId): Node | undefined => {\n const def = nodeRegistry[drag.type];\n if (!def) {\n return undefined;\n }\n const drawn = boundsFromPoints(drag.from, drag.to);\n // Dropped from the palette there is no drawn box, so the type's default size stands in, in scene\n // units whatever the zoom. A box drawn on the canvas is exactly what the pointer swept:\n // it follows the cursor as the frame shows it, and a gesture that snapped to nothing creates nothing\n // rather than planting a default-sized node under the click.\n if (!drag.dropped && (drawn.width === 0 || drawn.height === 0)) {\n return undefined;\n }\n const size = drag.dropped ? nominalSize(def.defaultSize, cell) : { ...drawn };\n const center = drag.dropped\n ? { x: drag.from.x + size.width / 2, y: drag.from.y + size.height / 2 }\n : { x: drawn.x + drawn.width / 2, y: drawn.y + drawn.height / 2 };\n const props: CreateProps = { id, z: topZ(Object.values(scene.nodes)), center, size };\n const pending = pendingRef.current;\n // No `fontSize`: a new node inherits the view's default, as one created by dropping a link does.\n const node: Node = pending?.type === drag.type ? { ...pending.node, ...props } : def.create(props);\n pendingRef.current = { type: drag.type, node };\n return node;\n },\n [nodeRegistry, scene.nodes, cell],\n );\n\n /** Adds a new node; a new portal opens onto a fresh scene of its own, whichever path created it. */\n const addNode = useCallback(\n (node: Node) => {\n if (isFrameNode(node)) {\n registry.set(store.scenes, {\n ...registry.get(store.scenes),\n [node.scene]: {\n id: node.scene,\n name: 'Untitled',\n nodes: {},\n links: {},\n layers: { [DEFAULT_LAYER.id]: DEFAULT_LAYER },\n },\n });\n }\n projection.apply({ kind: 'create', node: { ...node, layer: activeLayer(scene, registry.get(atoms.layer)) } });\n },\n [projection, registry, store, scene, atoms.layer],\n );\n\n /** The node the gesture made, committed: the next gesture starts from a fresh `create`. */\n const commitCreated = useCallback(\n (node: Node) => {\n pendingRef.current = undefined;\n addNode(node);\n select([node.id]);\n },\n [addNode, select],\n );\n\n /** A gesture abandoned (Escape, a drag leaving the canvas): its pending node is dropped with it. */\n const cancelDrag = useCallback(() => {\n pendingRef.current = undefined;\n setDrag(undefined);\n }, [setDrag]);\n\n const onPointerUp = useCallback(\n (event?: { clientX: number; clientY: number }) => {\n const raw = registry.get(atoms.drag);\n if (!raw) {\n return;\n }\n setDrag(undefined);\n // Hover is not tracked during a captured drag, so it still names the node the gesture started on;\n // re-read it where the pointer was released.\n updateHover(event ? toScene(event) : undefined);\n const current = settle(raw);\n switch (current.kind) {\n case 'marquee': {\n const hits = nodesIntersecting(scene, boundsFromPoints(current.from, current.to)).map(({ id }) => id);\n const previous = registry.get(atoms.selection);\n select(\n current.mode === 'add'\n ? [...previous, ...hits]\n : current.mode === 'subtract'\n ? [...previous].filter((id) => !hits.includes(id))\n : hits,\n );\n break;\n }\n case 'move': {\n if (current.delta.x === 0 && current.delta.y === 0) {\n // A click (a press that never moved) on a node with embedded content makes that content live.\n if (current.ids.length === 1) {\n activate(current.ids[0]);\n }\n break;\n }\n // ⌘-drag leaves the selection where it was and drops a copy, which becomes the selection.\n const copy = current.copy ? duplicateSelection(scene, current.ids, current.delta, createId) : undefined;\n if (copy) {\n projection.apply(copy.intent);\n select(copy.ids);\n } else {\n projection.apply({ kind: 'move', ids: current.ids, delta: current.delta });\n }\n break;\n }\n case 'resize': {\n projection.apply({ kind: 'resize', id: current.id, bounds: current.bounds });\n break;\n }\n case 'link': {\n // A press that moved less than a grid cell is a click, not a link: with a link tool selected,\n // pressing and releasing draws nothing. Read from the raw gesture, since settling has already\n // snapped the landing point away from it.\n if (raw.kind === 'link' && !isLinkDrawn(raw, minor)) {\n // A click on the background with a link tool is a way out of the tool, as Escape is.\n if (isPointEndpoint(raw.source)) {\n setTool({ kind: 'select' });\n }\n break;\n }\n let target = current.target;\n let created: Node | undefined;\n if (!target && isPointEndpoint(current.source)) {\n // A free-ended link that never reached a node ends free too.\n target = { point: current.to };\n } else if (!target && capabilities.create) {\n // Dropping a link drag on empty canvas creates a node there and links to it (canvas-editor\n // behaviour): a copy of the shape it left, without its text, else a rectangle. It is centred on\n // the release point (not the settled end, already snapped to the coarse grid) with its top-left\n // on the minor grid, as a palette drop lands.\n const drop = raw.kind === 'link' ? raw.to : current.to;\n const source = scene.nodes[endpointNode(current.source) ?? ''];\n const def = source ? nodeRegistry[source.type] : undefined;\n const size = source?.size ?? nominalSize(NOMINAL_SIZES.rect, cell);\n const props = {\n id: createId(source?.type ?? 'rect'),\n z: topZ(Object.values(scene.nodes)),\n center: {\n x: snapMinor(drop.x - size.width / 2) + size.width / 2,\n y: snapMinor(drop.y - size.height / 2) + size.height / 2,\n },\n size,\n };\n const node =\n source && def\n ? cloneShape(source, def.create(props), nodeDef(nodeRegistry, source)?.parts)\n : createNode({ type: 'rect', ...props });\n addNode(node);\n created = node;\n target = { node: node.id };\n }\n if (target) {\n const link = createLink({\n type: current.type,\n id: createId(current.type),\n z: topZ(Object.values(scene.links)),\n source: current.source,\n target,\n midpoint: { x: snap((current.from.x + current.to.x) / 2), y: snap((current.from.y + current.to.y) / 2) },\n // A link between ports that declare a direction is drawn with one.\n ends: isDirected(scene, nodeRegistry, current.source, target) ? { end: 'arrow' } : undefined,\n });\n projection.apply({\n kind: 'link',\n link: { ...link, layer: activeLayer(scene, registry.get(atoms.layer)) },\n });\n // What the user just made is what they act on next (style, delete): the link, and the node\n // the drop created with it.\n select(created ? [link.id, created.id] : [link.id]);\n }\n break;\n }\n case 'create': {\n const node = createdNode(current, createId(current.type));\n if (!node) {\n break;\n }\n commitCreated(node);\n setTool({ kind: 'select' });\n break;\n }\n case 'point': {\n projection.apply({ kind: 'update', id: current.id, values: { points: current.points } });\n break;\n }\n case 'end': {\n // Dropped on a node it attaches there; dropped on empty canvas it becomes a free end at that point.\n const end: Endpoint = current.target ?? { point: current.to };\n projection.apply({ kind: 'update', id: current.id, values: { [current.end]: end } });\n break;\n }\n case 'pan':\n break;\n }\n },\n [\n registry,\n atoms.drag,\n updateHover,\n toScene,\n atoms.selection,\n setDrag,\n scene,\n select,\n projection,\n capabilities.create,\n snap,\n settle,\n nodeRegistry,\n setTool,\n createdNode,\n commitCreated,\n addNode,\n minor,\n cell,\n snapMinor,\n activate,\n ],\n );\n\n return {\n onBackgroundPointerDown,\n onPointerMove,\n onPointerUp,\n onContextMenu,\n cancelDrag,\n updateHover,\n\n onNodePointerDown,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n\n setTool,\n setDrag,\n toScene,\n removePoint,\n\n createdNode,\n commitCreated,\n\n menu,\n closeMenu,\n menuAnchorRef,\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { type Camera, type ElementId, type Size } from '../../model/types.ts';\nimport { animateCamera } from '../../utils/camera.ts';\n\n/** Quiet time after the last wheel step before the canvas takes pointer events again. */\nconst NAVIGATION_SETTLE_MS = 150;\n\nexport type SceneCamera = {\n /** Write the camera, from a value or from its predecessor. */\n setCamera: (next: Camera | ((camera: Camera) => Camera)) => void;\n /** Animate to `target`, calling `done` when the last frame lands; `duration` fixes its length in ms. */\n animateTo: (target: Camera, done?: () => void, duration?: number) => void;\n /** Abandon an animation in flight, leaving the camera where it reached. */\n cancelAnimation: () => void;\n /** The camera is moving on its own, so the canvas ignores the pointer. */\n navigating: boolean;\n /** The same, read at call time: a handler closes over the render's value, which is a frame behind. */\n isNavigating: () => boolean;\n /** Whether an animation is in flight, read at call time for the same reason. */\n isAnimating: () => boolean;\n setNavigation: (active: boolean) => void;\n /** Navigation that ends on its own: active until no further step arrives for a beat. */\n touchNavigation: () => void;\n /** The portal a drill-in is zooming into, while it is. */\n opening: ElementId | undefined;\n setOpening: (id: ElementId | undefined) => void;\n};\n\n/**\n * The camera and the animations that move it. While the camera moves on its own — a wheel zoom, a pan,\n * a drill-in — the canvas ignores the pointer: nothing under it is where it will be, so hover and\n * presses would land on passing content.\n */\nexport const useSceneCamera = (\n registry: ReturnType<typeof useRegistry>,\n atoms: SceneViewAtoms,\n viewport: Size,\n): SceneCamera => {\n const setCamera = useCallback(\n (next: Camera | ((camera: Camera) => Camera)) => {\n registry.set(atoms.camera, typeof next === 'function' ? next(registry.get(atoms.camera)) : next);\n },\n [registry, atoms.camera],\n );\n\n // Cleared as well as called: a cancelled frame never runs the completion callback that would.\n const cancelRef = useRef<() => void>(undefined);\n const [opening, setOpening] = useState<ElementId>();\n const [navigating, setNavigating] = useState(false);\n const navigatingRef = useRef(false);\n const settleRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n const setNavigation = useCallback(\n (active: boolean) => {\n clearTimeout(settleRef.current);\n settleRef.current = undefined;\n if (navigatingRef.current !== active) {\n navigatingRef.current = active;\n setNavigating(active);\n if (active) {\n registry.set(atoms.hover, undefined);\n }\n }\n },\n [registry, atoms.hover],\n );\n\n const touchNavigation = useCallback(() => {\n setNavigation(true);\n settleRef.current = setTimeout(() => setNavigation(false), NAVIGATION_SETTLE_MS);\n }, [setNavigation]);\n useEffect(() => () => clearTimeout(settleRef.current), []);\n\n const cancelAnimation = useCallback(() => {\n if (cancelRef.current) {\n cancelRef.current();\n cancelRef.current = undefined;\n setNavigation(false);\n }\n setOpening(undefined);\n }, [setNavigation]);\n\n const animateTo = useCallback(\n (target: Camera, done?: () => void, duration?: number) => {\n cancelAnimation();\n setNavigation(true);\n cancelRef.current = animateCamera(\n registry.get(atoms.camera),\n target,\n viewport,\n setCamera,\n () => {\n cancelRef.current = undefined;\n setNavigation(false);\n done?.();\n },\n duration,\n );\n },\n [registry, atoms.camera, viewport, setCamera, cancelAnimation, setNavigation],\n );\n\n const isNavigating = useCallback(() => navigatingRef.current, []);\n const isAnimating = useCallback(() => cancelRef.current !== undefined, []);\n\n return {\n setCamera,\n animateTo,\n cancelAnimation,\n navigating,\n isNavigating,\n isAnimating,\n setNavigation,\n touchNavigation,\n opening,\n setOpening,\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type Capabilities, type ElementId, type Point, type Scene } from '../../model/types.ts';\nimport { clipboardBounds, copySelection, pasteFragment } from '../../utils/clipboard.ts';\nimport { activeLayer } from '../../utils/layers.ts';\nimport { between, topZ } from '../../utils/order.ts';\nimport { type SceneSnap } from './useSceneSnap.ts';\n\nexport type UseSceneClipboardOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n scene: Scene;\n projection: Projection;\n capabilities: Capabilities;\n select: (ids: Iterable<ElementId>) => void;\n createId: (prefix: string) => string;\n} & Pick<SceneSnap, 'major' | 'snap'>;\n\nexport type SceneClipboard = {\n /** Whether anything was copied: a cut only deletes once the fragment is safely in the clipboard. */\n copy: () => boolean;\n cut: () => void;\n paste: (at?: Point) => void;\n};\n\n/**\n * Copy, cut and paste over the scene's own clipboard atom rather than the system one, so a fragment keeps\n * its links and z keys. Pasting repeatedly walks the copy away from the original instead of stacking it.\n */\nexport const useSceneClipboard = ({\n registry,\n atoms,\n scene,\n projection,\n capabilities,\n select,\n createId,\n major,\n snap,\n}: UseSceneClipboardOptions): SceneClipboard => {\n const copy = useCallback(() => {\n const fragment = copySelection(scene, registry.get(atoms.selection));\n if (fragment) {\n registry.set(atoms.clipboard, fragment);\n }\n return fragment !== undefined;\n }, [scene, registry, atoms.selection, atoms.clipboard]);\n\n const cut = useCallback(() => {\n if (!capabilities.delete || !copy()) {\n return;\n }\n projection.apply({ kind: 'delete', ids: [...registry.get(atoms.selection)] });\n select([]);\n }, [capabilities.delete, copy, projection, registry, atoms.selection, select]);\n\n /** Paste one grid step further each time, or with the fragment's top-left at `at` when given. */\n const paste = useCallback(\n (at?: Point) => {\n const fragment = registry.get(atoms.clipboard);\n if (!fragment || !capabilities.create) {\n return;\n }\n const bounds = clipboardBounds(fragment);\n const step = major * (fragment.pasted + 1);\n const offset = at && bounds ? { x: snap(at.x) - bounds.x, y: snap(at.y) - bounds.y } : { x: step, y: step };\n let nodeZ = topZ(Object.values(scene.nodes));\n let linkZ = topZ(Object.values(scene.links));\n const { intent, ids } = pasteFragment({\n clipboard: fragment,\n offset,\n createId,\n nodeZ: () => (nodeZ = between(nodeZ, undefined)),\n linkZ: () => (linkZ = between(linkZ, undefined)),\n layer: activeLayer(scene, registry.get(atoms.layer)),\n });\n projection.apply(intent);\n registry.set(atoms.clipboard, { ...fragment, pasted: at ? fragment.pasted : fragment.pasted + 1 });\n select(ids);\n },\n [\n registry,\n atoms.clipboard,\n capabilities.create,\n major,\n snap,\n scene.nodes,\n scene.links,\n scene,\n atoms.layer,\n projection,\n select,\n createId,\n ],\n );\n\n return { copy, cut, paste };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type KeyboardEvent, useCallback } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { isToolKey, keyAction } from '../../model/keys.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type LinkRegistry, type NodeRegistry } from '../../model/registry.ts';\nimport { type Bounds, type Capabilities, type ElementId, type Scene, type Size } from '../../model/types.ts';\nimport { NOMINAL_ZOOM, fitBounds, zoomAt } from '../../utils/camera.ts';\nimport { unionBounds } from '../../utils/hit.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\nimport { toolForKey } from '../Palette/Palette.tsx';\nimport { type PointerMachine } from './usePointerMachine.ts';\nimport { type SceneCamera } from './useSceneCamera.ts';\nimport { type SceneClipboard } from './useSceneClipboard.ts';\nimport { type SceneNavigation } from './useSceneNavigation.ts';\nimport { type SceneSnap } from './useSceneSnap.ts';\n\nexport type UseSceneKeysOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n scene: Scene;\n nodeRegistry: NodeRegistry;\n linkRegistry: LinkRegistry;\n projection: Projection;\n capabilities: Capabilities;\n viewport: Size;\n /** The current scene's frame, which `fit` frames. */\n bounds: Bounds;\n /** Least gap between that frame and a viewport edge when fitting, in scene units. */\n inset: number;\n /** Minor grid spacing in scene px; an arrow nudges by it. */\n grid: number;\n select: (ids: Iterable<ElementId>) => void;\n toggleSnap: () => void;\n toggleGuides: () => void;\n toggleLattice: () => void;\n toggleDebug: () => void;\n onUndo: () => void;\n onRedo: () => void;\n} & Pick<SceneCamera, 'animateTo'> &\n Pick<SceneNavigation, 'drillIn' | 'drillOut' | 'goHistory'> &\n Pick<SceneSnap, 'major'> &\n Pick<SceneClipboard, 'copy' | 'cut' | 'paste'> &\n Pick<PointerMachine, 'cancelDrag' | 'removePoint' | 'setTool'>;\n\n/**\n * What a chord does in the state the view is in. Every chord itself comes from `KEY_BINDINGS`, so this\n * decides only what the action means here — Escape backs out of whatever is innermost (a drag, then a\n * selected control point, then the selection, then the scene itself), and Delete reads the same way.\n */\nexport const useSceneKeys = ({\n registry,\n atoms,\n scene,\n nodeRegistry,\n linkRegistry,\n projection,\n capabilities,\n viewport,\n bounds,\n inset,\n grid,\n select,\n toggleSnap,\n toggleGuides,\n toggleLattice,\n toggleDebug,\n onUndo,\n onRedo,\n animateTo,\n drillIn,\n drillOut,\n goHistory,\n major,\n copy,\n cut,\n paste,\n cancelDrag,\n removePoint,\n setTool,\n}: UseSceneKeysOptions): ((event: KeyboardEvent) => void) => {\n return useCallback(\n (event: KeyboardEvent) => {\n const selected = [...registry.get(atoms.selection)];\n const selectedNodes = selected.filter((id) => scene.nodes[id] !== undefined);\n const point = registry.get(atoms.point);\n const action = keyAction(event);\n switch (action) {\n case 'cancel':\n if (registry.get(atoms.drag)) {\n cancelDrag();\n } else if (point) {\n registry.set(atoms.point, undefined);\n } else if (selected.length > 0) {\n select([]);\n } else {\n drillOut();\n }\n break;\n case 'delete':\n if (point) {\n removePoint(point);\n } else if (selected.length > 0 && capabilities.delete) {\n projection.apply({ kind: 'delete', ids: selected });\n select([]);\n }\n break;\n case 'open': {\n const node = selected.length === 1 ? scene.nodes[selected[0]] : undefined;\n if (node && nodeDef(nodeRegistry, node)?.openable) {\n drillIn(node);\n }\n break;\n }\n case 'fit':\n animateTo(fitBounds(bounds, viewport, inset, NOMINAL_ZOOM));\n event.preventDefault();\n break;\n case 'fitSelection': {\n const union = unionBounds(selectedNodes.map((id) => nodeBounds(scene.nodes[id])));\n if (union) {\n animateTo(fitBounds(union, viewport, inset, NOMINAL_ZOOM));\n }\n break;\n }\n case 'zoomReset':\n animateTo(\n zoomAt(registry.get(atoms.camera), { x: viewport.width / 2, y: viewport.height / 2 }, NOMINAL_ZOOM),\n );\n break;\n case 'back':\n goHistory(-1);\n break;\n case 'forward':\n goHistory(1);\n break;\n case 'nudge': {\n if (selectedNodes.length === 0 || !capabilities.move) {\n break;\n }\n // Shift moves by a major cell rather than a minor one.\n const step = event.shiftKey ? major : grid;\n const delta = {\n x: event.key === 'ArrowLeft' ? -step : event.key === 'ArrowRight' ? step : 0,\n y: event.key === 'ArrowUp' ? -step : event.key === 'ArrowDown' ? step : 0,\n };\n projection.apply({ kind: 'move', ids: selectedNodes, delta });\n event.preventDefault();\n break;\n }\n case 'copy':\n copy();\n event.preventDefault();\n break;\n case 'cut':\n cut();\n event.preventDefault();\n break;\n case 'paste':\n paste();\n event.preventDefault();\n break;\n case 'undo':\n onUndo();\n event.preventDefault();\n break;\n case 'redo':\n onRedo();\n event.preventDefault();\n break;\n case 'selectAll':\n select([...Object.keys(scene.nodes), ...Object.keys(scene.links)]);\n event.preventDefault();\n break;\n case 'snap':\n toggleSnap();\n break;\n case 'guides':\n toggleGuides();\n break;\n case 'lattice':\n toggleLattice();\n break;\n case 'debug':\n toggleDebug();\n break;\n case undefined:\n if (isToolKey(event)) {\n const next = toolForKey(nodeRegistry, linkRegistry, capabilities, event.key);\n if (next) {\n setTool(next);\n }\n }\n break;\n }\n },\n [\n registry,\n atoms.selection,\n atoms.drag,\n atoms.camera,\n atoms.point,\n removePoint,\n cancelDrag,\n select,\n drillOut,\n drillIn,\n capabilities,\n projection,\n scene,\n nodeRegistry,\n linkRegistry,\n animateTo,\n bounds,\n viewport,\n inset,\n goHistory,\n grid,\n major,\n setTool,\n toggleSnap,\n toggleGuides,\n toggleLattice,\n toggleDebug,\n onUndo,\n onRedo,\n copy,\n cut,\n paste,\n ],\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type Drag, type HistoryEntry, type SceneViewAtoms } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type NodeRegistry } from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Bounds,\n type Camera,\n type ElementId,\n type Node,\n type Scene,\n type SceneId,\n type Size,\n isFrameNode,\n} from '../../model/types.ts';\nimport {\n DRILL_ANIMATION_MS,\n NOMINAL_ZOOM,\n coverage,\n enterPortal,\n exitPortal,\n fitBounds,\n portalFrame,\n} from '../../utils/camera.ts';\nimport { contentBounds } from '../../utils/hit.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\nimport { type SceneCamera } from './useSceneCamera.ts';\n\n/** An empty root has nothing to frame: fitting it centres the origin at true size. */\nconst EMPTY_FRAME: Bounds = { x: 0, y: 0, width: 0, height: 0 };\n\n/** The shapes of a scene, unpadded: what Fit frames, with its inset as the only margin. */\nconst fitFrame = (scene: Scene): Bounds => contentBounds(scene, 0, 1) ?? EMPTY_FRAME;\n\n/** A portal covering this much of the viewport becomes the root; a root below this yields to its parent. */\nconst AUTO_ENTER = 0.85;\nconst AUTO_EXIT = 0.3;\nconst AUTO_DRILL_MS = 150;\n\nexport type UseSceneNavigationOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n nodeRegistry: NodeRegistry;\n store: SceneStore;\n scenes: Record<SceneId, Scene>;\n scene: Scene;\n path: SceneId[];\n camera: Camera;\n viewport: Size;\n /** Least gap between the scene's frame and a viewport edge when fitting, in scene units. */\n inset: number;\n drag: Drag | undefined;\n /** Set once the user takes the camera over, which stops the view re-fitting itself. */\n interactedRef: MutableRefObject<boolean>;\n select: (ids: Iterable<ElementId>) => void;\n} & Pick<SceneCamera, 'animateTo' | 'setCamera' | 'setOpening' | 'isAnimating'>;\n\nexport type SceneNavigation = {\n nameOf: (id: SceneId) => string;\n /** The portal in `parent` that shows `childId`, if any. */\n portalTo: (parentId: SceneId | undefined, childId: SceneId) => Node | undefined;\n /** What fitting the scene at the head of `path` shows: its parent portal's frame, or its content. */\n frameOf: (path: SceneId[], scene: Scene) => Bounds;\n /** The current scene's frame, held for the visit rather than re-derived as its content changes. */\n bounds: Bounds;\n /** What Fit shows: the current scene's shapes themselves (the margin is the fit's own inset). */\n fitTarget: Bounds;\n pushHistory: (entry: HistoryEntry) => void;\n /** Drills into a frame's scene, or opens the node in the host when its type has `hostOpen` for it. */\n drillIn: (portal: Node, animate?: boolean) => void;\n drillOut: (levels?: number, animate?: boolean) => void;\n goHistory: (offset: number) => void;\n};\n\n/**\n * Moving between scenes: the path, the frame each level is seen through, and the drill in and out that\n * swap the root under a camera transition. Auto-drill lives here too, since it is the same two moves\n * driven by how much of the viewport a portal covers rather than by a gesture.\n */\nexport const useSceneNavigation = ({\n registry,\n atoms,\n nodeRegistry,\n scenes,\n scene,\n path,\n camera,\n viewport,\n inset,\n drag,\n interactedRef,\n select,\n animateTo,\n setCamera,\n setOpening,\n isAnimating,\n}: UseSceneNavigationOptions): SceneNavigation => {\n const nameOf = useCallback((id: SceneId) => scenes[id]?.name ?? id, [scenes]);\n\n const portalTo = useCallback(\n (parentId: SceneId | undefined, childId: SceneId): Node | undefined => {\n const parent = parentId ? scenes[parentId] : undefined;\n return parent\n ? Object.values(parent.nodes).find((node) => isFrameNode(node) && node.scene === childId)\n : undefined;\n },\n [scenes],\n );\n\n const frameOf = useCallback(\n (scenePath: SceneId[], current: Scene): Bounds => {\n const portal = portalTo(scenePath[scenePath.length - 2], current.id);\n return portal ? portalFrame(portal, contentBounds(current)) : (contentBounds(current) ?? EMPTY_FRAME);\n },\n [portalTo],\n );\n\n // A scene entered through a portal keeps the frame it arrived with. Deriving it from the content on\n // every edit moves the child under the user as they work, and maps a drill-out differently from the\n // drill-in that opened it; the root has no portal to sit in, so its bounds stay derived.\n const frameRef = useRef<{ key: string; frame: Bounds } | undefined>(undefined);\n const bounds = useMemo(() => {\n if (path.length < 2) {\n frameRef.current = undefined;\n return frameOf(path, scene);\n }\n const key = path.join(' ');\n if (frameRef.current?.key !== key) {\n frameRef.current = { key, frame: frameOf(path, scene) };\n }\n return frameRef.current.frame;\n }, [frameOf, path, scene]);\n\n const fitTarget = useMemo(() => fitFrame(scene), [scene]);\n\n const pushHistory = useCallback(\n (entry: HistoryEntry) => {\n const history = registry.get(atoms.history);\n const entries = [...history.entries.slice(0, history.index + 1), entry];\n registry.set(atoms.history, { entries, index: entries.length - 1 });\n },\n [registry, atoms.history],\n );\n\n const hostOpen = useCallback((node: Node) => nodeDef(nodeRegistry, node)?.hostOpen?.(node), [nodeRegistry]);\n\n const drillIn = useCallback(\n (portal: Node, animate = true) => {\n const open = hostOpen(portal);\n if (open) {\n open();\n return;\n }\n const child = isFrameNode(portal) ? scenes[portal.scene] : undefined;\n if (!child) {\n return;\n }\n interactedRef.current = true;\n // The zoom is into the child, so the portal's selection outline and ports go before it starts.\n select([]);\n registry.set(atoms.hover, undefined);\n registry.set(atoms.editing, undefined);\n const childBounds = portalFrame(portal, contentBounds(child));\n const swap = (next: Camera) => {\n const entered = enterPortal(next, portal, childBounds);\n registry.set(atoms.path, [...registry.get(atoms.path), child.id]);\n setCamera(entered);\n setOpening(undefined);\n pushHistory({ path: registry.get(atoms.path), camera: entered });\n };\n if (animate) {\n // Land the child where fitting it would, margin and all, but never past 1:1, so its text lands at\n // its natural size rather than magnified to fill the view. Expressed in the child's own space and\n // mapped back out, so the zoom ends exactly where the swap puts the camera.\n const target = exitPortal(fitBounds(fitFrame(child), viewport, inset, NOMINAL_ZOOM), portal, childBounds);\n animateTo(target, () => swap(target), DRILL_ANIMATION_MS);\n setOpening(portal.id);\n } else {\n swap(registry.get(atoms.camera));\n }\n },\n [\n hostOpen,\n scenes,\n registry,\n atoms.path,\n atoms.camera,\n atoms.hover,\n atoms.editing,\n viewport,\n inset,\n interactedRef,\n animateTo,\n setCamera,\n setOpening,\n select,\n pushHistory,\n ],\n );\n\n const drillOut = useCallback(\n (levels = 1, animate = true) => {\n const current = registry.get(atoms.path);\n if (current.length < 2 || levels < 1) {\n return;\n }\n let next = current;\n let exited = registry.get(atoms.camera);\n for (let level = 0; level < levels && next.length > 1; level++) {\n const child = scenes[next[next.length - 1]];\n const parent = scenes[next[next.length - 2]];\n const portal = parent\n ? Object.values(parent.nodes).find((node) => isFrameNode(node) && node.scene === child?.id)\n : undefined;\n if (!child || !portal) {\n break;\n }\n // The level being left exits through the frame it was entered with, so the camera lands where\n // the drill-in took it from however the child was edited in between.\n exited = exitPortal(exited, portal, level === 0 ? bounds : portalFrame(portal, contentBounds(child)));\n next = next.slice(0, -1);\n }\n registry.set(atoms.path, next);\n select([]);\n setCamera(exited);\n const parent = scenes[next[next.length - 1]];\n if (animate && parent) {\n animateTo(fitBounds(fitFrame(parent), viewport, inset, NOMINAL_ZOOM), undefined, DRILL_ANIMATION_MS);\n }\n pushHistory({ path: next, camera: exited });\n },\n [\n registry,\n atoms.path,\n atoms.camera,\n scenes,\n viewport,\n inset,\n animateTo,\n setCamera,\n select,\n pushHistory,\n frameOf,\n bounds,\n ],\n );\n\n const goHistory = useCallback(\n (offset: number) => {\n const history = registry.get(atoms.history);\n const index = history.index + offset;\n const entry = history.entries[index];\n if (!entry) {\n return;\n }\n registry.set(atoms.history, { ...history, index });\n registry.set(atoms.path, entry.path);\n select([]);\n animateTo(entry.camera);\n },\n [registry, atoms.history, atoms.path, select, animateTo],\n );\n\n // Auto drill: a portal filling the viewport becomes the root; a root shrunk well below its size on\n // arrival yields to its parent. Arrival is the history entry for this path, so a child capped at 1:1\n // (or a frame that shrinks under a stationary camera) is measured against itself rather than an\n // absolute coverage.\n useEffect(() => {\n if (isAnimating() || drag || viewport.width === 0) {\n return;\n }\n const timer = setTimeout(() => {\n const portal = Object.values(scene.nodes).find(\n (node) => isFrameNode(node) && !hostOpen(node) && coverage(camera, nodeBounds(node), viewport) >= AUTO_ENTER,\n );\n if (portal) {\n drillIn(portal, false);\n } else if (path.length > 1) {\n const history = registry.get(atoms.history);\n const arrival = history.entries[history.index];\n const arrived =\n arrival && arrival.path.length === path.length && arrival.path.every((id, index) => id === path[index]);\n const reference = arrived ? coverage(arrival.camera, bounds, viewport) : 1;\n if (coverage(camera, bounds, viewport) < AUTO_EXIT * reference) {\n drillOut(1, false);\n }\n }\n }, AUTO_DRILL_MS);\n return () => clearTimeout(timer);\n }, [camera, scene, bounds, path, viewport, drag, hostOpen, drillIn, drillOut, registry, atoms.history, isAnimating]);\n\n return { nameOf, portalTo, frameOf, bounds, fitTarget, pushHistory, drillIn, drillOut, goHistory };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback, useMemo } from 'react';\n\nimport { MAJOR_GRID_RATIO } from '../../model/types.ts';\n\n/**\n * Grid levels a fourfold apart, from a quarter of the minor grid to far past the major one, so the levels\n * on screen depend on the zoom alone: a child scene seen at a quarter scale draws the same lines as its\n * parent, and a far zoom-out still shows a grid.\n */\nexport const GRID_LEVELS = [1 / MAJOR_GRID_RATIO, 1, MAJOR_GRID_RATIO, MAJOR_GRID_RATIO ** 2, MAJOR_GRID_RATIO ** 3];\n\n/** Screen px a cell must cover to be drawn, and the most lines a level may draw before it is dropped. */\nexport const GRID_RANGE: [number, number] = [6, 2048];\n\nexport type SceneSnap = {\n /** The finest level drawn, in scene units; moves and control points land on it. */\n minor: number;\n /** `MAJOR_GRID_RATIO` of those; creation and resizing land on it. */\n major: number;\n snap: (value: number) => number;\n snapMinor: (value: number) => number;\n};\n\n/**\n * What a gesture lands on: the grid levels actually drawn, which is what the user is aiming at. A level\n * fixed in scene units parts company with the lines as soon as the zoom moves — `Grid` keeps a level only\n * while its cells are legible on screen, so far enough in the drawn lines are finer than the snap and far\n * enough out (a nested scene, entered at a fraction of the parent's zoom) they are coarser and the snap\n * stops landing on anything visible. Reading the level back from the same rule keeps the two the same by\n * construction.\n */\nexport const useSceneSnap = (grid: number, zoom: number, enabled: boolean): SceneSnap => {\n const minor = useMemo(() => {\n const levels = GRID_LEVELS.map((ratio) => ratio * grid);\n return levels.find((size) => size * zoom >= GRID_RANGE[0]) ?? levels[levels.length - 1];\n }, [grid, zoom]);\n const major = minor * MAJOR_GRID_RATIO;\n\n const snap = useCallback((value: number) => (enabled ? Math.round(value / major) * major : value), [enabled, major]);\n // Moving is finer than creating or resizing: a placed node keeps its major-grid size and edges land on\n // minor lines, so ports (drawn at the nearest major line) stay aligned while placement is not coarse.\n const snapMinor = useCallback(\n (value: number) => (enabled ? Math.round(value / minor) * minor : value),\n [enabled, minor],\n );\n\n return { minor, major, snap, snapMinor };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Root view of the scene engine (§6–§8): owns the camera, the scene path, selection and the pointer\n// state machine; renders the current scene through `SceneLayer` under one CSS transform and drills\n// in and out of portals with a camera transition then a root swap. Every model change goes through\n// the projection as an intent; the view never writes coordinates itself (decision 11).\n//\n\nimport { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport React, { type ReactNode, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';\n\nimport * as Menu from '@dxos/react-ui/Menu';\nimport type * as Util from '@dxos/react-ui/Util';\nimport * as VirtualAnchor from '@dxos/react-ui/VirtualAnchor';\nimport { mx } from '@dxos/ui-theme';\n\nimport { SCENE_OVERLAY_ATTRIBUTE, useRegistry, useSceneProjection, useViewport, useWheel } from '../../hooks/index.ts';\nimport { type Drag, type PanelMode, type SceneViewAtoms, createSceneViewAtoms, isMoving } from '../../model/atoms.ts';\nimport { keyAction } from '../../model/keys.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport {\n type FreehandProjectionOptions,\n type Projection,\n readonlyCapabilities,\n reduceIntent,\n} from '../../model/projection.ts';\nimport {\n type LinkRegistry,\n type NodeRegistry,\n defaultLinkRegistry,\n defaultNodeRegistry,\n} from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Bounds,\n type Camera,\n DEFAULT_GRID,\n type ElementId,\n type Endpoint,\n type Intent,\n type Layer,\n type LayerId,\n type LinkId,\n MAJOR_GRID_RATIO,\n type Node,\n type NodeType,\n type Point,\n type Scene,\n type SceneId,\n isFrameNode,\n isPointEndpoint,\n} from '../../model/types.ts';\nimport {\n MIN_ZOOM,\n NOMINAL_ZOOM,\n cameraTransform,\n fitBounds,\n layerOpacity,\n panBy,\n sceneToScreen,\n screenToScene,\n zoomAt,\n} from '../../utils/camera.ts';\nimport { duplicateSelection } from '../../utils/clipboard.ts';\nimport { nodeDragType } from '../../utils/dnd.ts';\nimport { groupIntoScene } from '../../utils/group.ts';\nimport { boundsFromPoints, hitTest } from '../../utils/hit.ts';\nimport {\n activeLayer,\n createLayer,\n mergeLayersIntent,\n moveLayer,\n sceneLayers,\n visibleScene,\n} from '../../utils/layers.ts';\nimport { topZ } from '../../utils/order.ts';\nimport { type PartKey, partText, partValues } from '../../utils/parts.ts';\nimport { sceneOptions } from '../../utils/scenes.ts';\nimport { createLink, nodeBounds, nominalSize } from '../../utils/shapes.ts';\nimport { recordScenes, redo, undo } from '../../utils/undo.ts';\nimport { About, type AboutStat } from '../About/About.tsx';\nimport { ControlFrame } from '../ControlFrame/ControlFrame.tsx';\nimport { GridComponent } from '../Grid/index.ts';\nimport { LatticeGrid } from '../LatticeGrid/index.ts';\nimport { LayersPanel } from '../Layers/Layers.tsx';\nimport { Palette } from '../Palette/Palette.tsx';\nimport { Properties, type PropertiesProps } from '../Properties/Properties.tsx';\nimport { type ElementHandlers, MAX_LIVE_DEPTH, SceneLayer } from '../SceneLayer/SceneLayer.tsx';\nimport { ActionToolbar, CameraToolbar, NavigationToolbar, type ToolbarActions } from '../Toolbar/Toolbar.tsx';\nimport { Dock, DockProvider, type DockSection, useDockSection } from './Dock.tsx';\nimport { SceneViewProvider, useSceneViewContext } from './SceneViewContext.ts';\nimport { PREVIEW_NODE_ID, createId, isLinkDrawn, usePointerMachine } from './usePointerMachine.ts';\nimport { useSceneCamera } from './useSceneCamera.ts';\nimport { useSceneClipboard } from './useSceneClipboard.ts';\nimport { useSceneKeys } from './useSceneKeys.ts';\nimport { useSceneNavigation } from './useSceneNavigation.ts';\nimport { GRID_LEVELS, GRID_RANGE, useSceneSnap } from './useSceneSnap.ts';\n\n/** Major cells between the scene's frame and the viewport edge when fitting; `margin` overrides it. */\nconst DEFAULT_MARGIN = 2;\n/** Quiet time after the camera's last move before `onCameraChange` reports it. */\nconst CAMERA_SETTLE_MS = 300;\n/** Zoom factor of one toolbar step. */\nconst ZOOM_STEP = 1.25;\n/** How long a link stays hovered after the pointer leaves it, so the pointer can reach its end handles. */\nconst LINK_HOVER_GRACE_MS = 150;\n\n/** How long a move's pointer rests before the shapes snap to where they will land. */\nconst SETTLE_MS = 200;\n\n/** Where the properties and layers panels float: the top right, one at a time (properties with a selection). */\nconst PANEL_CLASSES = 'absolute top-2 right-2 w-80 h-auto max-h-[calc(100%-1rem)]';\n\n/** The link drawn as a preview during a drag; it never reaches the model. */\nconst PREVIEW_LINK_ID = 'preview-link';\n\nexport type SceneViewRootProps = Util.ThemedClassName<{\n store: SceneStore;\n root: SceneId;\n nodes?: NodeRegistry;\n links?: LinkRegistry;\n /** Projection per scene; freehand (identity) by default. */\n createProjection?: (options: FreehandProjectionOptions) => Projection;\n /** A host-owned projection instead, shared with the host's panels (see `useSceneProjection`). */\n projection?: Projection;\n /** Externally owned view state, e.g. to drive two views or persist the camera. */\n atoms?: SceneViewAtoms;\n /** Where the camera starts on the root scene, e.g. as last left; the scene is fitted when unset. */\n initialCamera?: Camera;\n /** Called once the camera settles on the root scene, so a host can persist it. */\n onCameraChange?: (camera: Camera) => void;\n /** Minor grid spacing in scene px; moves snap to it, creation and resizing to the major grid, `MAJOR_GRID_RATIO` times it. */\n grid?: number;\n /** Least gap between the scene's frame and each viewport edge when fitting, in major cells. */\n margin?: number;\n /**\n * Look, select and navigate only: no gesture or key reaches the model, and no handle or port is drawn,\n * whatever the projection would allow.\n */\n readonly?: boolean;\n /** Where the properties and layers panels sit: docked in a column beside the canvas, or floating over it. */\n panels?: PanelMode;\n children?: ReactNode;\n}>;\n\nconst SceneViewRoot = ({\n classNames,\n store,\n root,\n nodes: nodeRegistry = defaultNodeRegistry,\n links: linkRegistry = defaultLinkRegistry,\n createProjection,\n projection: projectionProp,\n atoms: atomsProp,\n initialCamera,\n onCameraChange,\n grid = DEFAULT_GRID,\n margin = DEFAULT_MARGIN,\n readonly = false,\n panels = 'docked',\n children,\n}: SceneViewRootProps) => {\n const registry = useRegistry();\n const atoms = useMemo(() => atomsProp ?? createSceneViewAtoms(root), [atomsProp, root]);\n const rootRef = useRef<HTMLDivElement>(null);\n const viewport = useViewport(rootRef);\n\n const path = useAtomValue(atoms.path);\n const projection = useSceneProjection({ store, atoms, createProjection, projection: projectionProp });\n const scene = useAtomValue(projection.scene);\n const visible = useMemo(() => visibleScene(scene), [scene]);\n const scenes = useAtomValue(store.scenes);\n const camera = useAtomValue(atoms.camera);\n const selection = useAtomValue(atoms.selection);\n const hover = useAtomValue(atoms.hover);\n const selectedPoint = useAtomValue(atoms.point);\n const tool = useAtomValue(atoms.tool);\n const snapEnabled = useAtomValue(atoms.snap);\n // The margin is in major cells, taken from the model's grid rather than the level currently drawn,\n // so a fit puts the same gap around the scene whatever the zoom.\n const inset = margin * grid * MAJOR_GRID_RATIO;\n // A new node's default size is nominal: major cells of the model's grid, not of the level drawn at this zoom.\n const cell = grid * MAJOR_GRID_RATIO;\n\n const drag = useAtomValue(atoms.drag);\n const undoState = useAtomValue(atoms.undo);\n const clipboard = useAtomValue(atoms.clipboard);\n const editing = useAtomValue(atoms.editing);\n const active = useAtomValue(atoms.active);\n // A node's content stays live only while the node is the selection; selecting anything else makes it inert again.\n useEffect(() => {\n if (active !== undefined && (selection.size !== 1 || !selection.has(active))) {\n registry.set(atoms.active, undefined);\n }\n }, [active, selection, registry, atoms.active]);\n const debug = useAtomValue(atoms.debug);\n const guides = useAtomValue(atoms.guides);\n const latticeOn = useAtomValue(atoms.lattice);\n const sceneId = path[path.length - 1];\n const canUndo = !readonly && undoState.key === sceneId && undoState.past.length > 0;\n const canRedo = !readonly && undoState.key === sceneId && undoState.future.length > 0;\n\n // Every gesture, key and control is gated on these, so a read-only view is the projection with nothing allowed.\n const capabilities = readonly ? readonlyCapabilities : projection.capabilities;\n\n //\n // Camera.\n //\n\n const {\n setCamera,\n animateTo,\n cancelAnimation,\n navigating,\n isNavigating,\n isAnimating,\n setNavigation,\n touchNavigation,\n opening,\n setOpening,\n } = useSceneCamera(registry, atoms, viewport);\n\n // Keep the scene fitted while the viewport settles, until the user takes the camera over. A layout\n // effect, so the fit lands before the first paint instead of one frame after it.\n // A restored camera counts as taken over, so the fit leaves it where it was.\n const interactedRef = useRef(initialCamera !== undefined);\n\n // Read-only, nothing is selected: a selection only exists to be edited.\n const select = useCallback(\n (ids: Iterable<ElementId>) => {\n registry.set(atoms.selection, new Set(readonly ? [] : ids));\n registry.set(atoms.point, undefined);\n },\n [registry, atoms.selection, atoms.point, readonly],\n );\n useEffect(() => {\n if (readonly) {\n select([]);\n }\n }, [readonly, select]);\n\n const { nameOf, portalTo, bounds, fitTarget, pushHistory, drillIn, drillOut, goHistory } = useSceneNavigation({\n registry,\n atoms,\n nodeRegistry,\n store,\n scenes,\n scene,\n path,\n camera,\n viewport,\n inset,\n drag,\n interactedRef,\n select,\n animateTo,\n setCamera,\n setOpening,\n isAnimating,\n });\n\n const measured = viewport.width > 0 && viewport.height > 0;\n useLayoutEffect(() => {\n if (initialCamera) {\n setCamera(initialCamera);\n }\n // Only the camera the view opened with is restored; later values are the host echoing ours back.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [setCamera]);\n useLayoutEffect(() => {\n if (!interactedRef.current && measured) {\n setCamera(fitBounds(fitTarget, viewport, inset, NOMINAL_ZOOM));\n }\n }, [measured, viewport, fitTarget, inset, setCamera]);\n\n // Reported after a quiet beat, so a wheel gesture or an animation is persisted once, where it ends.\n const atRoot = path.length === 1;\n useEffect(() => {\n if (!onCameraChange || !atRoot || !interactedRef.current) {\n return;\n }\n const timeout = setTimeout(() => onCameraChange(camera), CAMERA_SETTLE_MS);\n return () => clearTimeout(timeout);\n }, [onCameraChange, atRoot, camera]);\n\n useWheel(\n rootRef,\n useCallback(\n (event, pointer) => {\n interactedRef.current = true;\n cancelAnimation();\n touchNavigation();\n if (event.ctrlKey || event.metaKey) {\n setCamera((camera) => zoomAt(camera, pointer, camera.zoom * Math.exp(-event.deltaY * 0.01)));\n } else {\n setCamera((camera) => panBy(camera, { x: -event.deltaX / camera.zoom, y: -event.deltaY / camera.zoom }));\n }\n },\n [setCamera, cancelAnimation, touchNavigation],\n ),\n );\n\n //\n // Navigation.\n //\n\n // Undo restores a whole model snapshot, so the selection may name elements that no longer exist.\n const onUndo = useCallback(() => {\n if (!readonly && undo(projection, registry, atoms.undo, sceneId, store)) {\n select([]);\n }\n }, [readonly, projection, registry, atoms.undo, sceneId, store, select]);\n const onRedo = useCallback(() => {\n if (!readonly && redo(projection, registry, atoms.undo, sceneId, store)) {\n select([]);\n }\n }, [readonly, projection, registry, atoms.undo, sceneId, store, select]);\n\n //\n // Pointer state machine.\n //\n\n const { minor, major, snap, snapMinor } = useSceneSnap(grid, camera.zoom, snapEnabled);\n const toggleSnap = useCallback(() => registry.set(atoms.snap, !registry.get(atoms.snap)), [registry, atoms.snap]);\n const toggleGuides = useCallback(\n () => registry.set(atoms.guides, !registry.get(atoms.guides)),\n [registry, atoms.guides],\n );\n const toggleLattice = useCallback(\n () => registry.set(atoms.lattice, !registry.get(atoms.lattice)),\n [registry, atoms.lattice],\n );\n const toggleDebug = useCallback(() => registry.set(atoms.debug, !registry.get(atoms.debug)), [registry, atoms.debug]);\n const {\n onBackgroundPointerDown,\n onPointerMove,\n onPointerUp,\n onContextMenu,\n cancelDrag,\n updateHover,\n onNodePointerDown,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n setTool,\n setDrag,\n toScene,\n removePoint,\n createdNode,\n commitCreated,\n menu,\n closeMenu,\n menuAnchorRef,\n } = usePointerMachine({\n registry,\n atoms,\n store,\n // A hidden layer's elements are not hit: gestures see the scene as drawn.\n scene: visible,\n nodeRegistry,\n projection,\n capabilities,\n camera,\n rootRef,\n interactedRef,\n select,\n setCamera,\n cancelAnimation,\n isNavigating,\n cell,\n minor,\n major,\n snap,\n snapMinor,\n });\n\n // A gesture begun before the view turned read-only is dropped, not committed on release.\n useEffect(() => {\n if (readonly) {\n cancelDrag();\n }\n }, [readonly, cancelDrag]);\n\n //\n // Clipboard.\n //\n\n const { copy, cut, paste } = useSceneClipboard({\n registry,\n atoms,\n scene,\n projection,\n capabilities,\n select,\n createId,\n major,\n snap,\n });\n\n const onSceneKey = useSceneKeys({\n registry,\n atoms,\n scene,\n nodeRegistry,\n linkRegistry,\n projection,\n capabilities,\n viewport,\n bounds: fitTarget,\n inset,\n grid,\n select,\n toggleSnap,\n toggleGuides,\n toggleLattice,\n toggleDebug,\n onUndo,\n onRedo,\n animateTo,\n drillIn,\n drillOut,\n goHistory,\n major,\n copy,\n cut,\n paste,\n cancelDrag,\n removePoint,\n setTool,\n });\n\n // Shortcuts belong to the canvas itself: keys typed into a control the view hosts (the properties\n // panel, a toolbar) bubble here too, and must not toggle debug or delete the selection.\n const onKeyDown = useCallback<typeof onSceneKey>(\n (event) => {\n if (event.target === event.currentTarget) {\n onSceneKey(event);\n } else if (keyAction(event) === 'cancel' && registry.get(atoms.active) !== undefined) {\n // Escape out of a node's live content leaves it inert and the node selected, as a click outside would not.\n registry.set(atoms.active, undefined);\n rootRef.current?.focus();\n }\n },\n [onSceneKey, registry, atoms.active],\n );\n\n //\n // Render.\n //\n\n /** The node a create gesture would land while one is in flight; the ghost and the frame both read it. */\n const createPreview = useMemo(\n () => (drag?.kind === 'create' ? createdNode(drag, PREVIEW_NODE_ID) : undefined),\n [drag, createdNode],\n );\n\n // Transient drag state is rendered by projecting it onto a copy, so links re-route while dragging and\n // a link being drawn or re-attached over a drop target looks exactly as it will once dropped. Geometry\n // previews pass through the projection's `constrain`, so a drag shows where the drop will land, and\n // `blocked` says when the drop would be refused (drawn as is, outlined in red).\n // A move follows the pointer while it moves; once it rests for `SETTLE_MS`, the shapes snap to where they will land.\n const moveRaw = drag?.kind === 'move' ? drag.raw : undefined;\n const [settled, setSettled] = useState(false);\n useEffect(() => {\n setSettled(false);\n if (!moveRaw) {\n return;\n }\n const timer = setTimeout(() => setSettled(true), SETTLE_MS);\n return () => clearTimeout(timer);\n }, [moveRaw?.x, moveRaw?.y]);\n\n const { displayScene, blocked, landing } = useMemo<{\n displayScene: Scene;\n blocked: boolean;\n /** Where a move in flight will land (snapped and constrained), while the nodes follow the pointer. */\n landing?: Bounds[];\n }>(() => {\n const preview = (intent: Intent) => {\n const constrained = projection.constrain ? projection.constrain(intent) : intent;\n return { displayScene: reduceIntent(scene, constrained ?? intent), blocked: constrained === undefined };\n };\n if (drag?.kind === 'move') {\n // A copy previews beside the originals, which stay; the drop mints the copies' real ids.\n const { ids, copy } = drag;\n const moveBy = (delta: Point): Intent => {\n let next = 0;\n const duplicate = copy\n ? duplicateSelection(scene, ids, delta, (prefix) => `${PREVIEW_NODE_ID}-${prefix}-${next++}`)\n : undefined;\n return duplicate ? duplicate.intent : { kind: 'move', ids, delta };\n };\n // The nodes follow the pointer smoothly; the frames they will snap to on the drop are drawn under them.\n const landed = preview(moveBy(drag.delta));\n const moved = copy\n ? Object.values(landed.displayScene.nodes).filter((node) => !scene.nodes[node.id])\n : ids.flatMap((id) => landed.displayScene.nodes[id] ?? []);\n return settled\n ? { displayScene: landed.displayScene, blocked: landed.blocked }\n : {\n displayScene: reduceIntent(scene, moveBy(drag.raw ?? drag.delta)),\n blocked: landed.blocked,\n // The landing is drawn only when the drop would be refused, the one thing following the pointer hides.\n landing: landed.blocked ? moved.map(nodeBounds) : undefined,\n };\n }\n if (drag?.kind === 'resize') {\n return preview({ kind: 'resize', id: drag.id, bounds: drag.bounds });\n }\n // A node being created previews as the type's own view inside its frame, whether drawn on the canvas\n // or dragged in from the palette (whose drag carries no image of its own).\n if (drag?.kind === 'create') {\n return createPreview ? preview({ kind: 'create', node: createPreview }) : { displayScene: scene, blocked: false };\n }\n if (drag?.kind === 'point') {\n return {\n displayScene: reduceIntent(scene, { kind: 'update', id: drag.id, values: { points: drag.points } }),\n blocked: false,\n };\n }\n // A link previews only once it has gone a grid cell, so a click with a link tool draws nothing.\n if (drag?.kind === 'link' && isLinkDrawn(drag, minor) && (drag.target || isPointEndpoint(drag.source))) {\n // A port drag previews once it reaches a target; a free-ended link previews as it will land.\n const link = createLink({\n type: drag.type,\n id: PREVIEW_LINK_ID,\n z: topZ(Object.values(scene.links)),\n source: drag.source,\n target: drag.target ?? { point: drag.to },\n midpoint: { x: (drag.from.x + drag.to.x) / 2, y: (drag.from.y + drag.to.y) / 2 },\n });\n return { displayScene: reduceIntent(scene, { kind: 'link', link }), blocked: false };\n }\n if (drag?.kind === 'end') {\n // The link is drawn as it will land: re-attached over a target, free-ended over empty canvas.\n const end: Endpoint = drag.target ?? { point: drag.to };\n return {\n displayScene: reduceIntent(scene, { kind: 'update', id: drag.id, values: { [drag.end]: end } }),\n blocked: false,\n };\n }\n return { displayScene: scene, blocked: false };\n }, [scene, drag, settled, createPreview, projection, minor]);\n\n /** The bounds a create gesture would land, drawn as a frame whether or not the node itself previews. */\n const createFrame = useMemo(() => {\n const preview = createPreview && displayScene.nodes[createPreview.id];\n return preview ? nodeBounds(preview) : undefined;\n }, [createPreview, displayScene]);\n\n const onPartCommit = useCallback(\n (node: Node, part: PartKey, text: string) => {\n registry.set(atoms.editing, undefined);\n const values = partValues(nodeRegistry, node, part, text);\n if (values && capabilities.update && text !== partText(nodeRegistry, node, part)) {\n projection.apply({ kind: 'update', id: node.id, values });\n }\n },\n [registry, atoms.editing, capabilities.update, projection, nodeRegistry],\n );\n const onPartCancel = useCallback(() => registry.set(atoms.editing, undefined), [registry, atoms.editing]);\n\n // Leaving a link waits a moment before it clears, so the pointer can reach the end handles drawn over it.\n const linkHover = useAtomValue(atoms.linkHover);\n const linkHoverTimer = useRef<ReturnType<typeof setTimeout>>(undefined);\n const onLinkHover = useCallback(\n (id: LinkId | undefined) => {\n clearTimeout(linkHoverTimer.current);\n if (id) {\n registry.set(atoms.linkHover, id);\n } else {\n linkHoverTimer.current = setTimeout(() => registry.set(atoms.linkHover, undefined), LINK_HOVER_GRACE_MS);\n }\n },\n [registry, atoms.linkHover],\n );\n useEffect(() => () => clearTimeout(linkHoverTimer.current), []);\n\n const handlers = useMemo<ElementHandlers>(\n () => ({\n onNodePointerDown,\n onLinkHover,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onPartCommit,\n onPartCancel,\n onNodeOpen: drillIn,\n }),\n [\n onNodePointerDown,\n onLinkHover,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onPartCommit,\n onPartCancel,\n drillIn,\n ],\n );\n\n // Resolved at the root from the model: pointer capture during a drag retargets the click, so a\n // double-click never reaches the node element itself. A text part under the pointer opens its editor;\n // the DOM is asked only which part, and the node comes from the model, so a part of a nested (live)\n // scene never matches the root node over it.\n const onDoubleClick = useCallback(\n (event: React.MouseEvent) => {\n const node = hitTest(scene, toScene(event));\n if (!node) {\n return;\n }\n const target = document.elementFromPoint(event.clientX, event.clientY);\n // A floating panel over the node took the clicks, so the node beneath is not the one meant; content embedded in\n // the node (an editor) keeps its own double-click (selecting a word).\n if (\n !(target instanceof Element) ||\n !target.closest('[data-node-id]') ||\n target.closest(`[${SCENE_OVERLAY_ATTRIBUTE}]`)\n ) {\n return;\n }\n const partElement = target.closest('[data-part]');\n const part =\n partElement?.closest('[data-node-id]')?.getAttribute('data-node-id') === node.id\n ? (partElement?.getAttribute('data-part') ?? undefined)\n : undefined;\n if (part && capabilities.update && partText(nodeRegistry, node, part) !== undefined) {\n select([node.id]);\n registry.set(atoms.editing, { id: node.id, part });\n } else if (nodeDef(nodeRegistry, node)?.openable) {\n drillIn(node);\n }\n },\n [scene, toScene, nodeRegistry, drillIn, capabilities.update, select, registry, atoms.editing],\n );\n\n // A node type dragged in (from the palette or a host's draggable) previews as a create drag would and\n // lands through the same drop, so what the ghost shows is what is created.\n const onPointerUpRef = useRef(onPointerUp);\n onPointerUpRef.current = onPointerUp;\n useEffect(() => {\n const element = rootRef.current;\n if (!element) {\n return;\n }\n // The pointer is the shape's centre; its top-left snaps to the minor grid, as a move does, so the shape\n // lands where it was dropped rather than up to half a major cell away.\n const dragAt = (type: NodeType, input: { clientX: number; clientY: number }): Drag => {\n const point = toScene(input);\n const def = nodeRegistry[type];\n const size = def ? nominalSize(def.defaultSize, cell) : { width: 0, height: 0 };\n const from = { x: snapMinor(point.x - size.width / 2), y: snapMinor(point.y - size.height / 2) };\n return { kind: 'create', type, from, to: from, dropped: true };\n };\n return dropTargetForElements({\n element,\n canDrop: ({ source }) => capabilities.create === true && nodeDragType(source.data) !== undefined,\n onDragEnter: ({ source, location }) => {\n const type = nodeDragType(source.data);\n if (type !== undefined) {\n setDrag(dragAt(type, location.current.input));\n }\n },\n onDrag: ({ source, location }) => {\n const type = nodeDragType(source.data);\n if (type !== undefined) {\n setDrag(dragAt(type, location.current.input));\n }\n },\n onDragLeave: cancelDrag,\n // Placed where it is released: the last drag-over can lag the pointer by a step.\n onDrop: ({ source, location }) => {\n const type = nodeDragType(source.data);\n if (type !== undefined) {\n setDrag(dragAt(type, location.current.input));\n }\n onPointerUpRef.current();\n },\n });\n }, [capabilities.create, nodeRegistry, cell, toScene, snapMinor, setDrag, cancelDrag]);\n\n const pointer = useMemo(\n () => screenToScene(camera, { x: viewport.width / 2, y: viewport.height / 2 }),\n [camera, viewport],\n );\n\n // Shapes may land on free cells beyond the scene's frame, so the cells cover what is in view; only the view,\n // since a union with a distant frame would exceed the grid's cell budget and hide the lattice.\n const latticeBounds = useMemo(\n () =>\n boundsFromPoints(\n screenToScene(camera, { x: 0, y: 0 }),\n screenToScene(camera, { x: viewport.width, y: viewport.height }),\n ),\n [camera, viewport],\n );\n\n const zoomTo = useCallback(\n (zoom: number) => {\n interactedRef.current = true;\n const centre = { x: viewport.width / 2, y: viewport.height / 2 };\n animateTo(zoomAt(registry.get(atoms.camera), centre, zoom));\n },\n [viewport, animateTo, registry, atoms.camera],\n );\n const zoomBy = useCallback(\n (factor: number) => zoomTo(registry.get(atoms.camera).zoom * factor),\n [zoomTo, registry, atoms.camera],\n );\n\n const deleteSelection = useCallback(() => {\n const ids = [...registry.get(atoms.selection)];\n if (ids.length > 0 && capabilities.delete) {\n projection.apply({ kind: 'delete', ids });\n select([]);\n }\n }, [registry, atoms.selection, capabilities.delete, projection, select]);\n\n /** A default-sized node of `type` centred in the view, its top-left on the grid. */\n const createAtCentre = useCallback(\n (type: NodeType) => {\n const def = nodeRegistry[type];\n if (!def || !capabilities.create) {\n return;\n }\n const size = nominalSize(def.defaultSize, cell);\n const from = { x: snapMinor(pointer.x - size.width / 2), y: snapMinor(pointer.y - size.height / 2) };\n // `dropped`: there is no drawn box, so the type's default size applies, as for a palette drop.\n const node = createdNode({ kind: 'create', type, from, to: from, dropped: true }, createId(type));\n if (node) {\n commitCreated(node);\n }\n },\n [nodeRegistry, capabilities.create, cell, snapMinor, pointer, createdNode, commitCreated],\n );\n\n const toolbarActions = useMemo<ToolbarActions>(\n () => ({\n path,\n nameOf,\n onPath: (index) => drillOut(path.length - 1 - index),\n fit: () => animateTo(fitBounds(fitTarget, viewport, inset, NOMINAL_ZOOM)),\n zoomReset: () => zoomTo(NOMINAL_ZOOM),\n zoomIn: () => zoomBy(ZOOM_STEP),\n zoomOut: () => zoomBy(1 / ZOOM_STEP),\n snap: snapEnabled,\n toggleSnap,\n guides,\n toggleGuides,\n // Only a lattice scene has a lattice to snap to.\n ...(projection.lattice ? { lattice: latticeOn, toggleLattice } : {}),\n debug,\n toggleDebug,\n canUndo,\n canRedo,\n undo: onUndo,\n redo: onRedo,\n hasSelection: selection.size > 0,\n hasClipboard: clipboard !== undefined,\n cut,\n copy,\n paste: () => paste(),\n delete: deleteSelection,\n create: createAtCentre,\n // A selection of two or more is what the user asked to tidy; one node alone means the board.\n layout: capabilities.layout\n ? () => projection.apply({ kind: 'layout', ids: selection.size > 1 ? [...selection] : undefined })\n : undefined,\n }),\n [\n path,\n nameOf,\n drillOut,\n animateTo,\n fitTarget,\n viewport,\n inset,\n zoomBy,\n zoomTo,\n snapEnabled,\n toggleSnap,\n guides,\n toggleGuides,\n latticeOn,\n toggleLattice,\n debug,\n toggleDebug,\n canUndo,\n canRedo,\n onUndo,\n onRedo,\n selection,\n clipboard,\n cut,\n copy,\n paste,\n deleteSelection,\n createAtCentre,\n capabilities.layout,\n projection,\n ],\n );\n\n // The portal on screen that fills most of the view; the rest of the layer fades as it grows, so zooming into\n // a scene (by wheel or drill-in) fades out what surrounds it and zooming out fades it back in.\n const focus = useMemo(() => {\n let best: { id: ElementId; opacity: number } | undefined;\n for (const node of Object.values(displayScene.nodes)) {\n // A frame the host opens itself (one showing an object) is no scene to zoom into, so it keeps its frame.\n if (!isFrameNode(node) || nodeDef(nodeRegistry, node)?.hostOpen?.(node)) {\n continue;\n }\n const bounds = nodeBounds(node);\n const centre = sceneToScreen(camera, { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 });\n if (centre.x < 0 || centre.y < 0 || centre.x > viewport.width || centre.y > viewport.height) {\n continue;\n }\n const opacity = layerOpacity(camera, bounds, viewport);\n if (!best || opacity < best.opacity) {\n best = { id: node.id, opacity };\n }\n }\n return best;\n }, [displayScene.nodes, nodeRegistry, camera, viewport]);\n\n /** One screen pixel in scene units, for chrome that should not grow with the camera. */\n const frameUnit = 1 / Math.max(camera.zoom, MIN_ZOOM);\n\n return (\n <SceneViewProvider\n registry={registry}\n atoms={atoms}\n store={store}\n projection={projection}\n capabilities={capabilities}\n readonly={readonly}\n nodeRegistry={nodeRegistry}\n linkRegistry={linkRegistry}\n scene={scene}\n displayScene={displayScene}\n blocked={blocked}\n bounds={bounds}\n latticeBounds={latticeBounds}\n path={path}\n camera={camera}\n pointer={pointer}\n measured={measured}\n frameUnit={frameUnit}\n focus={focus}\n grid={grid}\n snapEnabled={snapEnabled}\n guides={guides}\n latticeOn={latticeOn}\n selection={selection}\n hover={hover}\n selectedPoint={selectedPoint}\n editing={editing}\n active={active}\n clipboard={clipboard}\n drag={drag}\n tool={tool}\n debug={debug}\n panels={panels}\n createFrame={createFrame}\n landing={landing}\n handlers={handlers}\n linkHover={linkHover}\n select={select}\n toolbarActions={toolbarActions}\n navigating={navigating}\n opening={opening}\n drillIn={drillIn}\n copy={copy}\n cut={cut}\n paste={paste}\n onBackgroundPointerDown={onBackgroundPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onContextMenu={onContextMenu}\n cancelDrag={cancelDrag}\n updateHover={updateHover}\n onHandlePointerDown={onHandlePointerDown}\n onPortPointerDown={onPortPointerDown}\n onEndPointerDown={onEndPointerDown}\n onPointPointerDown={onPointPointerDown}\n onMidpointPointerDown={onMidpointPointerDown}\n onPointContextMenu={onPointContextMenu}\n setTool={setTool}\n removePoint={removePoint}\n menu={menu}\n closeMenu={closeMenu}\n menuAnchorRef={menuAnchorRef}\n onDoubleClick={onDoubleClick}\n onKeyDown={onKeyDown}\n rootRef={rootRef}\n >\n <DockProvider>\n {/* The canvas beside the dock, which docked panels move into; with none docked, it takes no space.\n Clipped rather than hidden: a hidden box still scrolls, so focusing content embedded in a node (an editor's\n caret) would scroll the whole canvas to reveal it, out from under the camera. */}\n <div className={mx('flex dx-fill overflow-clip', classNames)}>\n <div\n ref={rootRef}\n tabIndex={0}\n className={mx(\n 'relative grow h-full overflow-clip bg-base-surface outline-none touch-none select-none',\n tool.kind === 'hand' && 'cursor-grab',\n tool.kind === 'node' && 'cursor-crosshair',\n )}\n style={{ contain: 'strict' }}\n data-testid='scene-view'\n onPointerDown={onBackgroundPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n // A cancelled pointer (a touch the browser took over) abandons the gesture rather than landing it.\n onPointerCancel={cancelDrag}\n onPointerLeave={() => updateHover(undefined)}\n onDoubleClick={onDoubleClick}\n onContextMenu={onContextMenu}\n onKeyDown={onKeyDown}\n >\n {children}\n </div>\n <Dock />\n </div>\n </DockProvider>\n </SceneViewProvider>\n );\n};\n\nSceneViewRoot.displayName = 'SceneView.Root';\n\n//\n// Canvas\n//\n\nexport type SceneViewCanvasProps = {\n /** Nested levels below the root that may mount live; deeper portals stay previews (decision 10). */\n liveDepth?: number;\n /** Extra layers drawn in scene coordinates under the camera, above the scene (e.g. a host's animations). */\n overlay?: ReactNode;\n};\n\n/** The scene itself under the camera: the grid, the layer, the control frame and the menu a gesture opens. */\nconst SceneViewCanvas = ({ liveDepth = MAX_LIVE_DEPTH, overlay }: SceneViewCanvasProps) => {\n const {\n registry,\n atoms,\n store,\n capabilities,\n readonly,\n projection,\n nodeRegistry,\n displayScene,\n blocked,\n bounds,\n latticeBounds,\n camera,\n measured,\n frameUnit,\n focus,\n grid,\n snapEnabled,\n guides,\n latticeOn,\n selection,\n hover,\n selectedPoint,\n editing,\n active,\n clipboard,\n drag,\n debug,\n createFrame,\n landing,\n handlers,\n linkHover,\n select,\n navigating,\n opening,\n copy,\n cut,\n paste,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n removePoint,\n menu,\n closeMenu,\n menuAnchorRef,\n } = useSceneViewContext('SceneView.Canvas');\n\n // Handles and ports belong to what is drawn: a hidden layer's elements show none.\n const shownScene = useMemo(() => visibleScene(displayScene), [displayScene]);\n\n return (\n <>\n {/* Only while snapping: the lines are what a gesture lands on, so drawing them when nothing snaps\n states a constraint the canvas is not applying. The minor level goes when its cells get too\n small to read. Read-only, nothing snaps, so neither grid nor guides are drawn. */}\n {snapEnabled && !readonly && (\n <GridComponent\n size={grid}\n scale={camera.zoom}\n offset={{ x: camera.x * camera.zoom, y: camera.y * camera.zoom }}\n showAxes={false}\n ratios={GRID_LEVELS}\n range={GRID_RANGE}\n />\n )}\n <div\n className={mx('absolute pointer-events-none', !measured && 'invisible')}\n style={{ transform: cameraTransform(camera), transformOrigin: '0 0' }}\n >\n {/* A lattice scene shows its cells: the places a shape may land, separated by the gutters. */}\n {guides && !readonly && latticeOn && projection.lattice && (\n <LatticeGrid spec={projection.lattice} bounds={latticeBounds} unit={frameUnit} />\n )}\n <div className='pointer-events-auto'>\n <SceneLayer\n store={store}\n scene={displayScene}\n registry={nodeRegistry}\n zoom={camera.zoom}\n depth={0}\n liveDepth={liveDepth}\n selected={selection}\n plain={isMoving(drag)}\n hover={hover}\n hoveredLink={linkHover}\n opening={opening}\n focus={focus}\n editing={editing}\n active={active}\n ghost={drag?.kind === 'create' ? PREVIEW_NODE_ID : undefined}\n debug={debug}\n handlers={handlers}\n // Routes follow the gutters in lattice mode, whether or not snap is on.\n lattice={latticeOn ? projection.lattice : undefined}\n cell={grid * MAJOR_GRID_RATIO}\n />\n </div>\n {/* Read-only, nothing is edited, so no selection frame, handle or port is drawn. */}\n {!readonly && (\n <ControlFrame\n scene={shownScene}\n registry={nodeRegistry}\n selection={selection}\n hover={hover}\n hoveredLink={drag ? undefined : linkHover}\n onLinkHover={handlers.onLinkHover}\n selectedPoint={selectedPoint}\n zoom={camera.zoom}\n drag={drag}\n capabilities={capabilities}\n createFrame={createFrame}\n landing={landing}\n blocked={blocked}\n lattice={latticeOn ? projection.lattice : undefined}\n onHandlePointerDown={onHandlePointerDown}\n onPortPointerDown={onPortPointerDown}\n onEndPointerDown={onEndPointerDown}\n onPointPointerDown={onPointPointerDown}\n onMidpointPointerDown={onMidpointPointerDown}\n onPointContextMenu={onPointContextMenu}\n />\n )}\n {overlay}\n </div>\n {/* Wheel events still bubble to the root through the shield, so a zoom keeps zooming. */}\n {navigating && <div className='dx-cover' data-testid='navigation-shield' />}\n <span\n ref={menuAnchorRef}\n className='absolute size-0 pointer-events-none'\n style={{ left: menu?.at.x ?? 0, top: menu?.at.y ?? 0 }}\n />\n <Menu.Root\n open={menu !== undefined}\n onOpenChange={({ open }) => !open && closeMenu()}\n positioning={{\n ...VirtualAnchor.virtualAnchor(menuAnchorRef),\n placement: 'right',\n gutter: 4,\n overflowPadding: 8,\n }}\n >\n <Menu.Content>\n {menu?.kind === 'point' && (\n <Menu.Item\n data-testid='remove-point'\n onSelect={() => {\n const point = registry.get(atoms.point);\n if (point) {\n removePoint(point);\n }\n }}\n item={{ value: 'Remove control point', label: 'Remove control point' }}\n />\n )}\n {menu?.kind === 'element' && (\n <>\n <Menu.Item\n data-testid='menu-cut'\n disabled={!capabilities.delete}\n onSelect={cut}\n item={{ value: 'Cut', label: 'Cut' }}\n />\n <Menu.Item data-testid='menu-copy' onSelect={copy} item={{ value: 'Copy', label: 'Copy' }} />\n <Menu.Item\n data-testid='menu-delete'\n disabled={!capabilities.delete}\n onSelect={() => {\n projection.apply({ kind: 'delete', ids: [...registry.get(atoms.selection)] });\n select([]);\n }}\n item={{ value: 'Delete', label: 'Delete' }}\n />\n </>\n )}\n {menu?.kind === 'canvas' && (\n <Menu.Item\n data-testid='menu-paste'\n disabled={!clipboard || !capabilities.create}\n onSelect={() => paste(menu.scene)}\n item={{ value: 'Paste', label: 'Paste' }}\n />\n )}\n </Menu.Content>\n </Menu.Root>\n </>\n );\n};\n\nSceneViewCanvas.displayName = 'SceneView.Canvas';\n\n//\n// Toolbars\n//\n\nexport type SceneViewBarProps = Util.ThemedClassName<{}>;\n\n/**\n * The frame a bar floats in: its content's width, but half the view at most (the bar scrolls beyond that).\n * The toolbar's own scroll frame is zero-height in flow, so `classNames` positions this frame, not the bar.\n */\nconst barFrame = 'absolute w-max max-w-[50%]';\n\n/** Where the view is in the scene tree. */\nconst SceneViewNavigation = ({ classNames = 'top-2 left-2' }: SceneViewBarProps) => {\n const { toolbarActions } = useSceneViewContext('SceneView.Navigation');\n return (\n <div className={mx(barFrame, classNames)}>\n <NavigationToolbar actions={toolbarActions} />\n </div>\n );\n};\n\nSceneViewNavigation.displayName = 'SceneView.Navigation';\n\n/** Everything that changes the view or the scene. */\nconst SceneViewActions = ({ classNames = 'bottom-2 left-1/2 -translate-x-1/2' }: SceneViewBarProps) => {\n const { toolbarActions, nodeRegistry, capabilities, readonly } = useSceneViewContext('SceneView.Actions');\n // Every action here edits the scene or how edits snap.\n if (readonly) {\n return null;\n }\n return (\n <div className={mx(barFrame, classNames)}>\n <ActionToolbar actions={toolbarActions} nodes={nodeRegistry} capabilities={capabilities} />\n </div>\n );\n};\n\nSceneViewActions.displayName = 'SceneView.Actions';\n\n/** The camera's controls and numbers; nothing here changes the scene. */\nconst SceneViewDebug = ({ classNames = 'bottom-2 left-2' }: SceneViewBarProps) => {\n const { toolbarActions, camera, pointer } = useSceneViewContext('SceneView.Debug');\n return (\n <div className={mx(barFrame, classNames)}>\n <CameraToolbar actions={toolbarActions}>\n {Math.round(camera.zoom * 100)}% · ({Math.round(pointer.x)}, {Math.round(pointer.y)})\n </CameraToolbar>\n </div>\n );\n};\n\nSceneViewDebug.displayName = 'SceneView.Debug';\n\n//\n// Palette\n//\n\n/** The tool rail: what the next gesture will draw. */\nconst SceneViewPalette = ({ classNames = 'absolute top-14 bottom-14 left-2' }: SceneViewBarProps) => {\n const { tool, nodeRegistry, linkRegistry, capabilities, setTool } = useSceneViewContext('SceneView.Palette');\n return (\n // Spans the room the rail may take, so it can fold its groups to fit; the canvas below the rail keeps the pointer.\n <div className={mx('pointer-events-none', classNames)}>\n <Palette\n tool={tool}\n nodes={nodeRegistry}\n links={linkRegistry}\n capabilities={capabilities}\n onToolChange={setTool}\n />\n </div>\n );\n};\n\nSceneViewPalette.displayName = 'SceneView.Palette';\n\n//\n// Properties\n//\n\nexport type SceneViewPropertiesProps = Util.ThemedClassName<\n Pick<PropertiesProps, 'fields' | 'db' | 'getOptions' | 'overrides'> & {\n /** Narrows the scenes a scene shape may open (e.g. to the host's own, not those it shows from elsewhere). */\n sceneFilter?: (id: SceneId) => boolean;\n }\n>;\n\n/** The selected element's properties as a floating panel; absent while nothing is selected. */\nconst SceneViewProperties = ({\n classNames = PANEL_CLASSES,\n fields,\n db,\n getOptions,\n overrides,\n sceneFilter,\n}: SceneViewPropertiesProps) => {\n const { projection, atoms, nodeRegistry, capabilities, readonly, selection, store, path, panels } =\n useSceneViewContext('SceneView.Properties');\n const docked = panels === 'docked' && !readonly;\n const registry = useRegistry();\n const scenes = useAtomValue(store.scenes);\n const options = useMemo(() => sceneOptions(scenes, path, sceneFilter), [scenes, path, sceneFilter]);\n\n // The selection moves into a new scene, opened by a shape where it was; the shape is then the selection.\n const onGroup = useCallback(() => {\n const id = createId('scene');\n const current = registry.get(projection.scene);\n const group = groupIntoScene(current, selection, id, activeLayer(current, registry.get(atoms.layer)));\n if (!group) {\n return;\n }\n const before = registry.get(store.scenes);\n registry.set(store.scenes, { ...before, [id]: { ...group.child, name: 'Untitled' } });\n projection.apply({ kind: 'batch', intents: group.intents });\n // A projection may refuse the batch (`apply` reports nothing), so the shape's presence is the result: without\n // it the new scene would be an orphan, so it goes and the selection stays.\n if (!registry.get(projection.scene).nodes[id]) {\n const { [id]: _, ...scenes } = registry.get(store.scenes);\n registry.set(store.scenes, scenes);\n return;\n }\n // One undo step takes the new scene away with the shape that opens it.\n recordScenes(registry, atoms.undo, path[path.length - 1], before);\n registry.set(atoms.selection, new Set([id]));\n registry.set(atoms.point, undefined);\n }, [registry, projection, selection, store.scenes, atoms.layer, atoms.selection, atoms.point, atoms.undo, path]);\n\n const panel = (\n <Properties\n classNames={docked ? 'h-auto' : mx('rounded-sm bg-modal-surface border border-separator', classNames)}\n docked={docked}\n projection={projection}\n atoms={atoms}\n nodes={nodeRegistry}\n fields={fields}\n db={db}\n getOptions={getOptions}\n overrides={overrides}\n sceneOptions={options}\n styles={store.styles}\n onGroup={capabilities.create && capabilities.delete ? onGroup : undefined}\n readonly={!capabilities.update}\n />\n );\n // Docked, the panel stays in its section whatever is selected (it says when nothing is); floating, it shows only\n // with a selection.\n const dockedPanel = useDockSection(PROPERTIES_SECTION, docked, panel);\n if (docked || readonly) {\n return dockedPanel;\n }\n return selection.size > 0 ? panel : null;\n};\n\nSceneViewProperties.displayName = 'SceneView.Properties';\n\n//\n// Dock\n//\n\nconst PROPERTIES_SECTION: DockSection = {\n id: 'properties',\n title: 'Properties',\n icon: 'ph--sliders-horizontal--regular',\n order: 0,\n};\n\nconst LAYERS_SECTION: DockSection = { id: 'layers', title: 'Layers', icon: 'ph--stack--regular', order: 1 };\n\n//\n// Layers\n//\n\nexport type SceneViewLayersProps = Util.ThemedClassName<{}>;\n\n/**\n * The current scene's layers as a floating panel where the properties panel goes, shown while nothing is selected\n * (the two take turns). Each edit is one intent, so one undo step.\n */\nconst SceneViewLayers = ({ classNames = PANEL_CLASSES }: SceneViewLayersProps) => {\n const {\n projection,\n atoms,\n capabilities,\n readonly: viewReadonly,\n selection,\n panels,\n } = useSceneViewContext('SceneView.Layers');\n const docked = panels === 'docked' && !viewReadonly;\n const registry = useRegistry();\n const scene = useAtomValue(projection.scene);\n const active = useAtomValue(atoms.layer);\n const layers = useMemo(() => sceneLayers(scene), [scene]);\n const readonly = !capabilities.update;\n const setLayer = useCallback((layer: Layer) => projection.apply({ kind: 'layer', layer }), [projection]);\n const byId = useCallback((id: LayerId) => layers.find((layer) => layer.id === id), [layers]);\n // The layers picked in the panel; the active layer (the top-most of them) is the one new shapes go on.\n const [picked, setPicked] = useState<LayerId[]>([]);\n const top = activeLayer(scene, active);\n const selected = useMemo(() => {\n const ids = picked.filter((id) => byId(id));\n return ids.includes(top) ? ids : [top];\n }, [picked, byId, top]);\n const select = useCallback(\n (ids: LayerId[]) => {\n setPicked(ids);\n const topMost = [...layers].reverse().find((layer) => ids.includes(layer.id));\n topMost && registry.set(atoms.layer, topMost.id);\n },\n [layers, registry, atoms],\n );\n const panel = (\n <LayersPanel\n classNames={docked ? 'h-auto' : mx('rounded-sm bg-modal-surface border border-separator', classNames)}\n docked={docked}\n layers={layers}\n selected={selected}\n readonly={readonly}\n onSelectedChange={select}\n onToggle={(id) => {\n const layer = byId(id);\n layer && setLayer({ ...layer, hidden: !layer.hidden });\n }}\n onRename={(id, name) => {\n const layer = byId(id);\n layer && setLayer({ ...layer, name });\n }}\n onMove={(id, index) => {\n const layer = moveLayer(scene, id, index);\n layer && setLayer(layer);\n }}\n onCreate={() => {\n const layer = createLayer(scene, createId('layer'));\n setLayer(layer);\n select([layer.id]);\n return layer.id;\n }}\n onDelete={\n capabilities.delete\n ? (ids) => {\n projection.apply({ kind: 'batch', intents: ids.map((id): Intent => ({ kind: 'removeLayer', id })) });\n setPicked([]);\n }\n : undefined\n }\n onMerge={(ids, into) => {\n const merge = mergeLayersIntent(scene, ids, into);\n if (merge) {\n projection.apply(merge);\n select([into]);\n }\n }}\n />\n );\n const dockedPanel = useDockSection(LAYERS_SECTION, docked, panel);\n if (docked || viewReadonly) {\n return dockedPanel;\n }\n // Floating, the layers take the properties panel's place while nothing is selected.\n return selection.size > 0 ? null : panel;\n};\n\nSceneViewLayers.displayName = 'SceneView.Layers';\n\n//\n// About\n//\n\nconst ABOUT_SECTION: DockSection = { id: 'about', title: 'About', icon: 'ph--info--regular', order: 2 };\n\nexport type SceneViewAboutProps = Util.ThemedClassName<{}>;\n\n/** Counts of the scene's objects and the drawing's scenes; a dock section only, since it has no place over the canvas. */\nconst SceneViewAbout = ({ classNames }: SceneViewAboutProps) => {\n const { scene, store, panels } = useSceneViewContext('SceneView.About');\n const scenes = useAtomValue(store.scenes);\n const docked = panels === 'docked';\n const stats = useMemo<AboutStat[]>(\n () => [\n { id: 'nodes', label: 'Nodes', value: Object.keys(scene.nodes).length },\n { id: 'links', label: 'Links', value: Object.keys(scene.links).length },\n { id: 'layers', label: 'Layers', value: Object.keys(scene.layers ?? {}).length },\n { id: 'scenes', label: 'Scenes', value: Object.keys(scenes).length },\n ],\n [scene, scenes],\n );\n return useDockSection(ABOUT_SECTION, docked, <About classNames={mx('h-auto', classNames)} stats={stats} />);\n};\n\nSceneViewAbout.displayName = 'SceneView.About';\n\nexport const SceneView = {\n Root: SceneViewRoot,\n Canvas: SceneViewCanvas,\n Navigation: SceneViewNavigation,\n Actions: SceneViewActions,\n Debug: SceneViewDebug,\n Palette: SceneViewPalette,\n Properties: SceneViewProperties,\n Layers: SceneViewLayers,\n About: SceneViewAbout,\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Variant 2 of §3: the model is a set of cardinal constraints between named nodes; the projection\n// solves them into a positioned scene and a `move` intent rewrites the moved node's constraints\n// against its nearest neighbour, then re-solves. Uses `@dxos/diagram`'s longest-path ranking per axis.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { Layout } from '@dxos/diagram';\n\nimport { centeredOrigin } from '../../utils/layout.ts';\nimport { initialKeys } from '../../utils/order.ts';\nimport { withTitle } from '../../utils/parts.ts';\nimport { createNode } from '../../utils/shapes.ts';\nimport { type Projection } from '../projection.ts';\nimport { defaultNodeRegistry } from '../registry.ts';\nimport {\n type BuiltinNodeType,\n type Capabilities,\n type Intent,\n type Node,\n type NodeStyle,\n type Point,\n type Scene,\n type Size,\n isBuiltinNode,\n isFrameNode,\n} from '../types.ts';\n\n/** `subject <relation> object`: \"A east of B\", \"A aligned with B\" (same row). */\nexport type Relation = 'east' | 'west' | 'north' | 'south' | 'aligned';\n\nexport type Constraint = { subject: string; relation: Relation; object: string };\n\n/** `type` is the node's shape; the solver places every type on the same grid. */\nexport type ConstrainedNode = { id: string; label?: string; type?: BuiltinNodeType; style?: NodeStyle };\n\nexport type ConstrainedModel = {\n nodes: ConstrainedNode[];\n constraints: Constraint[];\n};\n\nexport type ConstrainedOptions = {\n /** Distance between grid slots. */\n pitch?: Size;\n /** Every node has the same size (§3: equal sizes, snapped to the grid). */\n size?: Size;\n /** The first slot's centre; by default the layout straddles the origin. */\n origin?: Point;\n};\n\n/** Multiples of the major grid, so a solved layout is already snapped. */\nconst DEFAULTS: Required<Omit<ConstrainedOptions, 'origin'>> = {\n pitch: { width: 256, height: 192 },\n size: { width: 192, height: 128 },\n};\n\nexport const CONSTRAINED_SCENE_ID = 'constrained';\n\ntype Edge = { from: string; to: string };\n\nconst reaches = (edges: readonly Edge[], from: string, to: string): boolean => {\n const seen = new Set<string>([from]);\n const queue = [from];\n while (queue.length > 0) {\n const current = queue.shift();\n for (const edge of edges) {\n if (edge.from === current && !seen.has(edge.to)) {\n if (edge.to === to) {\n return true;\n }\n seen.add(edge.to);\n queue.push(edge.to);\n }\n }\n }\n return false;\n};\n\n/** Union-find over `aligned` pairs: members of a group share a row. */\nconst rowGroups = (model: ConstrainedModel): Map<string, string> => {\n const parent = new Map<string, string>(model.nodes.map(({ id }) => [id, id]));\n const find = (id: string): string => {\n const root = parent.get(id) ?? id;\n if (root === id) {\n return id;\n }\n const top = find(root);\n parent.set(id, top);\n return top;\n };\n for (const { subject, relation, object } of model.constraints) {\n if (relation === 'aligned') {\n parent.set(find(subject), find(object));\n }\n }\n return new Map(model.nodes.map(({ id }) => [id, find(id)]));\n};\n\nexport type Solution = {\n rows: Map<string, number>;\n columns: Map<string, number>;\n};\n\n/** Longest-path ranks per axis: `south`/`north` order rows, `east`/`west` order columns within a row. */\nexport const solveRanks = (model: ConstrainedModel): Solution => {\n const ids = model.nodes.map(({ id }) => id);\n const groups = rowGroups(model);\n const groupIds = [...new Set(groups.values())];\n\n const rowEdges: Edge[] = [];\n const columnEdges: Edge[] = [];\n for (const { subject, relation, object } of model.constraints) {\n switch (relation) {\n case 'south':\n rowEdges.push({ from: groups.get(object) ?? object, to: groups.get(subject) ?? subject });\n break;\n case 'north':\n rowEdges.push({ from: groups.get(subject) ?? subject, to: groups.get(object) ?? object });\n break;\n case 'east':\n columnEdges.push({ from: object, to: subject });\n break;\n case 'west':\n columnEdges.push({ from: subject, to: object });\n break;\n default:\n break;\n }\n }\n // A constraint that would close a cycle is dropped rather than breaking the solve.\n const acyclic = (edges: Edge[]): Edge[] => {\n const kept: Edge[] = [];\n for (const edge of edges) {\n if (!reaches(kept, edge.to, edge.from)) {\n kept.push(edge);\n }\n }\n return kept;\n };\n const groupRanks = Layout.rank(groupIds, acyclic(rowEdges));\n const rows = new Map(ids.map((id) => [id, groupRanks.get(groups.get(id) ?? id) ?? 0]));\n\n const columns = new Map<string, number>();\n const byRow = new Map<number, string[]>();\n for (const id of ids) {\n const row = rows.get(id) ?? 0;\n byRow.set(row, [...(byRow.get(row) ?? []), id]);\n }\n for (const members of byRow.values()) {\n const set = new Set(members);\n const edges = acyclic(columnEdges.filter(({ from, to }) => set.has(from) && set.has(to)));\n const ranks = Layout.rank(members, edges);\n // Unconstrained members of a row take the next free column after the constrained ones.\n const used = new Set<number>();\n for (const id of members) {\n if (edges.some(({ from, to }) => from === id || to === id)) {\n const column = ranks.get(id) ?? 0;\n columns.set(id, column);\n used.add(column);\n }\n }\n let free = 0;\n for (const id of members) {\n if (!columns.has(id)) {\n while (used.has(free)) {\n free++;\n }\n columns.set(id, free);\n used.add(free);\n }\n }\n }\n return { rows, columns };\n};\n\n/** Solve the model to a positioned scene. */\nexport const solve = (model: ConstrainedModel, options: ConstrainedOptions = {}): Scene => {\n const { pitch, size } = { ...DEFAULTS, ...options };\n const { rows, columns } = solveRanks(model);\n const extent = {\n columns: Math.max(...columns.values(), 0) + 1,\n rows: Math.max(...rows.values(), 0) + 1,\n };\n const origin = options.origin ?? centeredOrigin(extent, pitch, size);\n const keys = initialKeys(model.nodes.length);\n const nodes: Record<string, Node> = {};\n model.nodes.forEach((node, index) => {\n const center = {\n x: origin.x + (columns.get(node.id) ?? 0) * pitch.width,\n y: origin.y + (rows.get(node.id) ?? 0) * pitch.height,\n };\n const solved = withTitle(\n defaultNodeRegistry,\n createNode({ type: node.type ?? 'rect', id: node.id, z: keys[index], center, size }),\n node.label ?? node.id,\n );\n nodes[node.id] = node.style ? { ...solved, style: node.style } : solved;\n });\n return { id: CONSTRAINED_SCENE_ID, name: 'Constrained', nodes, links: {} };\n};\n\n/**\n * Rewrite the constraints of `id` from where it was dropped: the nearest other node becomes its\n * reference; a mostly horizontal offset makes it east/west of and aligned with that node, a mostly\n * vertical one north/south of it. Returns the model unchanged when there is no neighbour.\n */\nexport const rewriteForDrop = (model: ConstrainedModel, scene: Scene, id: string, delta: Point): ConstrainedModel => {\n const moved = scene.nodes[id];\n if (!moved) {\n return model;\n }\n const target = { x: moved.center.x + delta.x, y: moved.center.y + delta.y };\n let nearest: { id: string; dx: number; dy: number } | undefined;\n let best = Infinity;\n for (const node of Object.values(scene.nodes)) {\n if (node.id === id) {\n continue;\n }\n const dx = target.x - node.center.x;\n const dy = target.y - node.center.y;\n const distance = dx * dx + dy * dy;\n if (distance < best) {\n best = distance;\n nearest = { id: node.id, dx, dy };\n }\n }\n if (!nearest) {\n return model;\n }\n const kept = model.constraints.filter(({ subject, object }) => subject !== id && object !== id);\n const horizontal = Math.abs(nearest.dx) >= Math.abs(nearest.dy);\n const added: Constraint[] = horizontal\n ? [\n { subject: id, relation: nearest.dx > 0 ? 'east' : 'west', object: nearest.id },\n { subject: id, relation: 'aligned', object: nearest.id },\n ]\n : [{ subject: id, relation: nearest.dy > 0 ? 'south' : 'north', object: nearest.id }];\n return { ...model, constraints: [...kept, ...added] };\n};\n\n/** The display text of a node or a partial update, whichever field its type uses. */\nexport const labelOf = (values: object): string | undefined => {\n if ('label' in values && typeof values.label === 'string') {\n return values.label;\n }\n if ('name' in values && typeof values.name === 'string') {\n return values.name;\n }\n if ('text' in values && typeof values.text === 'string') {\n return values.text;\n }\n return undefined;\n};\n\nconst isConstrainedModel = (value: unknown): value is ConstrainedModel =>\n typeof value === 'object' && value !== null && 'nodes' in value && 'constraints' in value;\n\nexport const constrainedCapabilities: Capabilities = { move: true, create: true, delete: true, update: true };\n\nexport type ConstrainedProjectionOptions = {\n registry: Registry.AtomRegistry;\n model: Atom.Writable<ConstrainedModel>;\n options?: ConstrainedOptions;\n};\n\nexport const createConstrainedProjection = ({ registry, model, options }: ConstrainedProjectionOptions): Projection => {\n const scene = Atom.keepAlive(Atom.make((get) => solve(get(model), options)));\n const apply = (intent: Intent) => {\n const current = registry.get(model);\n switch (intent.kind) {\n case 'move': {\n let next = current;\n for (const id of intent.ids) {\n next = rewriteForDrop(next, registry.get(scene), id, intent.delta);\n }\n if (next !== current) {\n registry.set(model, next);\n }\n break;\n }\n case 'create': {\n // The model records built-in types only; a portal or a host type has no place in it and is refused.\n if (!isBuiltinNode(intent.node) || isFrameNode(intent.node)) {\n return;\n }\n const node: ConstrainedNode = {\n id: intent.node.id,\n type: intent.node.type,\n label: labelOf(intent.node),\n style: intent.node.style,\n };\n const added = { ...current, nodes: [...current.nodes, node] };\n // Constrain the new node as if it had been dropped where it was drawn.\n const solved = registry.get(scene);\n const provisional: Scene = { ...solved, nodes: { ...solved.nodes, [node.id]: intent.node } };\n registry.set(model, rewriteForDrop(added, provisional, node.id, { x: 0, y: 0 }));\n break;\n }\n case 'delete': {\n const ids = new Set(intent.ids);\n registry.set(model, {\n nodes: current.nodes.filter(({ id }) => !ids.has(id)),\n constraints: current.constraints.filter(({ subject, object }) => !ids.has(subject) && !ids.has(object)),\n });\n break;\n }\n case 'batch':\n intent.intents.forEach(apply);\n break;\n case 'update': {\n // Only the label and style live in the model; geometry is solved, so those edits are dropped.\n const label = labelOf(intent.values);\n const style = 'style' in intent.values ? intent.values.style : undefined;\n if (label !== undefined || style !== undefined) {\n registry.set(model, {\n ...current,\n nodes: current.nodes.map((node) =>\n node.id === intent.id\n ? { ...node, ...(label !== undefined && { label }), ...(style !== undefined && { style }) }\n : node,\n ),\n });\n }\n break;\n }\n default:\n break;\n }\n };\n return {\n scene,\n apply,\n capabilities: constrainedCapabilities,\n snapshot: () => registry.get(model),\n restore: (snapshot) => {\n if (isConstrainedModel(snapshot)) {\n registry.set(model, snapshot);\n }\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Dynamic projection (§3 variant 3): the model is an external graph of nodes and edges. A layout\n// engine ranks it into rows; an overlay of user overrides applies on top, so a `move` intent writes\n// an override rather than a coordinate, graph edits re-run the engine, and an override whose node\n// vanished is dropped.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { Layout } from '@dxos/diagram';\n\nimport { centeredOrigin } from '../../utils/layout.ts';\nimport { initialKeys } from '../../utils/order.ts';\nimport { withTitle } from '../../utils/parts.ts';\nimport { createNode } from '../../utils/shapes.ts';\nimport { type Projection } from '../projection.ts';\nimport { defaultNodeRegistry } from '../registry.ts';\nimport {\n type BuiltinNodeType,\n type Capabilities,\n type Intent,\n type Link,\n type Node,\n type Point,\n type Scene,\n type Size,\n endpointNode,\n} from '../types.ts';\nimport { labelOf } from './constrained.ts';\n\nexport type GraphNode = { id: string; label?: string; type?: BuiltinNodeType };\nexport type GraphEdge = { id: string; from: string; to: string };\n\nexport type GraphModel = {\n nodes: GraphNode[];\n edges: GraphEdge[];\n};\n\n/** User adjustments layered over the engine's layout (react-ui-diagram's pattern). */\nexport type Overlay = {\n positions: Record<string, Point>;\n};\n\nexport type DynamicOptions = {\n pitch?: Size;\n size?: Size;\n /** The first slot's centre; by default the layout straddles the origin. */\n origin?: Point;\n};\n\n/** Multiples of the major grid, so a laid-out graph is already snapped. */\nconst DEFAULTS: Required<Omit<DynamicOptions, 'origin'>> = {\n pitch: { width: 256, height: 192 },\n size: { width: 192, height: 128 },\n};\n\nexport const DYNAMIC_SCENE_ID = 'dynamic';\n\n/** Rank rows top-down along the edges; columns are the order within a row. Overrides win. */\nexport const layoutGraph = (graph: GraphModel, overlay: Overlay, options: DynamicOptions = {}): Scene => {\n const { pitch, size } = { ...DEFAULTS, ...options };\n const ids = graph.nodes.map(({ id }) => id);\n const known = new Set(ids);\n const ranks = Layout.rank(\n ids,\n graph.edges.filter(({ from, to }) => known.has(from) && known.has(to)),\n );\n const byRow = new Map<number, string[]>();\n for (const id of ids) {\n const row = ranks.get(id) ?? 0;\n byRow.set(row, [...(byRow.get(row) ?? []), id]);\n }\n const columns = new Map<string, number>();\n for (const members of byRow.values()) {\n [...members].sort().forEach((id, index) => columns.set(id, index));\n }\n\n // Taken from the ranks rather than from the placed nodes, so dragging a node (which only writes an\n // override) leaves the rest of the graph where it is.\n const extent = {\n columns: Math.max(...[...byRow.values()].map(({ length }) => length), 1),\n rows: Math.max(...byRow.keys(), 0) + 1,\n };\n const origin = options.origin ?? centeredOrigin(extent, pitch, size);\n\n const keys = initialKeys(graph.nodes.length + graph.edges.length);\n const nodes: Record<string, Node> = {};\n graph.nodes.forEach((node, index) => {\n const override = overlay.positions[node.id];\n const center = override ?? {\n x: origin.x + (columns.get(node.id) ?? 0) * pitch.width,\n y: origin.y + (ranks.get(node.id) ?? 0) * pitch.height,\n };\n nodes[node.id] = withTitle(\n defaultNodeRegistry,\n createNode({ type: node.type ?? 'rect', id: node.id, z: keys[graph.edges.length + index], center, size }),\n node.label ?? node.id,\n );\n });\n const links: Record<string, Link> = {};\n graph.edges.forEach((edge, index) => {\n if (known.has(edge.from) && known.has(edge.to)) {\n links[edge.id] = {\n type: 'curve',\n id: edge.id,\n z: keys[index],\n source: { node: edge.from },\n target: { node: edge.to },\n };\n }\n });\n return { id: DYNAMIC_SCENE_ID, name: 'Dynamic', nodes, links };\n};\n\n/** Drop overrides whose nodes are gone. */\nexport const pruneOverlay = (graph: GraphModel, overlay: Overlay): Overlay => {\n const known = new Set(graph.nodes.map(({ id }) => id));\n const positions = Object.fromEntries(Object.entries(overlay.positions).filter(([id]) => known.has(id)));\n return Object.keys(positions).length === Object.keys(overlay.positions).length ? overlay : { positions };\n};\n\ntype DynamicSnapshot = { graph: GraphModel; overlay: Overlay };\n\nconst isDynamicSnapshot = (value: unknown): value is DynamicSnapshot =>\n typeof value === 'object' && value !== null && 'graph' in value && 'overlay' in value;\n\nexport const dynamicCapabilities: Capabilities = { move: true, link: true, delete: true, update: true };\n\nexport type DynamicProjectionOptions = {\n registry: Registry.AtomRegistry;\n graph: Atom.Writable<GraphModel>;\n overlay: Atom.Writable<Overlay>;\n options?: DynamicOptions;\n};\n\nexport const createDynamicProjection = ({\n registry,\n graph,\n overlay,\n options,\n}: DynamicProjectionOptions): Projection => {\n const scene = Atom.keepAlive(\n Atom.make((get) => layoutGraph(get(graph), pruneOverlay(get(graph), get(overlay)), options)),\n );\n const apply = (intent: Intent) => {\n switch (intent.kind) {\n case 'move': {\n const current = registry.get(scene);\n const positions = { ...registry.get(overlay).positions };\n for (const id of intent.ids) {\n const node = current.nodes[id];\n if (node) {\n positions[id] = { x: node.center.x + intent.delta.x, y: node.center.y + intent.delta.y };\n }\n }\n registry.set(overlay, { positions });\n break;\n }\n case 'link': {\n const model = registry.get(graph);\n const { link } = intent;\n const from = endpointNode(link.source);\n const to = endpointNode(link.target);\n // The graph has edges between nodes only; a free-ended link has no place in it.\n if (from === undefined || to === undefined || model.edges.some((edge) => edge.id === link.id)) {\n return;\n }\n registry.set(graph, { ...model, edges: [...model.edges, { id: link.id, from, to }] });\n break;\n }\n case 'delete': {\n const ids = new Set(intent.ids);\n const model = registry.get(graph);\n registry.set(graph, {\n nodes: model.nodes.filter(({ id }) => !ids.has(id)),\n edges: model.edges.filter(({ id, from, to }) => !ids.has(id) && !ids.has(from) && !ids.has(to)),\n });\n break;\n }\n case 'batch':\n intent.intents.forEach(apply);\n break;\n case 'update': {\n // The label is the graph's; a geometry edit becomes an override like a move would.\n const model = registry.get(graph);\n const label = labelOf(intent.values);\n if (label !== undefined) {\n registry.set(graph, {\n ...model,\n nodes: model.nodes.map((node) => (node.id === intent.id ? { ...node, label } : node)),\n });\n }\n if ('center' in intent.values && intent.values.center) {\n const center = intent.values.center;\n registry.set(overlay, { positions: { ...registry.get(overlay).positions, [intent.id]: center } });\n }\n break;\n }\n default:\n break;\n }\n };\n return {\n scene,\n apply,\n capabilities: dynamicCapabilities,\n // Both atoms in one value, so an undo restores the layout and the overrides together.\n snapshot: () => ({ graph: registry.get(graph), overlay: registry.get(overlay) }),\n restore: (snapshot) => {\n if (isDynamicSnapshot(snapshot)) {\n registry.set(graph, snapshot.graph);\n registry.set(overlay, snapshot.overlay);\n }\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Lattice projection (docs/DESIGN.md §8b): freehand semantics, with every change to a node's geometry\n// snapped onto the lattice and refused when it would overlap another node's cells. Nodes stay in scene\n// pixels, so a lattice scene is stored exactly as a freehand one; the rule lives here, not in the data.\n//\n\nimport {\n DEFAULT_LATTICE,\n type LatticeSpec,\n cellBounds,\n collides,\n coveredCells,\n occupancy,\n onLattice,\n quantize,\n resizeCell,\n toCell,\n} from '../../utils/lattice.ts';\nimport { nodeBounds, resizeNode } from '../../utils/shapes.ts';\nimport {\n type FreehandProjectionOptions,\n type Projection,\n createFreehandProjection,\n freehandCapabilities,\n reduceIntent,\n} from '../projection.ts';\nimport { type Bounds, type Capabilities, type ElementId, type Intent, type Node, type Scene } from '../types.ts';\n\n/** Freehand, without auto layout: arranging by a layout engine would not respect the lattice. */\nexport const latticeCapabilities: Capabilities = { ...freehandCapabilities, layout: false };\n\n/** The bounds `node` would have after `values` (a geometry `update`), or undefined when they touch no geometry. */\nconst updatedBounds = (node: Node, values: object): Bounds | undefined => {\n const center = 'center' in values && isPoint(values.center) ? values.center : undefined;\n const size = 'size' in values && isSize(values.size) ? values.size : undefined;\n if (!center && !size) {\n return undefined;\n }\n return nodeBounds({ ...node, center: center ?? node.center, size: size ?? node.size });\n};\n\nconst isPoint = (value: unknown): value is { x: number; y: number } =>\n typeof value === 'object' && value !== null && 'x' in value && 'y' in value;\n\nconst isSize = (value: unknown): value is { width: number; height: number } =>\n typeof value === 'object' && value !== null && 'width' in value && 'height' in value;\n\n/** Whether `bounds` (snapped) would overlap a node other than `except`. */\nconst blocked = (scene: Scene, spec: LatticeSpec, bounds: Bounds, except: ReadonlySet<ElementId>): boolean =>\n collides(toCell(bounds, spec), occupancy(Object.values(scene.nodes), spec, except));\n\n/**\n * `intent` rewritten onto the lattice, or undefined when it would overlap occupied cells. Geometry\n * (create, move, resize, a centre or size `update`) is snapped; everything else passes through. A batch\n * is checked step by step against the scene each step leaves, and is refused whole if any step is.\n */\nexport const constrainIntent = (scene: Scene, intent: Intent, spec: LatticeSpec): Intent | undefined => {\n switch (intent.kind) {\n case 'create': {\n if (!onLattice(intent.node)) {\n return intent;\n }\n const bounds = quantize(nodeBounds(intent.node), spec);\n return blocked(scene, spec, bounds, new Set())\n ? undefined\n : { kind: 'create', node: resizeNode(intent.node, bounds) };\n }\n\n case 'resize': {\n // The dragged edge snaps to a cell edge and the opposite edge stays, so a face steps one cell at a time.\n const node = scene.nodes[intent.id];\n if (node && !onLattice(node)) {\n return intent;\n }\n const from = node && nodeBounds(node);\n const bounds = from\n ? cellBounds(resizeCell(toCell(from, spec), from, intent.bounds, spec), spec)\n : quantize(intent.bounds, spec);\n return blocked(scene, spec, bounds, new Set([intent.id])) ? undefined : { kind: 'resize', id: intent.id, bounds };\n }\n\n case 'move': {\n // Each moved node snaps on its own; together they must clear the nodes left behind and each other.\n const moving = new Set(intent.ids);\n const others = occupancy(Object.values(scene.nodes), spec, moving);\n const taken = new Map<string, ElementId>();\n // A node off the lattice (a group's backdrop) moves by the drag as is, beside the snapped ones.\n const free = intent.ids.filter((id) => {\n const node = scene.nodes[id];\n return node !== undefined && !node.locked && !onLattice(node);\n });\n const intents: Intent[] = free.length > 0 ? [{ kind: 'move', ids: free, delta: intent.delta }] : [];\n for (const id of intent.ids) {\n const node = scene.nodes[id];\n if (!node || node.locked || !onLattice(node)) {\n continue;\n }\n const from = nodeBounds(node);\n const bounds = quantize({ ...from, x: from.x + intent.delta.x, y: from.y + intent.delta.y }, spec);\n const cell = toCell(bounds, spec);\n if (collides(cell, others) || collides(cell, taken)) {\n return undefined;\n }\n for (const key of coveredCells(cell)) {\n taken.set(key, id);\n }\n intents.push({ kind: 'resize', id, bounds });\n }\n return { kind: 'batch', intents };\n }\n\n case 'update': {\n const node = scene.nodes[intent.id];\n const bounds = node && onLattice(node) ? updatedBounds(node, intent.values) : undefined;\n if (!node || !bounds) {\n return intent;\n }\n const snapped = quantize(bounds, spec);\n if (blocked(scene, spec, snapped, new Set([intent.id]))) {\n return undefined;\n }\n const placed = resizeNode(node, snapped);\n return { kind: 'update', id: intent.id, values: { ...intent.values, center: placed.center, size: placed.size } };\n }\n\n case 'batch': {\n let working = scene;\n const intents: Intent[] = [];\n for (const step of intent.intents) {\n const constrained = constrainIntent(working, step, spec);\n if (!constrained) {\n return undefined;\n }\n intents.push(constrained);\n working = reduceIntent(working, constrained);\n }\n return { kind: 'batch', intents };\n }\n\n case 'layout':\n return undefined;\n\n default:\n return intent;\n }\n};\n\nexport type LatticeProjectionOptions = FreehandProjectionOptions & {\n spec?: LatticeSpec;\n};\n\n/**\n * Freehand over the store, with geometry kept on the lattice; an intent that would overlap is refused. While\n * `constrained` says no (the view's snap is off) intents pass through as freehand, and a shape left off the\n * lattice snaps onto it the next time it is moved.\n */\nexport const createLatticeProjection = ({\n registry,\n store,\n sceneId,\n constrained = () => true,\n spec = DEFAULT_LATTICE,\n}: LatticeProjectionOptions): Projection => {\n const freehand = createFreehandProjection({ registry, store, sceneId });\n const constrain = (intent: Intent) =>\n constrained() ? constrainIntent(registry.get(freehand.scene), intent, spec) : intent;\n return {\n ...freehand,\n capabilities: latticeCapabilities,\n lattice: spec,\n constrain,\n apply: (intent) => {\n const constrained = constrain(intent);\n if (constrained) {\n freehand.apply(constrained);\n }\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Declarative scene fixtures for stories and tests: a scene is a tree of element values, each made by a\n// factory and refined with `properties()`, so a fixture reads like the diagram it describes. A nested\n// `scene` is a scene shape and its child scene in one; `build()` flattens the tree into the scenes a\n// store holds. Boxes are top-left; refs like `a#e2` name a port and `@x,y` a free end.\n//\n\nimport * as Exit from 'effect/Exit';\nimport * as Schema from 'effect/Schema';\n\nimport { type NodeRegistry, defaultNodeRegistry } from '../model/registry.ts';\nimport {\n type BuiltinNode,\n type BuiltinNodeType,\n type Endpoint,\n type FrameNode,\n type Link,\n type LinkType,\n type Node,\n type NodeBase,\n type NodeStyle,\n type Point,\n type Scene,\n type SceneId,\n} from '../model/types.ts';\nimport { DEFAULT_LAYER } from './layers.ts';\nimport { initialKeys } from './order.ts';\nimport { createNode } from './shapes.ts';\n\n/** Top-left box geometry; the builder stores the centre. */\nexport type Box = { x: number; y: number; width: number; height: number };\n\nconst center = ({ x, y, width, height }: Box): Point => ({ x: x + width / 2, y: y + height / 2 });\n\n/** `node`, `node#port`, or a free end `@x,y`. */\nconst endpoint = (ref: string): Endpoint => {\n if (ref.startsWith('@')) {\n const [x, y] = ref.slice(1).split(',').map(Number);\n return { point: { x, y } };\n }\n const [node, port] = ref.split('#');\n return port ? { node, port } : { node };\n};\n\ntype NodeOf<T extends BuiltinNodeType> = Extract<BuiltinNode, { type: T }>;\ntype LinkOf<T extends LinkType> = Extract<Link, { type: T }>;\n\n/** What `properties()` may set on a node: everything but its identity, its paint order and the frame its box fixes. */\nexport type NodeProperties<N> = Partial<Omit<N, 'id' | 'type' | 'z' | 'center' | 'size'>>;\n\n/** What `properties()` may set on a link: everything but its identity, its paint order and its ends. */\nexport type LinkProperties<L> = Partial<Omit<L, 'id' | 'type' | 'z' | 'source' | 'target'>>;\n\ntype NodeBody = Omit<NodeBase, 'z'> & Record<string, unknown>;\ntype LinkBody = DistributiveOmit<Link, 'z' | 'id'>;\n\n/** `Omit` over each member of a union, not over their intersection. */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\n/** Later values win; `style` merges key by key, so one call can add a hue without dropping another's fill. */\nconst mergeStyle = (base: { style?: NodeStyle }, values: { style?: NodeStyle }) =>\n base.style || values.style ? { style: { ...base.style, ...values.style } } : {};\n\n/**\n * A node of the scene, as written: refine it with `properties()`, which returns a new value. `N` types\n * the properties; `build()` checks the result against the type's schema.\n */\nexport class NodeElement<N extends NodeBase> {\n readonly kind = 'node';\n\n constructor(readonly node: NodeBody) {}\n\n properties(values: NodeProperties<N>): NodeElement<N> {\n return new NodeElement<N>({ ...this.node, ...values, ...mergeStyle(this.node, values) });\n }\n}\n\n/** A link of the scene, as written; its id defaults to its ends (`a-b`), unique within the scene. */\nexport class LinkElement<L extends Link> {\n readonly kind = 'link';\n\n constructor(\n readonly link: LinkBody,\n readonly linkId?: string,\n ) {}\n\n id(id: string): LinkElement<L> {\n return new LinkElement<L>(this.link, id);\n }\n\n properties(values: LinkProperties<L>): LinkElement<L> {\n return new LinkElement<L>({ ...this.link, ...values }, this.linkId);\n }\n}\n\nexport type BuilderElement = NodeElement<NodeBase> | LinkElement<Link> | SceneElement;\n\n/**\n * A scene and its elements in paint order. At the top it is the root scene; nested, it is also a scene\n * shape placed with `at()`, whose child scene shares its id.\n */\nexport class SceneElement {\n readonly kind = 'scene';\n\n constructor(\n readonly id: SceneId,\n readonly elements: readonly BuilderElement[],\n readonly frame?: Box,\n readonly sceneName?: string,\n readonly portal: NodeProperties<FrameNode> = {},\n ) {}\n\n /** The scene's name (breadcrumbs, previews). */\n name(name: string): SceneElement {\n return new SceneElement(this.id, this.elements, this.frame, name, this.portal);\n }\n\n /** Where the scene shape sits in its parent scene; required for a nested scene. */\n at(box: Box): SceneElement {\n return new SceneElement(this.id, this.elements, box, this.sceneName, this.portal);\n }\n\n /** The scene shape's own properties (label, contents, style). */\n properties(values: NodeProperties<FrameNode>): SceneElement {\n return new SceneElement(this.id, this.elements, this.frame, this.sceneName, {\n ...this.portal,\n ...values,\n ...mergeStyle(this.portal, values),\n });\n }\n\n /** Every scene of the tree, the root first, checked against `registry`'s node schemas. */\n build(registry: NodeRegistry = defaultNodeRegistry): SceneTree {\n const scenes: Scene[] = [];\n buildScene(this, registry, scenes);\n return { root: this.id, scenes };\n }\n}\n\nexport type SceneTree = { root: SceneId; scenes: Scene[] };\n\nconst buildScene = (element: SceneElement, registry: NodeRegistry, scenes: Scene[]): void => {\n // Maps, so any id (`constructor`, `__proto__`) is an ordinary key; `fromEntries` keeps them own properties.\n const nodes = new Map<string, Node>();\n const links = new Map<string, Link>();\n const keys = initialKeys(element.elements.length);\n // Every element names its layer, so a fixture reads as a scene the editor wrote.\n const index =\n scenes.push({\n id: element.id,\n name: element.sceneName,\n nodes: {},\n links: {},\n layers: { [DEFAULT_LAYER.id]: DEFAULT_LAYER },\n }) - 1;\n element.elements.forEach((child, order) => {\n const z = keys[order];\n switch (child.kind) {\n case 'node': {\n // A host's type starts from its own `create`, as a built-in starts from `createNode`, so a\n // fixture sets only what it means and the type supplies the rest of its content.\n const def = isBuiltinType(child.node.type) ? undefined : registry[child.node.type];\n const fresh = def?.create({ id: child.node.id, z, center: child.node.center, size: child.node.size });\n const node = { layer: DEFAULT_LAYER.id, ...fresh, ...child.node, z };\n check(registry, node);\n claim(nodes, node.id, element.id);\n nodes.set(node.id, node);\n break;\n }\n case 'link': {\n const id = child.linkId ?? uniqueId(links, linkId(child.link.source, child.link.target));\n claim(links, id, element.id);\n links.set(id, { layer: DEFAULT_LAYER.id, ...child.link, id, z });\n break;\n }\n case 'scene': {\n if (!child.frame) {\n throw new Error(`Nested scene ${child.id} needs a frame: call at(box).`);\n }\n const node: FrameNode = {\n ...createNode({ type: 'frame', id: child.id, z, center: center(child.frame), size: sizeOf(child.frame) }),\n layer: DEFAULT_LAYER.id,\n ...child.portal,\n type: 'frame',\n scene: child.id,\n };\n check(registry, node);\n claim(nodes, node.id, element.id);\n nodes.set(node.id, node);\n buildScene(child, registry, scenes);\n break;\n }\n }\n });\n scenes[index] = { ...scenes[index], nodes: Object.fromEntries(nodes), links: Object.fromEntries(links) };\n};\n\n/** A node its type does not describe (a wrong value, or a property the type does not have) fails the build. */\nconst check = (registry: NodeRegistry, node: Node): void => {\n const def = registry[node.type];\n if (!def) {\n return;\n }\n const result = Schema.encodeExit(def.schema, { onExcessProperty: 'error' })(node);\n if (Exit.isFailure(result)) {\n throw new Error(`Node ${node.id} is not a valid ${node.type}: ${result.cause}`);\n }\n};\n\n/** Two elements given one id would leave only the second, so the fixture fails instead. */\nconst claim = (taken: ReadonlyMap<string, unknown>, id: string, sceneId: SceneId): void => {\n if (taken.has(id)) {\n throw new Error(`Duplicate id ${id} in scene ${sceneId}.`);\n }\n};\n\nconst linkId = (source: Endpoint, target: Endpoint): string => {\n const name = (end: Endpoint) => ('node' in end ? end.node : `${end.point.x},${end.point.y}`);\n return `${name(source)}-${name(target)}`;\n};\n\nconst uniqueId = (taken: ReadonlyMap<string, unknown>, id: string): string => {\n let candidate = id;\n for (let suffix = 2; taken.has(candidate); ++suffix) {\n candidate = `${id}-${suffix}`;\n }\n return candidate;\n};\n\nconst sizeOf = ({ width, height }: Box) => ({ width, height });\n\n/** A built-in node of `type` with the type's default content, refined by `properties()`. */\nfunction node<T extends BuiltinNodeType>(type: T, id: string, box: Box): NodeElement<NodeOf<T>>;\n/** A host node type: whatever the host's registry schema accepts. */\nfunction node(type: string, id: string, box: Box): NodeElement<NodeBase & Record<string, unknown>>;\nfunction node(type: string, id: string, box: Box): NodeElement<NodeBase> {\n const base = { type, id, center: center(box), size: sizeOf(box) };\n if (isBuiltinType(type)) {\n const { z: _, ...fresh } = createNode({ ...base, type, z: '' });\n return new NodeElement<NodeBase>({ ...fresh });\n }\n return new NodeElement<NodeBase>(base);\n}\n\nconst BUILTIN_TYPES: readonly string[] = ['rect', 'ellipse', 'note', 'frame'] satisfies BuiltinNodeType[];\nconst isBuiltinType = (type: string): type is BuiltinNodeType => BUILTIN_TYPES.includes(type);\n\ntype Ends = Pick<Link, 'source' | 'target'>;\n\nconst LINKS: Record<LinkType, (ends: Ends) => LinkBody> = {\n line: (ends) => ({ type: 'line', ...ends }),\n curve: (ends) => ({ type: 'curve', ...ends }),\n spline: (ends) => ({ type: 'spline', ...ends, points: [] }),\n smart: (ends) => ({ type: 'smart', ...ends }),\n};\n\n/** A link of `type` from one ref to another; a spline starts with no control points. */\nconst link = <T extends LinkType>(type: T, from: string, to: string): LinkElement<LinkOf<T>> =>\n new LinkElement<LinkOf<T>>(LINKS[type]({ source: endpoint(from), target: endpoint(to) }));\n\n/** Factories for scene fixtures; see the module comment. */\nexport const SceneBuilder = {\n /** A scene of `elements`; the root of a fixture, or nested, a scene shape and its child scene. */\n scene: (id: SceneId, elements: readonly BuilderElement[] = []) => new SceneElement(id, elements),\n node,\n rect: (id: string, box: Box) => node('rect', id, box),\n ellipse: (id: string, box: Box) => node('ellipse', id, box),\n note: (id: string, box: Box) => node('note', id, box),\n link,\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Bridge from the scene engine to `@dxos/diagram`'s scene, so its `Diagnostics` and `Objective` —\n// the measurements the layout engines are selected by — can grade a scene a person is editing.\n//\n\nimport { type Scene as Diagram } from '@dxos/diagram';\n\nimport { type NodeRegistry } from '../model/registry.ts';\nimport { type ElementId, type Link, type Point, type Scene, isEllipseNode } from '../model/types.ts';\nimport { nodeTitle } from './parts.ts';\nimport { curvePoint, linkGeometry, smartPoints } from './route.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** Samples per curve: enough for crossings and routes-through-node to see the arc, not just its chord. */\nconst CURVE_SAMPLES = 8;\n\nexport type DiagramObjects = {\n objects: Diagram.WorldObject[];\n /** Scene element id for each diagram object id, to map a diagnostic's refs back onto the scene. */\n elementOf: ReadonlyMap<string, ElementId>;\n};\n\n/**\n * `Diagnostics` reads the owning object as the ref's prefix up to `/`, and `#` as a port; percent-encoding\n * removes both and stays injective, so distinct ids never merge into one owner.\n */\nconst objectId = (id: ElementId): string => encodeURIComponent(id);\n\n/** The polyline a link is drawn along, in scene coordinates. */\nconst linkPoints = (scene: Scene, registry: NodeRegistry, link: Link): Point[] | undefined => {\n const geometry = linkGeometry(scene, registry, link);\n if (!geometry) {\n return undefined;\n }\n const { source, target } = geometry;\n switch (link.type) {\n case 'line':\n return [source.point, target.point];\n case 'spline':\n return [source.point, ...link.points, target.point];\n case 'smart':\n return smartPoints(source, target);\n case 'curve':\n return Array.from({ length: CURVE_SAMPLES + 1 }, (_, index) => curvePoint(source, target, index / CURVE_SAMPLES));\n }\n};\n\n/**\n * One diagram object per node (a box with its label) and per link (a polyline), so `Diagnostics`\n * compares nodes across objects exactly as it does for an engine's output. Nodes that enclose\n * others read as containers there, which is what a guide frame around a group is.\n */\nexport const toDiagramObjects = (scene: Scene, registry: NodeRegistry): DiagramObjects => {\n const elementOf = new Map<string, ElementId>();\n const objects: Diagram.WorldObject[] = [];\n for (const node of Object.values(scene.nodes)) {\n const { x, y, width, height } = nodeBounds(node);\n const id = objectId(node.id);\n elementOf.set(id, node.id);\n objects.push({\n id,\n elements: [\n {\n kind: isEllipseNode(node) ? 'ellipse' : 'rect',\n id: 'box',\n x,\n y,\n w: width,\n h: height,\n ...(node.style?.guide ? {} : { text: nodeTitle(registry, node) }),\n },\n ],\n });\n }\n for (const link of Object.values(scene.links)) {\n const points = linkPoints(scene, registry, link);\n if (!points || points.length < 2) {\n continue;\n }\n const id = objectId(link.id);\n elementOf.set(id, link.id);\n objects.push({ id, elements: [{ kind: 'line', id: 'path', points }] });\n }\n return { objects, elementOf };\n};\n\n/** The scene elements a diagnostic implicates, from its `object/element` refs. */\nexport const diagnosticElements = ({ elementOf }: DiagramObjects, refs: readonly string[]): ElementId[] =>\n refs.flatMap((ref) => {\n const element = elementOf.get(ref.slice(0, ref.indexOf('/')));\n return element ? [element] : [];\n });\n"],"mappings":"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"}