@neta-art/cohub 9.0.1 → 10.0.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 (178) hide show
  1. package/README.md +100 -103
  2. package/dist/board/editor/align.d.ts +11 -0
  3. package/dist/board/editor/align.js +72 -0
  4. package/dist/board/editor/animation.d.ts +14 -0
  5. package/dist/board/editor/animation.js +172 -0
  6. package/dist/board/editor/camera.d.ts +32 -0
  7. package/dist/board/editor/camera.js +137 -0
  8. package/dist/board/editor/clipboard.d.ts +41 -0
  9. package/dist/board/editor/clipboard.js +122 -0
  10. package/dist/board/editor/connection-ports.d.ts +19 -0
  11. package/dist/board/editor/connection-ports.js +85 -0
  12. package/dist/board/editor/context.d.ts +111 -0
  13. package/dist/board/editor/context.js +30 -0
  14. package/dist/board/editor/copy.d.ts +17 -0
  15. package/dist/board/editor/copy.js +116 -0
  16. package/dist/board/editor/creation.d.ts +47 -0
  17. package/dist/board/editor/creation.js +224 -0
  18. package/dist/board/editor/deletion.d.ts +9 -0
  19. package/dist/board/editor/deletion.js +90 -0
  20. package/dist/board/editor/document-edits.d.ts +22 -0
  21. package/dist/board/editor/document-edits.js +193 -0
  22. package/dist/board/editor/document.d.ts +35 -0
  23. package/dist/board/editor/document.js +255 -0
  24. package/dist/board/editor/editor.d.ts +210 -0
  25. package/dist/board/editor/editor.js +429 -0
  26. package/dist/board/editor/index.d.ts +18 -0
  27. package/dist/board/editor/index.js +12 -0
  28. package/dist/board/editor/interaction.d.ts +115 -0
  29. package/dist/board/editor/interaction.js +584 -0
  30. package/dist/board/editor/query.d.ts +27 -0
  31. package/dist/board/editor/query.js +201 -0
  32. package/dist/board/editor/remote.d.ts +11 -0
  33. package/dist/board/editor/remote.js +55 -0
  34. package/dist/board/editor/selection-transform.d.ts +24 -0
  35. package/dist/board/editor/selection-transform.js +81 -0
  36. package/dist/board/editor/selection.d.ts +33 -0
  37. package/dist/board/editor/selection.js +196 -0
  38. package/dist/board/editor/snapping.d.ts +33 -0
  39. package/dist/board/editor/snapping.js +75 -0
  40. package/dist/board/editor/snapshots.d.ts +27 -0
  41. package/dist/board/editor/snapshots.js +132 -0
  42. package/dist/board/editor/spatial.d.ts +41 -0
  43. package/dist/board/editor/spatial.js +191 -0
  44. package/dist/board/editor/state.d.ts +12 -0
  45. package/dist/board/editor/state.js +49 -0
  46. package/dist/board/editor/tool.d.ts +10 -0
  47. package/dist/board/editor/tool.js +19 -0
  48. package/dist/board/editor/wheel.d.ts +5 -0
  49. package/dist/board/editor/wheel.js +17 -0
  50. package/dist/board/export/index.d.ts +5 -4
  51. package/dist/board/export/index.js +4 -3
  52. package/dist/board/export/node/index.d.ts +55 -0
  53. package/dist/board/{headless → export/node}/index.js +12 -12
  54. package/dist/board/export/node/sketch.d.ts +19 -0
  55. package/dist/board/{headless → export/node}/sketch.js +6 -6
  56. package/dist/board/export/scene.d.ts +6 -4
  57. package/dist/board/export/scene.js +4 -3
  58. package/dist/board/{animation.d.ts → model/animation.d.ts} +4 -4
  59. package/dist/board/{animation.js → model/animation.js} +3 -3
  60. package/dist/board/{core → model}/arrow-geometry.d.ts +2 -2
  61. package/dist/board/{core → model}/arrow-geometry.js +2 -2
  62. package/dist/board/{core → model}/draw-geometry.d.ts +2 -2
  63. package/dist/board/{core → model}/draw-geometry.js +1 -1
  64. package/dist/board/model/draw-input.d.ts +14 -0
  65. package/dist/board/model/draw-input.js +28 -0
  66. package/dist/board/{core → model}/export-assets.d.ts +1 -1
  67. package/dist/board/{core → model}/export-assets.js +1 -1
  68. package/dist/board/{core → model}/export-plan.d.ts +2 -2
  69. package/dist/board/{core → model}/export-plan.js +2 -2
  70. package/dist/board/{core → model}/file-preview.d.ts +1 -1
  71. package/dist/board/{core → model}/file-preview.js +1 -1
  72. package/dist/board/{core → model}/file-snapshot.d.ts +1 -1
  73. package/dist/board/{core → model}/file-snapshot.js +1 -1
  74. package/dist/board/{geometry.d.ts → model/geometry.d.ts} +3 -3
  75. package/dist/board/{geometry.js → model/geometry.js} +1 -1
  76. package/dist/board/{image-key.d.ts → model/image-key.d.ts} +2 -2
  77. package/dist/board/{image-key.js → model/image-key.js} +1 -1
  78. package/dist/board/model/index.d.ts +35 -0
  79. package/dist/board/{index.js → model/index.js} +26 -22
  80. package/dist/board/model/items/builtin.d.ts +5 -0
  81. package/dist/board/model/items/builtin.js +119 -0
  82. package/dist/board/model/items/create.d.ts +59 -0
  83. package/dist/board/model/items/create.js +271 -0
  84. package/dist/board/model/items/definition.d.ts +35 -0
  85. package/dist/board/model/items/definition.js +18 -0
  86. package/dist/board/model/items/id.d.ts +5 -0
  87. package/dist/board/model/items/id.js +11 -0
  88. package/dist/board/model/items/index.d.ts +6 -0
  89. package/dist/board/model/items/index.js +6 -0
  90. package/dist/board/model/items/registry.d.ts +35 -0
  91. package/dist/board/model/items/registry.js +84 -0
  92. package/dist/board/{media-playback.d.ts → model/media-playback.d.ts} +2 -2
  93. package/dist/board/{media-playback.js → model/media-playback.js} +1 -1
  94. package/dist/board/{media.d.ts → model/media.d.ts} +1 -1
  95. package/dist/board/{media.js → model/media.js} +1 -1
  96. package/dist/board/{core → model}/palette.d.ts +1 -1
  97. package/dist/board/{core → model}/palette.js +1 -1
  98. package/dist/board/{presets.d.ts → model/presets.d.ts} +3 -3
  99. package/dist/board/{presets.js → model/presets.js} +1 -1
  100. package/dist/board/{replay.d.ts → model/replay.d.ts} +5 -5
  101. package/dist/board/{replay.js → model/replay.js} +2 -2
  102. package/dist/board/{core → model}/scene.d.ts +1 -1
  103. package/dist/board/{core → model}/scene.js +1 -1
  104. package/dist/board/model/shape-types.d.ts +8 -0
  105. package/dist/board/model/shape-types.js +8 -0
  106. package/dist/board/{task.d.ts → model/task.d.ts} +4 -4
  107. package/dist/board/{task.js → model/task.js} +3 -3
  108. package/dist/board/{core → model}/text-metrics.d.ts +1 -1
  109. package/dist/board/{core → model}/text-metrics.js +1 -1
  110. package/dist/board/{core → model}/tool-styles.d.ts +1 -1
  111. package/dist/board/{core → model}/tool-styles.js +1 -1
  112. package/dist/board/{runtime/board-player.d.ts → player/index.d.ts} +2 -2
  113. package/dist/board/{runtime/board-player.js → player/index.js} +5 -4
  114. package/dist/board/render/board-background.d.ts +1 -1
  115. package/dist/board/render/clip.d.ts +1 -1
  116. package/dist/board/render/index.d.ts +2 -2
  117. package/dist/board/render/index.js +2 -2
  118. package/dist/board/render/media-interaction.d.ts +2 -2
  119. package/dist/board/render/media-interaction.js +1 -1
  120. package/dist/board/render/palette.d.ts +1 -1
  121. package/dist/board/render/palette.js +1 -1
  122. package/dist/board/render/renderers/arrow-card-renderer.js +1 -1
  123. package/dist/board/render/renderers/board-renderer-registry.d.ts +11 -6
  124. package/dist/board/render/renderers/board-renderer-registry.js +15 -15
  125. package/dist/board/render/renderers/draw-card-renderer.js +1 -1
  126. package/dist/board/render/renderers/far-plate.js +1 -1
  127. package/dist/board/render/renderers/file-card-renderer.d.ts +1 -1
  128. package/dist/board/render/renderers/file-card-renderer.js +2 -2
  129. package/dist/board/render/renderers/image-card-renderer.d.ts +1 -1
  130. package/dist/board/render/renderers/shape-card-renderer.js +1 -1
  131. package/dist/board/render/renderers/task-card-renderer.js +1 -1
  132. package/dist/board/render/renderers/text-card-renderer.js +1 -1
  133. package/dist/board/render/renderers/video-card-renderer.d.ts +1 -1
  134. package/dist/board/render/stroke.d.ts +1 -1
  135. package/dist/board/render/stroke.js +1 -1
  136. package/dist/board/render/text-measurement.js +1 -1
  137. package/dist/board/replica/index.d.ts +70 -0
  138. package/dist/board/replica/index.js +276 -0
  139. package/dist/board/stage/assets.d.ts +41 -0
  140. package/dist/board/stage/assets.js +350 -0
  141. package/dist/board/stage/index.d.ts +8 -0
  142. package/dist/board/stage/index.js +8 -0
  143. package/dist/board/stage/lru.d.ts +32 -0
  144. package/dist/board/stage/lru.js +29 -0
  145. package/dist/board/stage/pointer.d.ts +8 -0
  146. package/dist/board/stage/pointer.js +33 -0
  147. package/dist/board/stage/scene.d.ts +85 -0
  148. package/dist/board/stage/scene.js +512 -0
  149. package/dist/board/stage/stage.d.ts +66 -0
  150. package/dist/board/stage/stage.js +568 -0
  151. package/dist/board/stage/texture-pool.d.ts +24 -0
  152. package/dist/board/stage/texture-pool.js +154 -0
  153. package/dist/board/stage/views.d.ts +38 -0
  154. package/dist/board/stage/views.js +93 -0
  155. package/dist/chunks/environment.d.ts +24 -1
  156. package/dist/chunks/http.d.ts +99 -66
  157. package/dist/chunks/http.js +214 -207
  158. package/dist/chunks/websocket.d.ts +1 -1
  159. package/dist/http.d.ts +2 -2
  160. package/dist/index.d.ts +3 -3
  161. package/dist/index.js +20 -4
  162. package/dist/media.d.ts +1 -10
  163. package/dist/media.js +16 -27
  164. package/dist/protocol/dist/board-patch.js +1 -1
  165. package/dist/protocol/dist/board.d.ts +28 -2
  166. package/dist/protocol/dist/board.js +3 -1
  167. package/dist/protocol/dist/core/media.d.ts +5 -0
  168. package/dist/protocol/dist/core/media.js +39 -0
  169. package/dist/protocol/dist/index.d.ts +5 -5
  170. package/dist/types.d.ts +1 -1
  171. package/package.json +20 -8
  172. package/dist/board/core/shape-definition.d.ts +0 -23
  173. package/dist/board/core/shape-definition.js +0 -45
  174. package/dist/board/core/shape-types.d.ts +0 -38
  175. package/dist/board/core/shape-types.js +0 -22
  176. package/dist/board/headless/index.d.ts +0 -55
  177. package/dist/board/headless/sketch.d.ts +0 -19
  178. package/dist/board/index.d.ts +0 -30
