@dryui/ui 0.2.2 → 0.3.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 (433) hide show
  1. package/dist/adjust/adjust.svelte +1 -1
  2. package/dist/aurora/aurora.svelte +58 -11
  3. package/dist/aurora/aurora.svelte.d.ts +1 -0
  4. package/dist/aurora/index.d.ts +2 -0
  5. package/dist/diagram/diagram.svelte +769 -0
  6. package/dist/diagram/diagram.svelte.d.ts +10 -0
  7. package/dist/diagram/edge-routing.d.ts +9 -0
  8. package/dist/diagram/edge-routing.js +281 -0
  9. package/dist/diagram/index.d.ts +9 -0
  10. package/dist/diagram/index.js +1 -0
  11. package/dist/diagram/layout.d.ts +2 -0
  12. package/dist/diagram/layout.js +985 -0
  13. package/dist/diagram/types.d.ts +196 -0
  14. package/dist/displacement/displacement.svelte +39 -3
  15. package/dist/drag-and-drop/context.svelte.d.ts +1 -0
  16. package/dist/drag-and-drop/drag-and-drop-group.svelte +37 -0
  17. package/dist/drag-and-drop/drag-and-drop-group.svelte.d.ts +8 -0
  18. package/dist/drag-and-drop/drag-and-drop-handle.svelte +2 -0
  19. package/dist/drag-and-drop/drag-and-drop-item.svelte +25 -6
  20. package/dist/drag-and-drop/drag-and-drop-root.svelte +624 -34
  21. package/dist/drag-and-drop/group-context.svelte.d.ts +13 -0
  22. package/dist/drag-and-drop/group-context.svelte.js +8 -0
  23. package/dist/drag-and-drop/index.d.ts +2 -0
  24. package/dist/drag-and-drop/index.js +3 -1
  25. package/dist/drawer/drawer-content.svelte +2 -1
  26. package/dist/drawer/drawer-footer.svelte +1 -1
  27. package/dist/gradient-mesh/gradient-mesh.svelte +42 -5
  28. package/dist/halftone/halftone.svelte +16 -36
  29. package/dist/index.d.ts +1 -4
  30. package/dist/index.js +1 -2
  31. package/dist/logo-mark/logo-mark.svelte +2 -2
  32. package/dist/noise/noise.svelte +2 -2
  33. package/dist/shader-canvas/presets.js +1 -1
  34. package/dist/shader-canvas/shader-canvas.svelte +4 -1
  35. package/dist/sidebar/sidebar-footer.svelte +5 -4
  36. package/dist/spotlight/spotlight.svelte +42 -4
  37. package/dist/themes/aurora.css +229 -0
  38. package/dist/themes/dark.css +134 -0
  39. package/dist/themes/default.css +76 -0
  40. package/dist/themes/midnight.css +142 -0
  41. package/dist/themes/terminal.css +175 -0
  42. package/package.json +22 -27
  43. package/skills/dryui/SKILL.md +1 -0
  44. package/dist/system-map/index.d.ts +0 -17
  45. package/dist/system-map/index.js +0 -1
  46. package/dist/system-map/system-map.svelte +0 -311
  47. package/dist/system-map/system-map.svelte.d.ts +0 -25
  48. package/dist/system-map/types.d.ts +0 -99
  49. package/dist/thumbnail/_layout-content.svelte +0 -89
  50. package/dist/thumbnail/_layout-content.svelte.d.ts +0 -9
  51. package/dist/thumbnail/_layout-footer.svelte +0 -54
  52. package/dist/thumbnail/_layout-footer.svelte.d.ts +0 -9
  53. package/dist/thumbnail/_layout-header.svelte +0 -76
  54. package/dist/thumbnail/_layout-header.svelte.d.ts +0 -9
  55. package/dist/thumbnail/_layout-sidebar.svelte +0 -75
  56. package/dist/thumbnail/_layout-sidebar.svelte.d.ts +0 -9
  57. package/dist/thumbnail/accordion.svelte +0 -144
  58. package/dist/thumbnail/accordion.svelte.d.ts +0 -7
  59. package/dist/thumbnail/add-on-selector.svelte +0 -213
  60. package/dist/thumbnail/add-on-selector.svelte.d.ts +0 -7
  61. package/dist/thumbnail/affix-group.svelte +0 -55
  62. package/dist/thumbnail/affix-group.svelte.d.ts +0 -7
  63. package/dist/thumbnail/alert-dialog.svelte +0 -100
  64. package/dist/thumbnail/alert-dialog.svelte.d.ts +0 -7
  65. package/dist/thumbnail/alert.svelte +0 -79
  66. package/dist/thumbnail/alert.svelte.d.ts +0 -7
  67. package/dist/thumbnail/alpha-slider.svelte +0 -55
  68. package/dist/thumbnail/alpha-slider.svelte.d.ts +0 -7
  69. package/dist/thumbnail/amenity-grid.svelte +0 -236
  70. package/dist/thumbnail/amenity-grid.svelte.d.ts +0 -7
  71. package/dist/thumbnail/app-frame.svelte.d.ts +0 -7
  72. package/dist/thumbnail/apply-size.d.ts +0 -3
  73. package/dist/thumbnail/apply-size.js +0 -14
  74. package/dist/thumbnail/aspect-ratio.svelte +0 -64
  75. package/dist/thumbnail/aspect-ratio.svelte.d.ts +0 -7
  76. package/dist/thumbnail/aurora.svelte +0 -88
  77. package/dist/thumbnail/aurora.svelte.d.ts +0 -7
  78. package/dist/thumbnail/avatar-group.svelte.d.ts +0 -7
  79. package/dist/thumbnail/avatar.svelte +0 -60
  80. package/dist/thumbnail/avatar.svelte.d.ts +0 -7
  81. package/dist/thumbnail/backdrop.svelte +0 -73
  82. package/dist/thumbnail/backdrop.svelte.d.ts +0 -7
  83. package/dist/thumbnail/badge.svelte +0 -100
  84. package/dist/thumbnail/badge.svelte.d.ts +0 -7
  85. package/dist/thumbnail/booking-confirmation.svelte +0 -109
  86. package/dist/thumbnail/booking-confirmation.svelte.d.ts +0 -7
  87. package/dist/thumbnail/breadcrumb.svelte +0 -80
  88. package/dist/thumbnail/breadcrumb.svelte.d.ts +0 -7
  89. package/dist/thumbnail/button-group.svelte +0 -76
  90. package/dist/thumbnail/button-group.svelte.d.ts +0 -7
  91. package/dist/thumbnail/button.svelte +0 -62
  92. package/dist/thumbnail/button.svelte.d.ts +0 -7
  93. package/dist/thumbnail/calendar.svelte +0 -86
  94. package/dist/thumbnail/calendar.svelte.d.ts +0 -7
  95. package/dist/thumbnail/card.svelte +0 -113
  96. package/dist/thumbnail/card.svelte.d.ts +0 -7
  97. package/dist/thumbnail/carousel.svelte +0 -111
  98. package/dist/thumbnail/carousel.svelte.d.ts +0 -7
  99. package/dist/thumbnail/chart.svelte +0 -93
  100. package/dist/thumbnail/chart.svelte.d.ts +0 -7
  101. package/dist/thumbnail/chat-message.svelte.d.ts +0 -7
  102. package/dist/thumbnail/chat-thread.svelte +0 -140
  103. package/dist/thumbnail/chat-thread.svelte.d.ts +0 -7
  104. package/dist/thumbnail/checkbox.svelte +0 -71
  105. package/dist/thumbnail/checkbox.svelte.d.ts +0 -7
  106. package/dist/thumbnail/chip-group.svelte +0 -79
  107. package/dist/thumbnail/chip-group.svelte.d.ts +0 -7
  108. package/dist/thumbnail/chip.svelte +0 -76
  109. package/dist/thumbnail/chip.svelte.d.ts +0 -7
  110. package/dist/thumbnail/chromatic-shift.svelte +0 -55
  111. package/dist/thumbnail/chromatic-shift.svelte.d.ts +0 -7
  112. package/dist/thumbnail/clipboard.svelte +0 -68
  113. package/dist/thumbnail/clipboard.svelte.d.ts +0 -7
  114. package/dist/thumbnail/code-block.svelte +0 -125
  115. package/dist/thumbnail/code-block.svelte.d.ts +0 -7
  116. package/dist/thumbnail/collapsible.svelte +0 -101
  117. package/dist/thumbnail/collapsible.svelte.d.ts +0 -7
  118. package/dist/thumbnail/color-picker.svelte +0 -108
  119. package/dist/thumbnail/color-picker.svelte.d.ts +0 -7
  120. package/dist/thumbnail/combobox.svelte +0 -122
  121. package/dist/thumbnail/combobox.svelte.d.ts +0 -7
  122. package/dist/thumbnail/command-palette.svelte +0 -134
  123. package/dist/thumbnail/command-palette.svelte.d.ts +0 -7
  124. package/dist/thumbnail/commerce-header.svelte +0 -55
  125. package/dist/thumbnail/commerce-header.svelte.d.ts +0 -7
  126. package/dist/thumbnail/comparison-table.svelte +0 -193
  127. package/dist/thumbnail/comparison-table.svelte.d.ts +0 -7
  128. package/dist/thumbnail/container.svelte +0 -119
  129. package/dist/thumbnail/container.svelte.d.ts +0 -7
  130. package/dist/thumbnail/context-menu.svelte +0 -108
  131. package/dist/thumbnail/context-menu.svelte.d.ts +0 -7
  132. package/dist/thumbnail/country-select.svelte +0 -111
  133. package/dist/thumbnail/country-select.svelte.d.ts +0 -7
  134. package/dist/thumbnail/currency-selector.svelte +0 -111
  135. package/dist/thumbnail/currency-selector.svelte.d.ts +0 -7
  136. package/dist/thumbnail/data-grid.svelte +0 -230
  137. package/dist/thumbnail/data-grid.svelte.d.ts +0 -7
  138. package/dist/thumbnail/date-field.svelte +0 -132
  139. package/dist/thumbnail/date-field.svelte.d.ts +0 -7
  140. package/dist/thumbnail/date-picker.svelte +0 -126
  141. package/dist/thumbnail/date-picker.svelte.d.ts +0 -7
  142. package/dist/thumbnail/date-range-picker.svelte +0 -100
  143. package/dist/thumbnail/date-range-picker.svelte.d.ts +0 -7
  144. package/dist/thumbnail/date-time-input.svelte +0 -182
  145. package/dist/thumbnail/date-time-input.svelte.d.ts +0 -7
  146. package/dist/thumbnail/description-list.svelte +0 -142
  147. package/dist/thumbnail/description-list.svelte.d.ts +0 -7
  148. package/dist/thumbnail/dialog.svelte +0 -136
  149. package/dist/thumbnail/dialog.svelte.d.ts +0 -7
  150. package/dist/thumbnail/displacement.svelte +0 -55
  151. package/dist/thumbnail/displacement.svelte.d.ts +0 -7
  152. package/dist/thumbnail/drag-and-drop.svelte +0 -139
  153. package/dist/thumbnail/drag-and-drop.svelte.d.ts +0 -7
  154. package/dist/thumbnail/drawer.svelte +0 -112
  155. package/dist/thumbnail/drawer.svelte.d.ts +0 -7
  156. package/dist/thumbnail/drop-zone.svelte +0 -55
  157. package/dist/thumbnail/drop-zone.svelte.d.ts +0 -7
  158. package/dist/thumbnail/dropdown-menu.svelte +0 -128
  159. package/dist/thumbnail/dropdown-menu.svelte.d.ts +0 -7
  160. package/dist/thumbnail/empty-state.svelte.d.ts +0 -7
  161. package/dist/thumbnail/fare-class-picker.svelte +0 -225
  162. package/dist/thumbnail/fare-class-picker.svelte.d.ts +0 -7
  163. package/dist/thumbnail/feature-split-section.svelte.d.ts +0 -7
  164. package/dist/thumbnail/field.svelte +0 -82
  165. package/dist/thumbnail/field.svelte.d.ts +0 -7
  166. package/dist/thumbnail/fieldset.svelte +0 -123
  167. package/dist/thumbnail/fieldset.svelte.d.ts +0 -7
  168. package/dist/thumbnail/file-select.svelte +0 -90
  169. package/dist/thumbnail/file-select.svelte.d.ts +0 -7
  170. package/dist/thumbnail/file-upload.svelte +0 -84
  171. package/dist/thumbnail/file-upload.svelte.d.ts +0 -7
  172. package/dist/thumbnail/filter-sidebar.svelte +0 -201
  173. package/dist/thumbnail/filter-sidebar.svelte.d.ts +0 -7
  174. package/dist/thumbnail/flexible-dates-grid.svelte +0 -210
  175. package/dist/thumbnail/flexible-dates-grid.svelte.d.ts +0 -7
  176. package/dist/thumbnail/flight-timeline.svelte +0 -155
  177. package/dist/thumbnail/flight-timeline.svelte.d.ts +0 -7
  178. package/dist/thumbnail/flip-card.svelte +0 -128
  179. package/dist/thumbnail/flip-card.svelte.d.ts +0 -7
  180. package/dist/thumbnail/float-button.svelte +0 -63
  181. package/dist/thumbnail/float-button.svelte.d.ts +0 -7
  182. package/dist/thumbnail/focus-trap.svelte +0 -110
  183. package/dist/thumbnail/focus-trap.svelte.d.ts +0 -7
  184. package/dist/thumbnail/format-bytes.svelte +0 -51
  185. package/dist/thumbnail/format-bytes.svelte.d.ts +0 -7
  186. package/dist/thumbnail/format-date.svelte +0 -51
  187. package/dist/thumbnail/format-date.svelte.d.ts +0 -7
  188. package/dist/thumbnail/format-number.svelte +0 -51
  189. package/dist/thumbnail/format-number.svelte.d.ts +0 -7
  190. package/dist/thumbnail/gauge.svelte +0 -90
  191. package/dist/thumbnail/gauge.svelte.d.ts +0 -7
  192. package/dist/thumbnail/glass-surface.svelte.d.ts +0 -7
  193. package/dist/thumbnail/glow.svelte +0 -55
  194. package/dist/thumbnail/glow.svelte.d.ts +0 -7
  195. package/dist/thumbnail/gradient-mesh.svelte +0 -55
  196. package/dist/thumbnail/gradient-mesh.svelte.d.ts +0 -7
  197. package/dist/thumbnail/guest-room-selector.svelte +0 -214
  198. package/dist/thumbnail/guest-room-selector.svelte.d.ts +0 -7
  199. package/dist/thumbnail/halftone.svelte +0 -55
  200. package/dist/thumbnail/halftone.svelte.d.ts +0 -7
  201. package/dist/thumbnail/heading.svelte +0 -91
  202. package/dist/thumbnail/heading.svelte.d.ts +0 -7
  203. package/dist/thumbnail/hotel-gallery.svelte +0 -117
  204. package/dist/thumbnail/hotel-gallery.svelte.d.ts +0 -7
  205. package/dist/thumbnail/hotkey.svelte +0 -108
  206. package/dist/thumbnail/hotkey.svelte.d.ts +0 -7
  207. package/dist/thumbnail/hover-card.svelte +0 -117
  208. package/dist/thumbnail/hover-card.svelte.d.ts +0 -7
  209. package/dist/thumbnail/icon.svelte +0 -55
  210. package/dist/thumbnail/icon.svelte.d.ts +0 -7
  211. package/dist/thumbnail/image-comparison.svelte +0 -96
  212. package/dist/thumbnail/image-comparison.svelte.d.ts +0 -7
  213. package/dist/thumbnail/image.svelte +0 -74
  214. package/dist/thumbnail/image.svelte.d.ts +0 -7
  215. package/dist/thumbnail/index.d.ts +0 -12
  216. package/dist/thumbnail/index.js +0 -359
  217. package/dist/thumbnail/infinite-scroll.svelte +0 -129
  218. package/dist/thumbnail/infinite-scroll.svelte.d.ts +0 -7
  219. package/dist/thumbnail/input-group.svelte +0 -55
  220. package/dist/thumbnail/input-group.svelte.d.ts +0 -7
  221. package/dist/thumbnail/input.svelte +0 -74
  222. package/dist/thumbnail/input.svelte.d.ts +0 -7
  223. package/dist/thumbnail/itinerary-timeline.svelte +0 -143
  224. package/dist/thumbnail/itinerary-timeline.svelte.d.ts +0 -7
  225. package/dist/thumbnail/kbd.svelte +0 -112
  226. package/dist/thumbnail/kbd.svelte.d.ts +0 -7
  227. package/dist/thumbnail/label.svelte +0 -54
  228. package/dist/thumbnail/label.svelte.d.ts +0 -7
  229. package/dist/thumbnail/layout-header-content-footer.svelte +0 -64
  230. package/dist/thumbnail/layout-header-content-footer.svelte.d.ts +0 -7
  231. package/dist/thumbnail/layout-header-sidebar-main.svelte +0 -64
  232. package/dist/thumbnail/layout-header-sidebar-main.svelte.d.ts +0 -7
  233. package/dist/thumbnail/layout-sidebar-main.svelte +0 -57
  234. package/dist/thumbnail/layout-sidebar-main.svelte.d.ts +0 -7
  235. package/dist/thumbnail/link-preview.svelte +0 -141
  236. package/dist/thumbnail/link-preview.svelte.d.ts +0 -7
  237. package/dist/thumbnail/link.svelte +0 -70
  238. package/dist/thumbnail/link.svelte.d.ts +0 -7
  239. package/dist/thumbnail/list.svelte +0 -86
  240. package/dist/thumbnail/list.svelte.d.ts +0 -7
  241. package/dist/thumbnail/listbox.svelte +0 -102
  242. package/dist/thumbnail/listbox.svelte.d.ts +0 -7
  243. package/dist/thumbnail/location-autocomplete.svelte +0 -219
  244. package/dist/thumbnail/location-autocomplete.svelte.d.ts +0 -7
  245. package/dist/thumbnail/logo-cloud.svelte.d.ts +0 -7
  246. package/dist/thumbnail/loyalty-points-display.svelte +0 -147
  247. package/dist/thumbnail/loyalty-points-display.svelte.d.ts +0 -7
  248. package/dist/thumbnail/map-list-toggle.svelte +0 -140
  249. package/dist/thumbnail/map-list-toggle.svelte.d.ts +0 -7
  250. package/dist/thumbnail/map.svelte +0 -112
  251. package/dist/thumbnail/map.svelte.d.ts +0 -7
  252. package/dist/thumbnail/markdown-renderer.svelte +0 -113
  253. package/dist/thumbnail/markdown-renderer.svelte.d.ts +0 -7
  254. package/dist/thumbnail/marquee.svelte +0 -114
  255. package/dist/thumbnail/marquee.svelte.d.ts +0 -7
  256. package/dist/thumbnail/mask-reveal.svelte +0 -55
  257. package/dist/thumbnail/mask-reveal.svelte.d.ts +0 -7
  258. package/dist/thumbnail/mega-menu.svelte +0 -176
  259. package/dist/thumbnail/mega-menu.svelte.d.ts +0 -7
  260. package/dist/thumbnail/menubar.svelte +0 -99
  261. package/dist/thumbnail/menubar.svelte.d.ts +0 -7
  262. package/dist/thumbnail/multi-city-search-form.svelte +0 -241
  263. package/dist/thumbnail/multi-city-search-form.svelte.d.ts +0 -7
  264. package/dist/thumbnail/multi-select-combobox.svelte +0 -142
  265. package/dist/thumbnail/multi-select-combobox.svelte.d.ts +0 -7
  266. package/dist/thumbnail/navigation-menu.svelte +0 -102
  267. package/dist/thumbnail/navigation-menu.svelte.d.ts +0 -7
  268. package/dist/thumbnail/noise.svelte +0 -72
  269. package/dist/thumbnail/noise.svelte.d.ts +0 -7
  270. package/dist/thumbnail/notification-center.svelte +0 -152
  271. package/dist/thumbnail/notification-center.svelte.d.ts +0 -7
  272. package/dist/thumbnail/number-input.svelte +0 -113
  273. package/dist/thumbnail/number-input.svelte.d.ts +0 -7
  274. package/dist/thumbnail/option-swatch-group.svelte +0 -55
  275. package/dist/thumbnail/option-swatch-group.svelte.d.ts +0 -7
  276. package/dist/thumbnail/page-header.svelte.d.ts +0 -7
  277. package/dist/thumbnail/pagination.svelte +0 -121
  278. package/dist/thumbnail/pagination.svelte.d.ts +0 -7
  279. package/dist/thumbnail/passenger-class-selector.svelte +0 -142
  280. package/dist/thumbnail/passenger-class-selector.svelte.d.ts +0 -7
  281. package/dist/thumbnail/payment-card-input.svelte +0 -172
  282. package/dist/thumbnail/payment-card-input.svelte.d.ts +0 -7
  283. package/dist/thumbnail/phone-input.svelte +0 -103
  284. package/dist/thumbnail/phone-input.svelte.d.ts +0 -7
  285. package/dist/thumbnail/pin-input.svelte +0 -72
  286. package/dist/thumbnail/pin-input.svelte.d.ts +0 -7
  287. package/dist/thumbnail/popover.svelte +0 -122
  288. package/dist/thumbnail/popover.svelte.d.ts +0 -7
  289. package/dist/thumbnail/portal.svelte +0 -115
  290. package/dist/thumbnail/portal.svelte.d.ts +0 -7
  291. package/dist/thumbnail/price-calendar.svelte +0 -366
  292. package/dist/thumbnail/price-calendar.svelte.d.ts +0 -7
  293. package/dist/thumbnail/price-summary-panel.svelte +0 -165
  294. package/dist/thumbnail/price-summary-panel.svelte.d.ts +0 -7
  295. package/dist/thumbnail/progress-ring.svelte +0 -63
  296. package/dist/thumbnail/progress-ring.svelte.d.ts +0 -7
  297. package/dist/thumbnail/progress.svelte +0 -66
  298. package/dist/thumbnail/progress.svelte.d.ts +0 -7
  299. package/dist/thumbnail/promo-code-input.svelte +0 -111
  300. package/dist/thumbnail/promo-code-input.svelte.d.ts +0 -7
  301. package/dist/thumbnail/promo-mosaic.svelte +0 -55
  302. package/dist/thumbnail/promo-mosaic.svelte.d.ts +0 -7
  303. package/dist/thumbnail/prompt-input.svelte +0 -91
  304. package/dist/thumbnail/prompt-input.svelte.d.ts +0 -7
  305. package/dist/thumbnail/qr-code.svelte +0 -217
  306. package/dist/thumbnail/qr-code.svelte.d.ts +0 -7
  307. package/dist/thumbnail/radio-group.svelte +0 -97
  308. package/dist/thumbnail/radio-group.svelte.d.ts +0 -7
  309. package/dist/thumbnail/range-calendar.svelte +0 -92
  310. package/dist/thumbnail/range-calendar.svelte.d.ts +0 -7
  311. package/dist/thumbnail/rating.svelte +0 -61
  312. package/dist/thumbnail/rating.svelte.d.ts +0 -7
  313. package/dist/thumbnail/recent-searches.svelte +0 -197
  314. package/dist/thumbnail/recent-searches.svelte.d.ts +0 -7
  315. package/dist/thumbnail/relative-time.svelte +0 -51
  316. package/dist/thumbnail/relative-time.svelte.d.ts +0 -7
  317. package/dist/thumbnail/result-card-car.svelte +0 -149
  318. package/dist/thumbnail/result-card-car.svelte.d.ts +0 -7
  319. package/dist/thumbnail/result-card-flight.svelte +0 -170
  320. package/dist/thumbnail/result-card-flight.svelte.d.ts +0 -7
  321. package/dist/thumbnail/result-card-hotel.svelte +0 -174
  322. package/dist/thumbnail/result-card-hotel.svelte.d.ts +0 -7
  323. package/dist/thumbnail/reveal.svelte +0 -109
  324. package/dist/thumbnail/reveal.svelte.d.ts +0 -7
  325. package/dist/thumbnail/review-card.svelte +0 -153
  326. package/dist/thumbnail/review-card.svelte.d.ts +0 -7
  327. package/dist/thumbnail/rich-text-editor.svelte +0 -134
  328. package/dist/thumbnail/rich-text-editor.svelte.d.ts +0 -7
  329. package/dist/thumbnail/room-type-picker.svelte +0 -212
  330. package/dist/thumbnail/room-type-picker.svelte.d.ts +0 -7
  331. package/dist/thumbnail/root.svelte +0 -52
  332. package/dist/thumbnail/root.svelte.d.ts +0 -10
  333. package/dist/thumbnail/route-map.svelte +0 -132
  334. package/dist/thumbnail/route-map.svelte.d.ts +0 -7
  335. package/dist/thumbnail/scroll-area.svelte +0 -124
  336. package/dist/thumbnail/scroll-area.svelte.d.ts +0 -7
  337. package/dist/thumbnail/scroll-to-top.svelte +0 -60
  338. package/dist/thumbnail/scroll-to-top.svelte.d.ts +0 -7
  339. package/dist/thumbnail/search-form-tabs.svelte +0 -192
  340. package/dist/thumbnail/search-form-tabs.svelte.d.ts +0 -7
  341. package/dist/thumbnail/seat-map.svelte +0 -358
  342. package/dist/thumbnail/seat-map.svelte.d.ts +0 -7
  343. package/dist/thumbnail/segmented-control.svelte +0 -93
  344. package/dist/thumbnail/segmented-control.svelte.d.ts +0 -7
  345. package/dist/thumbnail/select.svelte +0 -82
  346. package/dist/thumbnail/select.svelte.d.ts +0 -7
  347. package/dist/thumbnail/selectable-tile-group.svelte +0 -55
  348. package/dist/thumbnail/selectable-tile-group.svelte.d.ts +0 -7
  349. package/dist/thumbnail/separator.svelte +0 -94
  350. package/dist/thumbnail/separator.svelte.d.ts +0 -7
  351. package/dist/thumbnail/shader-canvas.svelte +0 -55
  352. package/dist/thumbnail/shader-canvas.svelte.d.ts +0 -7
  353. package/dist/thumbnail/sidebar.svelte +0 -109
  354. package/dist/thumbnail/sidebar.svelte.d.ts +0 -7
  355. package/dist/thumbnail/skeleton.svelte +0 -94
  356. package/dist/thumbnail/skeleton.svelte.d.ts +0 -7
  357. package/dist/thumbnail/slider.svelte +0 -71
  358. package/dist/thumbnail/slider.svelte.d.ts +0 -7
  359. package/dist/thumbnail/sort-bar.svelte +0 -156
  360. package/dist/thumbnail/sort-bar.svelte.d.ts +0 -7
  361. package/dist/thumbnail/spacer.svelte +0 -95
  362. package/dist/thumbnail/spacer.svelte.d.ts +0 -7
  363. package/dist/thumbnail/sparkline.svelte +0 -59
  364. package/dist/thumbnail/sparkline.svelte.d.ts +0 -7
  365. package/dist/thumbnail/spinner.svelte +0 -63
  366. package/dist/thumbnail/spinner.svelte.d.ts +0 -7
  367. package/dist/thumbnail/splitter.svelte +0 -79
  368. package/dist/thumbnail/splitter.svelte.d.ts +0 -7
  369. package/dist/thumbnail/spotlight.svelte +0 -90
  370. package/dist/thumbnail/spotlight.svelte.d.ts +0 -7
  371. package/dist/thumbnail/star-rating.svelte +0 -106
  372. package/dist/thumbnail/star-rating.svelte.d.ts +0 -7
  373. package/dist/thumbnail/stat-card.svelte.d.ts +0 -7
  374. package/dist/thumbnail/stepper.svelte +0 -94
  375. package/dist/thumbnail/stepper.svelte.d.ts +0 -7
  376. package/dist/thumbnail/svg.svelte +0 -55
  377. package/dist/thumbnail/svg.svelte.d.ts +0 -8
  378. package/dist/thumbnail/swatch-strip.svelte.d.ts +0 -7
  379. package/dist/thumbnail/switch.svelte.d.ts +0 -7
  380. package/dist/thumbnail/system-map.svelte +0 -154
  381. package/dist/thumbnail/system-map.svelte.d.ts +0 -7
  382. package/dist/thumbnail/table-of-contents.svelte +0 -101
  383. package/dist/thumbnail/table-of-contents.svelte.d.ts +0 -7
  384. package/dist/thumbnail/table.svelte +0 -214
  385. package/dist/thumbnail/table.svelte.d.ts +0 -7
  386. package/dist/thumbnail/tabs.svelte +0 -133
  387. package/dist/thumbnail/tabs.svelte.d.ts +0 -7
  388. package/dist/thumbnail/tag.svelte +0 -95
  389. package/dist/thumbnail/tag.svelte.d.ts +0 -7
  390. package/dist/thumbnail/tags-input.svelte +0 -142
  391. package/dist/thumbnail/tags-input.svelte.d.ts +0 -7
  392. package/dist/thumbnail/text.svelte +0 -72
  393. package/dist/thumbnail/text.svelte.d.ts +0 -7
  394. package/dist/thumbnail/textarea.svelte +0 -111
  395. package/dist/thumbnail/textarea.svelte.d.ts +0 -7
  396. package/dist/thumbnail/time-input.svelte +0 -94
  397. package/dist/thumbnail/time-input.svelte.d.ts +0 -7
  398. package/dist/thumbnail/timeline.svelte +0 -123
  399. package/dist/thumbnail/timeline.svelte.d.ts +0 -7
  400. package/dist/thumbnail/toast.svelte +0 -105
  401. package/dist/thumbnail/toast.svelte.d.ts +0 -7
  402. package/dist/thumbnail/toggle-group.svelte +0 -76
  403. package/dist/thumbnail/toggle-group.svelte.d.ts +0 -7
  404. package/dist/thumbnail/toggle.svelte +0 -46
  405. package/dist/thumbnail/toggle.svelte.d.ts +0 -7
  406. package/dist/thumbnail/token-preview.svelte.d.ts +0 -7
  407. package/dist/thumbnail/toolbar.svelte +0 -109
  408. package/dist/thumbnail/toolbar.svelte.d.ts +0 -7
  409. package/dist/thumbnail/tooltip.svelte +0 -85
  410. package/dist/thumbnail/tooltip.svelte.d.ts +0 -7
  411. package/dist/thumbnail/tour.svelte +0 -149
  412. package/dist/thumbnail/tour.svelte.d.ts +0 -7
  413. package/dist/thumbnail/transfer.svelte +0 -168
  414. package/dist/thumbnail/transfer.svelte.d.ts +0 -7
  415. package/dist/thumbnail/tree.svelte +0 -215
  416. package/dist/thumbnail/tree.svelte.d.ts +0 -7
  417. package/dist/thumbnail/trip-card.svelte +0 -137
  418. package/dist/thumbnail/trip-card.svelte.d.ts +0 -7
  419. package/dist/thumbnail/trust-badges.svelte +0 -207
  420. package/dist/thumbnail/trust-badges.svelte.d.ts +0 -7
  421. package/dist/thumbnail/typing-indicator.svelte +0 -65
  422. package/dist/thumbnail/typing-indicator.svelte.d.ts +0 -7
  423. package/dist/thumbnail/typography.svelte +0 -80
  424. package/dist/thumbnail/typography.svelte.d.ts +0 -7
  425. package/dist/thumbnail/user.svelte.d.ts +0 -7
  426. package/dist/thumbnail/video-embed.svelte +0 -87
  427. package/dist/thumbnail/video-embed.svelte.d.ts +0 -7
  428. package/dist/thumbnail/virtual-list.svelte +0 -178
  429. package/dist/thumbnail/virtual-list.svelte.d.ts +0 -7
  430. package/dist/thumbnail/visually-hidden.svelte +0 -106
  431. package/dist/thumbnail/visually-hidden.svelte.d.ts +0 -7
  432. package/dist/thumbnail/wave-divider.svelte.d.ts +0 -7
  433. /package/dist/{system-map → diagram}/types.js +0 -0
