@heyramzi/ui 2.9.0 → 2.10.1

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 (313) hide show
  1. package/dist/agents/helpers.js +52 -0
  2. package/dist/agents/index.js +3 -0
  3. package/dist/agents/page-state.js +65 -0
  4. package/dist/agents/types.js +1 -0
  5. package/dist/agents/vendor/color.js +149 -0
  6. package/dist/agents/vendor/draw.js +548 -0
  7. package/dist/agents/vendor/engine.js +632 -0
  8. package/dist/agents/vendor/mesh.js +727 -0
  9. package/dist/agents/vendor/plastic.js +3273 -0
  10. package/dist/agents/vendor/presets.js +171 -0
  11. package/dist/agents/vendor/shapes.js +24 -0
  12. package/dist/agents/vendor/ticker.js +56 -0
  13. package/dist/agents/vendor/types.js +0 -0
  14. package/dist/agents/vendor/wear.js +1525 -0
  15. package/dist/ai/ai-button/index.js +2 -0
  16. package/dist/ai/confirmation/confirmation-context.svelte.js +12 -0
  17. package/dist/ai/confirmation/index.js +9 -0
  18. package/dist/ai/generation-progress/index.js +2 -0
  19. package/dist/ai/index.js +11 -0
  20. package/dist/ai/loading-state/index.js +3 -0
  21. package/dist/ai/prompt-input/index.js +6 -0
  22. package/dist/ai/reasoning/index.js +4 -0
  23. package/dist/ai/reasoning/reasoning-context.svelte.js +12 -0
  24. package/dist/ai/response/index.js +3 -0
  25. package/dist/ai/suggestion/index.js +3 -0
  26. package/dist/ai/thinking-dots/index.js +3 -0
  27. package/dist/ai/typing-dots/index.js +2 -0
  28. package/dist/ai/voice-waveform/index.js +3 -0
  29. package/dist/animations/text-swap.js +30 -0
  30. package/dist/brand/index.js +65 -0
  31. package/dist/canvas/card/resize.js +10 -0
  32. package/dist/canvas/edges/edge-path.js +284 -0
  33. package/dist/canvas/editor/context-menu.js +42 -0
  34. package/dist/canvas/editor/dispatch.svelte.js +157 -0
  35. package/dist/canvas/editor/editor-context.js +8 -0
  36. package/dist/canvas/editor/editor-mode.js +0 -0
  37. package/dist/canvas/editor/frame.js +87 -0
  38. package/dist/canvas/editor/hand-context.js +8 -0
  39. package/dist/canvas/editor/history-core.js +221 -0
  40. package/dist/canvas/editor/keymap.js +193 -0
  41. package/dist/canvas/editor/layout-actions.js +170 -0
  42. package/dist/canvas/editor/lock.js +65 -0
  43. package/dist/canvas/editor/rebase.js +279 -0
  44. package/dist/canvas/editor/style.js +174 -0
  45. package/dist/canvas/editor/text-field-context.js +8 -0
  46. package/dist/canvas/editor/z-order.js +82 -0
  47. package/dist/canvas/headless/alignment.js +20 -0
  48. package/dist/canvas/headless/break-apart-find.js +324 -0
  49. package/dist/canvas/headless/break-apart-pieces.js +74 -0
  50. package/dist/canvas/headless/break-apart-plan.js +378 -0
  51. package/dist/canvas/headless/break-apart-style.js +93 -0
  52. package/dist/canvas/headless/break-apart.js +206 -0
  53. package/dist/canvas/headless/canvas-cleanup.js +70 -0
  54. package/dist/canvas/headless/edge-anchors.js +134 -0
  55. package/dist/canvas/headless/edge-memo.js +28 -0
  56. package/dist/canvas/headless/edge-serialization.js +31 -0
  57. package/dist/canvas/headless/figure-geometry.js +331 -0
  58. package/dist/canvas/headless/fit-viewport.js +82 -0
  59. package/dist/canvas/headless/grid.js +96 -0
  60. package/dist/canvas/headless/icon-node.js +45 -0
  61. package/dist/canvas/headless/index.js +1 -0
  62. package/dist/canvas/headless/linkify.js +25 -0
  63. package/dist/canvas/headless/pen-marks.js +115 -0
  64. package/dist/canvas/headless/sketch.js +250 -0
  65. package/dist/canvas/headless/snap-guides.js +100 -0
  66. package/dist/canvas/headless/svg-figure.js +137 -0
  67. package/dist/canvas/headless/table-layout.js +161 -0
  68. package/dist/canvas/index.js +25 -0
  69. package/dist/canvas/lod/lod-mode.svelte.js +22 -0
  70. package/dist/canvas/lod/render-all.svelte.js +45 -0
  71. package/dist/canvas/ops/arrange.js +83 -0
  72. package/dist/canvas/ops/ops.js +318 -0
  73. package/dist/canvas/pen/colors.js +41 -0
  74. package/dist/canvas/pen/eraser.js +35 -0
  75. package/dist/canvas/pen/geometry.js +143 -0
  76. package/dist/canvas/pen/index.js +9 -0
  77. package/dist/canvas/pen/ops.js +15 -0
  78. package/dist/canvas/pen/pen-session.js +171 -0
  79. package/dist/canvas/pen/plugin.js +129 -0
  80. package/dist/canvas/pen/shapes.js +80 -0
  81. package/dist/canvas/pen/stroke-path.js +37 -0
  82. package/dist/canvas/pen/types.js +30 -0
  83. package/dist/canvas/pen/ui.js +20 -0
  84. package/dist/canvas/plugin.js +51 -0
  85. package/dist/canvas/screen/glyphs.js +24 -0
  86. package/dist/canvas/screen/labels.js +24 -0
  87. package/dist/canvas/screen/parts.js +140 -0
  88. package/dist/canvas/screen/plugin.js +71 -0
  89. package/dist/canvas/screen/types.js +44 -0
  90. package/dist/canvas/screen/ui.js +13 -0
  91. package/dist/canvas/test-utils.js +18 -0
  92. package/dist/canvas/types.js +0 -0
  93. package/dist/canvas/ui/forward-wheel.js +27 -0
  94. package/dist/canvas/ui/icons.js +133 -0
  95. package/dist/canvas/ui/place-panel.js +57 -0
  96. package/dist/canvas/ui/shortcut-tip.js +18 -0
  97. package/dist/canvas/ui/tools.js +411 -0
  98. package/dist/charts/dashboard/chart.js +1 -0
  99. package/dist/charts/dashboard/data-table.js +7 -0
  100. package/dist/charts/dashboard/index.js +13 -0
  101. package/dist/charts/dashboard/windows.js +5 -0
  102. package/dist/charts/edge-fade.js +7 -0
  103. package/dist/charts/hover-band.js +13 -0
  104. package/dist/charts/index.js +19 -0
  105. package/dist/charts/motion.js +15 -0
  106. package/dist/charts/primitives/chart-utils.js +22 -0
  107. package/dist/charts/primitives/index.js +4 -0
  108. package/dist/components/copy/clipboard.js +38 -0
  109. package/dist/components/copy/copied.svelte.js +26 -0
  110. package/dist/components/copy/index.js +3 -0
  111. package/dist/components/data-table/data-table.js +55 -0
  112. package/dist/components/data-table/index.js +7 -0
  113. package/dist/components/docs/index.js +3 -0
  114. package/dist/components/docs/scroll-spy.svelte.js +71 -0
  115. package/dist/components/field-row/index.js +1 -0
  116. package/dist/components/hold-to-confirm/index.js +1 -0
  117. package/dist/components/icon/index.js +1 -0
  118. package/dist/components/language-flag/index.js +1 -0
  119. package/dist/components/list-page/filter-section.js +4 -0
  120. package/dist/components/list-page/index.js +25 -0
  121. package/dist/components/list-page/list-table.js +5 -0
  122. package/dist/components/list-page/queue-rail.js +3 -0
  123. package/dist/components/list-page/section-host.js +8 -0
  124. package/dist/components/list-page/step.js +5 -0
  125. package/dist/components/list-page/types.js +0 -0
  126. package/dist/components/locale-switch/index.js +1 -0
  127. package/dist/components/mark/index.js +1 -0
  128. package/dist/components/open-in/index.js +1 -0
  129. package/dist/components/picker/index.js +3 -0
  130. package/dist/components/picker/trigger.js +33 -0
  131. package/dist/components/picker/types.js +0 -0
  132. package/dist/components/section-card/index.js +1 -0
  133. package/dist/components/section-header/index.js +2 -0
  134. package/dist/components/segmented/collapse.js +32 -0
  135. package/dist/components/segmented/index.js +8 -0
  136. package/dist/components/segmented/segmented.js +50 -0
  137. package/dist/components/star-rating-input/index.js +2 -0
  138. package/dist/components/svg/index.js +1 -0
  139. package/dist/components/table-view/index.js +1 -0
  140. package/dist/components/table-view/types.js +0 -0
  141. package/dist/components/tags-input/index.js +2 -0
  142. package/dist/components/tags-input/tags.js +90 -0
  143. package/dist/components/theme/index.js +3 -0
  144. package/dist/components/toolbar/index.js +3 -0
  145. package/dist/components/toolbar/toolbar-trigger.js +4 -0
  146. package/dist/editor/anchors.js +17 -0
  147. package/dist/editor/block-id.js +62 -0
  148. package/dist/editor/block-ops.js +105 -0
  149. package/dist/editor/doc-blocks.js +181 -0
  150. package/dist/editor/extensions.js +200 -0
  151. package/dist/editor/index.js +4 -0
  152. package/dist/editor/markdown-test-helpers.js +6 -0
  153. package/dist/editor/markdown.js +486 -0
  154. package/dist/editor/serializer.js +268 -0
  155. package/dist/editor/slash-items.js +104 -0
  156. package/dist/editor/youtube-url.js +27 -0
  157. package/dist/effects/animated-beam/index.js +1 -0
  158. package/dist/effects/animated-beam/path-calculator.svelte.js +42 -0
  159. package/dist/effects/animated-beam/types.js +0 -0
  160. package/dist/effects/border-beam/css.js +420 -0
  161. package/dist/effects/border-beam/presets.js +1792 -0
  162. package/dist/effects/border-beam/register-properties.js +39 -0
  163. package/dist/effects/border-beam/types.js +0 -0
  164. package/dist/effects/image-comparison/compare.js +4 -0
  165. package/dist/effects/image-reveal/index.js +1 -0
  166. package/dist/effects/image-reveal/types.js +0 -0
  167. package/dist/effects/magnetic/magnetic.js +54 -0
  168. package/dist/effects/reveal/index.js +4 -0
  169. package/dist/effects/reveal/observe.js +43 -0
  170. package/dist/effects/reveal/types.js +0 -0
  171. package/dist/effects/shader-gradient/color.js +34 -0
  172. package/dist/effects/shader-gradient/index.js +1 -0
  173. package/dist/effects/shader-gradient/renderer.js +320 -0
  174. package/dist/effects/shader-gradient/shaders.js +280 -0
  175. package/dist/effects/shader-gradient/types.js +0 -0
  176. package/dist/icons/apple-symbol-exports.js +126 -0
  177. package/dist/icons/sf-symbols.js +465 -0
  178. package/dist/icons/trades.js +34 -0
  179. package/dist/inbox/index.js +4 -0
  180. package/dist/inbox/logic.js +156 -0
  181. package/dist/inbox/types.js +46 -0
  182. package/dist/index.js +18 -0
  183. package/dist/lib/arrive.js +13 -0
  184. package/dist/lib/icon-types.js +0 -0
  185. package/dist/lib/initials.js +17 -0
  186. package/dist/lib/layout.js +1 -0
  187. package/dist/lib/panel.js +3 -0
  188. package/dist/lib/result.js +26 -0
  189. package/dist/lib/sliding-pill.js +45 -0
  190. package/dist/lib/theme-transition.js +53 -0
  191. package/dist/lib/tone.js +32 -0
  192. package/dist/lib/utils.js +5 -0
  193. package/dist/onboarding/define-tours.js +28 -0
  194. package/dist/onboarding/index.js +4 -0
  195. package/dist/onboarding/onboarding.svelte.js +15 -0
  196. package/dist/onboarding/pick.js +16 -0
  197. package/dist/onboarding/stores.js +50 -0
  198. package/dist/onboarding/types.js +1 -0
  199. package/dist/onboarding/wait.js +25 -0
  200. package/dist/panel/index.js +1 -0
  201. package/dist/panel/side-panel-types.js +0 -0
  202. package/dist/record/demo-data.js +512 -0
  203. package/dist/record/fields.js +148 -0
  204. package/dist/record/format.js +97 -0
  205. package/dist/record/gutter.js +1 -0
  206. package/dist/record/index.js +15 -0
  207. package/dist/record/kinds.js +110 -0
  208. package/dist/record/logic.js +255 -0
  209. package/dist/record/types.js +52 -0
  210. package/dist/shadcn/accordion/index.js +5 -0
  211. package/dist/shadcn/alert/index.js +5 -0
  212. package/dist/shadcn/alert-dialog/index.js +12 -0
  213. package/dist/shadcn/attachment/index.js +10 -0
  214. package/dist/shadcn/avatar/index.js +7 -0
  215. package/dist/shadcn/badge/index.js +2 -0
  216. package/dist/shadcn/breadcrumb/index.js +8 -0
  217. package/dist/shadcn/bubble/index.js +5 -0
  218. package/dist/shadcn/button/index.js +2 -0
  219. package/dist/shadcn/calendar/index.js +19 -0
  220. package/dist/shadcn/card/index.js +8 -0
  221. package/dist/shadcn/checkbox/index.js +2 -0
  222. package/dist/shadcn/code-block/index.js +9 -0
  223. package/dist/shadcn/collapsible/index.js +4 -0
  224. package/dist/shadcn/command/index.js +13 -0
  225. package/dist/shadcn/context-menu/index.js +17 -0
  226. package/dist/shadcn/dialog/index.js +11 -0
  227. package/dist/shadcn/dropdown-menu/index.js +19 -0
  228. package/dist/shadcn/dropdown-menu/menu-item.js +23 -0
  229. package/dist/shadcn/empty/index.js +7 -0
  230. package/dist/shadcn/field/index.js +12 -0
  231. package/dist/shadcn/hooks/highlighter.js +92 -0
  232. package/dist/shadcn/hooks/is-mobile.svelte.js +7 -0
  233. package/dist/shadcn/hooks/use-highlighted-code.svelte.js +65 -0
  234. package/dist/shadcn/hover-card/index.js +5 -0
  235. package/dist/shadcn/input/index.js +3 -0
  236. package/dist/shadcn/input-otp/index.js +5 -0
  237. package/dist/shadcn/kbd/index.js +3 -0
  238. package/dist/shadcn/label/index.js +2 -0
  239. package/dist/shadcn/marker/index.js +4 -0
  240. package/dist/shadcn/message/index.js +7 -0
  241. package/dist/shadcn/message-scroller/index.js +8 -0
  242. package/dist/shadcn/popover/index.js +9 -0
  243. package/dist/shadcn/progress/index.js +2 -0
  244. package/dist/shadcn/progress/tone.js +11 -0
  245. package/dist/shadcn/radio-group/index.js +3 -0
  246. package/dist/shadcn/scroll-area/index.js +3 -0
  247. package/dist/shadcn/select/index.js +12 -0
  248. package/dist/shadcn/separator/index.js +2 -0
  249. package/dist/shadcn/sheet/index.js +11 -0
  250. package/dist/shadcn/sidebar/constants.js +6 -0
  251. package/dist/shadcn/sidebar/context.svelte.js +38 -0
  252. package/dist/shadcn/sidebar/index.js +25 -0
  253. package/dist/shadcn/skeleton/index.js +2 -0
  254. package/dist/shadcn/slider/index.js +2 -0
  255. package/dist/shadcn/sonner/index.js +1 -0
  256. package/dist/shadcn/spinner/index.js +1 -0
  257. package/dist/shadcn/switch/index.js +2 -0
  258. package/dist/shadcn/table/index.js +9 -0
  259. package/dist/shadcn/tabs/index.js +5 -0
  260. package/dist/shadcn/textarea/index.js +2 -0
  261. package/dist/shadcn/toggle/index.js +3 -0
  262. package/dist/shadcn/toggle-group/index.js +3 -0
  263. package/dist/shadcn/tooltip/context.js +8 -0
  264. package/dist/shadcn/tooltip/index.js +6 -0
  265. package/dist/shadcn/trace/index.js +9 -0
  266. package/dist/slides/bridges.js +66 -0
  267. package/dist/slides/deck-controller.svelte.js +221 -0
  268. package/dist/slides/export/capture.js +81 -0
  269. package/dist/slides/export/ffmpeg.js +85 -0
  270. package/dist/slides/export/index.js +4 -0
  271. package/dist/slides/export/launch.js +8 -0
  272. package/dist/slides/export/pdf.js +78 -0
  273. package/dist/slides/export/types.js +0 -0
  274. package/dist/slides/index.js +7 -0
  275. package/dist/slides/labels.js +26 -0
  276. package/dist/slides/layout.js +47 -0
  277. package/dist/slides/model.js +9 -0
  278. package/dist/slides/navigation.js +89 -0
  279. package/dist/slides/types.js +6 -0
  280. package/dist/status/define-statuses.js +16 -0
  281. package/dist/status/index.js +4 -0
  282. package/dist/status/status-types.js +0 -0
  283. package/dist/test-setup.js +26 -0
  284. package/dist/thread/index.js +3 -0
  285. package/dist/thread/logic.js +94 -0
  286. package/dist/thread/types.js +23 -0
  287. package/dist/work/board-order.js +109 -0
  288. package/dist/work/dates.js +19 -0
  289. package/dist/work/detail/detail-types.js +20 -0
  290. package/dist/work/docs/edited.js +39 -0
  291. package/dist/work/docs/index.js +7 -0
  292. package/dist/work/docs/labels.js +38 -0
  293. package/dist/work/docs/menu.js +121 -0
  294. package/dist/work/docs/outline.js +39 -0
  295. package/dist/work/gantt/logic.js +260 -0
  296. package/dist/work/inbox/inbox-logic.js +94 -0
  297. package/dist/work/inbox/inbox-statuses.js +86 -0
  298. package/dist/work/inbox/inbox-types.js +0 -0
  299. package/dist/work/inbox/index.js +1 -0
  300. package/dist/work/index.js +21 -0
  301. package/dist/work/kanban-drag.js +25 -0
  302. package/dist/work/kanban-types.js +0 -0
  303. package/dist/work/presets/sales.js +35 -0
  304. package/dist/work/reorder.js +10 -0
  305. package/dist/work/task-types.js +0 -0
  306. package/dist/work/time/duration.js +60 -0
  307. package/dist/work/time/time-types.js +25 -0
  308. package/dist/work/use-kanban-dnd.svelte.js +128 -0
  309. package/package.json +45 -3
  310. package/src/components/toolbar/toolbar-trigger.ts +8 -2
  311. package/src/record/demo-data.ts +4 -4
  312. package/src/record/record-demo.svelte +2 -2
  313. package/src/status/status-dot.svelte +0 -2