@@ -0,0 +1,41 @@
1
+ import { BoardItem } from "../../protocol/dist/board-model.js";
2
+ import { BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME } from "../../protocol/dist/board.js";
3
+ import "../../protocol/dist/index.js";
4
+ import "../model/index.js";
5
+ //#region src/board/editor/clipboard.d.ts
6
+ /** How far a duplicate or repeated paste lands from its source. */
7
+ declare const DUPLICATE_OFFSET = 24;
8
+ declare const BOARD_CLIPBOARD_VERSION: 3;
9
+ declare const MAX_CLIPBOARD_ITEMS = 2000;
10
+ declare const MAX_CLIPBOARD_CHARS: number;
11
+ type BoardClipboardPayload = {
12
+ kind: typeof BOARD_CLIPBOARD_KIND;
13
+ version: typeof BOARD_CLIPBOARD_VERSION;
14
+ items: Record<string, BoardItem>;
15
+ origin: {
16
+ x: number;
17
+ y: number;
18
+ };
19
+ };
20
+ declare function encodeClipboard(items: Record<string, BoardItem>, origin: {
21
+ x: number;
22
+ y: number;
23
+ }): BoardClipboardPayload | null;
24
+ declare function parseClipboard(raw: unknown): BoardClipboardPayload | null;
25
+ declare function materializeClipboard(payload: BoardClipboardPayload, at: {
26
+ x: number;
27
+ y: number;
28
+ }, resolveEnd?: (id: string, which: "start" | "end") => {
29
+ x: number;
30
+ y: number;
31
+ } | null): Record<string, BoardItem>;
32
+ declare function remapItems(items: Record<string, BoardItem>, idMap: ReadonlyMap<string, string>, place?: (item: BoardItem) => BoardItem, resolveEnd?: (id: string, which: "start" | "end") => {
33
+ x: number;
34
+ y: number;
35
+ } | null): Record<string, BoardItem>;
36
+ declare function defaultPasteOffset(count?: number): {
37
+ x: number;
38
+ y: number;
39
+ };
40
+ //#endregion
41
+ export { BOARD_CLIPBOARD_MIME, BOARD_CLIPBOARD_VERSION, BoardClipboardPayload, DUPLICATE_OFFSET, MAX_CLIPBOARD_CHARS, MAX_CLIPBOARD_ITEMS, defaultPasteOffset, encodeClipboard, materializeClipboard, parseClipboard, remapItems };
@@ -0,0 +1,122 @@
1
+ import { parseBoardItem } from "../../protocol/dist/board-model.js";
2
+ import { arrowBindings, isArrowBinding } from "../../protocol/dist/board-layout.js";
3
+ import { BOARD_CLIPBOARD_KIND, BOARD_CLIPBOARD_MIME } from "../../protocol/dist/board.js";
4
+ import { createBoardItemId } from "../model/items/id.js";
5
+ //#region src/board/editor/clipboard.ts
6
+ /** How far a duplicate or repeated paste lands from its source. */
7
+ const DUPLICATE_OFFSET = 24;
8
+ const BOARD_CLIPBOARD_VERSION = 3;
9
+ const MAX_CLIPBOARD_ITEMS = 2e3;
10
+ const MAX_CLIPBOARD_CHARS = 4194304;
11
+ function encodeClipboard(items, origin) {
12
+ const ids = Object.keys(items);
13
+ if (ids.length === 0 || ids.length > 2e3) return null;
14
+ return {
15
+ kind: BOARD_CLIPBOARD_KIND,
16
+ version: 3,
17
+ items: Object.fromEntries(ids.map((id) => {
18
+ const item = items[id];
19
+ return [id, item.parent && items[item.parent] ? item : shiftItem(item, -origin.x, -origin.y)];
20
+ })),
21
+ origin
22
+ };
23
+ }
24
+ function parseClipboard(raw) {
25
+ if (raw == null) return null;
26
+ if (typeof raw === "string") {
27
+ if (raw.length > 4194304) return null;
28
+ try {
29
+ raw = JSON.parse(raw);
30
+ } catch {
31
+ return null;
32
+ }
33
+ }
34
+ if (!raw || typeof raw !== "object") return null;
35
+ const record = raw;
36
+ if (record.kind !== "cohub.board.clipboard" || record.version !== 3) return null;
37
+ const origin = record.origin;
38
+ if (typeof origin?.x !== "number" || typeof origin.y !== "number" || !Number.isFinite(origin.x) || !Number.isFinite(origin.y)) return null;
39
+ if (!record.items || typeof record.items !== "object" || Array.isArray(record.items)) return null;
40
+ const entries = Object.entries(record.items);
41
+ if (entries.length === 0 || entries.length > 2e3) return null;
42
+ const items = {};
43
+ for (const [id, value] of entries) {
44
+ const parsed = parseBoardItem(value);
45
+ if (!parsed.ok) return null;
46
+ items[id] = parsed.item;
47
+ }
48
+ return {
49
+ kind: BOARD_CLIPBOARD_KIND,
50
+ version: 3,
51
+ items,
52
+ origin: {
53
+ x: origin.x,
54
+ y: origin.y
55
+ }
56
+ };
57
+ }
58
+ function materializeClipboard(payload, at, resolveEnd = () => null) {
59
+ const idMap = new Map(Object.keys(payload.items).map((id) => [id, createBoardItemId()]));
60
+ return remapItems(payload.items, idMap, (item) => item.parent && idMap.has(item.parent) ? item : shiftItem(item, at.x, at.y), resolveEnd);
61
+ }
62
+ function remapItems(items, idMap, place = (item) => item, resolveEnd = () => null) {
63
+ const result = {};
64
+ for (const [id, source] of Object.entries(items)) {
65
+ let item = place(source);
66
+ const { locked: _locked, ...unlocked } = item;
67
+ item = unlocked;
68
+ if (item.parent) {
69
+ const parent = idMap.get(item.parent);
70
+ if (parent) item = {
71
+ ...item,
72
+ parent
73
+ };
74
+ else {
75
+ const { parent: _parent, ...root } = item;
76
+ item = root;
77
+ }
78
+ }
79
+ if (item.type === "arrow" && arrowBindings(item).length) {
80
+ const end = (which) => {
81
+ const value = item.type === "arrow" ? item.props[which] : null;
82
+ if (!value || !isArrowBinding(value)) return value;
83
+ const mapped = idMap.get(value.item);
84
+ if (mapped) return {
85
+ ...value,
86
+ item: mapped
87
+ };
88
+ return resolveEnd(id, which) ?? {
89
+ x: 0,
90
+ y: 0
91
+ };
92
+ };
93
+ item = {
94
+ ...item,
95
+ props: {
96
+ ...item.props,
97
+ start: end("start"),
98
+ end: end("end")
99
+ }
100
+ };
101
+ }
102
+ result[idMap.get(id) ?? createBoardItemId()] = item;
103
+ }
104
+ return result;
105
+ }
106
+ function defaultPasteOffset(count = 1) {
107
+ return {
108
+ x: 24 * count,
109
+ y: 24 * count
110
+ };
111
+ }
112
+ function shiftItem(item, dx, dy) {
113
+ return {
114
+ ...item,
115
+ position: {
116
+ x: item.position.x + dx,
117
+ y: item.position.y + dy
118
+ }
119
+ };
120
+ }
121
+ //#endregion
122
+ export { BOARD_CLIPBOARD_MIME, BOARD_CLIPBOARD_VERSION, DUPLICATE_OFFSET, MAX_CLIPBOARD_CHARS, MAX_CLIPBOARD_ITEMS, defaultPasteOffset, encodeClipboard, materializeClipboard, parseClipboard, remapItems };
@@ -0,0 +1,19 @@
1
+ import { BoardAnchorSide } from "../../protocol/dist/board-model.js";
2
+ import { BoardFrame } from "../../protocol/dist/board-layout.js";
3
+ import { WorldPoint } from "../model/geometry.js";
4
+ import "../model/index.js";
5
+ //#region src/board/editor/connection-ports.d.ts
6
+ declare const CONNECTION_SIDES: readonly BoardAnchorSide[];
7
+ declare const CONNECTION_PORT_OFFSET = 14;
8
+ declare const CONNECTION_PORT_RADIUS = 4;
9
+ declare const CONNECTION_PORT_HIT_RADIUS = 11;
10
+ declare const CONNECTION_PORT_TOUCH_HIT_RADIUS = 22;
11
+ type ConnectionPort = {
12
+ side: BoardAnchorSide;
13
+ point: WorldPoint;
14
+ };
15
+ declare function portHitRadius(pointerType: string): number;
16
+ declare function connectionPorts(frame: BoardFrame, zoom: number): ConnectionPort[];
17
+ declare function connectionPortAt(frame: BoardFrame, point: WorldPoint, zoom: number, pointerType: string): ConnectionPort | null;
18
+ //#endregion
19
+ export { CONNECTION_PORT_HIT_RADIUS, CONNECTION_PORT_OFFSET, CONNECTION_PORT_RADIUS, CONNECTION_PORT_TOUCH_HIT_RADIUS, CONNECTION_SIDES, ConnectionPort, connectionPortAt, connectionPorts, portHitRadius };
@@ -0,0 +1,85 @@
1
+ import { degToRad, frameRect, rectCenter, rotatePointAround, worldPoint } from "../model/geometry.js";
2
+ //#region src/board/editor/connection-ports.ts
3
+ const CONNECTION_SIDES = [
4
+ "top",
5
+ "right",
6
+ "bottom",
7
+ "left"
8
+ ];
9
+ const CONNECTION_PORT_OFFSET = 14;
10
+ const CONNECTION_PORT_RADIUS = 4;
11
+ const CONNECTION_PORT_HIT_RADIUS = 11;
12
+ const CONNECTION_PORT_TOUCH_HIT_RADIUS = 22;
13
+ function portHitRadius(pointerType) {
14
+ return pointerType === "touch" || pointerType === "pen" ? 22 : 11;
15
+ }
16
+ const SIDE_NORMAL = {
17
+ top: {
18
+ x: 0,
19
+ y: -1
20
+ },
21
+ right: {
22
+ x: 1,
23
+ y: 0
24
+ },
25
+ bottom: {
26
+ x: 0,
27
+ y: 1
28
+ },
29
+ left: {
30
+ x: -1,
31
+ y: 0
32
+ }
33
+ };
34
+ const SIDE_ANCHOR = {
35
+ top: {
36
+ nx: .5,
37
+ ny: 0
38
+ },
39
+ right: {
40
+ nx: 1,
41
+ ny: .5
42
+ },
43
+ bottom: {
44
+ nx: .5,
45
+ ny: 1
46
+ },
47
+ left: {
48
+ nx: 0,
49
+ ny: .5
50
+ }
51
+ };
52
+ function connectionPorts(frame, zoom) {
53
+ const offset = 14 / Math.max(zoom, 1e-4);
54
+ const center = rectCenter(frameRect(frame));
55
+ const rotation = frame.rotation ? degToRad(frame.rotation) : 0;
56
+ return CONNECTION_SIDES.map((side) => {
57
+ const anchor = SIDE_ANCHOR[side];
58
+ const base = worldPoint(frame.x + anchor.nx * frame.width, frame.y + anchor.ny * frame.height);
59
+ const rotated = rotation ? rotatePointAround(base, center, rotation) : base;
60
+ const normal = SIDE_NORMAL[side];
61
+ const direction = rotation ? {
62
+ x: normal.x * Math.cos(rotation) - normal.y * Math.sin(rotation),
63
+ y: normal.x * Math.sin(rotation) + normal.y * Math.cos(rotation)
64
+ } : normal;
65
+ return {
66
+ side,
67
+ point: worldPoint(rotated.x + direction.x * offset, rotated.y + direction.y * offset)
68
+ };
69
+ });
70
+ }
71
+ function connectionPortAt(frame, point, zoom, pointerType) {
72
+ const radius = portHitRadius(pointerType) / Math.max(zoom, 1e-4);
73
+ let closest = null;
74
+ let closestDistance = Number.POSITIVE_INFINITY;
75
+ for (const port of connectionPorts(frame, zoom)) {
76
+ const distance = Math.hypot(port.point.x - point.x, port.point.y - point.y);
77
+ if (distance <= radius && distance < closestDistance) {
78
+ closest = port;
79
+ closestDistance = distance;
80
+ }
81
+ }
82
+ return closest;
83
+ }
84
+ //#endregion
85
+ export { CONNECTION_PORT_HIT_RADIUS, CONNECTION_PORT_OFFSET, CONNECTION_PORT_RADIUS, CONNECTION_PORT_TOUCH_HIT_RADIUS, CONNECTION_SIDES, connectionPortAt, connectionPorts, portHitRadius };
@@ -0,0 +1,111 @@
1
+ import { BoardDocument, BoardPatch, BoardSettings } from "../../protocol/dist/board-model.js";
2
+ import { BoardViewport, WorldPoint } from "../model/geometry.js";
3
+ import { BoardScene } from "../model/scene.js";
4
+ import { BoardToolStyleMap } from "../model/tool-styles.js";
5
+ import { BoardRegistry } from "../model/items/registry.js";
6
+ import "../model/index.js";
7
+ import { DocumentModule } from "./document.js";
8
+ import { QueryModule } from "./query.js";
9
+ import { CameraModule } from "./camera.js";
10
+ import { SelectionModule } from "./selection.js";
11
+ import { BoardInteraction, InteractionModule } from "./interaction.js";
12
+ import { CreationModule } from "./creation.js";
13
+ import { DeletionModule } from "./deletion.js";
14
+ import { CopyModule } from "./copy.js";
15
+ import { SnapshotsModule } from "./snapshots.js";
16
+ import { RemoteModule } from "./remote.js";
17
+ import { SnapGuide } from "./snapping.js";
18
+ import { BoardEditorChannel, BoardEditorChannels } from "./state.js";
19
+ import { BoardToolId } from "./tool.js";
20
+ import { AnimationModule } from "./animation.js";
21
+ //#region src/board/editor/context.d.ts
22
+ type BoardCameraPolicy = "follow" | "free";
23
+ type BoardPlayhead = {
24
+ animationId: string;
25
+ time: number;
26
+ };
27
+ type BoardUndoEntry = {
28
+ undo: BoardPatch;
29
+ redo: BoardPatch;
30
+ };
31
+ type BoardEditorState = {
32
+ base: BoardDocument;
33
+ settingsPreview: BoardSettings | null;
34
+ scene: BoardScene;
35
+ structureVersion: number;
36
+ geometryVersion: number;
37
+ selection: string[];
38
+ camera: BoardViewport;
39
+ surfaceSize: {
40
+ width: number;
41
+ height: number;
42
+ };
43
+ cameraPolicy: BoardCameraPolicy;
44
+ tool: BoardToolId;
45
+ toolStyles: BoardToolStyleMap;
46
+ interaction: BoardInteraction;
47
+ snapGuides: SnapGuide[];
48
+ spaceHeld: boolean;
49
+ hoverId: string | null;
50
+ hoverPoint: WorldPoint | null;
51
+ hoverPointerType: string;
52
+ editingId: string | null;
53
+ draftTextId: string | null;
54
+ playhead: BoardPlayhead | null;
55
+ recording: boolean;
56
+ undoStack: BoardUndoEntry[];
57
+ redoStack: BoardUndoEntry[];
58
+ saveError: string | null;
59
+ pendingCommits: number;
60
+ };
61
+ declare const STATE_CHANNELS: { readonly [K in keyof BoardEditorState]: BoardEditorChannel; };
62
+ type BoardEditorPreferences = {
63
+ toolStyles: BoardToolStyleMap;
64
+ cameraPolicy: BoardCameraPolicy;
65
+ };
66
+ type BoardViewState = {
67
+ visibleRect: {
68
+ x: number;
69
+ y: number;
70
+ width: number;
71
+ height: number;
72
+ } | null;
73
+ selectedNodes: Array<{
74
+ id: string;
75
+ type: string;
76
+ title?: string;
77
+ }>;
78
+ };
79
+ type BoardEditorOptions = {
80
+ document: BoardDocument;
81
+ registry?: BoardRegistry;
82
+ viewport?: BoardViewport;
83
+ initialTool?: BoardToolId;
84
+ key?: string;
85
+ readonly?: boolean;
86
+ preferences?: Partial<BoardEditorPreferences>;
87
+ onPreferencesChange?: (preferences: BoardEditorPreferences) => void;
88
+ onCommit: (patch: BoardPatch) => void | Promise<void>;
89
+ onViewStateChange?: (state: BoardViewState) => void;
90
+ track?: (channel: BoardEditorChannel) => void;
91
+ };
92
+ type EditorContext = {
93
+ readonly options: BoardEditorOptions;
94
+ readonly registry: BoardRegistry;
95
+ readonly state: BoardEditorState;
96
+ readonly channels: BoardEditorChannels;
97
+ preferencesChanged(): void;
98
+ document: DocumentModule;
99
+ query: QueryModule;
100
+ camera: CameraModule;
101
+ selection: SelectionModule;
102
+ creation: CreationModule;
103
+ deletion: DeletionModule;
104
+ copy: CopyModule;
105
+ interaction: InteractionModule;
106
+ animation: AnimationModule;
107
+ snapshots: SnapshotsModule;
108
+ remote: RemoteModule;
109
+ };
110
+ //#endregion
111
+ export { BoardCameraPolicy, BoardEditorOptions, BoardEditorPreferences, BoardEditorState, BoardPlayhead, BoardUndoEntry, BoardViewState, EditorContext, STATE_CHANNELS };
@@ -0,0 +1,30 @@
1
+ //#region src/board/editor/context.ts
2
+ const STATE_CHANNELS = {
3
+ base: "document",
4
+ settingsPreview: "document",
5
+ scene: "scene",
6
+ structureVersion: "scene",
7
+ geometryVersion: "scene",
8
+ selection: "selection",
9
+ camera: "camera",
10
+ surfaceSize: "camera",
11
+ cameraPolicy: "camera",
12
+ tool: "tool",
13
+ toolStyles: "tool",
14
+ interaction: "interaction",
15
+ snapGuides: "interaction",
16
+ spaceHeld: "interaction",
17
+ hoverId: "hover",
18
+ hoverPoint: "hover",
19
+ hoverPointerType: "hover",
20
+ editingId: "editing",
21
+ draftTextId: "editing",
22
+ playhead: "playback",
23
+ recording: "playback",
24
+ undoStack: "history",
25
+ redoStack: "history",
26
+ saveError: "status",
27
+ pendingCommits: "status"
28
+ };
29
+ //#endregion
30
+ export { STATE_CHANNELS };
@@ -0,0 +1,17 @@
1
+ import { BoardItem } from "../../protocol/dist/board-model.js";
2
+ import { WorldPoint } from "../model/geometry.js";
3
+ import "../model/index.js";
4
+ import { BoardClipboardPayload } from "./clipboard.js";
5
+ import { EditorContext } from "./context.js";
6
+ //#region src/board/editor/copy.d.ts
7
+ declare function createCopyModule(ctx: EditorContext): {
8
+ duplicates: (ids: string[], offset: number) => Map<string, BoardItem>;
9
+ rootsOfCopies: (copies: ReadonlyMap<string, BoardItem>) => string[];
10
+ duplicateSelection: () => void;
11
+ copySelection: () => BoardClipboardPayload | null;
12
+ cutSelection: () => BoardClipboardPayload | null;
13
+ pasteClipboard: (raw?: unknown, at?: WorldPoint) => void;
14
+ };
15
+ type CopyModule = ReturnType<typeof createCopyModule>;
16
+ //#endregion
17
+ export { CopyModule, createCopyModule };
@@ -0,0 +1,116 @@
1
+ import { applyMatrix, arrowBindings, invertMatrix } from "../../protocol/dist/board-layout.js";
2
+ import { resolveSceneArrow } from "../model/arrow-geometry.js";
3
+ import { createBoardItemId } from "../model/items/id.js";
4
+ import { defaultPasteOffset, encodeClipboard, materializeClipboard, parseClipboard, remapItems } from "./clipboard.js";
5
+ //#region src/board/editor/copy.ts
6
+ function createCopyModule(ctx) {
7
+ const { state, options } = ctx;
8
+ let internalClipboard = null;
9
+ let pasteCount = 0;
10
+ function detachedSubtrees(ids) {
11
+ const { scene } = state;
12
+ const items = {};
13
+ for (const root of ctx.query.rootsOf(ids)) {
14
+ const item = scene.get(root);
15
+ if (!item) continue;
16
+ const { id: _id, frame, ...stored } = item;
17
+ items[root] = ctx.document.reparent(stored, frame, void 0, scene.layout.box(root));
18
+ for (const child of scene.descendants(root)) {
19
+ const value = ctx.document.displayItem(child);
20
+ if (value) items[child] = value;
21
+ }
22
+ }
23
+ return items;
24
+ }
25
+ function arrowEndPoint(id, which) {
26
+ const arrow = state.scene.get(id);
27
+ if (arrow?.type !== "arrow") return null;
28
+ const resolved = resolveSceneArrow(arrow, state.scene);
29
+ return applyMatrix(invertMatrix(state.scene.layout.matrix(id)), (which === "start" ? resolved.start : resolved.end).point);
30
+ }
31
+ function duplicates(ids, offset) {
32
+ const { scene } = state;
33
+ const copied = detachedSubtrees(ids);
34
+ for (const id of Object.keys(copied)) for (const arrowId of scene.binders(id)) {
35
+ const arrow = ctx.document.displayItem(arrowId);
36
+ const shown = scene.get(arrowId);
37
+ if (copied[arrowId] || !arrow || !shown || !arrowBindings(arrow).every((bound) => copied[bound])) continue;
38
+ copied[arrowId] = ctx.document.reparent(arrow, shown.frame, void 0, scene.layout.box(arrowId));
39
+ }
40
+ const idMap = new Map(Object.keys(copied).map((id) => [id, createBoardItemId()]));
41
+ const moved = remapItems(copied, idMap, (item) => item.parent && copied[item.parent] ? item : {
42
+ ...item,
43
+ position: {
44
+ x: item.position.x + offset,
45
+ y: item.position.y + offset
46
+ }
47
+ }, arrowEndPoint);
48
+ let z = ctx.document.topZ(void 0);
49
+ return new Map(Object.entries(moved).map(([id, item]) => [id, item.parent ? item : {
50
+ ...item,
51
+ z: z++
52
+ }]));
53
+ }
54
+ function rootsOfCopies(copies) {
55
+ return [...copies].filter(([, item]) => !item.parent || !copies.has(item.parent)).map(([id]) => id);
56
+ }
57
+ function duplicateSelection() {
58
+ if (options.readonly || state.selection.length === 0) return;
59
+ const copies = duplicates(state.selection, 24);
60
+ if (copies.size === 0) return;
61
+ const roots = rootsOfCopies(copies);
62
+ ctx.document.markAdded(roots);
63
+ state.selection = roots;
64
+ ctx.document.commitItems(copies);
65
+ }
66
+ function copySelection() {
67
+ const { selection } = state;
68
+ if (selection.length === 0) return null;
69
+ const copied = detachedSubtrees(selection);
70
+ const origin = ctx.query.contentBounds(ctx.query.rootsOf(selection));
71
+ const payload = origin ? encodeClipboard(copied, {
72
+ x: origin.x,
73
+ y: origin.y
74
+ }) : null;
75
+ if (payload) {
76
+ internalClipboard = payload;
77
+ pasteCount = 0;
78
+ }
79
+ return payload;
80
+ }
81
+ function cutSelection() {
82
+ const payload = copySelection();
83
+ if (payload) ctx.deletion.deleteSelection();
84
+ return payload;
85
+ }
86
+ function pasteClipboard(raw, at) {
87
+ if (options.readonly) return;
88
+ const parsed = parseClipboard(raw) ?? (raw == null ? parseClipboard(internalClipboard) : null);
89
+ if (!parsed) return;
90
+ pasteCount += 1;
91
+ const offset = at ?? {
92
+ x: parsed.origin.x + defaultPasteOffset(pasteCount).x,
93
+ y: parsed.origin.y + defaultPasteOffset(pasteCount).y
94
+ };
95
+ const pasted = materializeClipboard(parsed, offset);
96
+ const entries = Object.entries(pasted).map(([id, item]) => ({
97
+ id,
98
+ item
99
+ }));
100
+ const roots = entries.filter(({ item }) => !item.parent).map(({ id }) => id);
101
+ const changes = ctx.creation.placeNew(entries);
102
+ ctx.document.markAdded(roots);
103
+ state.selection = roots;
104
+ ctx.document.commitItems(changes);
105
+ }
106
+ return {
107
+ duplicates,
108
+ rootsOfCopies,
109
+ duplicateSelection,
110
+ copySelection,
111
+ cutSelection,
112
+ pasteClipboard
113
+ };
114
+ }
115
+ //#endregion
116
+ export { createCopyModule };
@@ -0,0 +1,47 @@
1
+ import { BoardArrowEnd, BoardDrawPoint, BoardItem, BoardMediaSnapshot, BoardTaskSnapshot } from "../../protocol/dist/board-model.js";
2
+ import { BoardMatrix } from "../../protocol/dist/board-layout.js";
3
+ import { WorldPoint } from "../model/geometry.js";
4
+ import { BoardFileSnapshotFacts } from "../model/file-snapshot.js";
5
+ import { ShapeKind } from "../model/shape-types.js";
6
+ import { BoardItemEntry, createAppBoardItem } from "../model/items/create.js";
7
+ import { BoardItemInput } from "../model/items/registry.js";
8
+ import "../model/index.js";
9
+ import { BoardInteraction } from "./interaction.js";
10
+ import { EditorContext } from "./context.js";
11
+ //#region src/board/editor/creation.d.ts
12
+ type BoardAppMetadata = Parameters<typeof createAppBoardItem>[0];
13
+ type BoardTaskSource = {
14
+ itemId: string;
15
+ sourcePortId: string;
16
+ targetPortId: string;
17
+ };
18
+ declare function createCreationModule(ctx: EditorContext): {
19
+ placeNew: (entries: readonly BoardItemEntry[]) => Map<string, BoardItem>;
20
+ add: (entries: BoardItemEntry[], { select, enter }?: {
21
+ select?: boolean;
22
+ enter?: boolean;
23
+ }) => void;
24
+ addItem: (type: string, input: BoardItemInput) => string | null;
25
+ addApp: (app: BoardAppMetadata, at: WorldPoint) => string;
26
+ addFile: (path: string, at: WorldPoint, snapshot?: BoardMediaSnapshot & BoardFileSnapshotFacts) => string;
27
+ addTask: (taskRunId: string, snapshot: BoardTaskSnapshot, at: WorldPoint, metadata?: Record<string, unknown>) => string;
28
+ addTaskWithSources: (taskRunId: string, snapshot: BoardTaskSnapshot, at: WorldPoint, sources: BoardTaskSource[], metadata?: Record<string, unknown>) => string | null;
29
+ addText: (text: string, at: WorldPoint) => void;
30
+ addShape: (at: WorldPoint, geometry?: ShapeKind) => void;
31
+ addFrame: (at: WorldPoint) => void;
32
+ commitBox: (gesture: Extract<BoardInteraction, {
33
+ type: "creatingBox";
34
+ }>) => void;
35
+ commitDraw: (id: string, points: BoardDrawPoint[], color: string, size: number) => void;
36
+ commitArrow: (gesture: Extract<BoardInteraction, {
37
+ type: "creatingArrow";
38
+ }>, cancelled: boolean) => void;
39
+ arrowEnd: (point: WorldPoint, targetItemId: string | null, arrowMatrix?: BoardMatrix) => BoardArrowEnd;
40
+ beginTextDraft: (at: WorldPoint) => void;
41
+ previewTextLayout: (id: string, text: string) => void;
42
+ updateText: (id: string, text: string, created?: boolean) => void;
43
+ commitTextEdit: (id: string, text: string) => void;
44
+ };
45
+ type CreationModule = ReturnType<typeof createCreationModule>;
46
+ //#endregion
47
+ export { BoardAppMetadata, BoardTaskSource, CreationModule, createCreationModule };