@oh-just-another/state 0.58.0 → 0.60.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 (272) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/README.md +78 -27
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/actions/actionArrange.d.ts +13 -0
  5. package/dist/actions/actionArrange.d.ts.map +1 -0
  6. package/dist/actions/actionArrange.js +130 -0
  7. package/dist/actions/actionArrange.js.map +1 -0
  8. package/dist/actions/actionClipboard.d.ts +2 -0
  9. package/dist/actions/actionClipboard.d.ts.map +1 -1
  10. package/dist/actions/actionClipboard.js +32 -1
  11. package/dist/actions/actionClipboard.js.map +1 -1
  12. package/dist/actions/actionKeyboard.d.ts.map +1 -1
  13. package/dist/actions/actionKeyboard.js +77 -9
  14. package/dist/actions/actionKeyboard.js.map +1 -1
  15. package/dist/actions/actionMode.d.ts +4 -0
  16. package/dist/actions/actionMode.d.ts.map +1 -1
  17. package/dist/actions/actionMode.js +54 -0
  18. package/dist/actions/actionMode.js.map +1 -1
  19. package/dist/actions/actionSelection.d.ts.map +1 -1
  20. package/dist/actions/actionSelection.js +1 -0
  21. package/dist/actions/actionSelection.js.map +1 -1
  22. package/dist/actions/actionText.d.ts +5 -0
  23. package/dist/actions/actionText.d.ts.map +1 -0
  24. package/dist/actions/actionText.js +37 -0
  25. package/dist/actions/actionText.js.map +1 -0
  26. package/dist/actions/actionView.d.ts +6 -0
  27. package/dist/actions/actionView.d.ts.map +1 -1
  28. package/dist/actions/actionView.js +20 -2
  29. package/dist/actions/actionView.js.map +1 -1
  30. package/dist/actions/actionZoom.d.ts.map +1 -1
  31. package/dist/actions/actionZoom.js +5 -0
  32. package/dist/actions/actionZoom.js.map +1 -1
  33. package/dist/actions/index.d.ts +6 -4
  34. package/dist/actions/index.d.ts.map +1 -1
  35. package/dist/actions/index.js +6 -4
  36. package/dist/actions/index.js.map +1 -1
  37. package/dist/actions/registry.d.ts.map +1 -1
  38. package/dist/actions/registry.js +17 -0
  39. package/dist/actions/registry.js.map +1 -1
  40. package/dist/actions/types.d.ts +10 -1
  41. package/dist/actions/types.d.ts.map +1 -1
  42. package/dist/actions/types.js.map +1 -1
  43. package/dist/auto-layout-scheduler.d.ts +1 -3
  44. package/dist/auto-layout-scheduler.d.ts.map +1 -1
  45. package/dist/auto-layout-scheduler.js +1 -2
  46. package/dist/auto-layout-scheduler.js.map +1 -1
  47. package/dist/built-in-handlers.d.ts.map +1 -1
  48. package/dist/built-in-handlers.js +14 -1
  49. package/dist/built-in-handlers.js.map +1 -1
  50. package/dist/clipboard.d.ts +0 -14
  51. package/dist/clipboard.d.ts.map +1 -1
  52. package/dist/clipboard.js +1 -1
  53. package/dist/clipboard.js.map +1 -1
  54. package/dist/constants.d.ts +208 -41
  55. package/dist/constants.d.ts.map +1 -1
  56. package/dist/constants.js +210 -25
  57. package/dist/constants.js.map +1 -1
  58. package/dist/dom-events.d.ts +8 -2
  59. package/dist/dom-events.d.ts.map +1 -1
  60. package/dist/dom-events.js +12 -0
  61. package/dist/dom-events.js.map +1 -1
  62. package/dist/editor/animation-scene.d.ts +36 -0
  63. package/dist/editor/animation-scene.d.ts.map +1 -0
  64. package/dist/editor/animation-scene.js +194 -0
  65. package/dist/editor/animation-scene.js.map +1 -0
  66. package/dist/editor/animation.d.ts +43 -0
  67. package/dist/editor/animation.d.ts.map +1 -0
  68. package/dist/editor/animation.js +80 -0
  69. package/dist/editor/animation.js.map +1 -0
  70. package/dist/editor/applies/arrange.d.ts +46 -0
  71. package/dist/editor/applies/arrange.d.ts.map +1 -0
  72. package/dist/editor/applies/arrange.js +162 -0
  73. package/dist/editor/applies/arrange.js.map +1 -0
  74. package/dist/editor/applies/create.d.ts +0 -6
  75. package/dist/editor/applies/create.d.ts.map +1 -1
  76. package/dist/editor/applies/create.js +1 -1
  77. package/dist/editor/applies/create.js.map +1 -1
  78. package/dist/editor/applies/edge.d.ts +8 -1
  79. package/dist/editor/applies/edge.d.ts.map +1 -1
  80. package/dist/editor/applies/edge.js +31 -1
  81. package/dist/editor/applies/edge.js.map +1 -1
  82. package/dist/editor/applies/link-move.d.ts +0 -8
  83. package/dist/editor/applies/link-move.d.ts.map +1 -1
  84. package/dist/editor/applies/link-move.js +1 -1
  85. package/dist/editor/applies/link-move.js.map +1 -1
  86. package/dist/editor/applies/move.d.ts +6 -0
  87. package/dist/editor/applies/move.d.ts.map +1 -1
  88. package/dist/editor/applies/move.js +6 -0
  89. package/dist/editor/applies/move.js.map +1 -1
  90. package/dist/editor/applies/resize.d.ts +26 -5
  91. package/dist/editor/applies/resize.d.ts.map +1 -1
  92. package/dist/editor/applies/resize.js +91 -13
  93. package/dist/editor/applies/resize.js.map +1 -1
  94. package/dist/editor/caret-blink.d.ts +18 -0
  95. package/dist/editor/caret-blink.d.ts.map +1 -0
  96. package/dist/editor/caret-blink.js +42 -0
  97. package/dist/editor/caret-blink.js.map +1 -0
  98. package/dist/editor/container-ops.d.ts.map +1 -1
  99. package/dist/editor/container-ops.js +2 -2
  100. package/dist/editor/container-ops.js.map +1 -1
  101. package/dist/editor/dirty-rect.d.ts +23 -0
  102. package/dist/editor/dirty-rect.d.ts.map +1 -0
  103. package/dist/editor/dirty-rect.js +115 -0
  104. package/dist/editor/dirty-rect.js.map +1 -0
  105. package/dist/editor/gif-playback.d.ts +45 -0
  106. package/dist/editor/gif-playback.d.ts.map +1 -0
  107. package/dist/editor/gif-playback.js +125 -0
  108. package/dist/editor/gif-playback.js.map +1 -0
  109. package/dist/editor/hit-test.d.ts +3 -3
  110. package/dist/editor/hit-test.d.ts.map +1 -1
  111. package/dist/editor/hit-test.js +40 -15
  112. package/dist/editor/hit-test.js.map +1 -1
  113. package/dist/editor/interaction-state.d.ts +184 -0
  114. package/dist/editor/interaction-state.d.ts.map +1 -0
  115. package/dist/editor/interaction-state.js +139 -0
  116. package/dist/editor/interaction-state.js.map +1 -0
  117. package/dist/editor/link-handle-drag.d.ts +152 -0
  118. package/dist/editor/link-handle-drag.d.ts.map +1 -0
  119. package/dist/editor/link-handle-drag.js +300 -0
  120. package/dist/editor/link-handle-drag.js.map +1 -0
  121. package/dist/editor/long-press.d.ts.map +1 -1
  122. package/dist/editor/long-press.js +2 -2
  123. package/dist/editor/long-press.js.map +1 -1
  124. package/dist/editor/pinch.d.ts.map +1 -1
  125. package/dist/editor/pinch.js +6 -6
  126. package/dist/editor/pinch.js.map +1 -1
  127. package/dist/editor/pointer-binding.d.ts +9 -11
  128. package/dist/editor/pointer-binding.d.ts.map +1 -1
  129. package/dist/editor/pointer-binding.js +1191 -890
  130. package/dist/editor/pointer-binding.js.map +1 -1
  131. package/dist/editor/public/arrange-group.d.ts +3 -9
  132. package/dist/editor/public/arrange-group.d.ts.map +1 -1
  133. package/dist/editor/public/arrange-group.js +4 -6
  134. package/dist/editor/public/arrange-group.js.map +1 -1
  135. package/dist/editor/public/brush.d.ts +31 -12
  136. package/dist/editor/public/brush.d.ts.map +1 -1
  137. package/dist/editor/public/brush.js +66 -17
  138. package/dist/editor/public/brush.js.map +1 -1
  139. package/dist/editor/public/clipboard.d.ts +2 -4
  140. package/dist/editor/public/clipboard.d.ts.map +1 -1
  141. package/dist/editor/public/clipboard.js +2 -4
  142. package/dist/editor/public/clipboard.js.map +1 -1
  143. package/dist/editor/public/cursor.d.ts +29 -0
  144. package/dist/editor/public/cursor.d.ts.map +1 -0
  145. package/dist/editor/public/cursor.js +146 -0
  146. package/dist/editor/public/cursor.js.map +1 -0
  147. package/dist/editor/public/eraser.d.ts +55 -0
  148. package/dist/editor/public/eraser.d.ts.map +1 -0
  149. package/dist/editor/public/eraser.js +65 -0
  150. package/dist/editor/public/eraser.js.map +1 -0
  151. package/dist/editor/public/frame-name.d.ts +20 -0
  152. package/dist/editor/public/frame-name.d.ts.map +1 -0
  153. package/dist/editor/public/frame-name.js +54 -0
  154. package/dist/editor/public/frame-name.js.map +1 -0
  155. package/dist/editor/public/image-insert.d.ts +1 -1
  156. package/dist/editor/public/image-insert.d.ts.map +1 -1
  157. package/dist/editor/public/laser.d.ts +38 -0
  158. package/dist/editor/public/laser.d.ts.map +1 -0
  159. package/dist/editor/public/laser.js +42 -0
  160. package/dist/editor/public/laser.js.map +1 -0
  161. package/dist/editor/public/layers.d.ts.map +1 -1
  162. package/dist/editor/public/layers.js +2 -2
  163. package/dist/editor/public/layers.js.map +1 -1
  164. package/dist/editor/public/link.d.ts +11 -2
  165. package/dist/editor/public/link.d.ts.map +1 -1
  166. package/dist/editor/public/link.js +70 -2
  167. package/dist/editor/public/link.js.map +1 -1
  168. package/dist/editor/public/placement.d.ts +60 -2
  169. package/dist/editor/public/placement.d.ts.map +1 -1
  170. package/dist/editor/public/placement.js +193 -2
  171. package/dist/editor/public/placement.js.map +1 -1
  172. package/dist/editor/public/selection-ops.d.ts +35 -1
  173. package/dist/editor/public/selection-ops.d.ts.map +1 -1
  174. package/dist/editor/public/selection-ops.js +97 -2
  175. package/dist/editor/public/selection-ops.js.map +1 -1
  176. package/dist/editor/public/stroke-eraser-coverage.d.ts +37 -0
  177. package/dist/editor/public/stroke-eraser-coverage.d.ts.map +1 -0
  178. package/dist/editor/public/stroke-eraser-coverage.js +168 -0
  179. package/dist/editor/public/stroke-eraser-coverage.js.map +1 -0
  180. package/dist/editor/public/stroke-eraser.d.ts +50 -0
  181. package/dist/editor/public/stroke-eraser.d.ts.map +1 -0
  182. package/dist/editor/public/stroke-eraser.js +176 -0
  183. package/dist/editor/public/stroke-eraser.js.map +1 -0
  184. package/dist/editor/public/stroke-smoothing.d.ts +21 -0
  185. package/dist/editor/public/stroke-smoothing.d.ts.map +1 -0
  186. package/dist/editor/public/stroke-smoothing.js +37 -0
  187. package/dist/editor/public/stroke-smoothing.js.map +1 -0
  188. package/dist/editor/public/text-edit.d.ts +1 -10
  189. package/dist/editor/public/text-edit.d.ts.map +1 -1
  190. package/dist/editor/public/text-edit.js +2 -16
  191. package/dist/editor/public/text-edit.js.map +1 -1
  192. package/dist/editor/public/tool-ops.d.ts +130 -0
  193. package/dist/editor/public/tool-ops.d.ts.map +1 -0
  194. package/dist/editor/public/tool-ops.js +392 -0
  195. package/dist/editor/public/tool-ops.js.map +1 -0
  196. package/dist/editor/public/z-order.d.ts +1 -12
  197. package/dist/editor/public/z-order.d.ts.map +1 -1
  198. package/dist/editor/public/z-order.js +5 -5
  199. package/dist/editor/public/z-order.js.map +1 -1
  200. package/dist/editor/public/zoom-pan.d.ts +15 -4
  201. package/dist/editor/public/zoom-pan.d.ts.map +1 -1
  202. package/dist/editor/public/zoom-pan.js +39 -7
  203. package/dist/editor/public/zoom-pan.js.map +1 -1
  204. package/dist/editor/render-orchestrator.d.ts +177 -5
  205. package/dist/editor/render-orchestrator.d.ts.map +1 -1
  206. package/dist/editor/render-orchestrator.js +519 -358
  207. package/dist/editor/render-orchestrator.js.map +1 -1
  208. package/dist/editor/resize-helpers.d.ts +21 -5
  209. package/dist/editor/resize-helpers.d.ts.map +1 -1
  210. package/dist/editor/resize-helpers.js +59 -19
  211. package/dist/editor/resize-helpers.js.map +1 -1
  212. package/dist/editor/text-edit.d.ts +136 -0
  213. package/dist/editor/text-edit.d.ts.map +1 -0
  214. package/dist/editor/text-edit.js +328 -0
  215. package/dist/editor/text-edit.js.map +1 -0
  216. package/dist/editor/viewport-helpers.d.ts.map +1 -1
  217. package/dist/editor/viewport-helpers.js +3 -3
  218. package/dist/editor/viewport-helpers.js.map +1 -1
  219. package/dist/editor-events.d.ts +1 -1
  220. package/dist/editor-events.d.ts.map +1 -1
  221. package/dist/editor.d.ts +603 -346
  222. package/dist/editor.d.ts.map +1 -1
  223. package/dist/editor.js +1843 -1630
  224. package/dist/editor.js.map +1 -1
  225. package/dist/file-drop.d.ts.map +1 -1
  226. package/dist/file-drop.js +1 -2
  227. package/dist/file-drop.js.map +1 -1
  228. package/dist/frame-helpers.d.ts.map +1 -1
  229. package/dist/frame-helpers.js +5 -5
  230. package/dist/frame-helpers.js.map +1 -1
  231. package/dist/group-helpers.d.ts.map +1 -1
  232. package/dist/group-helpers.js +4 -4
  233. package/dist/group-helpers.js.map +1 -1
  234. package/dist/handle.d.ts +59 -6
  235. package/dist/handle.d.ts.map +1 -1
  236. package/dist/handle.js +99 -7
  237. package/dist/handle.js.map +1 -1
  238. package/dist/hotkeys-binding.d.ts +26 -0
  239. package/dist/hotkeys-binding.d.ts.map +1 -0
  240. package/dist/hotkeys-binding.js +35 -0
  241. package/dist/hotkeys-binding.js.map +1 -0
  242. package/dist/index.d.ts +9 -3
  243. package/dist/index.d.ts.map +1 -1
  244. package/dist/index.js +10 -3
  245. package/dist/index.js.map +1 -1
  246. package/dist/link-selection.d.ts +3 -5
  247. package/dist/link-selection.d.ts.map +1 -1
  248. package/dist/link-selection.js +3 -12
  249. package/dist/link-selection.js.map +1 -1
  250. package/dist/machine.d.ts +27 -1
  251. package/dist/machine.d.ts.map +1 -1
  252. package/dist/machine.js +38 -0
  253. package/dist/machine.js.map +1 -1
  254. package/dist/modes.d.ts +15 -1
  255. package/dist/modes.d.ts.map +1 -1
  256. package/dist/modes.js.map +1 -1
  257. package/dist/overlay.d.ts +92 -6
  258. package/dist/overlay.d.ts.map +1 -1
  259. package/dist/overlay.js +582 -125
  260. package/dist/overlay.js.map +1 -1
  261. package/dist/search.d.ts +37 -0
  262. package/dist/search.d.ts.map +1 -0
  263. package/dist/search.js +45 -0
  264. package/dist/search.js.map +1 -0
  265. package/dist/selection.d.ts.map +1 -1
  266. package/dist/selection.js +2 -10
  267. package/dist/selection.js.map +1 -1
  268. package/dist/util.d.ts +8 -0
  269. package/dist/util.d.ts.map +1 -0
  270. package/dist/util.js +17 -0
  271. package/dist/util.js.map +1 -0
  272. package/package.json +7 -7