@@ -0,0 +1,985 @@
1
+ import { computeEdgePaths, emptyEdge } from './edge-routing.js';
2
+ const DEFAULT_NODE_GAP = 28;
3
+ const DEFAULT_LAYER_GAP = 56;
4
+ const DEFAULT_CLUSTER_PADDING = 32;
5
+ const DEFAULT_NODE_HEIGHT = 44;
6
+ const DESC_NODE_HEIGHT = 80;
7
+ const MIN_NODE_WIDTH = 140;
8
+ const CHAR_WIDTH = 8.5;
9
+ const NODE_PADDING_X = 48;
10
+ const MARGIN = 40;
11
+ // ── Helpers ────────────────────────────────────────────────
12
+ function estimateNodeWidth(label, description) {
13
+ const labelWidth = label.length * CHAR_WIDTH + NODE_PADDING_X;
14
+ const descWidth = description ? description.length * 6.5 + NODE_PADDING_X + 16 : 0;
15
+ return Math.max(MIN_NODE_WIDTH, labelWidth, descWidth);
16
+ }
17
+ function isHorizontal(dir) {
18
+ return dir === 'LR' || dir === 'RL';
19
+ }
20
+ function isReversed(dir) {
21
+ return dir === 'BT' || dir === 'RL';
22
+ }
23
+ function buildGraph(nodeIds, edges) {
24
+ const adjacencyOut = new Map();
25
+ const adjacencyIn = new Map();
26
+ const inDegree = new Map();
27
+ for (const id of nodeIds) {
28
+ adjacencyOut.set(id, []);
29
+ adjacencyIn.set(id, []);
30
+ inDegree.set(id, 0);
31
+ }
32
+ for (const e of edges) {
33
+ if (!adjacencyOut.has(e.from) || !adjacencyOut.has(e.to))
34
+ continue;
35
+ adjacencyOut.get(e.from).push(e.to);
36
+ adjacencyIn.get(e.to).push(e.from);
37
+ inDegree.set(e.to, (inDegree.get(e.to) || 0) + 1);
38
+ }
39
+ // Kahn's algorithm
40
+ const queue = [];
41
+ for (const id of nodeIds) {
42
+ if (inDegree.get(id) === 0)
43
+ queue.push(id);
44
+ }
45
+ const order = [];
46
+ const visited = new Set();
47
+ while (queue.length > 0) {
48
+ const node = queue.shift();
49
+ if (visited.has(node))
50
+ continue;
51
+ visited.add(node);
52
+ order.push(node);
53
+ for (const succ of adjacencyOut.get(node)) {
54
+ const deg = inDegree.get(succ) - 1;
55
+ inDegree.set(succ, deg);
56
+ if (deg === 0)
57
+ queue.push(succ);
58
+ }
59
+ }
60
+ // Handle cycles: any unvisited nodes have cycles
61
+ const reversedEdges = new Set();
62
+ if (visited.size < nodeIds.length) {
63
+ for (const id of nodeIds) {
64
+ if (!visited.has(id)) {
65
+ // Break cycle by removing an incoming edge
66
+ const incoming = adjacencyIn.get(id);
67
+ for (const src of incoming) {
68
+ if (!visited.has(src)) {
69
+ reversedEdges.add(`${src}->${id}`);
70
+ const outList = adjacencyOut.get(src);
71
+ const idx = outList.indexOf(id);
72
+ if (idx >= 0)
73
+ outList.splice(idx, 1);
74
+ inDegree.set(id, (inDegree.get(id) || 1) - 1);
75
+ }
76
+ }
77
+ if (!visited.has(id)) {
78
+ visited.add(id);
79
+ order.push(id);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ return { adjacencyOut, adjacencyIn, order, reversedEdges };
85
+ }
86
+ // ── Layer Assignment (longest-path) ────────────────────────
87
+ function assignLayers(order, adjacencyOut) {
88
+ const layer = new Map();
89
+ for (const id of order)
90
+ layer.set(id, 0);
91
+ for (const id of order) {
92
+ const currentLayer = layer.get(id);
93
+ for (const succ of adjacencyOut.get(id)) {
94
+ layer.set(succ, Math.max(layer.get(succ), currentLayer + 1));
95
+ }
96
+ }
97
+ return layer;
98
+ }
99
+ // ── Within-Layer Ordering (barycenter, 2 sweeps, cluster-aware) ───────────
100
+ function orderWithinLayers(layers, adjacencyOut, adjacencyIn, clusterMap) {
101
+ const posInLayer = new Map();
102
+ // Initialize positions
103
+ for (const layer of layers) {
104
+ for (let i = 0; i < layer.length; i++) {
105
+ posInLayer.set(layer[i], i);
106
+ }
107
+ }
108
+ // Down sweep
109
+ for (let i = 1; i < layers.length; i++) {
110
+ const sorted = layers[i].map((nodeId) => {
111
+ const preds = adjacencyIn.get(nodeId) || [];
112
+ const positions = preds
113
+ .map((p) => posInLayer.get(p))
114
+ .filter((p) => p !== undefined);
115
+ const barycenter = positions.length > 0
116
+ ? positions.reduce((a, b) => a + b, 0) / positions.length
117
+ : (posInLayer.get(nodeId) ?? 0);
118
+ return { id: nodeId, bary: barycenter };
119
+ });
120
+ sorted.sort((a, b) => a.bary - b.bary);
121
+ layers[i] = sorted.map((s) => s.id);
122
+ for (let j = 0; j < layers[i].length; j++) {
123
+ posInLayer.set(layers[i][j], j);
124
+ }
125
+ }
126
+ // Up sweep
127
+ for (let i = layers.length - 2; i >= 0; i--) {
128
+ const sorted = layers[i].map((nodeId) => {
129
+ const succs = adjacencyOut.get(nodeId) || [];
130
+ const positions = succs
131
+ .map((s) => posInLayer.get(s))
132
+ .filter((p) => p !== undefined);
133
+ const barycenter = positions.length > 0
134
+ ? positions.reduce((a, b) => a + b, 0) / positions.length
135
+ : (posInLayer.get(nodeId) ?? 0);
136
+ return { id: nodeId, bary: barycenter };
137
+ });
138
+ sorted.sort((a, b) => a.bary - b.bary);
139
+ layers[i] = sorted.map((s) => s.id);
140
+ for (let j = 0; j < layers[i].length; j++) {
141
+ posInLayer.set(layers[i][j], j);
142
+ }
143
+ }
144
+ // Cluster-aware grouping: after barycenter ordering, group cluster members together
145
+ // and push non-clustered nodes to the edges
146
+ if (clusterMap && clusterMap.size > 0) {
147
+ for (let i = 0; i < layers.length; i++) {
148
+ layers[i] = groupByCluster(layers[i], clusterMap, adjacencyIn, adjacencyOut, posInLayer);
149
+ for (let j = 0; j < layers[i].length; j++) {
150
+ posInLayer.set(layers[i][j], j);
151
+ }
152
+ }
153
+ }
154
+ return layers;
155
+ }
156
+ /** Group nodes in a layer so cluster members are adjacent, non-clustered nodes at edges */
157
+ function groupByCluster(layer, clusterMap, adjacencyIn, adjacencyOut, posInLayer) {
158
+ if (layer.length <= 1)
159
+ return layer;
160
+ // Separate into cluster groups and non-clustered nodes
161
+ const clusterGroups = new Map();
162
+ const nonClustered = [];
163
+ for (const nodeId of layer) {
164
+ const clusterId = clusterMap.get(nodeId);
165
+ if (clusterId) {
166
+ if (!clusterGroups.has(clusterId))
167
+ clusterGroups.set(clusterId, []);
168
+ clusterGroups.get(clusterId).push(nodeId);
169
+ }
170
+ else {
171
+ nonClustered.push(nodeId);
172
+ }
173
+ }
174
+ // If no clusters in this layer, nothing to reorder
175
+ if (clusterGroups.size === 0)
176
+ return layer;
177
+ // If no non-clustered nodes, just keep cluster groups in barycenter order
178
+ if (nonClustered.length === 0) {
179
+ // Order cluster groups by average barycenter position of their members
180
+ const groups = [...clusterGroups.entries()].map(([cid, nodes]) => {
181
+ const avgPos = nodes.reduce((s, n) => s + (posInLayer.get(n) ?? 0), 0) / nodes.length;
182
+ return { cid, nodes, avgPos };
183
+ });
184
+ groups.sort((a, b) => a.avgPos - b.avgPos);
185
+ return groups.flatMap((g) => g.nodes);
186
+ }
187
+ // Compute average barycenter position for each cluster group
188
+ const groupEntries = [...clusterGroups.entries()].map(([cid, nodes]) => {
189
+ const avgPos = nodes.reduce((s, n) => s + (posInLayer.get(n) ?? 0), 0) / nodes.length;
190
+ return { cid, nodes, avgPos };
191
+ });
192
+ groupEntries.sort((a, b) => a.avgPos - b.avgPos);
193
+ // Compute average connected position for non-clustered nodes to decide
194
+ // whether they go before or after the cluster groups
195
+ const allClusterPositions = groupEntries.flatMap((g) => g.nodes.map((n) => posInLayer.get(n) ?? 0));
196
+ const clusterCenter = allClusterPositions.reduce((a, b) => a + b, 0) / allClusterPositions.length;
197
+ // Split non-clustered into before/after based on their barycenter relative to cluster center
198
+ const before = [];
199
+ const after = [];
200
+ for (const nodeId of nonClustered) {
201
+ const pos = posInLayer.get(nodeId) ?? 0;
202
+ if (pos <= clusterCenter) {
203
+ before.push(nodeId);
204
+ }
205
+ else {
206
+ after.push(nodeId);
207
+ }
208
+ }
209
+ // If all ended up on one side, that's fine — just keep them there
210
+ // If none on either side, push all to the end
211
+ if (before.length === 0 && after.length === 0) {
212
+ after.push(...nonClustered);
213
+ }
214
+ return [...before, ...groupEntries.flatMap((g) => g.nodes), ...after];
215
+ }
216
+ // ── Coordinate Assignment ──────────────────────────────────
217
+ const CLUSTER_GROUP_GAP = 40;
218
+ function assignCoordinates(layers, nodeDims, direction, nodeGap, layerGap, clusterMap) {
219
+ const positions = new Map();
220
+ const horizontal = isHorizontal(direction);
221
+ const reversed = isReversed(direction);
222
+ // Compute layer extents (max node size in layer direction)
223
+ const layerSizes = [];
224
+ for (const layer of layers) {
225
+ let maxSize = 0;
226
+ for (const id of layer) {
227
+ const dims = nodeDims.get(id);
228
+ maxSize = Math.max(maxSize, horizontal ? dims.w : dims.h);
229
+ }
230
+ layerSizes.push(maxSize);
231
+ }
232
+ // Find max cross-axis extent per layer for centering (including cluster group gaps)
233
+ const layerCrossExtents = [];
234
+ for (const layer of layers) {
235
+ let total = 0;
236
+ for (const id of layer) {
237
+ const dims = nodeDims.get(id);
238
+ total += horizontal ? dims.h : dims.w;
239
+ }
240
+ total += (layer.length - 1) * nodeGap;
241
+ // Add extra gap at cluster/non-cluster boundaries
242
+ if (clusterMap && clusterMap.size > 0) {
243
+ total += countClusterBoundaries(layer, clusterMap) * CLUSTER_GROUP_GAP;
244
+ }
245
+ layerCrossExtents.push(total);
246
+ }
247
+ const maxCrossExtent = Math.max(...layerCrossExtents);
248
+ // Assign positions
249
+ let layerOffset = MARGIN;
250
+ const layerOrder = reversed ? [...layers].reverse() : layers;
251
+ const sizeOrder = reversed ? [...layerSizes].reverse() : layerSizes;
252
+ for (let li = 0; li < layerOrder.length; li++) {
253
+ const layer = layerOrder[li];
254
+ const layerSize = sizeOrder[li];
255
+ // Center this layer's nodes
256
+ const crossExtent = layerCrossExtents[reversed ? layerOrder.length - 1 - li : li];
257
+ let crossOffset = MARGIN + (maxCrossExtent - crossExtent) / 2;
258
+ for (let ni = 0; ni < layer.length; ni++) {
259
+ const id = layer[ni];
260
+ const dims = nodeDims.get(id);
261
+ const primaryOffset = reversed ? (horizontal ? layerSize - dims.w : layerSize - dims.h) : 0;
262
+ // Add extra gap at cluster/non-cluster boundary
263
+ if (ni > 0 && clusterMap && clusterMap.size > 0) {
264
+ const prevCluster = clusterMap.get(layer[ni - 1]);
265
+ const currCluster = clusterMap.get(id);
266
+ if (prevCluster !== currCluster &&
267
+ (prevCluster !== undefined || currCluster !== undefined)) {
268
+ crossOffset += CLUSTER_GROUP_GAP;
269
+ }
270
+ }
271
+ if (horizontal) {
272
+ positions.set(id, {
273
+ x: layerOffset + primaryOffset,
274
+ y: crossOffset
275
+ });
276
+ crossOffset += dims.h + nodeGap;
277
+ }
278
+ else {
279
+ positions.set(id, {
280
+ x: crossOffset,
281
+ y: layerOffset + primaryOffset
282
+ });
283
+ crossOffset += dims.w + nodeGap;
284
+ }
285
+ }
286
+ layerOffset += layerSize + layerGap;
287
+ }
288
+ return positions;
289
+ }
290
+ /** Count how many cluster/non-cluster boundaries exist in a layer ordering */
291
+ function countClusterBoundaries(layer, clusterMap) {
292
+ let count = 0;
293
+ for (let i = 1; i < layer.length; i++) {
294
+ const prevCluster = clusterMap.get(layer[i - 1]);
295
+ const currCluster = clusterMap.get(layer[i]);
296
+ if (prevCluster !== currCluster && (prevCluster !== undefined || currCluster !== undefined)) {
297
+ count++;
298
+ }
299
+ }
300
+ return count;
301
+ }
302
+ // ── Cluster Bounds ─────────────────────────────────────────
303
+ function computeClusterBounds(config, positions, nodeDims, padding) {
304
+ if (!config.clusters)
305
+ return [];
306
+ return config.clusters.map((cluster) => {
307
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
308
+ for (const nodeId of cluster.nodes) {
309
+ const pos = positions.get(nodeId);
310
+ const dims = nodeDims.get(nodeId);
311
+ if (!pos || !dims)
312
+ continue;
313
+ minX = Math.min(minX, pos.x);
314
+ minY = Math.min(minY, pos.y);
315
+ maxX = Math.max(maxX, pos.x + dims.w);
316
+ maxY = Math.max(maxY, pos.y + dims.h);
317
+ }
318
+ if (minX === Infinity) {
319
+ return {
320
+ id: cluster.id,
321
+ x: 0,
322
+ y: 0,
323
+ width: 0,
324
+ height: 0,
325
+ label: cluster.label,
326
+ color: cluster.color || 'neutral',
327
+ dashed: cluster.dashed ?? true
328
+ };
329
+ }
330
+ // Add space for label above
331
+ const labelPad = cluster.label ? 24 : 0;
332
+ return {
333
+ id: cluster.id,
334
+ x: minX - padding,
335
+ y: minY - padding - labelPad,
336
+ width: maxX - minX + padding * 2,
337
+ height: maxY - minY + padding * 2 + labelPad,
338
+ label: cluster.label,
339
+ color: cluster.color || 'neutral',
340
+ dashed: cluster.dashed ?? true
341
+ };
342
+ });
343
+ }
344
+ // ── Annotations ────────────────────────────────────────────
345
+ const ANNOTATION_CHAR_WIDTH = 6;
346
+ const ANNOTATION_HEIGHT = 14;
347
+ const ANNOTATION_COLLISION_PAD = 20;
348
+ function resolveAnnotations(config, positions, nodeDims) {
349
+ if (!config.annotations)
350
+ return [];
351
+ const resolved = config.annotations.map((ann) => {
352
+ let x, y;
353
+ if (typeof ann.anchor === 'string') {
354
+ const pos = positions.get(ann.anchor);
355
+ const dims = nodeDims.get(ann.anchor);
356
+ if (pos && dims) {
357
+ x = pos.x + dims.w / 2;
358
+ y = pos.y - 12;
359
+ }
360
+ else {
361
+ x = 0;
362
+ y = 0;
363
+ }
364
+ }
365
+ else {
366
+ x = ann.anchor.x;
367
+ y = ann.anchor.y;
368
+ }
369
+ return {
370
+ text: ann.text,
371
+ x: x + (ann.offset?.dx ?? 0),
372
+ y: y + (ann.offset?.dy ?? 0),
373
+ color: ann.color || 'neutral'
374
+ };
375
+ });
376
+ // Collision avoidance: check annotations against nodes and other annotations
377
+ for (let i = 0; i < resolved.length; i++) {
378
+ const ann = resolved[i];
379
+ const annW = ann.text.length * ANNOTATION_CHAR_WIDTH;
380
+ const annH = ANNOTATION_HEIGHT;
381
+ // Check against all nodes — shift upward if overlapping
382
+ let shifted = true;
383
+ let maxIter = 10; // prevent infinite loop
384
+ while (shifted && maxIter-- > 0) {
385
+ shifted = false;
386
+ for (const [nodeId, pos] of positions) {
387
+ const dims = nodeDims.get(nodeId);
388
+ if (!dims)
389
+ continue;
390
+ // Check overlap with padding
391
+ if (ann.x + annW > pos.x - ANNOTATION_COLLISION_PAD &&
392
+ ann.x < pos.x + dims.w + ANNOTATION_COLLISION_PAD &&
393
+ ann.y + annH > pos.y - ANNOTATION_COLLISION_PAD &&
394
+ ann.y < pos.y + dims.h + ANNOTATION_COLLISION_PAD) {
395
+ // Shift annotation above the node
396
+ ann.y = pos.y - ANNOTATION_COLLISION_PAD - annH;
397
+ shifted = true;
398
+ }
399
+ }
400
+ }
401
+ // Check against previously placed annotations
402
+ for (let j = 0; j < i; j++) {
403
+ const other = resolved[j];
404
+ const otherW = other.text.length * ANNOTATION_CHAR_WIDTH;
405
+ const otherH = ANNOTATION_HEIGHT;
406
+ if (ann.x + annW > other.x - ANNOTATION_COLLISION_PAD &&
407
+ ann.x < other.x + otherW + ANNOTATION_COLLISION_PAD &&
408
+ ann.y + annH > other.y - ANNOTATION_COLLISION_PAD &&
409
+ ann.y < other.y + otherH + ANNOTATION_COLLISION_PAD) {
410
+ // Shift this annotation above the other
411
+ ann.y = other.y - ANNOTATION_COLLISION_PAD - annH;
412
+ }
413
+ }
414
+ }
415
+ return resolved;
416
+ }
417
+ // ── Layered Layout (main entry) ────────────────────────────
418
+ function layoutLayered(config) {
419
+ const direction = config.direction || 'TB';
420
+ const nodeGap = config.spacing?.nodeGap ?? DEFAULT_NODE_GAP;
421
+ const layerGap = config.spacing?.layerGap ?? DEFAULT_LAYER_GAP;
422
+ const clusterPadding = config.spacing?.clusterPadding ?? DEFAULT_CLUSTER_PADDING;
423
+ const nodeIds = config.nodes.map((n) => n.id);
424
+ const nodeDims = buildNodeDims(config.nodes);
425
+ // Build cluster membership map: nodeId -> clusterId
426
+ const clusterMap = buildClusterMap(config);
427
+ // Build graph and sort
428
+ const graph = buildGraph(nodeIds, config.edges);
429
+ // Assign layers
430
+ const layerMap = assignLayers(graph.order, graph.adjacencyOut);
431
+ // Group by layer
432
+ const maxLayer = Math.max(0, ...layerMap.values());
433
+ const layers = Array.from({ length: maxLayer + 1 }, () => []);
434
+ for (const id of graph.order) {
435
+ layers[layerMap.get(id)].push(id);
436
+ }
437
+ // Order within layers (cluster-aware)
438
+ const orderedLayers = orderWithinLayers(layers, graph.adjacencyOut, graph.adjacencyIn, clusterMap);
439
+ // Assign coordinates (cluster-aware gaps)
440
+ const positions = assignCoordinates(orderedLayers, nodeDims, direction, nodeGap, layerGap, clusterMap);
441
+ // Build positioned nodes
442
+ const positionedNodes = buildPositionedNodes(config.nodes, positions, nodeDims);
443
+ // Compute clusters
444
+ const clusters = computeClusterBounds(config, positions, nodeDims, clusterPadding);
445
+ // Compute edges
446
+ const positionedEdges = computeEdgePaths(config.edges, positions, nodeDims, direction);
447
+ // Compute annotations
448
+ const annotations = resolveAnnotations(config, positions, nodeDims);
449
+ // Compute viewBox with full bounds coverage
450
+ let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
451
+ // Include all node bounds
452
+ for (const n of positionedNodes) {
453
+ minX = Math.min(minX, n.x);
454
+ minY = Math.min(minY, n.y);
455
+ maxX = Math.max(maxX, n.x + n.width);
456
+ maxY = Math.max(maxY, n.y + n.height);
457
+ }
458
+ // Include all cluster bounds
459
+ for (const c of clusters) {
460
+ minX = Math.min(minX, c.x);
461
+ minY = Math.min(minY, c.y);
462
+ maxX = Math.max(maxX, c.x + c.width);
463
+ maxY = Math.max(maxY, c.y + c.height);
464
+ }
465
+ // Include annotation positions (estimated text width)
466
+ for (const ann of annotations) {
467
+ const annW = ann.text.length * ANNOTATION_CHAR_WIDTH;
468
+ minX = Math.min(minX, ann.x);
469
+ minY = Math.min(minY, ann.y - ANNOTATION_HEIGHT);
470
+ maxX = Math.max(maxX, ann.x + annW);
471
+ maxY = Math.max(maxY, ann.y);
472
+ }
473
+ // Include edge label positions (estimated text width)
474
+ for (const e of positionedEdges) {
475
+ if (e.label) {
476
+ const labelW = e.label.length * 5;
477
+ minX = Math.min(minX, e.labelX - labelW / 2);
478
+ minY = Math.min(minY, e.labelY - 7);
479
+ maxX = Math.max(maxX, e.labelX + labelW / 2);
480
+ maxY = Math.max(maxY, e.labelY + 7);
481
+ }
482
+ }
483
+ // Handle empty diagram
484
+ if (minX === Infinity) {
485
+ minX = 0;
486
+ minY = 0;
487
+ maxX = MARGIN * 2;
488
+ maxY = MARGIN * 2;
489
+ }
490
+ // Shift everything so all coordinates are non-negative
491
+ const shiftX = minX < 0 ? -minX + MARGIN : 0;
492
+ const shiftY = minY < 0 ? -minY + MARGIN : 0;
493
+ if (shiftX > 0 || shiftY > 0) {
494
+ shiftAllPositions(positionedNodes, clusters, annotations, positionedEdges, shiftX, shiftY);
495
+ maxX += shiftX;
496
+ maxY += shiftY;
497
+ }
498
+ return {
499
+ nodes: positionedNodes,
500
+ edges: positionedEdges,
501
+ clusters,
502
+ swimlanes: [],
503
+ regions: [],
504
+ annotations,
505
+ messages: [],
506
+ lifelines: [],
507
+ positionedFragments: [],
508
+ viewBox: { width: maxX + MARGIN, height: maxY + MARGIN }
509
+ };
510
+ }
511
+ // ── Swimlane Layout ────────────────────────────────────────
512
+ function layoutSwimlane(config) {
513
+ const nodeGap = config.spacing?.nodeGap ?? 32;
514
+ const lanes = config.swimlanes || [];
515
+ const nodeDims = buildNodeDims(config.nodes);
516
+ const headerHeight = 50;
517
+ // Assign lanes
518
+ const laneMap = new Map();
519
+ for (let i = 0; i < lanes.length; i++) {
520
+ for (const nid of lanes[i].nodes) {
521
+ laneMap.set(nid, i);
522
+ }
523
+ }
524
+ // Compute dynamic lane widths: max(180, widest node in lane + 40)
525
+ const laneWidths = lanes.map((lane) => {
526
+ let maxW = 0;
527
+ for (const nid of lane.nodes) {
528
+ const dims = nodeDims.get(nid);
529
+ if (dims)
530
+ maxW = Math.max(maxW, dims.w);
531
+ }
532
+ return Math.max(180, maxW + 40);
533
+ });
534
+ // Compute lane start X offsets
535
+ const laneStartX = [];
536
+ let laneX = MARGIN;
537
+ for (let i = 0; i < laneWidths.length; i++) {
538
+ laneStartX.push(laneX);
539
+ laneX += laneWidths[i];
540
+ }
541
+ // Topological order for Y positions
542
+ const nodeIds = config.nodes.map((n) => n.id);
543
+ const graph = buildGraph(nodeIds, config.edges);
544
+ // Assign Y positions sequentially
545
+ const positions = new Map();
546
+ let currentY = MARGIN + headerHeight + 20;
547
+ for (const id of graph.order) {
548
+ const laneIdx = laneMap.get(id) ?? 0;
549
+ const dims = nodeDims.get(id);
550
+ const lw = laneWidths[laneIdx] ?? 180;
551
+ const startX = laneStartX[laneIdx] ?? MARGIN;
552
+ const x = startX + (lw - dims.w) / 2;
553
+ positions.set(id, { x, y: currentY });
554
+ currentY += dims.h + nodeGap;
555
+ }
556
+ const totalHeight = currentY + MARGIN;
557
+ const totalWidth = MARGIN + laneX;
558
+ const positionedNodes = buildPositionedNodes(config.nodes, positions, nodeDims);
559
+ // Build swimlane positioned data
560
+ const positionedSwimlanes = lanes.map((lane, i) => ({
561
+ id: lane.id,
562
+ label: lane.label,
563
+ x: laneStartX[i],
564
+ lineX: laneStartX[i] + laneWidths[i] / 2,
565
+ headerY: MARGIN,
566
+ footerY: totalHeight - MARGIN,
567
+ lineY1: MARGIN + headerHeight,
568
+ lineY2: totalHeight - MARGIN,
569
+ color: lane.color || 'neutral'
570
+ }));
571
+ // Edges: horizontal arrows between lanes
572
+ const positionedEdges = computeSwimEdgePaths(config.edges, positions, nodeDims, laneMap, laneWidths[0] ?? 180);
573
+ // Regions
574
+ const positionedRegions = (config.regions || []).map((region) => {
575
+ let minY = Infinity, maxY = -Infinity;
576
+ let minLane = Infinity, maxLane = -Infinity;
577
+ for (const nid of region.contains) {
578
+ const pos = positions.get(nid);
579
+ const dims = nodeDims.get(nid);
580
+ const laneIdx = laneMap.get(nid);
581
+ if (pos && dims) {
582
+ minY = Math.min(minY, pos.y);
583
+ maxY = Math.max(maxY, pos.y + dims.h);
584
+ }
585
+ if (laneIdx !== undefined) {
586
+ minLane = Math.min(minLane, laneIdx);
587
+ maxLane = Math.max(maxLane, laneIdx);
588
+ }
589
+ }
590
+ if (minY === Infinity) {
591
+ return {
592
+ id: region.id,
593
+ x: 0,
594
+ y: 0,
595
+ width: 0,
596
+ height: 0,
597
+ label: region.label,
598
+ color: region.color || 'neutral',
599
+ dashed: region.dashed ?? true
600
+ };
601
+ }
602
+ const pad = 16;
603
+ const regionX = laneStartX[minLane] - pad;
604
+ let regionEndX = laneStartX[maxLane] + laneWidths[maxLane] + pad;
605
+ return {
606
+ id: region.id,
607
+ x: regionX,
608
+ y: minY - pad - 20,
609
+ width: regionEndX - regionX,
610
+ height: maxY - minY + pad * 2 + 20,
611
+ label: region.label,
612
+ color: region.color || 'neutral',
613
+ dashed: region.dashed ?? true
614
+ };
615
+ });
616
+ // Annotations
617
+ const annotations = resolveAnnotations(config, positions, nodeDims);
618
+ // Compute viewBox with full bounds coverage
619
+ let minX = Infinity, minY = Infinity, maxViewX = -Infinity, maxViewY = -Infinity;
620
+ for (const n of positionedNodes) {
621
+ minX = Math.min(minX, n.x);
622
+ minY = Math.min(minY, n.y);
623
+ maxViewX = Math.max(maxViewX, n.x + n.width);
624
+ maxViewY = Math.max(maxViewY, n.y + n.height);
625
+ }
626
+ // Include swimlane headers
627
+ for (let si = 0; si < positionedSwimlanes.length; si++) {
628
+ const sl = positionedSwimlanes[si];
629
+ minX = Math.min(minX, sl.x);
630
+ minY = Math.min(minY, sl.headerY);
631
+ maxViewX = Math.max(maxViewX, sl.x + (laneWidths[si] ?? 180));
632
+ maxViewY = Math.max(maxViewY, sl.lineY2);
633
+ }
634
+ // Include annotation positions
635
+ for (const ann of annotations) {
636
+ const annW = ann.text.length * ANNOTATION_CHAR_WIDTH;
637
+ minX = Math.min(minX, ann.x);
638
+ minY = Math.min(minY, ann.y - ANNOTATION_HEIGHT);
639
+ maxViewX = Math.max(maxViewX, ann.x + annW);
640
+ maxViewY = Math.max(maxViewY, ann.y);
641
+ }
642
+ // Include edge labels
643
+ for (const e of positionedEdges) {
644
+ if (e.label) {
645
+ const labelW = e.label.length * 5;
646
+ minX = Math.min(minX, e.labelX - labelW / 2);
647
+ minY = Math.min(minY, e.labelY - 7);
648
+ maxViewX = Math.max(maxViewX, e.labelX + labelW / 2);
649
+ maxViewY = Math.max(maxViewY, e.labelY + 7);
650
+ }
651
+ }
652
+ // Include regions
653
+ for (const r of positionedRegions) {
654
+ minX = Math.min(minX, r.x);
655
+ minY = Math.min(minY, r.y);
656
+ maxViewX = Math.max(maxViewX, r.x + r.width);
657
+ maxViewY = Math.max(maxViewY, r.y + r.height);
658
+ }
659
+ // Handle empty diagram
660
+ if (minX === Infinity) {
661
+ minX = 0;
662
+ minY = 0;
663
+ maxViewX = totalWidth;
664
+ maxViewY = totalHeight;
665
+ }
666
+ // Shift everything so all coordinates are non-negative
667
+ const shiftX = minX < 0 ? -minX + MARGIN : 0;
668
+ const shiftY = minY < 0 ? -minY + MARGIN : 0;
669
+ if (shiftX > 0 || shiftY > 0) {
670
+ shiftAllPositions(positionedNodes, [], annotations, positionedEdges, shiftX, shiftY);
671
+ // Also shift swimlanes and regions
672
+ for (const sl of positionedSwimlanes) {
673
+ sl.x += shiftX;
674
+ sl.lineX += shiftX;
675
+ sl.headerY += shiftY;
676
+ sl.lineY1 += shiftY;
677
+ sl.lineY2 += shiftY;
678
+ }
679
+ for (const r of positionedRegions) {
680
+ r.x += shiftX;
681
+ r.y += shiftY;
682
+ }
683
+ maxViewX += shiftX;
684
+ maxViewY += shiftY;
685
+ }
686
+ return {
687
+ nodes: positionedNodes,
688
+ edges: positionedEdges,
689
+ clusters: [],
690
+ swimlanes: positionedSwimlanes,
691
+ regions: positionedRegions,
692
+ annotations,
693
+ messages: [],
694
+ lifelines: [],
695
+ positionedFragments: [],
696
+ viewBox: {
697
+ width: Math.max(totalWidth, maxViewX + MARGIN),
698
+ height: Math.max(totalHeight, maxViewY + MARGIN)
699
+ }
700
+ };
701
+ }
702
+ // ── Shared Helpers ─────────────────────────────────────────
703
+ /** Build a map from nodeId -> clusterId for cluster-aware ordering */
704
+ function buildClusterMap(config) {
705
+ const map = new Map();
706
+ if (!config.clusters)
707
+ return map;
708
+ for (const cluster of config.clusters) {
709
+ for (const nodeId of cluster.nodes) {
710
+ map.set(nodeId, cluster.id);
711
+ }
712
+ }
713
+ return map;
714
+ }
715
+ /** Shift all positioned elements by (dx, dy) to ensure non-negative coordinates */
716
+ function shiftAllPositions(nodes, clusters, annotations, edges, dx, dy) {
717
+ for (const n of nodes) {
718
+ n.x += dx;
719
+ n.y += dy;
720
+ }
721
+ for (const c of clusters) {
722
+ c.x += dx;
723
+ c.y += dy;
724
+ }
725
+ for (const a of annotations) {
726
+ a.x += dx;
727
+ a.y += dy;
728
+ }
729
+ for (const e of edges) {
730
+ e.labelX += dx;
731
+ e.labelY += dy;
732
+ // Shift SVG path coordinates
733
+ e.path = shiftSvgPath(e.path, dx, dy);
734
+ }
735
+ }
736
+ /** Shift all absolute coordinates in an SVG path string by (dx, dy) */
737
+ function shiftSvgPath(path, dx, dy) {
738
+ // Match SVG path commands and their coordinate pairs
739
+ // This handles M, L, C, Q, S, T commands with absolute coords
740
+ return path.replace(/([MLCSQT])\s*([-\d.]+)\s+([-\d.]+)/gi, (_match, cmd, x, y) => {
741
+ const upper = cmd.toUpperCase();
742
+ // Only shift absolute commands (uppercase)
743
+ if (cmd === upper) {
744
+ return `${cmd} ${parseFloat(x) + dx} ${parseFloat(y) + dy}`;
745
+ }
746
+ return `${cmd} ${x} ${y}`;
747
+ });
748
+ }
749
+ function buildNodeDims(nodes) {
750
+ const dims = new Map();
751
+ for (const node of nodes) {
752
+ const w = node.width ?? estimateNodeWidth(node.label, node.description);
753
+ const h = node.height ?? (node.description ? DESC_NODE_HEIGHT : DEFAULT_NODE_HEIGHT);
754
+ dims.set(node.id, { w, h });
755
+ }
756
+ return dims;
757
+ }
758
+ function buildPositionedNodes(nodes, positions, nodeDims) {
759
+ return nodes.map((node) => {
760
+ const pos = positions.get(node.id) || { x: 0, y: 0 };
761
+ const dims = nodeDims.get(node.id);
762
+ return {
763
+ id: node.id,
764
+ x: pos.x,
765
+ y: pos.y,
766
+ width: dims.w,
767
+ height: dims.h,
768
+ label: node.label,
769
+ description: node.description,
770
+ icon: node.icon,
771
+ variant: node.variant || 'default',
772
+ color: node.color || 'neutral',
773
+ state: node.state || 'default'
774
+ };
775
+ });
776
+ }
777
+ // ── Swimlane Edge Paths ────────────────────────────────────
778
+ function computeSwimEdgePaths(edges, positions, nodeDims, laneMap, laneWidth) {
779
+ return edges.map((edge) => {
780
+ const fromPos = positions.get(edge.from);
781
+ const toPos = positions.get(edge.to);
782
+ const fromDims = nodeDims.get(edge.from);
783
+ const toDims = nodeDims.get(edge.to);
784
+ if (!fromPos || !toPos || !fromDims || !toDims) {
785
+ return emptyEdge(edge);
786
+ }
787
+ const fromLane = laneMap.get(edge.from) ?? 0;
788
+ const toLane = laneMap.get(edge.to) ?? 0;
789
+ let path;
790
+ let labelX;
791
+ let labelY;
792
+ if (fromLane === toLane) {
793
+ // Same lane: vertical arrow
794
+ const cx = fromPos.x + fromDims.w / 2;
795
+ const y1 = fromPos.y + fromDims.h;
796
+ const y2 = toPos.y;
797
+ path = `M ${cx} ${y1} L ${cx} ${y2}`;
798
+ labelX = cx + 10;
799
+ labelY = (y1 + y2) / 2;
800
+ }
801
+ else {
802
+ // Cross-lane: horizontal arrow at midpoint Y
803
+ const midY = fromPos.y + fromDims.h / 2;
804
+ const x1 = fromLane < toLane ? fromPos.x + fromDims.w : fromPos.x;
805
+ const x2 = fromLane < toLane ? toPos.x : toPos.x + toDims.w;
806
+ path = `M ${x1} ${midY} L ${x2} ${midY}`;
807
+ labelX = (x1 + x2) / 2;
808
+ labelY = midY - 8;
809
+ }
810
+ return {
811
+ from: edge.from,
812
+ to: edge.to,
813
+ path,
814
+ label: edge.label,
815
+ labelX,
816
+ labelY,
817
+ arrow: edge.arrow || 'end',
818
+ dashed: edge.dashed || false,
819
+ color: edge.color || 'neutral'
820
+ };
821
+ });
822
+ }
823
+ // ── Public API ─────────────────────────────────────────────
824
+ // ── Sequence Layout ───────────────────────────────────────
825
+ const SEQ_ACTOR_GAP = 180;
826
+ const SEQ_MESSAGE_GAP = 40;
827
+ const SEQ_ACTOR_BOX_HEIGHT = 36;
828
+ const SEQ_TOP_MARGIN = 40;
829
+ const SEQ_SELF_LOOP_WIDTH = 30;
830
+ const SEQ_SELF_LOOP_HEIGHT = 24;
831
+ const SEQ_FRAGMENT_PAD_X = 20;
832
+ const SEQ_FRAGMENT_PAD_Y = 16;
833
+ const SEQ_FRAGMENT_TAG_HEIGHT = 20;
834
+ function layoutSequence(config) {
835
+ const actors = config.nodes;
836
+ const messages = config.messages || [];
837
+ const fragments = config.fragments || [];
838
+ // Position actors evenly across the x-axis
839
+ const actorXMap = new Map();
840
+ const actorColorMap = new Map();
841
+ for (let i = 0; i < actors.length; i++) {
842
+ const x = MARGIN + i * SEQ_ACTOR_GAP + SEQ_ACTOR_GAP / 2;
843
+ actorXMap.set(actors[i].id, x);
844
+ actorColorMap.set(actors[i].id, actors[i].color || 'neutral');
845
+ }
846
+ // Compute message Y positions (increment per message)
847
+ const messageStartY = SEQ_TOP_MARGIN + SEQ_ACTOR_BOX_HEIGHT + 30;
848
+ const messageYPositions = [];
849
+ let currentY = messageStartY;
850
+ for (let i = 0; i < messages.length; i++) {
851
+ messageYPositions.push(currentY);
852
+ const isSelf = messages[i].from === messages[i].to;
853
+ currentY += isSelf ? SEQ_MESSAGE_GAP + SEQ_SELF_LOOP_HEIGHT : SEQ_MESSAGE_GAP;
854
+ }
855
+ // Bottom of the diagram
856
+ const bottomY = currentY + 30 + SEQ_ACTOR_BOX_HEIGHT;
857
+ const totalHeight = bottomY + MARGIN;
858
+ const totalWidth = MARGIN * 2 + actors.length * SEQ_ACTOR_GAP;
859
+ // Build lifelines
860
+ const lifelines = actors.map((actor) => ({
861
+ id: actor.id,
862
+ label: actor.label,
863
+ x: actorXMap.get(actor.id),
864
+ topY: SEQ_TOP_MARGIN,
865
+ bottomY: bottomY,
866
+ color: (actor.color || 'neutral')
867
+ }));
868
+ // Build positioned messages
869
+ const positionedMessages = messages.map((msg, i) => {
870
+ const fromX = actorXMap.get(msg.from) ?? 0;
871
+ const toX = actorXMap.get(msg.to) ?? 0;
872
+ const y = messageYPositions[i];
873
+ const isSelf = msg.from === msg.to;
874
+ let labelX;
875
+ let labelY;
876
+ if (isSelf) {
877
+ labelX = fromX + SEQ_SELF_LOOP_WIDTH + 8;
878
+ labelY = y + SEQ_SELF_LOOP_HEIGHT / 2;
879
+ }
880
+ else {
881
+ labelX = (fromX + toX) / 2;
882
+ labelY = y - 8;
883
+ }
884
+ return {
885
+ from: msg.from,
886
+ to: msg.to,
887
+ label: msg.label,
888
+ x1: fromX,
889
+ y,
890
+ x2: toX,
891
+ labelX,
892
+ labelY,
893
+ arrow: msg.arrow || 'end',
894
+ dashed: msg.dashed || false,
895
+ color: (msg.color || 'neutral'),
896
+ isSelf
897
+ };
898
+ });
899
+ // Build positioned fragments
900
+ const positionedFragments = fragments.map((frag) => {
901
+ if (frag.messages.length === 0) {
902
+ return {
903
+ id: frag.id,
904
+ label: frag.label,
905
+ condition: frag.condition,
906
+ x: 0,
907
+ y: 0,
908
+ width: 0,
909
+ height: 0,
910
+ color: (frag.color || 'neutral'),
911
+ dashed: frag.dashed ?? false
912
+ };
913
+ }
914
+ // Find bounds from contained messages
915
+ let minX = Infinity;
916
+ let maxX = -Infinity;
917
+ let minY = Infinity;
918
+ let maxY = -Infinity;
919
+ for (const msgIdx of frag.messages) {
920
+ if (msgIdx < 0 || msgIdx >= positionedMessages.length)
921
+ continue;
922
+ const msg = positionedMessages[msgIdx];
923
+ const leftX = Math.min(msg.x1, msg.x2);
924
+ const rightX = msg.isSelf ? msg.x1 + SEQ_SELF_LOOP_WIDTH : Math.max(msg.x1, msg.x2);
925
+ minX = Math.min(minX, leftX);
926
+ maxX = Math.max(maxX, rightX);
927
+ minY = Math.min(minY, msg.y);
928
+ maxY = Math.max(maxY, msg.isSelf ? msg.y + SEQ_SELF_LOOP_HEIGHT : msg.y);
929
+ }
930
+ if (minX === Infinity) {
931
+ return {
932
+ id: frag.id,
933
+ label: frag.label,
934
+ condition: frag.condition,
935
+ x: 0,
936
+ y: 0,
937
+ width: 0,
938
+ height: 0,
939
+ color: (frag.color || 'neutral'),
940
+ dashed: frag.dashed ?? false
941
+ };
942
+ }
943
+ return {
944
+ id: frag.id,
945
+ label: frag.label,
946
+ condition: frag.condition,
947
+ x: minX - SEQ_FRAGMENT_PAD_X,
948
+ y: minY - SEQ_FRAGMENT_PAD_Y - SEQ_FRAGMENT_TAG_HEIGHT,
949
+ width: maxX - minX + SEQ_FRAGMENT_PAD_X * 2,
950
+ height: maxY - minY + SEQ_FRAGMENT_PAD_Y * 2 + SEQ_FRAGMENT_TAG_HEIGHT,
951
+ color: (frag.color || 'neutral'),
952
+ dashed: frag.dashed ?? false
953
+ };
954
+ });
955
+ // Annotations
956
+ const positions = new Map();
957
+ const nodeDims = new Map();
958
+ for (const actor of actors) {
959
+ const x = actorXMap.get(actor.id);
960
+ positions.set(actor.id, { x: x - 60, y: SEQ_TOP_MARGIN });
961
+ nodeDims.set(actor.id, { w: 120, h: SEQ_ACTOR_BOX_HEIGHT });
962
+ }
963
+ const annotations = resolveAnnotations(config, positions, nodeDims);
964
+ return {
965
+ nodes: [],
966
+ edges: [],
967
+ clusters: [],
968
+ swimlanes: [],
969
+ regions: [],
970
+ annotations,
971
+ messages: positionedMessages,
972
+ lifelines,
973
+ positionedFragments,
974
+ viewBox: { width: totalWidth, height: totalHeight }
975
+ };
976
+ }
977
+ // ── Public API ─────────────────────────────────────────────
978
+ export function computeLayout(config) {
979
+ if (config.layout === 'sequence')
980
+ return layoutSequence(config);
981
+ if (config.layout === 'swimlane') {
982
+ return layoutSwimlane(config);
983
+ }
984
+ return layoutLayered(config);
985
+ }