@@ -0,0 +1,70 @@
1
+ const RUNTIME_DATA_FIELDS = new Set([
2
+ "leftChildCount",
3
+ "rightChildCount",
4
+ "locale"
5
+ ]);
6
+ function persistentData(source) {
7
+ const data = {};
8
+ for (const [key, value] of Object.entries(source ?? {})){
9
+ if (RUNTIME_DATA_FIELDS.has(key)) continue;
10
+ if (typeof value === "function" || value === undefined) continue;
11
+ data[key] = value;
12
+ }
13
+ return data;
14
+ }
15
+ export function stripCallbacks(nodes) {
16
+ return nodes.map((n)=>{
17
+ const result = {
18
+ id: n.id,
19
+ type: n.type,
20
+ position: n.position,
21
+ data: persistentData(n.data)
22
+ };
23
+ if (n.parentId) result.parentId = n.parentId;
24
+ if (n.extent) result.extent = n.extent;
25
+ if (n.style) result.style = n.style;
26
+ if (typeof n.width === "number") result.width = n.width;
27
+ if (typeof n.height === "number") result.height = n.height;
28
+ if (typeof n.zIndex === "number") result.zIndex = n.zIndex;
29
+ return result;
30
+ });
31
+ }
32
+ export function removeOrphanedEdges(edges, nodeIds) {
33
+ return edges.filter((edge)=>nodeIds.has(edge.source) && nodeIds.has(edge.target));
34
+ }
35
+ export function sortParentsFirst(nodes) {
36
+ const idSet = new Set(nodes.map((n)=>n.id));
37
+ const roots = [];
38
+ const childrenOf = new Map();
39
+ for (const n of nodes){
40
+ if (!n.parentId || !idSet.has(n.parentId)) {
41
+ roots.push(n);
42
+ } else {
43
+ const siblings = childrenOf.get(n.parentId) ?? [];
44
+ siblings.push(n);
45
+ childrenOf.set(n.parentId, siblings);
46
+ }
47
+ }
48
+ const sorted = [];
49
+ const stack = roots.toReversed();
50
+ for(let node = stack.pop(); node !== undefined; node = stack.pop()){
51
+ sorted.push(node);
52
+ const children = childrenOf.get(node.id);
53
+ if (children) {
54
+ for(let i = children.length - 1; i >= 0; i--){
55
+ stack.push(children[i]);
56
+ }
57
+ }
58
+ }
59
+ return sorted;
60
+ }
61
+ export function fixBrokenParentIds(nodes) {
62
+ const nodeIds = new Set(nodes.map((n)=>n.id));
63
+ return nodes.map((node)=>{
64
+ if (node.parentId && !nodeIds.has(node.parentId)) {
65
+ const { parentId: _, extent: __, ...rest } = node;
66
+ return rest;
67
+ }
68
+ return node;
69
+ });
70
+ }
@@ -0,0 +1,134 @@
1
+ function center(rect) {
2
+ return {
3
+ x: rect.x + rect.width / 2,
4
+ y: rect.y + rect.height / 2
5
+ };
6
+ }
7
+ function anchorOn(rect, side) {
8
+ const c = center(rect);
9
+ switch(side){
10
+ case "top":
11
+ return {
12
+ x: c.x,
13
+ y: rect.y,
14
+ side
15
+ };
16
+ case "bottom":
17
+ return {
18
+ x: c.x,
19
+ y: rect.y + rect.height,
20
+ side
21
+ };
22
+ case "left":
23
+ return {
24
+ x: rect.x,
25
+ y: c.y,
26
+ side
27
+ };
28
+ case "right":
29
+ return {
30
+ x: rect.x + rect.width,
31
+ y: c.y,
32
+ side
33
+ };
34
+ }
35
+ }
36
+ export function sideFromHandle(id) {
37
+ return id === "top" || id === "right" || id === "bottom" || id === "left" ? id : null;
38
+ }
39
+ function sideFacing(rect, point) {
40
+ const c = center(rect);
41
+ const dx = (point.x - c.x) / rect.width;
42
+ const dy = (point.y - c.y) / rect.height;
43
+ if (Math.abs(dx) > Math.abs(dy)) return dx >= 0 ? "right" : "left";
44
+ return dy >= 0 ? "bottom" : "top";
45
+ }
46
+ function pinnedAnchors(source, target, pins) {
47
+ if (pins.source && pins.target) {
48
+ return {
49
+ source: anchorOn(source, pins.source),
50
+ target: anchorOn(target, pins.target)
51
+ };
52
+ }
53
+ if (pins.source) {
54
+ const from = anchorOn(source, pins.source);
55
+ return {
56
+ source: from,
57
+ target: anchorOn(target, sideFacing(target, from))
58
+ };
59
+ }
60
+ if (pins.target) {
61
+ const to = anchorOn(target, pins.target);
62
+ return {
63
+ source: anchorOn(source, sideFacing(source, to)),
64
+ target: to
65
+ };
66
+ }
67
+ return null;
68
+ }
69
+ export function bestAnchors(source, target, pins = {}) {
70
+ const pinned = pinnedAnchors(source, target, pins);
71
+ if (pinned) return pinned;
72
+ const gapX = Math.max(target.x - (source.x + source.width), source.x - (target.x + target.width));
73
+ const gapY = Math.max(target.y - (source.y + source.height), source.y - (target.y + target.height));
74
+ if (gapX <= 0 && gapY <= 0) {
75
+ const side = detourSide(source, target);
76
+ return {
77
+ source: anchorOn(source, side),
78
+ target: anchorOn(target, side)
79
+ };
80
+ }
81
+ if (gapX > gapY) {
82
+ const targetIsRight = center(target).x >= center(source).x;
83
+ return {
84
+ source: anchorOn(source, targetIsRight ? "right" : "left"),
85
+ target: anchorOn(target, targetIsRight ? "left" : "right")
86
+ };
87
+ }
88
+ const targetIsBelow = center(target).y >= center(source).y;
89
+ return {
90
+ source: anchorOn(source, targetIsBelow ? "bottom" : "top"),
91
+ target: anchorOn(target, targetIsBelow ? "top" : "bottom")
92
+ };
93
+ }
94
+ function detourSide(source, target) {
95
+ const sL = source.x;
96
+ const sR = source.x + source.width;
97
+ const tL = target.x;
98
+ const tR = target.x + target.width;
99
+ if (sL <= tL && sR >= tR) {
100
+ return sR - tR >= tL - sL ? "right" : "left";
101
+ }
102
+ if (tL <= sL && tR >= sR) {
103
+ return tR - sR >= sL - tL ? "right" : "left";
104
+ }
105
+ return "right";
106
+ }
107
+ export function sideDetour(anchors, margin = 40) {
108
+ const { source, target } = anchors;
109
+ switch(source.side){
110
+ case "left":
111
+ return Math.min(source.x, target.x) - margin;
112
+ case "right":
113
+ return Math.max(source.x, target.x) + margin;
114
+ case "top":
115
+ return Math.min(source.y, target.y) - margin;
116
+ case "bottom":
117
+ return Math.max(source.y, target.y) + margin;
118
+ }
119
+ }
120
+ export function outlinePoint(o, toward, gap = 0) {
121
+ const dx = toward.x - o.cx;
122
+ const dy = toward.y - o.cy;
123
+ const len = Math.hypot(dx, dy);
124
+ if (len === 0) return {
125
+ x: o.cx,
126
+ y: o.cy
127
+ };
128
+ const t = o.round ? 1 / Math.hypot(dx / o.rx, dy / o.ry) : Math.min(dx === 0 ? Infinity : o.rx / Math.abs(dx), dy === 0 ? Infinity : o.ry / Math.abs(dy));
129
+ const reach = t * len + gap;
130
+ return {
131
+ x: o.cx + dx / len * reach,
132
+ y: o.cy + dy / len * reach
133
+ };
134
+ }
@@ -0,0 +1,28 @@
1
+ export function boxKey(rect) {
2
+ return rect ? `${rect.x},${rect.y},${rect.width},${rect.height}` : "";
3
+ }
4
+ export function parseBox(key) {
5
+ if (!key) return null;
6
+ const [x, y, width, height] = key.split(",").map(Number);
7
+ return {
8
+ x,
9
+ y,
10
+ width,
11
+ height
12
+ };
13
+ }
14
+ export function createMemo(limit) {
15
+ const seen = new Map();
16
+ return (key, compute)=>{
17
+ const hit = seen.get(key);
18
+ if (hit !== undefined) {
19
+ seen.delete(key);
20
+ seen.set(key, hit);
21
+ return hit;
22
+ }
23
+ const value = compute();
24
+ seen.set(key, value);
25
+ if (seen.size > limit) seen.delete(seen.keys().next().value);
26
+ return value;
27
+ };
28
+ }
@@ -0,0 +1,31 @@
1
+ export function serializeFlowEdge(edge) {
2
+ return {
3
+ id: edge.id,
4
+ source: edge.source,
5
+ target: edge.target,
6
+ ...edge.type && {
7
+ type: edge.type
8
+ },
9
+ ...edge.label && {
10
+ label: edge.label
11
+ },
12
+ ...edge.animated && {
13
+ animated: edge.animated
14
+ },
15
+ ...edge.sourceHandle && {
16
+ sourceHandle: edge.sourceHandle
17
+ },
18
+ ...edge.targetHandle && {
19
+ targetHandle: edge.targetHandle
20
+ },
21
+ ...edge.style && {
22
+ style: edge.style
23
+ },
24
+ ...edge.data && {
25
+ data: edge.data
26
+ }
27
+ };
28
+ }
29
+ export function serializeFlowEdges(edges) {
30
+ return edges.map(serializeFlowEdge);
31
+ }
@@ -0,0 +1,331 @@
1
+ const FALLBACK_FONT = 16;
2
+ const ORIGIN = {
3
+ x: 0,
4
+ y: 0
5
+ };
6
+ export function isEl(child) {
7
+ return typeof child !== "string";
8
+ }
9
+ export function num(value, fallback = 0) {
10
+ const parsed = Number.parseFloat(value ?? "");
11
+ return Number.isFinite(parsed) ? parsed : fallback;
12
+ }
13
+ export function solid(value) {
14
+ return Boolean(value) && value !== "none";
15
+ }
16
+ export function plus(a, b) {
17
+ return {
18
+ x: a.x + b.x,
19
+ y: a.y + b.y
20
+ };
21
+ }
22
+ export function translateOf(el) {
23
+ const raw = el.attrs.transform?.trim();
24
+ if (!raw) return {
25
+ x: 0,
26
+ y: 0
27
+ };
28
+ const match = raw.match(/^translate\(\s*(-?[\d.]+)[\s,]*(-?[\d.]+)?\s*\)$/);
29
+ return match ? {
30
+ x: Number(match[1]),
31
+ y: Number(match[2] ?? 0)
32
+ } : null;
33
+ }
34
+ export function union(a, b) {
35
+ if (!a) return b;
36
+ if (!b) return a;
37
+ return {
38
+ x1: Math.min(a.x1, b.x1),
39
+ y1: Math.min(a.y1, b.y1),
40
+ x2: Math.max(a.x2, b.x2),
41
+ y2: Math.max(a.y2, b.y2)
42
+ };
43
+ }
44
+ export function boxOf(points) {
45
+ if (points.length === 0) return null;
46
+ return {
47
+ x1: Math.min(...points.map((p)=>p.x)),
48
+ y1: Math.min(...points.map((p)=>p.y)),
49
+ x2: Math.max(...points.map((p)=>p.x)),
50
+ y2: Math.max(...points.map((p)=>p.y))
51
+ };
52
+ }
53
+ export function within(inner, outer, tolerance = 1) {
54
+ return inner.x1 >= outer.x1 - tolerance && inner.y1 >= outer.y1 - tolerance && inner.x2 <= outer.x2 + tolerance && inner.y2 <= outer.y2 + tolerance;
55
+ }
56
+ export function contains(box, point, tolerance) {
57
+ return point.x >= box.x1 - tolerance && point.x <= box.x2 + tolerance && point.y >= box.y1 - tolerance && point.y <= box.y2 + tolerance;
58
+ }
59
+ export const areaOf = (b)=>(b.x2 - b.x1) * (b.y2 - b.y1);
60
+ export const centerOf = (b)=>({
61
+ x: (b.x1 + b.x2) / 2,
62
+ y: (b.y1 + b.y2) / 2
63
+ });
64
+ export function distanceToBox(box, p) {
65
+ return Math.hypot(Math.max(box.x1 - p.x, 0, p.x - box.x2), Math.max(box.y1 - p.y, 0, p.y - box.y2));
66
+ }
67
+ export function distanceToSegment(a, b, p) {
68
+ const dx = b.x - a.x;
69
+ const dy = b.y - a.y;
70
+ const len = dx * dx + dy * dy;
71
+ const t = len === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len));
72
+ return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
73
+ }
74
+ const PATH_ARITY = {
75
+ M: 2,
76
+ L: 2,
77
+ H: 1,
78
+ V: 1,
79
+ C: 6,
80
+ S: 4,
81
+ Q: 4,
82
+ T: 2,
83
+ A: 7,
84
+ Z: 0
85
+ };
86
+ function pathEnd(upper, rel, args, cur) {
87
+ const at = (from, value)=>rel ? from + value : value;
88
+ if (upper === "H") return {
89
+ x: at(cur.x, args[0]),
90
+ y: cur.y
91
+ };
92
+ if (upper === "V") return {
93
+ x: cur.x,
94
+ y: at(cur.y, args[0])
95
+ };
96
+ return {
97
+ x: at(cur.x, args[args.length - 2]),
98
+ y: at(cur.y, args[args.length - 1])
99
+ };
100
+ }
101
+ export function pathPoints(d) {
102
+ const out = [];
103
+ let cur = {
104
+ x: 0,
105
+ y: 0
106
+ };
107
+ let start = {
108
+ x: 0,
109
+ y: 0
110
+ };
111
+ for (const part of d.matchAll(/([a-zA-Z])([^a-zA-Z]*)/g)){
112
+ const cmd = part[1];
113
+ const upper = cmd.toUpperCase();
114
+ const size = PATH_ARITY[upper];
115
+ if (size === undefined) continue;
116
+ const nums = (part[2].match(/-?(?:\d+\.?\d*|\.\d+)(?:e-?\d+)?/gi) ?? []).map(Number);
117
+ if (upper === "Z") {
118
+ cur = start;
119
+ out.push(cur);
120
+ continue;
121
+ }
122
+ for(let i = 0; i + size <= nums.length; i += size){
123
+ cur = pathEnd(upper, cmd !== upper, nums.slice(i, i + size), cur);
124
+ if (upper === "M" && i === 0) start = cur;
125
+ out.push(cur);
126
+ }
127
+ }
128
+ return out;
129
+ }
130
+ export function pointList(raw) {
131
+ const nums = (raw ?? "").match(/-?(?:\d+\.?\d*|\.\d+)/g)?.map(Number) ?? [];
132
+ const out = [];
133
+ for(let i = 0; i + 1 < nums.length; i += 2)out.push({
134
+ x: nums[i],
135
+ y: nums[i + 1]
136
+ });
137
+ return out;
138
+ }
139
+ export function textLines(el) {
140
+ const lines = [];
141
+ let line = "";
142
+ const flush = ()=>{
143
+ const clean = line.replace(/\s+/g, " ").trim();
144
+ if (clean) lines.push(clean);
145
+ line = "";
146
+ };
147
+ for (const child of el.children){
148
+ if (typeof child === "string") line += child;
149
+ else if (child.tag === "tspan") {
150
+ if ("dy" in child.attrs || "y" in child.attrs) flush();
151
+ line += child.children.map((c)=>typeof c === "string" ? c : "").join("");
152
+ }
153
+ }
154
+ flush();
155
+ return lines;
156
+ }
157
+ export function isBold(el) {
158
+ const weight = el.attrs["font-weight"];
159
+ return num(weight) >= 600 || weight === "bold";
160
+ }
161
+ export function fontSize(el) {
162
+ return num(el.attrs["font-size"], FALLBACK_FONT);
163
+ }
164
+ function rectBox({ attrs: a }) {
165
+ return {
166
+ x1: num(a.x),
167
+ y1: num(a.y),
168
+ x2: num(a.x) + num(a.width),
169
+ y2: num(a.y) + num(a.height)
170
+ };
171
+ }
172
+ function ellipseBox({ attrs: a }) {
173
+ const rx = num(a.rx, num(a.r));
174
+ const ry = num(a.ry, num(a.r));
175
+ return {
176
+ x1: num(a.cx) - rx,
177
+ y1: num(a.cy) - ry,
178
+ x2: num(a.cx) + rx,
179
+ y2: num(a.cy) + ry
180
+ };
181
+ }
182
+ function lineBox({ attrs: a }) {
183
+ return boxOf([
184
+ {
185
+ x: num(a.x1),
186
+ y: num(a.y1)
187
+ },
188
+ {
189
+ x: num(a.x2),
190
+ y: num(a.y2)
191
+ }
192
+ ]);
193
+ }
194
+ function polyBox({ attrs: a }) {
195
+ return boxOf(pointList(a.points));
196
+ }
197
+ function pathBox({ attrs: a }) {
198
+ return boxOf(pathPoints(a.d ?? ""));
199
+ }
200
+ function textLeft(x, width, anchor) {
201
+ if (anchor === "middle") return x - width / 2;
202
+ return anchor === "end" ? x - width : x;
203
+ }
204
+ function textBox(el) {
205
+ const lines = textLines(el);
206
+ const size = fontSize(el);
207
+ const width = Math.max(0, ...lines.map((l)=>l.length)) * size * (isBold(el) ? 0.6 : 0.55);
208
+ const left = textLeft(num(el.attrs.x), width, el.attrs["text-anchor"]);
209
+ const y = num(el.attrs.y);
210
+ return {
211
+ x1: left,
212
+ y1: y - size * 0.8,
213
+ x2: left + width,
214
+ y2: y + size * 0.2 + Math.max(0, lines.length - 1) * size * 1.2
215
+ };
216
+ }
217
+ function groupBox(el) {
218
+ let box = null;
219
+ for (const child of el.children){
220
+ if (isEl(child)) box = union(box, boxOfEl(child, ORIGIN));
221
+ }
222
+ return box;
223
+ }
224
+ const MEASURE = new Map([
225
+ [
226
+ "rect",
227
+ rectBox
228
+ ],
229
+ [
230
+ "circle",
231
+ ellipseBox
232
+ ],
233
+ [
234
+ "ellipse",
235
+ ellipseBox
236
+ ],
237
+ [
238
+ "line",
239
+ lineBox
240
+ ],
241
+ [
242
+ "polyline",
243
+ polyBox
244
+ ],
245
+ [
246
+ "polygon",
247
+ polyBox
248
+ ],
249
+ [
250
+ "path",
251
+ pathBox
252
+ ],
253
+ [
254
+ "text",
255
+ textBox
256
+ ],
257
+ [
258
+ "g",
259
+ groupBox
260
+ ],
261
+ [
262
+ "svg",
263
+ groupBox
264
+ ]
265
+ ]);
266
+ export function boxOfEl(el, offset) {
267
+ const box = MEASURE.get(el.tag)?.(el);
268
+ if (!box) return null;
269
+ const at = plus(offset, translateOf(el) ?? ORIGIN);
270
+ return {
271
+ x1: box.x1 + at.x,
272
+ y1: box.y1 + at.y,
273
+ x2: box.x2 + at.x,
274
+ y2: box.y2 + at.y
275
+ };
276
+ }
277
+ export function visible(el) {
278
+ const fill = el.attrs.fill;
279
+ const stroke = el.attrs.stroke;
280
+ return fill !== undefined && fill !== "none" || stroke !== undefined && stroke !== "none";
281
+ }
282
+ export function viewBoxOf(root) {
283
+ const raw = root.attrs.viewBox ?? root.attrs.viewbox;
284
+ if (raw) {
285
+ const [x, y, w, h] = raw.trim().split(/[\s,]+/).map(Number);
286
+ if (w > 0 && h > 0) return {
287
+ x1: x,
288
+ y1: y,
289
+ x2: x + w,
290
+ y2: y + h
291
+ };
292
+ }
293
+ const w = num(root.attrs.width);
294
+ const h = num(root.attrs.height);
295
+ return w > 0 && h > 0 ? {
296
+ x1: 0,
297
+ y1: 0,
298
+ x2: w,
299
+ y2: h
300
+ } : null;
301
+ }
302
+ export function hasText(el) {
303
+ return el.tag === "text" && textLines(el).length > 0;
304
+ }
305
+ export function strokeEnds(el, offset) {
306
+ const shift = translateOf(el);
307
+ if (!shift) return null;
308
+ const a = el.attrs;
309
+ let pts = [];
310
+ if (el.tag === "line") {
311
+ pts = [
312
+ {
313
+ x: num(a.x1),
314
+ y: num(a.y1)
315
+ },
316
+ {
317
+ x: num(a.x2),
318
+ y: num(a.y2)
319
+ }
320
+ ];
321
+ } else if (el.tag === "polyline") pts = pointList(a.points);
322
+ else if (el.tag === "path") pts = pathPoints(a.d ?? "");
323
+ if (pts.length < 2) return null;
324
+ const at = plus(offset, shift);
325
+ const first = pts[0];
326
+ const last = pts[pts.length - 1];
327
+ return [
328
+ plus(first, at),
329
+ plus(last, at)
330
+ ];
331
+ }
@@ -0,0 +1,82 @@
1
+ const FALLBACK_NODE = {
2
+ width: 240,
3
+ height: 80
4
+ };
5
+ function num(value) {
6
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
7
+ }
8
+ function cssDim(css, prop) {
9
+ const found = css.match(new RegExp(`(?:^|[;\\s])${prop}:\\s*(\\d+(?:\\.\\d+)?)px`))?.[1];
10
+ return found ? Number(found) : null;
11
+ }
12
+ function styleDim(style, prop) {
13
+ if (typeof style === "string") return cssDim(style, prop);
14
+ if (!style || typeof style !== "object") return null;
15
+ return num(style[prop]);
16
+ }
17
+ function readSize(node) {
18
+ return {
19
+ width: num(node.width) ?? styleDim(node.style, "width") ?? FALLBACK_NODE.width,
20
+ height: num(node.height) ?? styleDim(node.style, "height") ?? FALLBACK_NODE.height
21
+ };
22
+ }
23
+ export function diagramBounds(nodes) {
24
+ const boxes = nodes.filter((node)=>!node.parentId).map((node)=>({
25
+ ...readSize(node),
26
+ x: node.position.x,
27
+ y: node.position.y
28
+ }));
29
+ if (boxes.length === 0) return null;
30
+ const minX = Math.min(...boxes.map((box)=>box.x));
31
+ const minY = Math.min(...boxes.map((box)=>box.y));
32
+ const maxX = Math.max(...boxes.map((box)=>box.x + box.width));
33
+ const maxY = Math.max(...boxes.map((box)=>box.y + box.height));
34
+ return {
35
+ x: minX,
36
+ y: minY,
37
+ width: maxX - minX,
38
+ height: maxY - minY
39
+ };
40
+ }
41
+ export function fitViewport(nodes, container, padding = 0.04) {
42
+ const bounds = diagramBounds(nodes);
43
+ if (!bounds || bounds.width <= 0 || bounds.height <= 0) return null;
44
+ if (container.width <= 0 || container.height <= 0) return null;
45
+ const usableWidth = container.width * (1 - padding * 2);
46
+ const usableHeight = container.height * (1 - padding * 2);
47
+ const zoom = Math.min(usableWidth / bounds.width, usableHeight / bounds.height);
48
+ return {
49
+ x: (container.width - bounds.width * zoom) / 2 - bounds.x * zoom,
50
+ y: (container.height - bounds.height * zoom) / 2 - bounds.y * zoom,
51
+ zoom
52
+ };
53
+ }
54
+ const MIN_READABLE_ZOOM = 0.3;
55
+ export function openingViewport(nodes, container, padding = 0.04, gutter = 0) {
56
+ const whole = fitViewport(nodes, container, padding);
57
+ if (!whole || whole.zoom >= MIN_READABLE_ZOOM) return whole;
58
+ const bounds = diagramBounds(nodes);
59
+ if (!bounds) return null;
60
+ const inset = container.width * padding;
61
+ const left = inset + gutter;
62
+ const zoom = Math.min((container.width - left - inset) / bounds.width, 1);
63
+ return {
64
+ x: left - bounds.x * zoom,
65
+ y: inset - bounds.y * zoom,
66
+ zoom
67
+ };
68
+ }
69
+ export function viewShowsContent(nodes, viewport, container, inset = {
70
+ left: 0
71
+ }) {
72
+ const bounds = diagramBounds(nodes);
73
+ if (!bounds || viewport.zoom <= 0) return true;
74
+ const left = (inset.left - viewport.x) / viewport.zoom;
75
+ const right = (container.width - viewport.x) / viewport.zoom;
76
+ const top = -viewport.y / viewport.zoom;
77
+ const bottom = (container.height - viewport.y) / viewport.zoom;
78
+ const onScreen = bounds.x < right && bounds.x + bounds.width > left && bounds.y < bottom && bounds.y + bounds.height > top;
79
+ if (!onScreen) return false;
80
+ const fits = bounds.width * viewport.zoom <= container.width - inset.left;
81
+ return !(fits && bounds.x < left - 4 / viewport.zoom);
82
+ }