@@ -0,0 +1,146 @@
1
+ import { getElement } from "@oh-just-another/scene";
2
+ import { cursorForHandle } from "../../handle.js";
3
+ import { ANCHOR_DOT_ACTIVE_RADIUS, LINK_START_ANCHOR_OUTSET } from "../../constants.js";
4
+ import { anchorOverlayPoints } from "../anchor-points.js";
5
+ /** Resize handle → cursor override role. */
6
+ const RESIZE_ROLE = {
7
+ nw: "resize-nwse",
8
+ se: "resize-nwse",
9
+ ne: "resize-nesw",
10
+ sw: "resize-nesw",
11
+ n: "resize-ns",
12
+ s: "resize-ns",
13
+ e: "resize-ew",
14
+ w: "resize-ew",
15
+ };
16
+ /** Build a CSS `cursor` value from a {@link CursorSpec}. */
17
+ const cssCursor = (spec, fallbackKeyword) => {
18
+ if (typeof spec === "string")
19
+ return spec;
20
+ const hx = spec.hotspot?.x ?? 0;
21
+ const hy = spec.hotspot?.y ?? 0;
22
+ const img = spec.url2x !== undefined
23
+ ? `image-set(url("${spec.url}") 1x, url("${spec.url2x}") 2x)`
24
+ : `url("${spec.url}")`;
25
+ return `${img} ${String(hx)} ${String(hy)}, ${spec.fallback ?? fallbackKeyword}`;
26
+ };
27
+ /**
28
+ * Resolve a cursor role to a CSS `cursor` value: a host-registered custom image
29
+ * (via {@link Editor.setCursorOverride}) if present, else `fallbackKeyword`.
30
+ */
31
+ const resolveCursor = (editor, role, fallbackKeyword) => {
32
+ const spec = editor.getCursorOverride(role);
33
+ return spec === undefined ? fallbackKeyword : cssCursor(spec, fallbackKeyword);
34
+ };
35
+ /**
36
+ * True when `p` is within the grab radius of one of the single selected
37
+ * element's link-start dots — used to show a `crosshair` (start a link).
38
+ * Mirrors the anchor-drag hit-test in pointer-binding so the cursor matches
39
+ * exactly where a press would begin a link.
40
+ */
41
+ const isOverLinkStartDot = (editor, p) => {
42
+ if (editor.mode !== "select" || editor._selection.size !== 1)
43
+ return false;
44
+ const id = [...editor._selection][0];
45
+ if (id === undefined)
46
+ return false;
47
+ const shape = getElement(editor._scene, id);
48
+ if (!shape)
49
+ return false;
50
+ const zoom = editor._scene.viewport.zoom || 1;
51
+ const { worldPoints } = anchorOverlayPoints(shape, LINK_START_ANCHOR_OUTSET / zoom);
52
+ const grab = (ANCHOR_DOT_ACTIVE_RADIUS + editor.anchorStartHitSlop) / zoom;
53
+ const grab2 = grab * grab;
54
+ for (const wp of worldPoints) {
55
+ const dx = wp.x - p.x;
56
+ const dy = wp.y - p.y;
57
+ if (dx * dx + dy * dy <= grab2)
58
+ return true;
59
+ }
60
+ return false;
61
+ };
62
+ /**
63
+ * The CSS cursor for the current interaction state. Priority: active gesture →
64
+ * text edit → pan affordance → draw tool → idle hover hit-test. Pure read of
65
+ * editor state; no side effects.
66
+ */
67
+ export const computeCursor = (editor, p) => {
68
+ // Each outcome is a (role, fallback-keyword) pair; `resolveCursor` returns a
69
+ // host-registered custom image for that role if one exists, else the keyword.
70
+ const r = (role, keyword) => resolveCursor(editor, role, keyword);
71
+ const resizeRole = (h) => r(RESIZE_ROLE[h], cursorForHandle(h));
72
+ // 1. Active gestures (highest priority — what the pointer is doing now).
73
+ if (editor.panGesture)
74
+ return r("pan-active", "grabbing");
75
+ if (editor.linkDragFromAnchor?.moved === true)
76
+ return r("draw", "crosshair");
77
+ if (editor.isDraggingWaypoint || editor.isDraggingSegment)
78
+ return r("move", "grabbing");
79
+ if (editor.annotationDrag?.moved === true)
80
+ return r("move", "grabbing");
81
+ if (editor.brushStroke)
82
+ return r("draw", "crosshair");
83
+ // Machine-driven drag past the threshold (`gestureTx` opens then): resize
84
+ // shows the handle's arrow; element / link move shows grabbing.
85
+ if (editor.gestureTx) {
86
+ const t = editor.actor.getSnapshot().context.pressTarget;
87
+ if (t && (t.kind === "handle" || t.kind === "group-handle"))
88
+ return resizeRole(t.handle);
89
+ if (t?.kind === "rotate-handle")
90
+ return r("rotate", "grabbing");
91
+ if (t && (t.kind === "element" || t.kind === "link" || t.kind === "edge-endpoint")) {
92
+ return r("move", "grabbing");
93
+ }
94
+ }
95
+ // 1b. Armed colour-picker pipette → crosshair, waiting for the pick click.
96
+ if (editor.isEyedropperArmed)
97
+ return r("draw", "crosshair");
98
+ // 2. In-canvas text editing → I-beam.
99
+ if (editor.editingTextElement !== null)
100
+ return r("text", "text");
101
+ // 3. Pan affordance (idle): Space held or hand tool.
102
+ if (editor.spaceHeld || editor.mode === "hand")
103
+ return r("pan-ready", "grab");
104
+ // 4. Draw tools (idle, before a gesture starts).
105
+ switch (editor.mode) {
106
+ case "draw-rect":
107
+ case "draw-ellipse":
108
+ case "draw-frame":
109
+ case "draw-edge":
110
+ case "brush":
111
+ case "laser":
112
+ case "eyedropper":
113
+ case "crop":
114
+ return r("draw", "crosshair");
115
+ // Erase hides the OS cursor: the overlay paints a size-matched ring (and a
116
+ // fading trail while dragging) in its place, so `none` lets that composite
117
+ // cleanly at any radius.
118
+ case "erase":
119
+ return r("erase", "none");
120
+ case "draw-text":
121
+ return r("text", "text");
122
+ default:
123
+ break;
124
+ }
125
+ // 5. Idle hover in select mode — key off the hit-test target.
126
+ if (p) {
127
+ if (isOverLinkStartDot(editor, p))
128
+ return r("link-start", "crosshair");
129
+ const t = editor.hitTest(p);
130
+ switch (t.kind) {
131
+ case "handle":
132
+ case "group-handle":
133
+ return resizeRole(t.handle);
134
+ case "rotate-handle":
135
+ return r("rotate", "grab");
136
+ case "edge-endpoint":
137
+ return r("link-handle", "grab");
138
+ case "annotation":
139
+ return r("annotation", "pointer");
140
+ default:
141
+ return r("default", "default");
142
+ }
143
+ }
144
+ return r("default", "default");
145
+ };
146
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../src/editor/public/cursor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { Element, Scene, Patch } from "@oh-just-another/scene";
2
+ import type { ElementId, Vec2 } from "@oh-just-another/types";
3
+ import type { Interval } from "./stroke-eraser-coverage.js";
4
+ /**
5
+ * Mutable state of an in-progress eraser stroke. The editor owns one instance
6
+ * and delegates the four lifecycle calls (begin / extend / commit / cancel)
7
+ * through it. `pending` is the set of element ids swept so far (previewed
8
+ * dimmed, deleted on release); `last` is the previous sampled world point so
9
+ * the next extend can sample the segment between them.
10
+ *
11
+ * `strokeMode` (Shift held at press) switches the gesture to STROKE-ERASE:
12
+ * brush strokes are cut into fragments instead of deleted whole; non-brush
13
+ * shapes still object-erase. `erased` maps each touched brush id to the covered
14
+ * arc-length spans erased so far — the editor grows it INCREMENTALLY (each move
15
+ * accumulates only the new segment via `markErasedIntervals`), so the cost per
16
+ * move is O(points) instead of O(points × path length) per frame. The eraser cuts
17
+ * the stroke's GEOMETRY by arc length, not by vertex, so a big disc grazing a
18
+ * sparse line still removes the covered span. Unused in object mode.
19
+ */
20
+ export interface EraseStrokeState {
21
+ readonly pending: Set<ElementId>;
22
+ last: Vec2;
23
+ /** Per-brush covered arc-length spans, grown incrementally in stroke mode. */
24
+ readonly erased: Map<ElementId, Interval[]>;
25
+ /** Shift held at press: cut brush strokes instead of deleting them. */
26
+ readonly strokeMode: boolean;
27
+ }
28
+ export declare const beginEraseStroke: (world: Vec2, strokeMode?: boolean) => EraseStrokeState;
29
+ /**
30
+ * Sample points along the segment `from → to` at {@link ERASER_SAMPLE_STEP}
31
+ * spacing, hit-test each through `hitAt`, and mark every hit element in
32
+ * `pending`. Sampling (rather than testing only the endpoint) stops a fast
33
+ * swipe from skipping small shapes between two pointer-move events.
34
+ *
35
+ * `restore` flips the direction: normally hits are ADDED to `pending`
36
+ * (marked-for-erase); with `restore` (Alt held) a hit already in `pending` is
37
+ * REMOVED (un-marked), so dragging back over a marked shape with Alt rescues it
38
+ * — matching the Excalidraw eraser. Returns `true` when `pending` changed (so
39
+ * the caller can skip a redundant re-render). Mutates `pending` in place.
40
+ *
41
+ * In `strokeMode` (Shift), brush hits are skipped here — brushes are cut by the
42
+ * path-based stroke-erase on commit, not added to the object-delete `pending`.
43
+ */
44
+ export declare const sampleErase: (from: Vec2, to: Vec2, hitAt: (p: Vec2) => Element | undefined, pending: Set<ElementId>, restore?: boolean, strokeMode?: boolean) => boolean;
45
+ /**
46
+ * Produce the scene + patches that delete every id in `pending` (dropping any
47
+ * attached links first, exactly like a Delete-key delete). Returns `null` when
48
+ * nothing valid remains to erase. Reuses {@link computeDeleteSelection} so the
49
+ * eraser and the selection-delete share one implementation.
50
+ */
51
+ export declare const computeEraseCommit: (scene: Scene, pending: ReadonlySet<ElementId>) => {
52
+ readonly scene: Scene;
53
+ readonly patches: Patch[];
54
+ } | null;
55
+ //# sourceMappingURL=eraser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eraser.d.ts","sourceRoot":"","sources":["../../../src/editor/public/eraser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAI9D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAE5D;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC;IACjC,IAAI,EAAE,IAAI,CAAC;IACX,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5C,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;CAC9B;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,IAAI,EAAE,oBAAkB,KAAG,gBAKjE,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,IAAI,EACV,IAAI,IAAI,EACR,OAAO,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,GAAG,SAAS,EACvC,SAAS,GAAG,CAAC,SAAS,CAAC,EACvB,iBAAe,EACf,oBAAkB,KACjB,OAmBF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,SAAS,WAAW,CAAC,SAAS,CAAC,KAC9B;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;CAAE,GAAG,IAOzD,CAAC"}
@@ -0,0 +1,65 @@
1
+ import * as Selection from "../../selection.js";
2
+ import { computeDeleteSelection } from "./selection-ops.js";
3
+ import { ERASER_SAMPLE_STEP } from "../../constants.js";
4
+ export const beginEraseStroke = (world, strokeMode = false) => ({
5
+ pending: new Set(),
6
+ last: world,
7
+ erased: new Map(),
8
+ strokeMode,
9
+ });
10
+ /**
11
+ * Sample points along the segment `from → to` at {@link ERASER_SAMPLE_STEP}
12
+ * spacing, hit-test each through `hitAt`, and mark every hit element in
13
+ * `pending`. Sampling (rather than testing only the endpoint) stops a fast
14
+ * swipe from skipping small shapes between two pointer-move events.
15
+ *
16
+ * `restore` flips the direction: normally hits are ADDED to `pending`
17
+ * (marked-for-erase); with `restore` (Alt held) a hit already in `pending` is
18
+ * REMOVED (un-marked), so dragging back over a marked shape with Alt rescues it
19
+ * — matching the Excalidraw eraser. Returns `true` when `pending` changed (so
20
+ * the caller can skip a redundant re-render). Mutates `pending` in place.
21
+ *
22
+ * In `strokeMode` (Shift), brush hits are skipped here — brushes are cut by the
23
+ * path-based stroke-erase on commit, not added to the object-delete `pending`.
24
+ */
25
+ export const sampleErase = (from, to, hitAt, pending, restore = false, strokeMode = false) => {
26
+ const dx = to.x - from.x;
27
+ const dy = to.y - from.y;
28
+ const dist = Math.hypot(dx, dy);
29
+ const steps = Math.max(1, Math.ceil(dist / ERASER_SAMPLE_STEP));
30
+ let changed = false;
31
+ for (let i = 1; i <= steps; i++) {
32
+ const t = i / steps;
33
+ const hit = hitAt({ x: from.x + dx * t, y: from.y + dy * t });
34
+ if (!hit)
35
+ continue;
36
+ if (strokeMode && hit.type === "brush")
37
+ continue;
38
+ if (restore) {
39
+ if (pending.delete(hit.id))
40
+ changed = true;
41
+ }
42
+ else if (!pending.has(hit.id)) {
43
+ pending.add(hit.id);
44
+ changed = true;
45
+ }
46
+ }
47
+ return changed;
48
+ };
49
+ /**
50
+ * Produce the scene + patches that delete every id in `pending` (dropping any
51
+ * attached links first, exactly like a Delete-key delete). Returns `null` when
52
+ * nothing valid remains to erase. Reuses {@link computeDeleteSelection} so the
53
+ * eraser and the selection-delete share one implementation.
54
+ */
55
+ export const computeEraseCommit = (scene, pending) => {
56
+ let sel = Selection.EMPTY;
57
+ for (const id of pending) {
58
+ if (scene.elements.has(id))
59
+ sel = Selection.add(sel, id);
60
+ }
61
+ if (sel.size === 0)
62
+ return null;
63
+ return computeDeleteSelection(scene, sel, new Set());
64
+ };
65
+ //# sourceMappingURL=eraser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eraser.js","sourceRoot":"","sources":["../../../src/editor/public/eraser.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AA4BxD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAW,EAAE,UAAU,GAAG,KAAK,EAAoB,EAAE,CAAC,CAAC;IACtF,OAAO,EAAE,IAAI,GAAG,EAAa;IAC7B,IAAI,EAAE,KAAK;IACX,MAAM,EAAE,IAAI,GAAG,EAAyB;IACxC,UAAU;CACX,CAAC,CAAC;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,IAAU,EACV,EAAQ,EACR,KAAuC,EACvC,OAAuB,EACvB,OAAO,GAAG,KAAK,EACf,UAAU,GAAG,KAAK,EACT,EAAE;IACX,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACzB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC,CAAC,CAAC;IAChE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAChC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACpB,MAAM,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,IAAI,UAAU,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO;YAAE,SAAS;QACjD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,OAAO,GAAG,IAAI,CAAC;QAC7C,CAAC;aAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACpB,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAY,EACZ,OAA+B,EAC8B,EAAE;IAC/D,IAAI,GAAG,GAAwB,SAAS,CAAC,KAAK,CAAC;IAC/C,KAAK,MAAM,EAAE,IAAI,OAAO,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAChC,OAAO,sBAAsB,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;AACvD,CAAC,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type Scene, type Patch } from "@oh-just-another/scene";
2
+ import type { ElementId, Vec2 } from "@oh-just-another/types";
3
+ /**
4
+ * Frame whose header strip (the label bar ABOVE the body) contains the world
5
+ * point — top-most by z-order. Used to route a double-click on the header to a
6
+ * name edit, since the header sits outside the frame's hit-test bounds. Assumes
7
+ * unrotated frames (the common case).
8
+ */
9
+ export declare const frameHeaderAt: (scene: Scene, p: Vec2) => ElementId | null;
10
+ /**
11
+ * Compute the patch committing an edited frame name. Empty / whitespace-only
12
+ * clears the stored name (the renderer falls back to "Frame"). Returns `null`
13
+ * when the shape isn't a frame or the name is unchanged — the caller still
14
+ * clears the editing state and notifies.
15
+ */
16
+ export declare const computeFrameNameCommit: (scene: Scene, id: ElementId, name: string) => {
17
+ readonly scene: Scene;
18
+ readonly patch: Patch;
19
+ } | null;
20
+ //# sourceMappingURL=frame-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-name.d.ts","sourceRoot":"","sources":["../../../src/editor/public/frame-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,KAAK,EACV,KAAK,KAAK,EACX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,EAAE,GAAG,IAAI,KAAG,SAAS,GAAG,IAmBjE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,GACjC,OAAO,KAAK,EACZ,IAAI,SAAS,EACb,MAAM,MAAM,KACX;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAcrD,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { getElement, updateElement, isFrame, FRAME_HEADER_HEIGHT, } from "@oh-just-another/scene";
2
+ /**
3
+ * Frame whose header strip (the label bar ABOVE the body) contains the world
4
+ * point — top-most by z-order. Used to route a double-click on the header to a
5
+ * name edit, since the header sits outside the frame's hit-test bounds. Assumes
6
+ * unrotated frames (the common case).
7
+ */
8
+ export const frameHeaderAt = (scene, p) => {
9
+ let bestId = null;
10
+ let bestOrder = "";
11
+ for (const s of scene.elements.values()) {
12
+ if (!isFrame(s))
13
+ continue;
14
+ const hx = s.position.x;
15
+ // The header strip can extend up to the frame's full width (it hugs the
16
+ // label but is capped there), so the rename hit zone spans it.
17
+ const hw = s.width * s.scale.x;
18
+ const hh = FRAME_HEADER_HEIGHT * s.scale.y;
19
+ const hyTop = s.position.y - hh;
20
+ if (p.x >= hx && p.x <= hx + hw && p.y >= hyTop && p.y <= hyTop + hh) {
21
+ if (bestId === null || s.order > bestOrder) {
22
+ bestId = s.id;
23
+ bestOrder = s.order;
24
+ }
25
+ }
26
+ }
27
+ return bestId;
28
+ };
29
+ /**
30
+ * Compute the patch committing an edited frame name. Empty / whitespace-only
31
+ * clears the stored name (the renderer falls back to "Frame"). Returns `null`
32
+ * when the shape isn't a frame or the name is unchanged — the caller still
33
+ * clears the editing state and notifies.
34
+ */
35
+ export const computeFrameNameCommit = (scene, id, name) => {
36
+ const shape = getElement(scene, id);
37
+ if (shape === undefined || !isFrame(shape))
38
+ return null;
39
+ const trimmed = name.trim();
40
+ const current = shape.name ?? "";
41
+ if (trimmed === current)
42
+ return null;
43
+ const r = updateElement(scene, id, (s) => {
44
+ const copy = { ...s };
45
+ // `exactOptionalPropertyTypes`: drop the key when cleared.
46
+ if (trimmed === "")
47
+ delete copy.name;
48
+ else
49
+ copy.name = trimmed;
50
+ return copy;
51
+ });
52
+ return { scene: r.scene, patch: r.patch };
53
+ };
54
+ //# sourceMappingURL=frame-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-name.js","sourceRoot":"","sources":["../../../src/editor/public/frame-name.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,aAAa,EACb,OAAO,EACP,mBAAmB,GAGpB,MAAM,wBAAwB,CAAC;AAGhC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,KAAY,EAAE,CAAO,EAAoB,EAAE;IACvE,IAAI,MAAM,GAAqB,IAAI,CAAC;IACpC,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,SAAS;QAC1B,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;QACxB,wEAAwE;QACxE,+DAA+D;QAC/D,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,MAAM,EAAE,GAAG,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;YACrE,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,CAAC,KAAK,GAAG,SAAS,EAAE,CAAC;gBAC3C,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC;gBACd,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,CACpC,KAAY,EACZ,EAAa,EACb,IAAY,EAC6C,EAAE;IAC3D,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAI,KAA2B,CAAC,IAAI,IAAI,EAAE,CAAC;IACxD,IAAI,OAAO,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,CAAC,GAAG,aAAa,CAAC,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE;QACvC,MAAM,IAAI,GAAG,EAAE,GAAG,CAAC,EAAkC,CAAC;QACtD,2DAA2D;QAC3D,IAAI,OAAO,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC;;YAChC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;AAC5C,CAAC,CAAC"}
@@ -9,7 +9,7 @@ export declare const buildImageElement: (scene: Scene, input: {
9
9
  width: number;
10
10
  height: number;
11
11
  position: Vec2;
12
- image?: HTMLImageElement;
12
+ image?: ImageBitmap | HTMLImageElement;
13
13
  animated?: boolean;
14
14
  fileId?: FileId;
15
15
  animationKind?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"image-insert.d.ts","sourceRoot":"","sources":["../../../src/editor/public/image-insert.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,KAAK,EAEX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAG/E;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,KAAK,EACZ,OAAO;IACL,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,EACD,IAAI,SAAS,EACb,SAAS,OAAO,KACf,OA0BF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,KAAK,EACZ,MAAM,IAAI,EACV,MAAM,MAAM,GAAG,SAAS,EACxB,YAAY,MAAM,MAAM,KACvB,OAAO,CAAC;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAS/E,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,GAAI,OAAO,KAAK,KAAG,OAKjD,CAAC"}
1
+ {"version":3,"file":"image-insert.d.ts","sourceRoot":"","sources":["../../../src/editor/public/image-insert.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,KAAK,EACV,KAAK,OAAO,EACZ,KAAK,KAAK,EAEX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAG/E;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,KAAK,EACZ,OAAO;IACL,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;IACf,KAAK,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAAC;IACvC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB,EACD,IAAI,SAAS,EACb,SAAS,OAAO,KACf,OA0BF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,KAAK,EACZ,MAAM,IAAI,EACV,MAAM,MAAM,GAAG,SAAS,EACxB,YAAY,MAAM,MAAM,KACvB,OAAO,CAAC;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAS/E,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,GAAI,OAAO,KAAK,KAAG,OAKjD,CAAC"}
@@ -0,0 +1,38 @@
1
+ import type { Vec2 } from "@oh-just-another/types";
2
+ /** One point of a laser trail — world position plus the time it was laid down. */
3
+ export interface LaserPoint {
4
+ readonly x: number;
5
+ readonly y: number;
6
+ /** Birth timestamp (ms, `performance.now()` domain) — drives the fade. */
7
+ readonly t: number;
8
+ }
9
+ /**
10
+ * A single laser stroke: an ordered list of timestamped world points. Purely
11
+ * ephemeral — never enters the scene or history. The overlay ramps each point's
12
+ * opacity from 1 → 0 over {@link LASER_TRAIL_TTL_MS}; the editor prunes points
13
+ * past that age so the trail vanishes shortly after the pointer stops.
14
+ */
15
+ export interface LaserStroke {
16
+ readonly points: LaserPoint[];
17
+ }
18
+ export declare const beginLaserStroke: (world: Vec2, now: number) => LaserStroke;
19
+ export declare const extendLaserStroke: (stroke: LaserStroke, world: Vec2, now: number) => void;
20
+ /**
21
+ * Drop every point older than `ttl` (and any stroke left empty). Returns the
22
+ * surviving strokes plus a `changed` flag; when nothing expired the SAME array
23
+ * reference is returned so the render-overlay memo can skip a rebuild. The
24
+ * returned array is fresh only when a prune actually happened.
25
+ */
26
+ export declare const pruneLaserStrokes: (strokes: readonly LaserStroke[], now: number, ttl?: number) => {
27
+ readonly strokes: LaserStroke[];
28
+ readonly changed: boolean;
29
+ };
30
+ /**
31
+ * Resample a laser trail into a smooth, dense point list for rendering (via the
32
+ * shared {@link smoothStrokePoints} spline resampler). Each resampled point
33
+ * carries a birth timestamp linearly interpolated between its span endpoints, so
34
+ * the overlay's per-segment TTL fade still melts the trail tail-first exactly as
35
+ * it does for the raw points.
36
+ */
37
+ export declare const smoothLaserPoints: (points: readonly LaserPoint[], perSegment?: number) => LaserPoint[];
38
+ //# sourceMappingURL=laser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laser.d.ts","sourceRoot":"","sources":["../../../src/editor/public/laser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAInD,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;CAC/B;AAED,eAAO,MAAM,gBAAgB,GAAI,OAAO,IAAI,EAAE,KAAK,MAAM,KAAG,WAE1D,CAAC;AAEH,eAAO,MAAM,iBAAiB,GAAI,QAAQ,WAAW,EAAE,OAAO,IAAI,EAAE,KAAK,MAAM,KAAG,IAEjF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,GAC5B,SAAS,SAAS,WAAW,EAAE,EAC/B,KAAK,MAAM,EACX,MAAK,MAA2B,KAC/B;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,EAAE,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAa9D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,UAAU,EAAE,EAC7B,aAAY,MAA8B,KACzC,UAAU,EAKR,CAAC"}
@@ -0,0 +1,42 @@
1
+ import { LASER_SMOOTH_SEGMENTS, LASER_TRAIL_TTL_MS } from "../../constants.js";
2
+ import { smoothStrokePoints } from "./stroke-smoothing.js";
3
+ export const beginLaserStroke = (world, now) => ({
4
+ points: [{ x: world.x, y: world.y, t: now }],
5
+ });
6
+ export const extendLaserStroke = (stroke, world, now) => {
7
+ stroke.points.push({ x: world.x, y: world.y, t: now });
8
+ };
9
+ /**
10
+ * Drop every point older than `ttl` (and any stroke left empty). Returns the
11
+ * surviving strokes plus a `changed` flag; when nothing expired the SAME array
12
+ * reference is returned so the render-overlay memo can skip a rebuild. The
13
+ * returned array is fresh only when a prune actually happened.
14
+ */
15
+ export const pruneLaserStrokes = (strokes, now, ttl = LASER_TRAIL_TTL_MS) => {
16
+ let changed = false;
17
+ const next = [];
18
+ for (const stroke of strokes) {
19
+ const kept = stroke.points.filter((p) => now - p.t < ttl);
20
+ if (kept.length === stroke.points.length) {
21
+ next.push(stroke);
22
+ continue;
23
+ }
24
+ changed = true;
25
+ if (kept.length > 0)
26
+ next.push({ points: kept });
27
+ }
28
+ return changed ? { strokes: next, changed } : { strokes: strokes, changed };
29
+ };
30
+ /**
31
+ * Resample a laser trail into a smooth, dense point list for rendering (via the
32
+ * shared {@link smoothStrokePoints} spline resampler). Each resampled point
33
+ * carries a birth timestamp linearly interpolated between its span endpoints, so
34
+ * the overlay's per-segment TTL fade still melts the trail tail-first exactly as
35
+ * it does for the raw points.
36
+ */
37
+ export const smoothLaserPoints = (points, perSegment = LASER_SMOOTH_SEGMENTS) => smoothStrokePoints(points, perSegment, (a, b, pos, u) => ({
38
+ x: pos.x,
39
+ y: pos.y,
40
+ t: a.t + (b.t - a.t) * u,
41
+ }));
42
+ //# sourceMappingURL=laser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"laser.js","sourceRoot":"","sources":["../../../src/editor/public/laser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAoB3D,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAW,EAAE,GAAW,EAAe,EAAE,CAAC,CAAC;IAC1E,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC;CAC7C,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAmB,EAAE,KAAW,EAAE,GAAW,EAAQ,EAAE;IACvF,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;AACzD,CAAC,CAAC;AAEF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,OAA+B,EAC/B,GAAW,EACX,MAAc,kBAAkB,EACgC,EAAE;IAClE,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,IAAI,GAAkB,EAAE,CAAC;IAC/B,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;QAC1D,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACzC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,IAAI,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAwB,EAAE,OAAO,EAAE,CAAC;AAC/F,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAA6B,EAC7B,aAAqB,qBAAqB,EAC5B,EAAE,CAChB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,CAAC,EAAE,GAAG,CAAC,CAAC;IACR,CAAC,EAAE,GAAG,CAAC,CAAC;IACR,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;CACzB,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../../src/editor/public/layers.ts"],"names":[],"mappings":"AAAA,OAAO,EAUL,KAAK,KAAK,EACV,KAAK,KAAK,EACX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,KAAK,SAAS,MAAM,oBAAoB,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,MAAM,MAAM,EACZ,YAAY,OAAO,KAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAK3E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,IAAI,OAAO,EACX,eAAe,OAAO,KACrB;IACD,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,GAAG,IA+BH,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,IAAI,OAAO,EACX,MAAM,MAAM,KACX;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAKrD,CAAC;AAEF,+BAA+B;AAC/B,eAAO,MAAM,4BAA4B,GACvC,OAAO,KAAK,EACZ,IAAI,OAAO,KACV;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAIrD,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,sBAAsB,GACjC,OAAO,KAAK,EACZ,IAAI,OAAO,KACV;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAIrD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACtC,OAAO,KAAK,EACZ,WAAW,SAAS,CAAC,SAAS,EAC9B,aAAa,OAAO,KACnB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;CAAE,GAAG,IAazD,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,OACe,CAAC"}
1
+ {"version":3,"file":"layers.d.ts","sourceRoot":"","sources":["../../../src/editor/public/layers.ts"],"names":[],"mappings":"AAAA,OAAO,EAWL,KAAK,KAAK,EACV,KAAK,KAAK,EACX,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAEtD,OAAO,KAAK,KAAK,SAAS,MAAM,oBAAoB,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,MAAM,MAAM,EACZ,YAAY,OAAO,KAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;CAK3E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,IAAI,OAAO,EACX,eAAe,OAAO,KACrB;IACD,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,iBAAiB,EAAE,OAAO,CAAC;CAC5B,GAAG,IA6BH,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,GAC7B,OAAO,KAAK,EACZ,IAAI,OAAO,EACX,MAAM,MAAM,KACX;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAKrD,CAAC;AAEF,+BAA+B;AAC/B,eAAO,MAAM,4BAA4B,GACvC,OAAO,KAAK,EACZ,IAAI,OAAO,KACV;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAIrD,CAAC;AAEF,8BAA8B;AAC9B,eAAO,MAAM,sBAAsB,GACjC,OAAO,KAAK,EACZ,IAAI,OAAO,KACV;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAIrD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,GACtC,OAAO,KAAK,EACZ,WAAW,SAAS,CAAC,SAAS,EAC9B,aAAa,OAAO,KACnB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,CAAA;CAAE,GAAG,IAazD,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,UAAU,GAAI,MAAM,MAAM,KAAG,OACe,CAAC"}
@@ -1,4 +1,4 @@
1
- import { addLayer, getElement, orderForTop, removeLink, removeLayer, removeElement, updateLayer, updateElement, } from "@oh-just-another/scene";
1
+ import { addLayer, byOrderDesc, getElement, orderForTop, removeLink, removeLayer, removeElement, updateLayer, updateElement, } from "@oh-just-another/scene";
2
2
  import { layerId as castLayerId } from "@oh-just-another/types";
3
3
  /**
4
4
  * Build a fresh top-of-stack layer + the patch that adds it. Caller
@@ -46,7 +46,7 @@ export const computeRemoveLayer = (scene, id, currentActive) => {
46
46
  patches.push(r.patch);
47
47
  let nextActive = currentActive;
48
48
  if (currentActive === id) {
49
- const top = [...s.layers.values()].sort((a, b) => a.order > b.order ? -1 : a.order < b.order ? 1 : 0)[0];
49
+ const top = [...s.layers.values()].sort(byOrderDesc)[0];
50
50
  if (top)
51
51
  nextActive = top.id;
52
52
  }
@@ -1 +1 @@
1
- {"version":3,"file":"layers.js","sourceRoot":"","sources":["../../../src/editor/public/layers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"layers.js","sourceRoot":"","sources":["../../../src/editor/public/layers.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { type Scene, type Patch } from "@oh-just-another/scene";
2
- import type { ElementId } from "@oh-just-another/types";
1
+ import { type Scene, type Patch, type SnapEngine, type LinkEndpoint } from "@oh-just-another/scene";
2
+ import type { ElementId, Vec2 } from "@oh-just-another/types";
3
3
  /**
4
4
  * Normalise user-entered link text into a safe, storable href, or
5
5
  * `null` to clear / reject. Adds `https://` to a scheme-less URL,
@@ -22,4 +22,13 @@ export declare const computeSetLink: (scene: Scene, ids: Iterable<ElementId>, hr
22
22
  readonly scene: Scene;
23
23
  readonly patch: Patch;
24
24
  } | null;
25
+ /**
26
+ * Resolve where a link endpoint should attach when dropped at `worldPoint`.
27
+ * Attach contract: a port dot → *fixed* anchor; near an EDGE (not a dot) →
28
+ * *fixed* outline point (a perimeter ratio — survives move/resize); the body
29
+ * interior → *floating* against the whole shape (re-aims as shapes move); empty
30
+ * canvas → a free point. `pressTargetElement` biases the pick toward the pressed
31
+ * shape, but a dot drawn outside the body still binds even when it's null.
32
+ */
33
+ export declare const snapLinkEndpoint: (scene: Scene, snapEngine: SnapEngine, threshold: number, pressTargetElement: ElementId | null, worldPoint: Vec2) => LinkEndpoint;
25
34
  //# sourceMappingURL=link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/editor/public/link.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAUxD;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAQtD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,MAAM,GAAG,IAGnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,KAAK,EACZ,KAAK,QAAQ,CAAC,SAAS,CAAC,EACxB,MAAM,MAAM,GAAG,IAAI,KAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAyBrD,CAAC"}
1
+ {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../src/editor/public/link.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,KAAK,EACV,KAAK,KAAK,EACV,KAAK,UAAU,EAEf,KAAK,YAAY,EAGlB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAa9D;;;;GAIG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAQtD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,MAAM,GAAG,SAAS,GAAG,IAAI,KAAG,MAAM,GAAG,IAGnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GACzB,OAAO,KAAK,EACZ,KAAK,QAAQ,CAAC,SAAS,CAAC,EACxB,MAAM,MAAM,GAAG,IAAI,KAClB;IAAE,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAA;CAAE,GAAG,IAyBrD,CAAC;AAwBF;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,GAC3B,OAAO,KAAK,EACZ,YAAY,UAAU,EACtB,WAAW,MAAM,EACjB,oBAAoB,SAAS,GAAG,IAAI,EACpC,YAAY,IAAI,KACf,YAyCF,CAAC"}