@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,157 @@
1
+ import { applyOps } from "../ops/ops.js";
2
+ import { tryCatch } from "../../lib/result.js";
3
+ import { applyHistoryEntry, diffFlowState, mergeHistoryEntries } from "./history-core.js";
4
+ const MAX_ENTRIES = 200;
5
+ const COALESCE_WINDOW_MS = 1000;
6
+ const STUCK_TRANSACTION_MS = 10_000;
7
+ export function createCanvasDispatcher(io) {
8
+ const now = io.now ?? Date.now;
9
+ let undoStack = $state.raw([]);
10
+ let redoStack = $state.raw([]);
11
+ let depth = 0;
12
+ let baseline = null;
13
+ let lastActivityAt = 0;
14
+ let session = null;
15
+ function snapshot() {
16
+ const state = io.getState();
17
+ return {
18
+ nodes: [
19
+ ...state.nodes
20
+ ],
21
+ edges: [
22
+ ...state.edges
23
+ ]
24
+ };
25
+ }
26
+ function isStale() {
27
+ return depth > 0 && now() - lastActivityAt > STUCK_TRANSACTION_MS;
28
+ }
29
+ function finish(coalesceKey) {
30
+ depth = 0;
31
+ const before = baseline;
32
+ baseline = null;
33
+ const entry = before && diffFlowState(before, io.getState());
34
+ if (!entry) return;
35
+ const at = now();
36
+ const top = undoStack.at(-1);
37
+ if (coalesceKey && top && session?.key === coalesceKey && at - session.at < COALESCE_WINDOW_MS) {
38
+ undoStack = [
39
+ ...undoStack.slice(0, -1),
40
+ mergeHistoryEntries(top, entry)
41
+ ];
42
+ session = {
43
+ key: coalesceKey,
44
+ at
45
+ };
46
+ } else {
47
+ undoStack = [
48
+ ...undoStack.slice(-(MAX_ENTRIES - 1)),
49
+ entry
50
+ ];
51
+ session = coalesceKey ? {
52
+ key: coalesceKey,
53
+ at
54
+ } : null;
55
+ }
56
+ redoStack = [];
57
+ io.onMutated();
58
+ }
59
+ function recoverStuck() {
60
+ if (isStale()) finish();
61
+ }
62
+ function begin() {
63
+ recoverStuck();
64
+ lastActivityAt = now();
65
+ if (depth === 0) baseline = snapshot();
66
+ depth += 1;
67
+ }
68
+ function commit(coalesceKey) {
69
+ lastActivityAt = now();
70
+ if (depth > 1) {
71
+ depth -= 1;
72
+ return;
73
+ }
74
+ if (depth === 1) finish(coalesceKey);
75
+ }
76
+ function run(fn, coalesceKey) {
77
+ begin();
78
+ const res = tryCatch(fn);
79
+ commit(coalesceKey);
80
+ if (!res.ok) throw res.error;
81
+ return res.value;
82
+ }
83
+ function dispatch(ops, options) {
84
+ const asked = Array.isArray(ops) ? ops : [
85
+ ops
86
+ ];
87
+ const list = io.guard ? io.guard(io.getState().nodes, asked) : asked;
88
+ if (list.length === 0) return true;
89
+ return run(()=>{
90
+ const state = io.getState();
91
+ const res = tryCatch(()=>applyOps({
92
+ nodes: state.nodes,
93
+ edges: state.edges
94
+ }, list, io.opDefinitions));
95
+ if (!res.ok) return false;
96
+ io.setState({
97
+ nodes: res.value.nodes,
98
+ edges: res.value.edges
99
+ });
100
+ return true;
101
+ }, options?.coalesceKey);
102
+ }
103
+ function undo() {
104
+ recoverStuck();
105
+ session = null;
106
+ const entry = undoStack.at(-1);
107
+ if (!entry || depth > 0) return;
108
+ undoStack = undoStack.slice(0, -1);
109
+ redoStack = [
110
+ ...redoStack,
111
+ entry
112
+ ];
113
+ io.setState(applyHistoryEntry(io.getState(), entry, "undo"));
114
+ io.onMutated();
115
+ }
116
+ function redo() {
117
+ recoverStuck();
118
+ session = null;
119
+ const entry = redoStack.at(-1);
120
+ if (!entry || depth > 0) return;
121
+ redoStack = redoStack.slice(0, -1);
122
+ undoStack = [
123
+ ...undoStack,
124
+ entry
125
+ ];
126
+ io.setState(applyHistoryEntry(io.getState(), entry, "redo"));
127
+ io.onMutated();
128
+ }
129
+ return {
130
+ get canUndo () {
131
+ return undoStack.length > 0;
132
+ },
133
+ get canRedo () {
134
+ return redoStack.length > 0;
135
+ },
136
+ get isOpen () {
137
+ return depth > 0 && !isStale();
138
+ },
139
+ begin,
140
+ touch () {
141
+ if (depth > 0) lastActivityAt = now();
142
+ },
143
+ commit: ()=>commit(),
144
+ run: (fn)=>run(fn),
145
+ dispatch,
146
+ endCoalesce () {
147
+ session = null;
148
+ },
149
+ undo,
150
+ redo,
151
+ clear () {
152
+ undoStack = [];
153
+ redoStack = [];
154
+ session = null;
155
+ }
156
+ };
157
+ }
@@ -0,0 +1,8 @@
1
+ import { getContext, setContext } from "svelte";
2
+ const KEY = Symbol("diagram-editor-context");
3
+ export function setDiagramEditorContext(context) {
4
+ setContext(KEY, context);
5
+ }
6
+ export function getDiagramEditorContext() {
7
+ return getContext(KEY) ?? null;
8
+ }
File without changes
@@ -0,0 +1,87 @@
1
+ const CLICK_DRAG = 8;
2
+ const DEFAULT_FRAME = {
3
+ width: 480,
4
+ height: 300
5
+ };
6
+ const MIN_FRAME = {
7
+ width: 80,
8
+ height: 60
9
+ };
10
+ export function frameRect(from, to) {
11
+ const width = Math.abs(to.x - from.x);
12
+ const height = Math.abs(to.y - from.y);
13
+ if (width < CLICK_DRAG && height < CLICK_DRAG) {
14
+ return {
15
+ x: Math.round(from.x),
16
+ y: Math.round(from.y),
17
+ ...DEFAULT_FRAME
18
+ };
19
+ }
20
+ return {
21
+ x: Math.round(Math.min(from.x, to.x)),
22
+ y: Math.round(Math.min(from.y, to.y)),
23
+ width: Math.round(Math.max(width, MIN_FRAME.width)),
24
+ height: Math.round(Math.max(height, MIN_FRAME.height))
25
+ };
26
+ }
27
+ function sizeOf(node) {
28
+ const width = node.measured?.width ?? node.width;
29
+ const height = node.measured?.height ?? node.height;
30
+ return width && height ? {
31
+ width,
32
+ height
33
+ } : null;
34
+ }
35
+ export function frameOps(rect, nodes, { type, title, data = {} }) {
36
+ const id = crypto.randomUUID();
37
+ const inside = nodes.filter((node)=>{
38
+ const size = sizeOf(node);
39
+ if (!size || node.parentId || node.type === type) return false;
40
+ const { x, y } = node.position;
41
+ return x >= rect.x && y >= rect.y && x + size.width <= rect.x + rect.width && y + size.height <= rect.y + rect.height;
42
+ });
43
+ const ops = [
44
+ {
45
+ kind: "addNode",
46
+ node: {
47
+ id,
48
+ type,
49
+ position: {
50
+ x: rect.x,
51
+ y: rect.y
52
+ },
53
+ data: {
54
+ ...data,
55
+ label: title,
56
+ frame: true
57
+ },
58
+ width: rect.width,
59
+ height: rect.height,
60
+ style: {
61
+ width: rect.width,
62
+ height: rect.height
63
+ }
64
+ }
65
+ },
66
+ ...inside.flatMap((node)=>[
67
+ {
68
+ kind: "setParent",
69
+ nodeId: node.id,
70
+ parentId: id,
71
+ extent: "parent"
72
+ },
73
+ {
74
+ kind: "moveNode",
75
+ nodeId: node.id,
76
+ position: {
77
+ x: node.position.x - rect.x,
78
+ y: node.position.y - rect.y
79
+ }
80
+ }
81
+ ])
82
+ ];
83
+ return {
84
+ id,
85
+ ops
86
+ };
87
+ }
@@ -0,0 +1,8 @@
1
+ import { getContext, setContext } from "svelte";
2
+ const KEY = Symbol("canvas-hand-drawn");
3
+ export function setHandDrawn(read) {
4
+ setContext(KEY, read);
5
+ }
6
+ export function useHandDrawn() {
7
+ return getContext(KEY) ?? (()=>false);
8
+ }
@@ -0,0 +1,221 @@
1
+ import { sortParentsFirst } from "../headless/canvas-cleanup.js";
2
+ const VOLATILE_NODE_FIELDS = new Set([
3
+ "selected",
4
+ "dragging",
5
+ "measured",
6
+ "resizing"
7
+ ]);
8
+ const VOLATILE_EDGE_FIELDS = new Set([
9
+ "selected"
10
+ ]);
11
+ function stripVolatile(record, volatile) {
12
+ const out = {};
13
+ for (const [key, value] of Object.entries(record)){
14
+ if (volatile.has(key) || value === undefined) continue;
15
+ out[key] = value;
16
+ }
17
+ return out;
18
+ }
19
+ function clone(value) {
20
+ return JSON.parse(JSON.stringify(value));
21
+ }
22
+ function signature(record, volatile) {
23
+ return JSON.stringify(stripVolatile(record, volatile));
24
+ }
25
+ export function isSameNode(a, b) {
26
+ return a === b || signature(a, VOLATILE_NODE_FIELDS) === signature(b, VOLATILE_NODE_FIELDS);
27
+ }
28
+ export function isSameEdge(a, b) {
29
+ return a === b || signature(a, VOLATILE_EDGE_FIELDS) === signature(b, VOLATILE_EDGE_FIELDS);
30
+ }
31
+ function diffOrder(base, current) {
32
+ const before = base.map((item)=>item.id);
33
+ const after = current.map((item)=>item.id);
34
+ const same = before.length === after.length && before.every((id, i)=>id === after[i]);
35
+ return same ? undefined : {
36
+ before,
37
+ after
38
+ };
39
+ }
40
+ function diffCollection(base, current, volatile) {
41
+ const baseById = new Map(base.map((item)=>[
42
+ item.id,
43
+ item
44
+ ]));
45
+ const currentById = new Map(current.map((item)=>[
46
+ item.id,
47
+ item
48
+ ]));
49
+ const before = [];
50
+ const after = [];
51
+ for (const item of base){
52
+ const counterpart = currentById.get(item.id);
53
+ if (!counterpart) {
54
+ before.push(clone(stripVolatile(item, volatile)));
55
+ continue;
56
+ }
57
+ if (item !== counterpart && signature(item, volatile) !== signature(counterpart, volatile)) {
58
+ before.push(clone(stripVolatile(item, volatile)));
59
+ after.push(clone(stripVolatile(counterpart, volatile)));
60
+ }
61
+ }
62
+ for (const item of current){
63
+ if (!baseById.has(item.id)) {
64
+ after.push(clone(stripVolatile(item, volatile)));
65
+ }
66
+ }
67
+ return {
68
+ before,
69
+ after
70
+ };
71
+ }
72
+ export function diffFlowState(base, current) {
73
+ const nodes = diffCollection(base.nodes, current.nodes, VOLATILE_NODE_FIELDS);
74
+ const edges = diffCollection(base.edges, current.edges, VOLATILE_EDGE_FIELDS);
75
+ if (nodes.before.length === 0 && nodes.after.length === 0 && edges.before.length === 0 && edges.after.length === 0) {
76
+ return null;
77
+ }
78
+ const nodeOrder = diffOrder(base.nodes, current.nodes);
79
+ const edgeOrder = diffOrder(base.edges, current.edges);
80
+ return {
81
+ nodesBefore: nodes.before,
82
+ nodesAfter: nodes.after,
83
+ edgesBefore: edges.before,
84
+ edgesAfter: edges.after,
85
+ ...nodeOrder && {
86
+ nodeOrder
87
+ },
88
+ ...edgeOrder && {
89
+ edgeOrder
90
+ }
91
+ };
92
+ }
93
+ function sortByOrder(items, order) {
94
+ if (!order) return items;
95
+ const rank = new Map(order.map((id, index)=>[
96
+ id,
97
+ index
98
+ ]));
99
+ const at = (item)=>rank.get(item.id) ?? order.length;
100
+ return items.toSorted((a, b)=>at(a) - at(b));
101
+ }
102
+ function parentsFirst(nodes) {
103
+ const seen = new Set();
104
+ const ids = new Set(nodes.map((node)=>node.id));
105
+ for (const node of nodes){
106
+ if (node.parentId && ids.has(node.parentId) && !seen.has(node.parentId)) {
107
+ return sortParentsFirst(nodes);
108
+ }
109
+ seen.add(node.id);
110
+ }
111
+ return nodes;
112
+ }
113
+ function applyCollection(items, restore, discard) {
114
+ const restoreById = new Map(restore.map((item)=>[
115
+ item.id,
116
+ item
117
+ ]));
118
+ const discardIds = new Set(discard.map((item)=>item.id));
119
+ let next = items.filter((item)=>!(discardIds.has(item.id) && !restoreById.has(item.id)));
120
+ const present = new Set(next.map((item)=>item.id));
121
+ next = next.map((item)=>{
122
+ const restored = restoreById.get(item.id);
123
+ if (!restored) return item;
124
+ const selected = item.selected;
125
+ return {
126
+ ...clone(restored),
127
+ ...selected !== undefined && {
128
+ selected
129
+ }
130
+ };
131
+ });
132
+ for (const item of restore){
133
+ if (!present.has(item.id)) next.push(clone(item));
134
+ }
135
+ return next;
136
+ }
137
+ export function applyHistoryEntry(state, entry, direction) {
138
+ const [restoreNodes, discardNodes] = direction === "undo" ? [
139
+ entry.nodesBefore,
140
+ entry.nodesAfter
141
+ ] : [
142
+ entry.nodesAfter,
143
+ entry.nodesBefore
144
+ ];
145
+ const [restoreEdges, discardEdges] = direction === "undo" ? [
146
+ entry.edgesBefore,
147
+ entry.edgesAfter
148
+ ] : [
149
+ entry.edgesAfter,
150
+ entry.edgesBefore
151
+ ];
152
+ const side = direction === "undo" ? "before" : "after";
153
+ return {
154
+ nodes: parentsFirst(sortByOrder(applyCollection(state.nodes, restoreNodes, discardNodes), entry.nodeOrder?.[side])),
155
+ edges: sortByOrder(applyCollection(state.edges, restoreEdges, discardEdges), entry.edgeOrder?.[side])
156
+ };
157
+ }
158
+ function mergeSides(first, second) {
159
+ const firstTouched = new Set([
160
+ ...first.before,
161
+ ...first.after
162
+ ].map((item)=>item.id));
163
+ const secondTouched = new Set([
164
+ ...second.before,
165
+ ...second.after
166
+ ].map((item)=>item.id));
167
+ const before = [
168
+ ...first.before,
169
+ ...second.before.filter((item)=>!firstTouched.has(item.id))
170
+ ];
171
+ const after = [
172
+ ...first.after.filter((item)=>!secondTouched.has(item.id)),
173
+ ...second.after
174
+ ];
175
+ return {
176
+ before,
177
+ after
178
+ };
179
+ }
180
+ function sameIds(a, b) {
181
+ return a.length === b.length && a.every((id, i)=>id === b[i]);
182
+ }
183
+ function mergeOrder(first, second) {
184
+ const before = first?.before ?? second?.before;
185
+ const after = second?.after ?? first?.after;
186
+ if (!before || !after) return undefined;
187
+ return sameIds(before, after) ? undefined : {
188
+ before,
189
+ after
190
+ };
191
+ }
192
+ export function mergeHistoryEntries(first, second) {
193
+ const nodes = mergeSides({
194
+ before: first.nodesBefore,
195
+ after: first.nodesAfter
196
+ }, {
197
+ before: second.nodesBefore,
198
+ after: second.nodesAfter
199
+ });
200
+ const edges = mergeSides({
201
+ before: first.edgesBefore,
202
+ after: first.edgesAfter
203
+ }, {
204
+ before: second.edgesBefore,
205
+ after: second.edgesAfter
206
+ });
207
+ const nodeOrder = mergeOrder(first.nodeOrder, second.nodeOrder);
208
+ const edgeOrder = mergeOrder(first.edgeOrder, second.edgeOrder);
209
+ return {
210
+ nodesBefore: nodes.before,
211
+ nodesAfter: nodes.after,
212
+ edgesBefore: edges.before,
213
+ edgesAfter: edges.after,
214
+ ...nodeOrder && {
215
+ nodeOrder
216
+ },
217
+ ...edgeOrder && {
218
+ edgeOrder
219
+ }
220
+ };
221
+ }
@@ -0,0 +1,193 @@
1
+ export function isEditingTarget(target) {
2
+ const el = target;
3
+ const tag = el?.tagName;
4
+ return tag === "INPUT" || tag === "TEXTAREA" || el?.isContentEditable === true;
5
+ }
6
+ export function resolveEditorKeyAction(event, hasSelection) {
7
+ const key = event.key.toLowerCase();
8
+ const mod = event.metaKey || event.ctrlKey;
9
+ const editing = isEditingTarget(event.target);
10
+ if (mod) return modAction(key, event.shiftKey, editing);
11
+ if (event.key === "Delete" || event.key === "Backspace") {
12
+ return hasSelection && !editing ? "delete" : null;
13
+ }
14
+ return editing || event.altKey ? null : plainAction(event);
15
+ }
16
+ const SHIFT_ZOOM = new Map([
17
+ [
18
+ "Digit0",
19
+ "zoom-100"
20
+ ],
21
+ [
22
+ "Digit1",
23
+ "zoom-fit"
24
+ ],
25
+ [
26
+ "Digit2",
27
+ "zoom-selection"
28
+ ]
29
+ ]);
30
+ const PLAIN_KEYS = new Map([
31
+ [
32
+ "]",
33
+ "bring-forward"
34
+ ],
35
+ [
36
+ "[",
37
+ "send-backward"
38
+ ],
39
+ [
40
+ "+",
41
+ "zoom-in"
42
+ ],
43
+ [
44
+ "=",
45
+ "zoom-in"
46
+ ],
47
+ [
48
+ "-",
49
+ "zoom-out"
50
+ ],
51
+ [
52
+ "_",
53
+ "zoom-out"
54
+ ]
55
+ ]);
56
+ function plainAction(event) {
57
+ const zoom = event.shiftKey ? SHIFT_ZOOM.get(event.code) : undefined;
58
+ return zoom ?? PLAIN_KEYS.get(event.key) ?? null;
59
+ }
60
+ export function resolveNudge(event) {
61
+ if (event.metaKey || event.ctrlKey || event.altKey || isEditingTarget(event.target)) return null;
62
+ const step = event.shiftKey ? 10 : 1;
63
+ switch(event.key){
64
+ case "ArrowLeft":
65
+ return {
66
+ dx: -step,
67
+ dy: 0
68
+ };
69
+ case "ArrowRight":
70
+ return {
71
+ dx: step,
72
+ dy: 0
73
+ };
74
+ case "ArrowUp":
75
+ return {
76
+ dx: 0,
77
+ dy: -step
78
+ };
79
+ case "ArrowDown":
80
+ return {
81
+ dx: 0,
82
+ dy: step
83
+ };
84
+ default:
85
+ return null;
86
+ }
87
+ }
88
+ const both = (action)=>[
89
+ action,
90
+ action
91
+ ];
92
+ const CHORDS = new Map([
93
+ [
94
+ "c",
95
+ [
96
+ "copy",
97
+ "copy-as-png"
98
+ ]
99
+ ],
100
+ [
101
+ "v",
102
+ both("paste")
103
+ ],
104
+ [
105
+ "a",
106
+ both("select-all")
107
+ ],
108
+ [
109
+ "d",
110
+ [
111
+ "duplicate",
112
+ null
113
+ ]
114
+ ],
115
+ [
116
+ "g",
117
+ [
118
+ "group",
119
+ "ungroup"
120
+ ]
121
+ ],
122
+ [
123
+ "l",
124
+ [
125
+ null,
126
+ "lock"
127
+ ]
128
+ ],
129
+ [
130
+ "]",
131
+ both("bring-to-front")
132
+ ],
133
+ [
134
+ "[",
135
+ both("send-to-back")
136
+ ],
137
+ [
138
+ "enter",
139
+ both("present")
140
+ ],
141
+ [
142
+ "=",
143
+ both("zoom-in")
144
+ ],
145
+ [
146
+ "+",
147
+ both("zoom-in")
148
+ ],
149
+ [
150
+ "-",
151
+ both("zoom-out")
152
+ ],
153
+ [
154
+ "_",
155
+ both("zoom-out")
156
+ ]
157
+ ]);
158
+ function modAction(key, shift, editing) {
159
+ if (key === "z") return shift ? "redo" : "undo";
160
+ if (key === "y") return "redo";
161
+ if (key === "s" && !shift) return "save";
162
+ if (editing) return null;
163
+ return CHORDS.get(key)?.[shift ? 1 : 0] ?? null;
164
+ }
165
+ const SPACE_OWNING_TAGS = new Set([
166
+ "BUTTON",
167
+ "A",
168
+ "SUMMARY",
169
+ "SELECT",
170
+ "OPTION"
171
+ ]);
172
+ const SPACE_OWNING_ROLES = new Set([
173
+ "button",
174
+ "checkbox",
175
+ "switch",
176
+ "menuitem",
177
+ "menuitemcheckbox",
178
+ "menuitemradio",
179
+ "option",
180
+ "radio",
181
+ "tab"
182
+ ]);
183
+ export function isPanActivationKey(event) {
184
+ if (event.code !== "Space" && event.key !== " ") return false;
185
+ if (event.metaKey || event.ctrlKey || event.altKey) return false;
186
+ if (isEditingTarget(event.target)) return false;
187
+ return !ownsSpace(event.target);
188
+ }
189
+ function ownsSpace(el) {
190
+ if (el?.tagName && SPACE_OWNING_TAGS.has(el.tagName)) return true;
191
+ const role = el?.getAttribute?.("role");
192
+ return Boolean(role && SPACE_OWNING_ROLES.has(role));
193
+ }