@q9labsai/chalk-whiteboard 5.2.0 → 5.2.2
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.
- package/dist/assets.d.ts +13 -0
- package/dist/assets.js +10 -0
- package/dist/chunk-BN4VA2BS.js +20 -0
- package/dist/collab/view-limits.d.ts +1 -0
- package/dist/collab/view.d.ts +26 -0
- package/dist/embedded/chalk-whiteboard/Figtree-Regular.ttf +0 -0
- package/dist/embedded/chalk-whiteboard/Figtree-SemiBold.ttf +0 -0
- package/dist/embedded/chalk-whiteboard/asset-manifest.json +19 -4
- package/dist/embedded/chalk-whiteboard/chalk.css +44 -0
- package/dist/embedded/chalk-whiteboard/licenses/Figtree.txt +93 -0
- package/dist/embedded/chalk-whiteboard/renderer.js +1669 -1418
- package/dist/embedded/controller.d.ts +16 -14
- package/dist/embedded/index.d.ts +1 -1
- package/dist/embedded/index.js +127 -8
- package/dist/embedded/protocol.d.ts +86 -0
- package/dist/embedded/renderer-assets.d.ts +1 -0
- package/dist/embedded/renderer-bridge.d.ts +10 -0
- package/dist/embedded/renderer-entry.d.ts +2 -0
- package/dist/embedded/renderer.d.ts +0 -5
- package/dist/react/board/Board.d.ts +41 -0
- package/dist/react/board/BoardCursors.d.ts +23 -0
- package/dist/react/board/BoardIcon.d.ts +46 -0
- package/dist/react/board/BoardIsland.d.ts +22 -0
- package/dist/react/board/BoardMenu.d.ts +20 -0
- package/dist/react/board/BoardStyles.d.ts +2 -0
- package/dist/react/board/board-draw-policy.d.ts +10 -0
- package/dist/react/board/board-engine.d.ts +30 -0
- package/dist/react/board/board-history.d.ts +7 -0
- package/dist/react/board/board-model.d.ts +91 -0
- package/dist/react/board/board-toasts.d.ts +15 -0
- package/dist/react/board/board-view-versions.d.ts +1 -0
- package/dist/react/board/controls/ChalkMenu.d.ts +22 -0
- package/dist/react/board/controls/ChalkPopover.d.ts +13 -0
- package/dist/react/board/controls/ChalkTooltip.d.ts +5 -0
- package/dist/react/board/controls/index.d.ts +3 -0
- package/dist/react/board/useMediaQuery.d.ts +6 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.js +1811 -18
- package/package.json +19 -5
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { WhiteboardView } from "../collab/view.js";
|
|
2
|
+
import type { ChalkEmbeddedBoardContext, ChalkEmbeddedBoardNotice } from "./protocol.js";
|
|
1
3
|
import type { WhiteboardCommit, WhiteboardJsonValue } from "../collab/wire.js";
|
|
2
4
|
import { type ChalkEmbeddedWhiteboardTheme, type ChalkEmbeddedWhiteboardViewport } from "./protocol.js";
|
|
3
5
|
export type ChalkEmbeddedWhiteboardTransportElement = {
|
|
@@ -33,23 +35,12 @@ export type ChalkEmbeddedWhiteboardTransportEvent = {
|
|
|
33
35
|
readonly type: "reset_required";
|
|
34
36
|
readonly sceneId: string;
|
|
35
37
|
readonly reason: "scene_changed" | "cursor_expired" | "gap";
|
|
36
|
-
} | ({
|
|
38
|
+
} | (WhiteboardView & {
|
|
37
39
|
readonly type: "view";
|
|
38
40
|
readonly participantId: string;
|
|
39
41
|
readonly displayName: string;
|
|
40
|
-
readonly x: number;
|
|
41
|
-
readonly y: number;
|
|
42
|
-
readonly width: number;
|
|
43
|
-
readonly height: number;
|
|
44
|
-
readonly bring: boolean;
|
|
45
42
|
readonly occurredAt: string;
|
|
46
|
-
}
|
|
47
|
-
readonly originParticipantId: string;
|
|
48
|
-
readonly originSequence: number;
|
|
49
|
-
} | {
|
|
50
|
-
readonly originParticipantId?: never;
|
|
51
|
-
readonly originSequence?: never;
|
|
52
|
-
}));
|
|
43
|
+
});
|
|
53
44
|
export interface ChalkEmbeddedWhiteboardFileTransport {
|
|
54
45
|
readonly getDownloadUrl: (fileId: string) => Promise<{
|
|
55
46
|
readonly downloadUrl: string;
|
|
@@ -70,6 +61,9 @@ export interface ChalkEmbeddedWhiteboardTransport {
|
|
|
70
61
|
}) => void;
|
|
71
62
|
readonly requestSnapshot: () => Promise<void>;
|
|
72
63
|
readonly clear: () => Promise<WhiteboardCommit>;
|
|
64
|
+
readonly sendView?: (view: WhiteboardView) => boolean;
|
|
65
|
+
readonly setDrawPolicy?: (policy: "everyone" | "hosts" | "picked") => Promise<void>;
|
|
66
|
+
readonly setDrawPermission?: (participantId: string, canDraw: boolean) => Promise<void>;
|
|
73
67
|
readonly files: ChalkEmbeddedWhiteboardFileTransport;
|
|
74
68
|
}
|
|
75
69
|
export interface ChalkEmbeddedWhiteboardRendererPort {
|
|
@@ -107,7 +101,13 @@ export interface ChalkEmbeddedWhiteboardControllerOptions {
|
|
|
107
101
|
readonly format: "png" | "svg";
|
|
108
102
|
readonly mimeType: string;
|
|
109
103
|
readonly dataURL: string;
|
|
110
|
-
|
|
104
|
+
readonly action?: "download" | "copy";
|
|
105
|
+
}) => void | Promise<void>;
|
|
106
|
+
readonly manageSceneSubscription?: boolean;
|
|
107
|
+
readonly board?: ChalkEmbeddedBoardContext;
|
|
108
|
+
readonly onNotice?: (notice: ChalkEmbeddedBoardNotice | null) => void;
|
|
109
|
+
readonly onFollow?: (participantId: string | null) => void;
|
|
110
|
+
readonly onCloseBoard?: () => void;
|
|
111
111
|
readonly onCloseReady?: (reason: string) => void;
|
|
112
112
|
}
|
|
113
113
|
export declare class ChalkWhiteboardController {
|
|
@@ -120,6 +120,8 @@ export declare class ChalkWhiteboardController {
|
|
|
120
120
|
readonly canDraw: boolean;
|
|
121
121
|
readonly canClear: boolean;
|
|
122
122
|
}): void;
|
|
123
|
+
performNoticeAction(id: string): void;
|
|
124
|
+
setBoard(board: ChalkEmbeddedBoardContext): void;
|
|
123
125
|
setViewport(viewport: ChalkEmbeddedWhiteboardViewport): void;
|
|
124
126
|
requestUserExport(requestId: string, format: "png" | "svg"): void;
|
|
125
127
|
prepareClose(reason: string): void;
|
package/dist/embedded/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { ChalkWhiteboardController } from "./controller.js";
|
|
|
2
2
|
export type { ChalkEmbeddedWhiteboardControllerOptions, ChalkEmbeddedWhiteboardFileTransport, ChalkEmbeddedWhiteboardRendererPort, ChalkEmbeddedWhiteboardTransport, ChalkEmbeddedWhiteboardTransportEvent } from "./controller.js";
|
|
3
3
|
export { chalkEmbeddedWhiteboardManifest } from "./manifest.js";
|
|
4
4
|
export { CHALK_EMBEDDED_WHITEBOARD_BRIDGE_VERSION, CHALK_EMBEDDED_WHITEBOARD_EXCALIDRAW_VERSION, CHALK_EMBEDDED_WHITEBOARD_MAX_MESSAGE_BYTES, CHALK_EMBEDDED_WHITEBOARD_RENDERER_BUILD_ID, decodeEmbeddedWhiteboardHostMessage, decodeEmbeddedWhiteboardRendererMessage, encodeEmbeddedWhiteboardMessage, } from "./protocol.js";
|
|
5
|
-
export type { ChalkEmbeddedWhiteboardBridgeEnvelope, ChalkEmbeddedWhiteboardHostEnvelope, ChalkEmbeddedWhiteboardHostMessage, ChalkEmbeddedWhiteboardMessageContext, ChalkEmbeddedWhiteboardOperationResult, ChalkEmbeddedWhiteboardRendererEnvelope, ChalkEmbeddedWhiteboardRendererMessage, ChalkEmbeddedWhiteboardTheme, ChalkEmbeddedWhiteboardViewport, } from "./protocol.js";
|
|
5
|
+
export type { ChalkEmbeddedBoardContext, ChalkEmbeddedBoardNotice, ChalkEmbeddedWhiteboardBridgeEnvelope, ChalkEmbeddedWhiteboardHostEnvelope, ChalkEmbeddedWhiteboardHostMessage, ChalkEmbeddedWhiteboardMessageContext, ChalkEmbeddedWhiteboardOperationResult, ChalkEmbeddedWhiteboardRendererEnvelope, ChalkEmbeddedWhiteboardRendererMessage, ChalkEmbeddedWhiteboardTheme, ChalkEmbeddedWhiteboardViewport, } from "./protocol.js";
|
package/dist/embedded/index.js
CHANGED
|
@@ -31,8 +31,42 @@ function decodeEmbeddedWhiteboardHostMessage(value, expectedGeneration) {
|
|
|
31
31
|
function decodeEmbeddedWhiteboardRendererMessage(value, expectedGeneration) {
|
|
32
32
|
return decodeEnvelope(value, expectedGeneration, rendererMessageTypes);
|
|
33
33
|
}
|
|
34
|
-
var hostMessageTypes = /* @__PURE__ */ new Set([
|
|
35
|
-
|
|
34
|
+
var hostMessageTypes = /* @__PURE__ */ new Set([
|
|
35
|
+
"notice_action",
|
|
36
|
+
"set_board",
|
|
37
|
+
"apply_view",
|
|
38
|
+
"initialize",
|
|
39
|
+
"apply_snapshot",
|
|
40
|
+
"apply_update",
|
|
41
|
+
"apply_cursor",
|
|
42
|
+
"reset_required",
|
|
43
|
+
"set_capabilities",
|
|
44
|
+
"set_viewport",
|
|
45
|
+
"operation_result",
|
|
46
|
+
"provide_file_bytes",
|
|
47
|
+
"request_user_export",
|
|
48
|
+
"prepare_close"
|
|
49
|
+
]);
|
|
50
|
+
var rendererMessageTypes = /* @__PURE__ */ new Set([
|
|
51
|
+
"set_draw_policy",
|
|
52
|
+
"set_draw_permission",
|
|
53
|
+
"notice",
|
|
54
|
+
"view",
|
|
55
|
+
"follow",
|
|
56
|
+
"close_board",
|
|
57
|
+
"ready",
|
|
58
|
+
"local_update",
|
|
59
|
+
"cursor",
|
|
60
|
+
"camera",
|
|
61
|
+
"request_snapshot",
|
|
62
|
+
"clear",
|
|
63
|
+
"file_read",
|
|
64
|
+
"file_write",
|
|
65
|
+
"user_export",
|
|
66
|
+
"metric",
|
|
67
|
+
"error",
|
|
68
|
+
"close_ready"
|
|
69
|
+
]);
|
|
36
70
|
function decodeEnvelope(value, expectedGeneration, allowedTypes) {
|
|
37
71
|
if (encodedBytes(value) > CHALK_EMBEDDED_WHITEBOARD_MAX_MESSAGE_BYTES) throw new Error("embedded whiteboard message exceeds the bridge limit");
|
|
38
72
|
let parsed;
|
|
@@ -166,6 +200,7 @@ var ChalkWhiteboardController = class {
|
|
|
166
200
|
#nextMessageId;
|
|
167
201
|
#canDraw;
|
|
168
202
|
#canClear;
|
|
203
|
+
#board;
|
|
169
204
|
#viewport = null;
|
|
170
205
|
#rendererGeneration = null;
|
|
171
206
|
#sceneId = null;
|
|
@@ -200,7 +235,7 @@ var ChalkWhiteboardController = class {
|
|
|
200
235
|
this.#documentCompatible = true;
|
|
201
236
|
this.#rendererMessageIds.clear();
|
|
202
237
|
this.#abortFileTransfers();
|
|
203
|
-
if (this.#transportStarted) this.options.transport.stopSceneSubscription();
|
|
238
|
+
if (this.#transportStarted && this.options.manageSceneSubscription !== false) this.options.transport.stopSceneSubscription();
|
|
204
239
|
this.#transportStarted = false;
|
|
205
240
|
}
|
|
206
241
|
setCapabilities(value) {
|
|
@@ -208,6 +243,13 @@ var ChalkWhiteboardController = class {
|
|
|
208
243
|
this.#canClear = value.canClear;
|
|
209
244
|
this.#sendEffectiveCapabilities();
|
|
210
245
|
}
|
|
246
|
+
performNoticeAction(id) {
|
|
247
|
+
this.#send({ type: "notice_action", payload: { id } });
|
|
248
|
+
}
|
|
249
|
+
setBoard(board) {
|
|
250
|
+
this.#board = board;
|
|
251
|
+
this.#send({ type: "set_board", payload: board });
|
|
252
|
+
}
|
|
211
253
|
setViewport(viewport) {
|
|
212
254
|
this.#viewport = viewport;
|
|
213
255
|
this.#send({ type: "set_viewport", payload: viewport });
|
|
@@ -233,6 +275,60 @@ var ChalkWhiteboardController = class {
|
|
|
233
275
|
case "ready":
|
|
234
276
|
await this.#ready(message);
|
|
235
277
|
return;
|
|
278
|
+
case "view": {
|
|
279
|
+
const payload = message.payload;
|
|
280
|
+
const requestId = requireString(payload.requestId, "request ID");
|
|
281
|
+
await this.#operation(requestId, async () => {
|
|
282
|
+
const board = this.#board ?? this.options.board;
|
|
283
|
+
if (!board?.viewsAvailable || !isWhiteboardView(payload, board.viewBounds)) throw new Error("whiteboard view is invalid");
|
|
284
|
+
if (payload.bring && !this.#effectiveCanClear()) throw new Error("whiteboard presentation is not permitted");
|
|
285
|
+
const { requestId: _requestId, ...view } = payload;
|
|
286
|
+
if (!this.options.transport.sendView?.(view)) throw new Error("whiteboard view could not be sent");
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
case "notice": {
|
|
291
|
+
if (message.payload === null) {
|
|
292
|
+
this.options.onNotice?.(null);
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const notice = requireRecord(message.payload, ["id", "message", "kind"], ["actionLabel"]);
|
|
296
|
+
if (notice.kind !== "info" && notice.kind !== "error") throw new Error("Board notice kind is invalid");
|
|
297
|
+
this.options.onNotice?.({ id: requireString(notice.id, "notice ID"), message: requireString(notice.message, "notice message", 1024), kind: notice.kind, ...typeof notice.actionLabel === "string" ? { actionLabel: requireString(notice.actionLabel, "notice action", 64) } : {} });
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
case "follow": {
|
|
301
|
+
const payload = message.payload;
|
|
302
|
+
if (typeof payload !== "object" || payload === null || !("participantId" in payload) || payload.participantId !== null && typeof payload.participantId !== "string") throw new Error("whiteboard follow target is invalid");
|
|
303
|
+
this.options.onFollow?.(payload.participantId);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
case "set_draw_policy": {
|
|
307
|
+
const payload = requireRecord(message.payload, ["requestId", "policy"]);
|
|
308
|
+
const requestId = requireString(payload.requestId, "request ID");
|
|
309
|
+
const policy = payload.policy;
|
|
310
|
+
if (policy !== "everyone" && policy !== "hosts" && policy !== "picked") throw new Error("whiteboard draw policy is invalid");
|
|
311
|
+
await this.#operation(requestId, async () => {
|
|
312
|
+
if (!this.#canClear || !this.options.transport.setDrawPolicy) throw new Error("whiteboard policy changes are unavailable");
|
|
313
|
+
await this.options.transport.setDrawPolicy(policy);
|
|
314
|
+
});
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
case "set_draw_permission": {
|
|
318
|
+
const payload = requireRecord(message.payload, ["requestId", "participantId", "canDraw"]);
|
|
319
|
+
const requestId = requireString(payload.requestId, "request ID");
|
|
320
|
+
const participantId = requireString(payload.participantId, "participant ID");
|
|
321
|
+
const canDraw = payload.canDraw;
|
|
322
|
+
if (typeof canDraw !== "boolean") throw new Error("whiteboard draw permission is invalid");
|
|
323
|
+
await this.#operation(requestId, async () => {
|
|
324
|
+
if (!this.#canClear || !this.options.transport.setDrawPermission) throw new Error("whiteboard permission changes are unavailable");
|
|
325
|
+
await this.options.transport.setDrawPermission(participantId, canDraw);
|
|
326
|
+
});
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
case "close_board":
|
|
330
|
+
this.options.onCloseBoard?.();
|
|
331
|
+
return;
|
|
236
332
|
case "local_update":
|
|
237
333
|
await this.#localUpdate(message);
|
|
238
334
|
return;
|
|
@@ -273,9 +369,14 @@ var ChalkWhiteboardController = class {
|
|
|
273
369
|
case "error":
|
|
274
370
|
this.options.onError?.(requireRendererError(message.payload));
|
|
275
371
|
return;
|
|
276
|
-
case "user_export":
|
|
277
|
-
|
|
372
|
+
case "user_export": {
|
|
373
|
+
const payload = requireUserExport(message.payload);
|
|
374
|
+
await this.#operation(payload.requestId, async () => {
|
|
375
|
+
if (!this.options.onUserExport) throw new Error("Board export is unavailable");
|
|
376
|
+
await this.options.onUserExport(payload);
|
|
377
|
+
});
|
|
278
378
|
return;
|
|
379
|
+
}
|
|
279
380
|
case "close_ready":
|
|
280
381
|
this.options.onCloseReady?.(requireCloseReady(message.payload).reason);
|
|
281
382
|
}
|
|
@@ -295,11 +396,12 @@ var ChalkWhiteboardController = class {
|
|
|
295
396
|
canDraw: this.#effectiveCanDraw(),
|
|
296
397
|
canClear: this.#effectiveCanClear(),
|
|
297
398
|
theme: this.options.theme ?? "light",
|
|
399
|
+
...this.#board ?? this.options.board ? { board: this.#board ?? this.options.board } : {},
|
|
298
400
|
...this.options.localParticipantColor ? { localParticipantColor: this.options.localParticipantColor } : {}
|
|
299
401
|
}
|
|
300
402
|
});
|
|
301
403
|
if (this.#viewport) this.#send({ type: "set_viewport", payload: this.#viewport });
|
|
302
|
-
if (!this.#transportStarted) {
|
|
404
|
+
if (!this.#transportStarted && this.options.manageSceneSubscription !== false) {
|
|
303
405
|
await this.options.transport.startSceneSubscription();
|
|
304
406
|
this.#transportStarted = true;
|
|
305
407
|
} else {
|
|
@@ -415,8 +517,15 @@ var ChalkWhiteboardController = class {
|
|
|
415
517
|
case "cursor":
|
|
416
518
|
this.#send({ type: "apply_cursor", payload: event });
|
|
417
519
|
return;
|
|
418
|
-
case "view":
|
|
520
|
+
case "view": {
|
|
521
|
+
if (event.bring) {
|
|
522
|
+
const board = this.#board ?? this.options.board;
|
|
523
|
+
if (board) this.#board = { ...board, following: event.participantId };
|
|
524
|
+
this.options.onFollow?.(event.participantId);
|
|
525
|
+
}
|
|
526
|
+
this.#send({ type: "apply_view", payload: event });
|
|
419
527
|
return;
|
|
528
|
+
}
|
|
420
529
|
case "reset_required":
|
|
421
530
|
this.#sceneGeneration = null;
|
|
422
531
|
this.#send({ type: "reset_required", payload: event });
|
|
@@ -604,11 +713,12 @@ function requireRendererError(value) {
|
|
|
604
713
|
};
|
|
605
714
|
}
|
|
606
715
|
function requireUserExport(value) {
|
|
607
|
-
const record = requireRecord(value, ["requestId", "format", "mimeType", "dataURL"]);
|
|
716
|
+
const record = requireRecord(value, ["requestId", "format", "mimeType", "dataURL"], ["action"]);
|
|
608
717
|
if (record.format !== "png" && record.format !== "svg") throw new Error("embedded whiteboard export is invalid");
|
|
609
718
|
return {
|
|
610
719
|
requestId: requireString(record.requestId, "request ID"),
|
|
611
720
|
format: record.format,
|
|
721
|
+
...record.action === "copy" || record.action === "download" ? { action: record.action } : {},
|
|
612
722
|
mimeType: normalizeMimeType(requireString(record.mimeType, "MIME type")),
|
|
613
723
|
dataURL: requireString(record.dataURL, "export data", CHALK_EMBEDDED_WHITEBOARD_MAX_MESSAGE_BYTES - 1024)
|
|
614
724
|
};
|
|
@@ -838,6 +948,15 @@ function recordMessageId(messageIds, messageId) {
|
|
|
838
948
|
}
|
|
839
949
|
return true;
|
|
840
950
|
}
|
|
951
|
+
function isWhiteboardView(value, bounds) {
|
|
952
|
+
if (typeof value !== "object" || value === null || !("x" in value) || !("y" in value) || !("width" in value) || !("height" in value) || !("bring" in value)) return false;
|
|
953
|
+
if (typeof value.x !== "number" || !Number.isFinite(value.x) || Math.abs(value.x) > bounds.maxCoordinate || typeof value.y !== "number" || !Number.isFinite(value.y) || Math.abs(value.y) > bounds.maxCoordinate) return false;
|
|
954
|
+
if (typeof value.width !== "number" || !Number.isFinite(value.width) || value.width <= 0 || value.width > bounds.maxExtent || typeof value.height !== "number" || !Number.isFinite(value.height) || value.height <= 0 || value.height > bounds.maxExtent || typeof value.bring !== "boolean")
|
|
955
|
+
return false;
|
|
956
|
+
if ("lead" in value && typeof value.lead !== "boolean") return false;
|
|
957
|
+
if (!("originParticipantId" in value) || value.originParticipantId === void 0) return !("originSequence" in value) && !("originEpoch" in value);
|
|
958
|
+
return typeof value.originParticipantId === "string" && value.originParticipantId.length > 0 && value.originParticipantId.length <= 256 && "originSequence" in value && typeof value.originSequence === "number" && Number.isSafeInteger(value.originSequence) && value.originSequence > 0 && (!("originEpoch" in value) || typeof value.originEpoch === "string" && value.originEpoch.length > 0 && value.originEpoch.length <= 128);
|
|
959
|
+
}
|
|
841
960
|
export {
|
|
842
961
|
CHALK_EMBEDDED_WHITEBOARD_BRIDGE_VERSION,
|
|
843
962
|
CHALK_EMBEDDED_WHITEBOARD_EXCALIDRAW_VERSION,
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { WhoCanDraw } from "../react/board/board-draw-policy.js";
|
|
2
|
+
import type { WhiteboardView, WhiteboardViewBounds } from "../collab/view.js";
|
|
1
3
|
import type { WhiteboardCommit, WhiteboardWireElement } from "../collab/wire.js";
|
|
2
4
|
export declare const CHALK_EMBEDDED_WHITEBOARD_BRIDGE_VERSION: 1;
|
|
3
5
|
export declare const CHALK_EMBEDDED_WHITEBOARD_EXCALIDRAW_VERSION: "0.18.1";
|
|
@@ -22,6 +24,44 @@ export type ChalkEmbeddedWhiteboardOperationResult = {
|
|
|
22
24
|
readonly recoverable: boolean;
|
|
23
25
|
};
|
|
24
26
|
};
|
|
27
|
+
export type ChalkEmbeddedBoardNotice = {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly message: string;
|
|
30
|
+
readonly kind: "info" | "error";
|
|
31
|
+
readonly actionLabel?: string;
|
|
32
|
+
};
|
|
33
|
+
export type ChalkEmbeddedBoardContext = {
|
|
34
|
+
readonly primary: boolean;
|
|
35
|
+
readonly phone: boolean;
|
|
36
|
+
readonly landscapeControlsVisible?: boolean;
|
|
37
|
+
readonly following: string | null;
|
|
38
|
+
readonly ownParticipantId: string | null;
|
|
39
|
+
readonly people: readonly {
|
|
40
|
+
readonly id: string;
|
|
41
|
+
readonly displayName: string;
|
|
42
|
+
}[];
|
|
43
|
+
readonly viewBounds: WhiteboardViewBounds;
|
|
44
|
+
readonly sceneId: string | null;
|
|
45
|
+
readonly sceneStatus: string;
|
|
46
|
+
readonly connectionStatus: string;
|
|
47
|
+
readonly viewsAvailable: boolean;
|
|
48
|
+
readonly whoCanDraw?: Pick<WhoCanDraw, "policy" | "people">;
|
|
49
|
+
readonly colors: {
|
|
50
|
+
readonly canvas: string;
|
|
51
|
+
readonly surface: string;
|
|
52
|
+
readonly raised: string;
|
|
53
|
+
readonly popover: string;
|
|
54
|
+
readonly hover: string;
|
|
55
|
+
readonly line: string;
|
|
56
|
+
readonly lineStrong: string;
|
|
57
|
+
readonly text: string;
|
|
58
|
+
readonly textStrong: string;
|
|
59
|
+
readonly textMuted: string;
|
|
60
|
+
readonly textSoft: string;
|
|
61
|
+
readonly dangerText: string;
|
|
62
|
+
readonly focus: string;
|
|
63
|
+
};
|
|
64
|
+
};
|
|
25
65
|
export type ChalkEmbeddedWhiteboardHostMessage = {
|
|
26
66
|
readonly type: "initialize";
|
|
27
67
|
readonly payload: {
|
|
@@ -29,6 +69,7 @@ export type ChalkEmbeddedWhiteboardHostMessage = {
|
|
|
29
69
|
readonly canClear: boolean;
|
|
30
70
|
readonly theme: ChalkEmbeddedWhiteboardTheme;
|
|
31
71
|
readonly localParticipantColor?: string;
|
|
72
|
+
readonly board?: ChalkEmbeddedBoardContext;
|
|
32
73
|
};
|
|
33
74
|
} | {
|
|
34
75
|
readonly type: "apply_snapshot";
|
|
@@ -70,6 +111,21 @@ export type ChalkEmbeddedWhiteboardHostMessage = {
|
|
|
70
111
|
readonly canDraw: boolean;
|
|
71
112
|
readonly canClear: boolean;
|
|
72
113
|
};
|
|
114
|
+
} | {
|
|
115
|
+
readonly type: "notice_action";
|
|
116
|
+
readonly payload: {
|
|
117
|
+
readonly id: string;
|
|
118
|
+
};
|
|
119
|
+
} | {
|
|
120
|
+
readonly type: "set_board";
|
|
121
|
+
readonly payload: ChalkEmbeddedBoardContext;
|
|
122
|
+
} | {
|
|
123
|
+
readonly type: "apply_view";
|
|
124
|
+
readonly payload: WhiteboardView & {
|
|
125
|
+
readonly participantId: string;
|
|
126
|
+
readonly displayName: string;
|
|
127
|
+
readonly occurredAt: string;
|
|
128
|
+
};
|
|
73
129
|
} | {
|
|
74
130
|
readonly type: "set_viewport";
|
|
75
131
|
readonly payload: ChalkEmbeddedWhiteboardViewport;
|
|
@@ -117,6 +173,35 @@ export type ChalkEmbeddedWhiteboardRendererMessage = {
|
|
|
117
173
|
readonly x: number;
|
|
118
174
|
readonly y: number;
|
|
119
175
|
};
|
|
176
|
+
} | {
|
|
177
|
+
readonly type: "view";
|
|
178
|
+
readonly payload: WhiteboardView & {
|
|
179
|
+
readonly requestId: string;
|
|
180
|
+
};
|
|
181
|
+
} | {
|
|
182
|
+
readonly type: "notice";
|
|
183
|
+
readonly payload: ChalkEmbeddedBoardNotice | null;
|
|
184
|
+
} | {
|
|
185
|
+
readonly type: "follow";
|
|
186
|
+
readonly payload: {
|
|
187
|
+
readonly participantId: string | null;
|
|
188
|
+
};
|
|
189
|
+
} | {
|
|
190
|
+
readonly type: "set_draw_policy";
|
|
191
|
+
readonly payload: {
|
|
192
|
+
readonly requestId: string;
|
|
193
|
+
readonly policy: WhoCanDraw["policy"];
|
|
194
|
+
};
|
|
195
|
+
} | {
|
|
196
|
+
readonly type: "set_draw_permission";
|
|
197
|
+
readonly payload: {
|
|
198
|
+
readonly requestId: string;
|
|
199
|
+
readonly participantId: string;
|
|
200
|
+
readonly canDraw: boolean;
|
|
201
|
+
};
|
|
202
|
+
} | {
|
|
203
|
+
readonly type: "close_board";
|
|
204
|
+
readonly payload: {};
|
|
120
205
|
} | {
|
|
121
206
|
readonly type: "camera";
|
|
122
207
|
readonly payload: {
|
|
@@ -157,6 +242,7 @@ export type ChalkEmbeddedWhiteboardRendererMessage = {
|
|
|
157
242
|
readonly format: "png" | "svg";
|
|
158
243
|
readonly mimeType: string;
|
|
159
244
|
readonly dataURL: string;
|
|
245
|
+
readonly action?: "download" | "copy";
|
|
160
246
|
};
|
|
161
247
|
} | {
|
|
162
248
|
readonly type: "metric";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { WhiteboardView } from "../collab/view.js";
|
|
1
2
|
import type { WhiteboardCommit } from "../collab/wire.js";
|
|
2
3
|
import { type ChalkEmbeddedWhiteboardHostEnvelope, type ChalkEmbeddedWhiteboardRendererMessage } from "./protocol.js";
|
|
3
4
|
declare global {
|
|
@@ -20,7 +21,16 @@ export declare class ChalkEmbeddedWhiteboardRendererBridge {
|
|
|
20
21
|
readonly syncAll: boolean;
|
|
21
22
|
readonly elements: readonly import("../collab/wire").WhiteboardWireElement[];
|
|
22
23
|
}): Promise<WhiteboardCommit>;
|
|
24
|
+
sendView(view: WhiteboardView): Promise<boolean>;
|
|
25
|
+
exportImage(payload: {
|
|
26
|
+
readonly format: "png";
|
|
27
|
+
readonly mimeType: "image/png";
|
|
28
|
+
readonly dataURL: string;
|
|
29
|
+
readonly action: "download" | "copy";
|
|
30
|
+
}): Promise<void>;
|
|
23
31
|
requestSnapshot(): Promise<void>;
|
|
32
|
+
setDrawPolicy(policy: import("../react/board/board-draw-policy").WhoCanDraw["policy"]): Promise<void>;
|
|
33
|
+
setDrawPermission(participantId: string, canDraw: boolean): Promise<void>;
|
|
24
34
|
clear(): Promise<WhiteboardCommit>;
|
|
25
35
|
downloadFile(fileId: string): Promise<{
|
|
26
36
|
readonly mimeType: string;
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { WhiteboardCollaborationEvent } from "../collab/engine.js";
|
|
2
2
|
import { ChalkEmbeddedWhiteboardRendererBridge } from "./renderer-bridge.js";
|
|
3
|
-
declare global {
|
|
4
|
-
interface Window {
|
|
5
|
-
EXCALIDRAW_ASSET_PATH?: string;
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
3
|
export declare function createCollaborationBridge(rendererBridge: ChalkEmbeddedWhiteboardRendererBridge): {
|
|
9
4
|
submitUpdate: (payload: Parameters<ChalkEmbeddedWhiteboardRendererBridge["submitUpdate"]>[0]) => Promise<import("..").WhiteboardCommit>;
|
|
10
5
|
sendCursor: ({ x, y }: {
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { WhiteboardView as ChalkWhiteboardView } from "../../collab/view.js";
|
|
2
|
+
import type { WhiteboardCanvasProps } from "../WhiteboardCanvas.js";
|
|
3
|
+
import type { WhiteboardViewBounds } from "../../collab/view.js";
|
|
4
|
+
import type { ReactNode } from "react";
|
|
5
|
+
import { type CallTheme } from "./board-model.js";
|
|
6
|
+
import type { WhoCanDraw } from "./board-draw-policy.js";
|
|
7
|
+
export type BoardProps = {
|
|
8
|
+
readonly board: Omit<WhiteboardCanvasProps, "classNames" | "icons">;
|
|
9
|
+
readonly isHost: boolean;
|
|
10
|
+
readonly connectionStatus: string;
|
|
11
|
+
readonly sceneId: string | null;
|
|
12
|
+
readonly sceneStatus: string;
|
|
13
|
+
readonly ownParticipantId: string | null;
|
|
14
|
+
readonly viewBounds: WhiteboardViewBounds;
|
|
15
|
+
readonly participantIds?: readonly string[];
|
|
16
|
+
readonly whoCanDraw?: WhoCanDraw;
|
|
17
|
+
readonly renderCursorAvatar?: (name: string) => ReactNode;
|
|
18
|
+
readonly onExport?: (image: Blob, action: "download" | "copy") => Promise<void>;
|
|
19
|
+
/** False for the Grid tile: the live drawing with no controls. */
|
|
20
|
+
readonly primary: boolean;
|
|
21
|
+
readonly visible: boolean;
|
|
22
|
+
readonly phone?: boolean;
|
|
23
|
+
readonly landscapeControlsVisible?: boolean;
|
|
24
|
+
readonly presentation?: "web" | "mobile";
|
|
25
|
+
readonly colorScheme: CallTheme;
|
|
26
|
+
readonly people: readonly {
|
|
27
|
+
readonly id: string;
|
|
28
|
+
readonly displayName: string;
|
|
29
|
+
}[];
|
|
30
|
+
readonly following: string | null;
|
|
31
|
+
readonly onFollow: (participantId: string | null) => void;
|
|
32
|
+
/** Absent, or answering false, when the board service does not share views. */
|
|
33
|
+
readonly sendView?: (view: ChalkWhiteboardView) => boolean | Promise<boolean>;
|
|
34
|
+
readonly downloadLabel?: string;
|
|
35
|
+
readonly onClose?: () => void;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Chalk's board: Excalidraw draws, and every control around it is the call's own. Each person picks their own
|
|
39
|
+
* surface and island place; the drawing, the cursors and the views are shared.
|
|
40
|
+
*/
|
|
41
|
+
export declare function Board({ board, primary, visible, colorScheme, people, following, onFollow, sendView, onClose, isHost, connectionStatus, sceneId, sceneStatus, ownParticipantId, participantIds, whoCanDraw, viewBounds, renderCursorAvatar, onExport, phone: phoneOverride, downloadLabel, presentation, landscapeControlsVisible, }: BoardProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type MutableRefObject } from "react";
|
|
2
|
+
import type { ReactNode } from "react";
|
|
3
|
+
import { type Camera } from "./board-model.js";
|
|
4
|
+
export type RemoteCursor = {
|
|
5
|
+
readonly participantId: string;
|
|
6
|
+
readonly displayName: string;
|
|
7
|
+
readonly x: number;
|
|
8
|
+
readonly y: number;
|
|
9
|
+
readonly occurredAt: string;
|
|
10
|
+
};
|
|
11
|
+
/** Pruning belongs to receipt too: grid boards do not mount the cursor layer. */
|
|
12
|
+
export declare function rememberCursor(cursors: Map<string, RemoteCursor>, cursor: RemoteCursor): void;
|
|
13
|
+
/**
|
|
14
|
+
* Remote people's cursors over the board: a rounded arrow, the Facehash and the name, in the person's colour.
|
|
15
|
+
* Updates arrive about 15 times a second and unevenly, so each shown cursor is a spring chasing the newest one.
|
|
16
|
+
*/
|
|
17
|
+
export declare function BoardCursors({ cursorsRef, cameraRef, colorFor, hidden, renderAvatar, }: {
|
|
18
|
+
readonly cursorsRef: MutableRefObject<Map<string, RemoteCursor>>;
|
|
19
|
+
readonly cameraRef: MutableRefObject<Camera>;
|
|
20
|
+
readonly colorFor: (participantId: string) => string;
|
|
21
|
+
readonly hidden: boolean;
|
|
22
|
+
readonly renderAvatar?: (name: string) => ReactNode;
|
|
23
|
+
}): import("react").JSX.Element;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
declare const GLYPHS: {
|
|
2
|
+
readonly select: import("react").JSX.Element;
|
|
3
|
+
readonly hand: import("react").JSX.Element;
|
|
4
|
+
readonly pen: import("react").JSX.Element;
|
|
5
|
+
readonly highlighter: import("react").JSX.Element;
|
|
6
|
+
readonly rectangle: import("react").JSX.Element;
|
|
7
|
+
readonly ellipse: import("react").JSX.Element;
|
|
8
|
+
readonly diamond: import("react").JSX.Element;
|
|
9
|
+
readonly arrow: import("react").JSX.Element;
|
|
10
|
+
readonly line: import("react").JSX.Element;
|
|
11
|
+
readonly text: import("react").JSX.Element;
|
|
12
|
+
readonly note: import("react").JSX.Element;
|
|
13
|
+
readonly eraser: import("react").JSX.Element;
|
|
14
|
+
readonly laser: import("react").JSX.Element;
|
|
15
|
+
readonly undo: import("react").JSX.Element;
|
|
16
|
+
readonly redo: import("react").JSX.Element;
|
|
17
|
+
readonly minus: import("react").JSX.Element;
|
|
18
|
+
readonly plus: import("react").JSX.Element;
|
|
19
|
+
readonly fit: import("react").JSX.Element;
|
|
20
|
+
readonly download: import("react").JSX.Element;
|
|
21
|
+
readonly copy: import("react").JSX.Element;
|
|
22
|
+
readonly trash: import("react").JSX.Element;
|
|
23
|
+
readonly close: import("react").JSX.Element;
|
|
24
|
+
readonly check: import("react").JSX.Element;
|
|
25
|
+
readonly target: import("react").JSX.Element;
|
|
26
|
+
readonly eye: import("react").JSX.Element;
|
|
27
|
+
readonly wifiOff: import("react").JSX.Element;
|
|
28
|
+
readonly lock: import("react").JSX.Element;
|
|
29
|
+
readonly more: import("react").JSX.Element;
|
|
30
|
+
readonly chevron: import("react").JSX.Element;
|
|
31
|
+
};
|
|
32
|
+
export type BoardGlyph = keyof typeof GLYPHS;
|
|
33
|
+
export declare function BoardIcon({ name, size, className }: {
|
|
34
|
+
readonly name: BoardGlyph;
|
|
35
|
+
readonly size?: number;
|
|
36
|
+
readonly className?: string;
|
|
37
|
+
}): import("react").JSX.Element;
|
|
38
|
+
/** Six dots in two columns: the island's drag handle. */
|
|
39
|
+
export declare function GripIcon({ className }: {
|
|
40
|
+
readonly className?: string;
|
|
41
|
+
}): import("react").JSX.Element;
|
|
42
|
+
/** The remote cursor: a rounded arrow with a white outline, filled in the person's colour. */
|
|
43
|
+
export declare function CursorArrow({ color }: {
|
|
44
|
+
readonly color: string;
|
|
45
|
+
}): import("react").JSX.Element;
|
|
46
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type BoardSurface, type BoardTool, type CallTheme, type IslandPlace, type PenColor, type PenWidth, type ShapeTool } from "./board-model.js";
|
|
2
|
+
export type IslandProps = {
|
|
3
|
+
readonly tool: BoardTool;
|
|
4
|
+
readonly shape: ShapeTool;
|
|
5
|
+
readonly onTool: (tool: BoardTool) => void;
|
|
6
|
+
readonly color: PenColor;
|
|
7
|
+
readonly width: PenWidth;
|
|
8
|
+
readonly onColor: (color: PenColor) => void;
|
|
9
|
+
readonly onWidth: (width: PenWidth) => void;
|
|
10
|
+
readonly surface: BoardSurface;
|
|
11
|
+
readonly theme: CallTheme;
|
|
12
|
+
readonly canUndo: boolean;
|
|
13
|
+
readonly canRedo: boolean;
|
|
14
|
+
readonly onUndo: () => void;
|
|
15
|
+
readonly onRedo: () => void;
|
|
16
|
+
readonly place: IslandPlace;
|
|
17
|
+
readonly onPlace: (place: IslandPlace, announce: boolean) => void;
|
|
18
|
+
readonly compact: boolean;
|
|
19
|
+
readonly primaryToolsFirst?: boolean;
|
|
20
|
+
};
|
|
21
|
+
/** The tool island: a pill of tools that docks at the bottom, the top or the left, or one pen button when compact. */
|
|
22
|
+
export declare function BoardIsland(props: IslandProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { WhoCanDraw } from "./board-draw-policy.js";
|
|
2
|
+
import { type BoardSurface, type IslandPlace } from "./board-model.js";
|
|
3
|
+
export type BoardMenuProps = {
|
|
4
|
+
readonly presentation?: "web" | "mobile";
|
|
5
|
+
readonly surface: BoardSurface;
|
|
6
|
+
readonly onSurface: (surface: BoardSurface) => void;
|
|
7
|
+
/** Offered outside a phone, to people who can draw. */
|
|
8
|
+
readonly place?: IslandPlace;
|
|
9
|
+
readonly onPlace: (place: IslandPlace) => void;
|
|
10
|
+
readonly downloadLabel?: string;
|
|
11
|
+
readonly onDownload: () => void;
|
|
12
|
+
readonly onCopy: () => void;
|
|
13
|
+
/** Offered to hosts. */
|
|
14
|
+
readonly whoCanDraw?: WhoCanDraw;
|
|
15
|
+
readonly onBring?: () => void;
|
|
16
|
+
readonly onClear?: () => void;
|
|
17
|
+
readonly onClose?: () => void;
|
|
18
|
+
};
|
|
19
|
+
/** The board's own menu: export, the person's own appearance, and the host's board actions. */
|
|
20
|
+
export declare function BoardMenu({ surface, onSurface, place, onPlace, onDownload, onCopy, whoCanDraw, onBring, onClear, onClose, downloadLabel, presentation }: BoardMenuProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type WhoCanDraw = {
|
|
2
|
+
readonly policy: "everyone" | "hosts" | "picked";
|
|
3
|
+
readonly people: readonly {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly name: string;
|
|
6
|
+
readonly picked: boolean;
|
|
7
|
+
}[];
|
|
8
|
+
readonly onPolicy: (policy: WhoCanDraw["policy"]) => void;
|
|
9
|
+
readonly onPick: (id: string, picked: boolean) => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { WhiteboardEngineHandle } from "../WhiteboardCanvas.js";
|
|
2
|
+
import { type BoardSurface, type BoardTool, type CallTheme, type Camera, type PenColor, type PenWidth } from "./board-model.js";
|
|
3
|
+
/** The pen the person has chosen, and the surface it is drawn on. */
|
|
4
|
+
export type PenChoice = {
|
|
5
|
+
readonly color: PenColor;
|
|
6
|
+
readonly width: PenWidth;
|
|
7
|
+
readonly surface: BoardSurface;
|
|
8
|
+
readonly theme: CallTheme;
|
|
9
|
+
};
|
|
10
|
+
export declare function applyTool(engine: WhiteboardEngineHandle, tool: BoardTool, pen: PenChoice): void;
|
|
11
|
+
type PenChanges = {
|
|
12
|
+
readonly color?: PenColor;
|
|
13
|
+
readonly width?: PenWidth;
|
|
14
|
+
};
|
|
15
|
+
/** A colour or width change applies to what is selected, as well as to the next stroke. */
|
|
16
|
+
export declare function restyleSelection(engine: WhiteboardEngineHandle, pen: PenChoice, changes: PenChanges): boolean;
|
|
17
|
+
/** Places a plain sticky note centred on the board point and opens its text at once. */
|
|
18
|
+
export declare function placeNote(engine: WhiteboardEngineHandle, container: HTMLElement, point: {
|
|
19
|
+
readonly x: number;
|
|
20
|
+
readonly y: number;
|
|
21
|
+
}, color: PenColor): void;
|
|
22
|
+
/** Text written in a note sits at its top left, like the mockup's notes. */
|
|
23
|
+
export declare function settleNoteText(engine: WhiteboardEngineHandle): void;
|
|
24
|
+
/** Undo and redo have no engine call, so the board presses the engine's own keys. */
|
|
25
|
+
export declare function pressHistory(container: HTMLElement, redo: boolean): void;
|
|
26
|
+
export declare function readCamera(engine: WhiteboardEngineHandle): Camera;
|
|
27
|
+
export declare function setCamera(engine: WhiteboardEngineHandle, camera: Camera): void;
|
|
28
|
+
export declare function boardImage(engine: WhiteboardEngineHandle, background: string): Promise<Blob>;
|
|
29
|
+
export declare function sceneSignature(engine: WhiteboardEngineHandle): number;
|
|
30
|
+
export {};
|