@heyramzi/ui 2.9.0 → 2.10.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 (312) 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
@@ -0,0 +1,318 @@
1
+ import { z } from "zod";
2
+ const positionSchema = z.object({
3
+ x: z.number(),
4
+ y: z.number()
5
+ });
6
+ export const addNodeOp = z.object({
7
+ kind: z.literal("addNode"),
8
+ node: z.object({
9
+ id: z.string().min(1).optional(),
10
+ type: z.string().min(1),
11
+ position: positionSchema.optional(),
12
+ data: z.record(z.string(), z.unknown()),
13
+ style: z.record(z.string(), z.unknown()).optional(),
14
+ width: z.number().optional(),
15
+ height: z.number().optional(),
16
+ parentId: z.string().min(1).optional()
17
+ })
18
+ });
19
+ export const removeNodeOp = z.object({
20
+ kind: z.literal("removeNode"),
21
+ nodeId: z.string().min(1)
22
+ });
23
+ export const patchNodeOp = z.object({
24
+ kind: z.literal("patchNode"),
25
+ nodeId: z.string().min(1),
26
+ data: z.record(z.string(), z.unknown()).optional(),
27
+ style: z.record(z.string(), z.unknown()).optional(),
28
+ width: z.number().optional(),
29
+ height: z.number().optional()
30
+ });
31
+ export const moveNodeOp = z.object({
32
+ kind: z.literal("moveNode"),
33
+ nodeId: z.string().min(1),
34
+ position: positionSchema
35
+ });
36
+ export const setParentOp = z.object({
37
+ kind: z.literal("setParent"),
38
+ nodeId: z.string().min(1),
39
+ parentId: z.string().min(1).nullable(),
40
+ extent: z.literal("parent").nullable().optional()
41
+ });
42
+ export const addEdgeOp = z.object({
43
+ kind: z.literal("addEdge"),
44
+ edge: z.object({
45
+ id: z.string().min(1).optional(),
46
+ source: z.string().min(1),
47
+ target: z.string().min(1),
48
+ sourceHandle: z.string().optional(),
49
+ targetHandle: z.string().optional(),
50
+ type: z.string().optional(),
51
+ label: z.string().optional(),
52
+ animated: z.boolean().optional(),
53
+ style: z.record(z.string(), z.unknown()).optional(),
54
+ data: z.record(z.string(), z.unknown()).optional()
55
+ })
56
+ });
57
+ export const removeEdgeOp = z.object({
58
+ kind: z.literal("removeEdge"),
59
+ edgeId: z.string().min(1)
60
+ });
61
+ export const patchEdgeOp = z.object({
62
+ kind: z.literal("patchEdge"),
63
+ edgeId: z.string().min(1),
64
+ patch: z.object({
65
+ label: z.string().optional(),
66
+ animated: z.boolean().optional(),
67
+ type: z.string().optional(),
68
+ style: z.record(z.string(), z.unknown()).optional(),
69
+ data: z.record(z.string(), z.unknown()).optional(),
70
+ sourceHandle: z.string().optional(),
71
+ targetHandle: z.string().optional(),
72
+ source: z.string().min(1).optional(),
73
+ target: z.string().min(1).optional()
74
+ }).refine((v)=>Object.keys(v).length > 0, {
75
+ message: "patch must include at least one field"
76
+ })
77
+ });
78
+ export const CORE_OP_SCHEMAS = [
79
+ addNodeOp,
80
+ removeNodeOp,
81
+ patchNodeOp,
82
+ moveNodeOp,
83
+ setParentOp,
84
+ addEdgeOp,
85
+ removeEdgeOp,
86
+ patchEdgeOp
87
+ ];
88
+ export const canvasOpSchema = z.discriminatedUnion("kind", [
89
+ ...CORE_OP_SCHEMAS
90
+ ]);
91
+ export class CanvasOpError extends Error {
92
+ opIndex;
93
+ constructor(message, opIndex){
94
+ super(message), this.opIndex = opIndex;
95
+ this.name = "CanvasOpError";
96
+ }
97
+ }
98
+ export function randomId() {
99
+ return crypto.randomUUID();
100
+ }
101
+ export function getNodeId(node) {
102
+ return typeof node.id === "string" ? node.id : undefined;
103
+ }
104
+ export function getNodeData(node) {
105
+ return typeof node.data === "object" && node.data !== null ? node.data : {};
106
+ }
107
+ export function hasNode(nodes, id) {
108
+ return nodes.some((n)=>getNodeId(n) === id);
109
+ }
110
+ export function mapNodeOrThrow(nodes, nodeId, opIndex, transform) {
111
+ let found = false;
112
+ const next = nodes.map((n)=>{
113
+ if (getNodeId(n) !== nodeId) return n;
114
+ found = true;
115
+ return transform(n);
116
+ });
117
+ if (!found) throw new CanvasOpError(`Unknown nodeId: ${nodeId}`, opIndex);
118
+ return next;
119
+ }
120
+ export function insertAt(list, item, index) {
121
+ const next = [
122
+ ...list
123
+ ];
124
+ next.splice(Math.min(index ?? next.length, next.length), 0, item);
125
+ return next;
126
+ }
127
+ export function assertIndex(index, length, what, opIndex) {
128
+ if (index >= length) throw new CanvasOpError(`${what} index ${index} out of bounds`, opIndex);
129
+ }
130
+ export function patchData(state, nodeId, opIndex, fields) {
131
+ state.nodes = mapNodeOrThrow(state.nodes, nodeId, opIndex, (n)=>{
132
+ const nodeData = getNodeData(n);
133
+ return {
134
+ ...n,
135
+ data: {
136
+ ...nodeData,
137
+ ...fields(nodeData)
138
+ }
139
+ };
140
+ });
141
+ }
142
+ function assertParentExists(nodes, nodeId, parentId, i) {
143
+ if (parentId === nodeId) throw new CanvasOpError(`Node cannot be its own parent: ${nodeId}`, i);
144
+ if (!hasNode(nodes, parentId)) throw new CanvasOpError(`Unknown parentId: ${parentId}`, i);
145
+ }
146
+ function addNode(state, op, i) {
147
+ const { node } = op;
148
+ const id = node.id ?? randomId();
149
+ if (hasNode(state.nodes, id)) throw new CanvasOpError(`Node id already exists: ${id}`, i);
150
+ if (node.parentId) assertParentExists(state.nodes, id, node.parentId, i);
151
+ state.nodes = [
152
+ ...state.nodes,
153
+ {
154
+ id,
155
+ type: node.type,
156
+ position: node.position ?? {
157
+ x: 0,
158
+ y: 0
159
+ },
160
+ data: node.data,
161
+ ...node.style && {
162
+ style: node.style
163
+ },
164
+ ...node.width != null && {
165
+ width: node.width
166
+ },
167
+ ...node.height != null && {
168
+ height: node.height
169
+ },
170
+ ...node.parentId && {
171
+ parentId: node.parentId,
172
+ extent: "parent"
173
+ }
174
+ }
175
+ ];
176
+ }
177
+ function removeNode(state, op, i) {
178
+ if (!hasNode(state.nodes, op.nodeId)) {
179
+ throw new CanvasOpError(`Unknown nodeId: ${op.nodeId}`, i);
180
+ }
181
+ state.nodes = state.nodes.filter((n)=>getNodeId(n) !== op.nodeId);
182
+ state.edges = state.edges.filter((e)=>e.source !== op.nodeId && e.target !== op.nodeId);
183
+ }
184
+ function patchNodeRecord(n, op) {
185
+ const next = {
186
+ ...n
187
+ };
188
+ if (op.data) next.data = {
189
+ ...getNodeData(n),
190
+ ...op.data
191
+ };
192
+ if (op.style) {
193
+ const existing = typeof n.style === "object" && n.style !== null ? n.style : {};
194
+ next.style = {
195
+ ...existing,
196
+ ...op.style
197
+ };
198
+ }
199
+ if (op.width != null) next.width = op.width;
200
+ if (op.height != null) next.height = op.height;
201
+ return next;
202
+ }
203
+ function patchNode(state, op, i) {
204
+ if (!op.data && !op.style && op.width == null && op.height == null) {
205
+ throw new CanvasOpError("patchNode requires data, style, width or height", i);
206
+ }
207
+ state.nodes = mapNodeOrThrow(state.nodes, op.nodeId, i, (n)=>patchNodeRecord(n, op));
208
+ }
209
+ function moveNode(state, op, i) {
210
+ state.nodes = mapNodeOrThrow(state.nodes, op.nodeId, i, (n)=>({
211
+ ...n,
212
+ position: {
213
+ x: op.position.x,
214
+ y: op.position.y
215
+ }
216
+ }));
217
+ }
218
+ function setParent(state, op, i) {
219
+ const { parentId } = op;
220
+ if (parentId !== null) assertParentExists(state.nodes, op.nodeId, parentId, i);
221
+ state.nodes = mapNodeOrThrow(state.nodes, op.nodeId, i, (n)=>{
222
+ const { parentId: _p, extent: _e, ...rest } = n;
223
+ if (parentId === null) return rest;
224
+ const extent = op.extent === null ? undefined : op.extent ?? "parent";
225
+ return extent ? {
226
+ ...rest,
227
+ parentId,
228
+ extent
229
+ } : {
230
+ ...rest,
231
+ parentId
232
+ };
233
+ });
234
+ }
235
+ function addEdge(state, op, i) {
236
+ const id = op.edge.id ?? randomId();
237
+ if (state.edges.some((e)=>e.id === id)) {
238
+ throw new CanvasOpError(`Edge id already exists: ${id}`, i);
239
+ }
240
+ if (!hasNode(state.nodes, op.edge.source)) {
241
+ throw new CanvasOpError(`Edge source not found: ${op.edge.source}`, i);
242
+ }
243
+ if (!hasNode(state.nodes, op.edge.target)) {
244
+ throw new CanvasOpError(`Edge target not found: ${op.edge.target}`, i);
245
+ }
246
+ state.edges = [
247
+ ...state.edges,
248
+ {
249
+ id,
250
+ ...op.edge
251
+ }
252
+ ];
253
+ }
254
+ function removeEdge(state, op, i) {
255
+ if (!state.edges.some((e)=>e.id === op.edgeId)) {
256
+ throw new CanvasOpError(`Unknown edgeId: ${op.edgeId}`, i);
257
+ }
258
+ state.edges = state.edges.filter((e)=>e.id !== op.edgeId);
259
+ }
260
+ function patchEdge(state, op, i) {
261
+ const { source, target } = op.patch;
262
+ if (source !== undefined && !hasNode(state.nodes, source)) {
263
+ throw new CanvasOpError(`Edge source not found: ${source}`, i);
264
+ }
265
+ if (target !== undefined && !hasNode(state.nodes, target)) {
266
+ throw new CanvasOpError(`Edge target not found: ${target}`, i);
267
+ }
268
+ let found = false;
269
+ state.edges = state.edges.map((e)=>{
270
+ if (e.id !== op.edgeId) return e;
271
+ found = true;
272
+ return {
273
+ ...e,
274
+ ...op.patch
275
+ };
276
+ });
277
+ if (!found) throw new CanvasOpError(`Unknown edgeId: ${op.edgeId}`, i);
278
+ }
279
+ const CORE_APPLY = {
280
+ addNode,
281
+ removeNode,
282
+ patchNode,
283
+ moveNode,
284
+ setParent,
285
+ addEdge,
286
+ removeEdge,
287
+ patchEdge
288
+ };
289
+ export function applyOps(data, ops, definitions = []) {
290
+ const state = {
291
+ nodes: [
292
+ ...data.nodes
293
+ ],
294
+ edges: [
295
+ ...data.edges
296
+ ]
297
+ };
298
+ const byKind = new Map(definitions.map((def)=>[
299
+ def.kind,
300
+ def
301
+ ]));
302
+ ops.forEach((op, i)=>{
303
+ const core = CORE_APPLY[op.kind];
304
+ if (core) return core(state, op, i);
305
+ const def = byKind.get(op.kind);
306
+ if (!def) throw new CanvasOpError(`Unknown op kind: ${op.kind}`, i);
307
+ def.apply(state, op, i);
308
+ });
309
+ const { nodes, edges } = state;
310
+ return data.viewport ? {
311
+ nodes,
312
+ edges,
313
+ viewport: data.viewport
314
+ } : {
315
+ nodes,
316
+ edges
317
+ };
318
+ }
@@ -0,0 +1,41 @@
1
+ export const PEN_HEX = {
2
+ ink: {
3
+ light: "#1e1e1e",
4
+ dark: "#e9ecef"
5
+ },
6
+ red: {
7
+ light: "#e03131",
8
+ dark: "#ff8787"
9
+ },
10
+ blue: {
11
+ light: "#1971c2",
12
+ dark: "#74c0fc"
13
+ },
14
+ green: {
15
+ light: "#2f9e44",
16
+ dark: "#69db7c"
17
+ },
18
+ amber: {
19
+ light: "#e8a33d",
20
+ dark: "#ffd43b"
21
+ },
22
+ violet: {
23
+ light: "#6741d9",
24
+ dark: "#b197fc"
25
+ },
26
+ indigo: {
27
+ light: "#414fd2",
28
+ dark: "#8b96ff"
29
+ },
30
+ terra: {
31
+ light: "#f0503d",
32
+ dark: "#ff8a78"
33
+ }
34
+ };
35
+ export function penColorVar(color) {
36
+ const known = color in PEN_HEX ? color : "ink";
37
+ return `var(--pen-${known}, ${PEN_HEX[known].light})`;
38
+ }
39
+ export function penCssTokens(mode) {
40
+ return Object.keys(PEN_HEX).map((name)=>`--pen-${name}: ${PEN_HEX[name][mode]};`).join(" ");
41
+ }
@@ -0,0 +1,35 @@
1
+ import { distanceToStroke } from "./geometry.js";
2
+ import { STROKE_NODE } from "./types.js";
3
+ function isStrokeData(data) {
4
+ return Array.isArray(data.points) && typeof data.size === "number";
5
+ }
6
+ export function strokesUnder(nodes, at, radius) {
7
+ const hits = [];
8
+ for (const node of nodes){
9
+ if (node.type !== STROKE_NODE || !isStrokeData(node.data)) continue;
10
+ const local = {
11
+ x: at.x - node.position.x,
12
+ y: at.y - node.position.y
13
+ };
14
+ if (distanceToStroke(node.data.points, local) <= radius + node.data.size / 2) {
15
+ hits.push(node.id);
16
+ }
17
+ }
18
+ return hits;
19
+ }
20
+ export function strokesAlong(nodes, from, to, radius) {
21
+ const length = Math.hypot(to.x - from.x, to.y - from.y);
22
+ const steps = Math.max(1, Math.ceil(length / Math.max(radius / 2, 1)));
23
+ const hits = new Set();
24
+ for(let i = 0; i <= steps; i++){
25
+ const t = i / steps;
26
+ const at = {
27
+ x: from.x + (to.x - from.x) * t,
28
+ y: from.y + (to.y - from.y) * t
29
+ };
30
+ for (const id of strokesUnder(nodes, at, radius))hits.add(id);
31
+ }
32
+ return [
33
+ ...hits
34
+ ];
35
+ }
@@ -0,0 +1,143 @@
1
+ import { PEN_DEFAULTS, STROKE_NODE } from "./types.js";
2
+ const SIMPLIFY_TOLERANCE = 0.6;
3
+ function round(value, places) {
4
+ const factor = 10 ** places;
5
+ return Math.round(value * factor) / factor;
6
+ }
7
+ export function distanceToSegment(p, a, b) {
8
+ const dx = b.x - a.x;
9
+ const dy = b.y - a.y;
10
+ const lengthSquared = dx * dx + dy * dy;
11
+ if (lengthSquared === 0) return Math.hypot(p.x - a.x, p.y - a.y);
12
+ const t = Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / lengthSquared));
13
+ return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));
14
+ }
15
+ export function simplifyPoints(points, tolerance) {
16
+ if (points.length <= 2) return [
17
+ ...points
18
+ ];
19
+ const keep = new Uint8Array(points.length);
20
+ keep[0] = 1;
21
+ keep[points.length - 1] = 1;
22
+ const stack = [
23
+ [
24
+ 0,
25
+ points.length - 1
26
+ ]
27
+ ];
28
+ while(stack.length > 0){
29
+ const [start, end] = stack.pop();
30
+ const a = {
31
+ x: points[start][0],
32
+ y: points[start][1]
33
+ };
34
+ const b = {
35
+ x: points[end][0],
36
+ y: points[end][1]
37
+ };
38
+ let farthest = -1;
39
+ let farthestDistance = tolerance;
40
+ for(let i = start + 1; i < end; i++){
41
+ const distance = distanceToSegment({
42
+ x: points[i][0],
43
+ y: points[i][1]
44
+ }, a, b);
45
+ if (distance > farthestDistance) {
46
+ farthest = i;
47
+ farthestDistance = distance;
48
+ }
49
+ }
50
+ if (farthest === -1) continue;
51
+ keep[farthest] = 1;
52
+ stack.push([
53
+ start,
54
+ farthest
55
+ ], [
56
+ farthest,
57
+ end
58
+ ]);
59
+ }
60
+ return points.filter((_, i)=>keep[i] === 1);
61
+ }
62
+ export function pointsBounds(points) {
63
+ let minX = Infinity;
64
+ let minY = Infinity;
65
+ let maxX = -Infinity;
66
+ let maxY = -Infinity;
67
+ for (const [x, y] of points){
68
+ minX = Math.min(minX, x);
69
+ minY = Math.min(minY, y);
70
+ maxX = Math.max(maxX, x);
71
+ maxY = Math.max(maxY, y);
72
+ }
73
+ return {
74
+ x: minX,
75
+ y: minY,
76
+ width: maxX - minX,
77
+ height: maxY - minY
78
+ };
79
+ }
80
+ export function buildStrokeNode(samples, options = {}) {
81
+ if (samples.length === 0) return null;
82
+ const tool = options.tool ?? "pen";
83
+ const size = options.size ?? PEN_DEFAULTS[tool].size;
84
+ const tolerance = SIMPLIFY_TOLERANCE / Math.max(options.zoom ?? 1, 0.1);
85
+ const source = samples.length === 1 ? [
86
+ samples[0],
87
+ samples[0]
88
+ ] : samples;
89
+ const simplified = simplifyPoints(source, tolerance);
90
+ const hasPressure = simplified.some((point)=>point[2] !== undefined);
91
+ const pad = Math.ceil(size / 2) + 2;
92
+ const box = pointsBounds(simplified);
93
+ const origin = {
94
+ x: box.x - pad,
95
+ y: box.y - pad
96
+ };
97
+ const points = simplified.map(([x, y, pressure])=>{
98
+ const px = round(x - origin.x, 1);
99
+ const py = round(y - origin.y, 1);
100
+ return hasPressure ? [
101
+ px,
102
+ py,
103
+ round(pressure ?? 0.5, 2)
104
+ ] : [
105
+ px,
106
+ py
107
+ ];
108
+ });
109
+ return {
110
+ id: options.id,
111
+ type: STROKE_NODE,
112
+ position: {
113
+ x: round(origin.x, 1),
114
+ y: round(origin.y, 1)
115
+ },
116
+ data: {
117
+ points,
118
+ color: options.color ?? PEN_DEFAULTS.color,
119
+ size,
120
+ tool,
121
+ simulatePressure: !hasPressure
122
+ },
123
+ width: Math.ceil(box.width + pad * 2),
124
+ height: Math.ceil(box.height + pad * 2)
125
+ };
126
+ }
127
+ export function distanceToStroke(points, p) {
128
+ if (points.length === 0) return Infinity;
129
+ if (points.length === 1) return Math.hypot(p.x - points[0][0], p.y - points[0][1]);
130
+ let best = Infinity;
131
+ for(let i = 1; i < points.length; i++){
132
+ const a = {
133
+ x: points[i - 1][0],
134
+ y: points[i - 1][1]
135
+ };
136
+ const b = {
137
+ x: points[i][0],
138
+ y: points[i][1]
139
+ };
140
+ best = Math.min(best, distanceToSegment(p, a, b));
141
+ }
142
+ return best;
143
+ }
@@ -0,0 +1,9 @@
1
+ export { PEN_HEX, penColorVar } from "./colors.js";
2
+ export { strokesAlong, strokesUnder } from "./eraser.js";
3
+ export { buildStrokeNode, distanceToStroke, pointsBounds, simplifyPoints } from "./geometry.js";
4
+ export { addPenNode, removePenNode } from "./ops.js";
5
+ export { createPenSession } from "./pen-session.js";
6
+ export { penPlugin } from "./plugin.js";
7
+ export { buildShapeNode, buildTextNode, dragBox, shapeOutline } from "./shapes.js";
8
+ export { outlineToPath, strokePath } from "./stroke-path.js";
9
+ export { HIGHLIGHTER_OPACITY, PEN_COLORS, PEN_DEFAULTS, SHAPE_KINDS, SHAPE_NODE, STROKE_NODE, TEXT_NODE } from "./types.js";
@@ -0,0 +1,15 @@
1
+ export function addPenNode(node) {
2
+ return {
3
+ kind: "addNode",
4
+ node: {
5
+ ...node,
6
+ id: node.id ?? crypto.randomUUID()
7
+ }
8
+ };
9
+ }
10
+ export function removePenNode(nodeId) {
11
+ return {
12
+ kind: "removeNode",
13
+ nodeId
14
+ };
15
+ }