@scrawl-board/board 0.1.0-beta.7 → 0.1.0-beta.8
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/README.md +11 -7
- package/dist/browser.d.ts +340 -21
- package/dist/browser.js +1536 -35811
- package/dist/core.d.ts +115 -30
- package/dist/core.js +260 -124
- package/dist/index.d.ts +454 -35
- package/dist/index.js +1627 -35810
- package/dist/local.d.ts +469 -0
- package/dist/local.js +234 -0
- package/dist/react.d.ts +369 -21
- package/dist/react.js +1377 -35736
- package/package.json +17 -3
package/dist/react.d.ts
CHANGED
|
@@ -155,6 +155,21 @@ interface CustomObjectDefinition<Props extends JsonValue = JsonValue> {
|
|
|
155
155
|
/** One pure, synchronous step per consecutive schema version. */
|
|
156
156
|
migrate?: Readonly<Record<number, (oldProps: JsonValue) => JsonValue>>;
|
|
157
157
|
describe(object: ReadonlyCustomObject<Props>, context: ObjectDescribeContext): BoardScene;
|
|
158
|
+
/**
|
|
159
|
+
* Optional point-level hit-test precision (Phase 8). Every custom object
|
|
160
|
+
* hit-tests against its bounding box (`fallback.bounds`) by default — this
|
|
161
|
+
* lets a non-rectangular shape (e.g. a circular card, an L-shaped region)
|
|
162
|
+
* reject a point that's inside that box but outside its actual visible
|
|
163
|
+
* silhouette, tightening a click/marquee/raycast hit to the shape's real
|
|
164
|
+
* outline. `point` is in this object's own local space — the same
|
|
165
|
+
* untransformed space `describe`'s returned geometry already lives in
|
|
166
|
+
* (the caller inverse-transforms the pointer's board point through
|
|
167
|
+
* `object.transform` before calling this). Absent means every point
|
|
168
|
+
* inside the bounding box hits, matching pre-Phase-8 behavior exactly.
|
|
169
|
+
* Rejecting a point here does not fall through to whatever's underneath —
|
|
170
|
+
* the gesture simply misses this object, same as clicking empty space.
|
|
171
|
+
*/
|
|
172
|
+
hitTest?(object: ReadonlyCustomObject<Props>, point: BoardPoint): boolean;
|
|
158
173
|
}
|
|
159
174
|
interface SceneNodeBase {
|
|
160
175
|
key: string;
|
|
@@ -188,6 +203,15 @@ interface SceneGroup extends SceneNodeBase {
|
|
|
188
203
|
kind: "group";
|
|
189
204
|
children: readonly BoardScene[];
|
|
190
205
|
}
|
|
206
|
+
/**
|
|
207
|
+
* **No renderer or SVG-export interpreter exists for this node kind yet**
|
|
208
|
+
* (tracked as deferred work — see `renderer/shapes/customObjects.ts`'s
|
|
209
|
+
* `"path"` case). Returning a `ScenePath` from `describe()` renders nothing,
|
|
210
|
+
* exports nothing, and contributes no hit-test bounds — it neither errors
|
|
211
|
+
* nor emits a diagnostic. Until an interpreter ships, build custom shapes
|
|
212
|
+
* from `SceneRect`/`SceneEllipse`/`SceneGroup`/`SceneText`/`SceneImage`
|
|
213
|
+
* instead.
|
|
214
|
+
*/
|
|
191
215
|
interface ScenePath extends SceneNodeBase {
|
|
192
216
|
kind: "path";
|
|
193
217
|
/** SVG-style path data, board-local coordinates. */
|
|
@@ -343,8 +367,23 @@ interface Lockable {
|
|
|
343
367
|
lockedByName?: string;
|
|
344
368
|
}
|
|
345
369
|
|
|
370
|
+
/**
|
|
371
|
+
* Per-object visibility (Phase 8) — mirrors `itemLock.ts`'s `Lockable`
|
|
372
|
+
* pattern exactly, but simpler: unlike a lock, hidden state carries no
|
|
373
|
+
* holder/ownership concept, so there's no analogue to `LockHolder`/
|
|
374
|
+
* `canUnlockItem`. A hidden object stays fully present in the Document
|
|
375
|
+
* (still serializes, persists, syncs, undoes/redoes) — it just skips
|
|
376
|
+
* rendering and hit-testing/selection candidacy. `hidden` absent or
|
|
377
|
+
* `false` means visible; this keeps every pre-Phase-8 document (which has
|
|
378
|
+
* no `hidden` field on any object at all) implicitly fully visible with
|
|
379
|
+
* zero migration needed.
|
|
380
|
+
*/
|
|
381
|
+
interface Hideable {
|
|
382
|
+
hidden?: boolean;
|
|
383
|
+
}
|
|
384
|
+
|
|
346
385
|
/** A kitchen timer sitting on the board. Remaining time is derived, not ticked. */
|
|
347
|
-
interface KitchenTimer extends Lockable {
|
|
386
|
+
interface KitchenTimer extends Lockable, Hideable {
|
|
348
387
|
id: string;
|
|
349
388
|
x: number;
|
|
350
389
|
y: number;
|
|
@@ -358,7 +397,7 @@ interface KitchenTimer extends Lockable {
|
|
|
358
397
|
runningSince?: number;
|
|
359
398
|
}
|
|
360
399
|
|
|
361
|
-
interface RectangleObject extends Lockable {
|
|
400
|
+
interface RectangleObject extends Lockable, Hideable {
|
|
362
401
|
id: string;
|
|
363
402
|
x: number;
|
|
364
403
|
y: number;
|
|
@@ -380,7 +419,7 @@ interface RectangleObject extends Lockable {
|
|
|
380
419
|
*/
|
|
381
420
|
rotation?: number;
|
|
382
421
|
}
|
|
383
|
-
interface EllipseObject extends Lockable {
|
|
422
|
+
interface EllipseObject extends Lockable, Hideable {
|
|
384
423
|
id: string;
|
|
385
424
|
x: number;
|
|
386
425
|
y: number;
|
|
@@ -396,7 +435,7 @@ interface EllipseObject extends Lockable {
|
|
|
396
435
|
}
|
|
397
436
|
/** `"none"` is a plain line with no arrowhead; today's only real head shape is `"triangle"`. New head shapes extend this union without touching `ArrowObject`'s own fields. */
|
|
398
437
|
type ArrowHeadStyle = "triangle" | "none";
|
|
399
|
-
interface LineObject extends Lockable {
|
|
438
|
+
interface LineObject extends Lockable, Hideable {
|
|
400
439
|
id: string;
|
|
401
440
|
start: BoardPoint;
|
|
402
441
|
end: BoardPoint;
|
|
@@ -404,7 +443,7 @@ interface LineObject extends Lockable {
|
|
|
404
443
|
strokeWidth?: number;
|
|
405
444
|
opacity?: number;
|
|
406
445
|
}
|
|
407
|
-
interface ArrowObject extends Lockable {
|
|
446
|
+
interface ArrowObject extends Lockable, Hideable {
|
|
408
447
|
id: string;
|
|
409
448
|
start: BoardPoint;
|
|
410
449
|
end: BoardPoint;
|
|
@@ -423,7 +462,7 @@ interface ArrowObject extends Lockable {
|
|
|
423
462
|
* `polygonStartAngle`, which encodes each side count's own vertex
|
|
424
463
|
* orientation so the outline always matches the legacy drag-preview shape.
|
|
425
464
|
*/
|
|
426
|
-
interface PolygonObject extends Lockable {
|
|
465
|
+
interface PolygonObject extends Lockable, Hideable {
|
|
427
466
|
id: string;
|
|
428
467
|
x: number;
|
|
429
468
|
y: number;
|
|
@@ -438,7 +477,7 @@ interface PolygonObject extends Lockable {
|
|
|
438
477
|
rotation?: number;
|
|
439
478
|
}
|
|
440
479
|
/** Same bounding-box/rotation convention as Rectangle; a 5-pointed star with a tuned inner-radius ratio, matching the legacy tool's own default (see `polygonGeometry.ts`'s `starPoints`). */
|
|
441
|
-
interface StarObject extends Lockable {
|
|
480
|
+
interface StarObject extends Lockable, Hideable {
|
|
442
481
|
id: string;
|
|
443
482
|
x: number;
|
|
444
483
|
y: number;
|
|
@@ -455,7 +494,7 @@ interface StarObject extends Lockable {
|
|
|
455
494
|
rotation?: number;
|
|
456
495
|
}
|
|
457
496
|
/** Same bounding-box/rotation convention as Rectangle; the standard parametric heart curve (see `polygonGeometry.ts`'s `heartPoints`), no extra parameters beyond the shared shape fields. */
|
|
458
|
-
interface HeartObject extends Lockable {
|
|
497
|
+
interface HeartObject extends Lockable, Hideable {
|
|
459
498
|
id: string;
|
|
460
499
|
x: number;
|
|
461
500
|
y: number;
|
|
@@ -480,7 +519,7 @@ interface HeartObject extends Lockable {
|
|
|
480
519
|
* a group into its leaf members is always done by the caller (recursively,
|
|
481
520
|
* with cycle protection), never assumed here.
|
|
482
521
|
*/
|
|
483
|
-
interface GroupObject extends Lockable {
|
|
522
|
+
interface GroupObject extends Lockable, Hideable {
|
|
484
523
|
id: string;
|
|
485
524
|
children: string[];
|
|
486
525
|
}
|
|
@@ -505,7 +544,7 @@ interface StrokePoint extends BoardPoint {
|
|
|
505
544
|
* geometric outline, not an expressive ink mark.
|
|
506
545
|
*/
|
|
507
546
|
type StrokeTool = "marker" | "highlighter" | "shape";
|
|
508
|
-
interface Stroke extends Lockable {
|
|
547
|
+
interface Stroke extends Lockable, Hideable {
|
|
509
548
|
id: string;
|
|
510
549
|
color: string;
|
|
511
550
|
baseWidth: number;
|
|
@@ -521,7 +560,7 @@ interface Stroke extends Lockable {
|
|
|
521
560
|
clusterId?: string;
|
|
522
561
|
}
|
|
523
562
|
type SerializedPoint = [number, number, number, number];
|
|
524
|
-
interface SerializedStroke extends Lockable {
|
|
563
|
+
interface SerializedStroke extends Lockable, Hideable {
|
|
525
564
|
id: string;
|
|
526
565
|
color: string;
|
|
527
566
|
baseWidth: number;
|
|
@@ -585,7 +624,7 @@ interface NoteVote {
|
|
|
585
624
|
* A sticky note: content floating above the board at a z-offset (pillar 3 —
|
|
586
625
|
* depth as an organizational axis). Center position in board space.
|
|
587
626
|
*/
|
|
588
|
-
interface StickyNote extends Lockable {
|
|
627
|
+
interface StickyNote extends Lockable, Hideable {
|
|
589
628
|
id: string;
|
|
590
629
|
x: number;
|
|
591
630
|
y: number;
|
|
@@ -603,7 +642,7 @@ interface StickyNote extends Lockable {
|
|
|
603
642
|
* top-left corner; lines flow downward (-y). Text joins the clustering
|
|
604
643
|
* system like handwriting (build prompt §6.4).
|
|
605
644
|
*/
|
|
606
|
-
interface TextBlock extends Lockable {
|
|
645
|
+
interface TextBlock extends Lockable, Hideable {
|
|
607
646
|
id: string;
|
|
608
647
|
x: number;
|
|
609
648
|
y: number;
|
|
@@ -617,7 +656,7 @@ interface TextBlock extends Lockable {
|
|
|
617
656
|
* Interactive structured table on the board. Position (x, y) is top-left in board units.
|
|
618
657
|
* Cells are indexed as `${row},${col}` keys mapping to cell text content.
|
|
619
658
|
*/
|
|
620
|
-
interface TableBlock extends Lockable {
|
|
659
|
+
interface TableBlock extends Lockable, Hideable {
|
|
621
660
|
id: string;
|
|
622
661
|
x: number;
|
|
623
662
|
y: number;
|
|
@@ -634,7 +673,7 @@ interface TableBlock extends Lockable {
|
|
|
634
673
|
* An imported image block on the board plane.
|
|
635
674
|
* Coordinates (x, y) represent the center of the image in board space.
|
|
636
675
|
*/
|
|
637
|
-
interface ImageBlock extends Lockable {
|
|
676
|
+
interface ImageBlock extends Lockable, Hideable {
|
|
638
677
|
id: string;
|
|
639
678
|
/**
|
|
640
679
|
* A legacy, read-only data URL (or, historically, an arbitrary string) —
|
|
@@ -845,6 +884,8 @@ interface BoardEventMap {
|
|
|
845
884
|
"asset-diagnostic": AssetDiagnostic;
|
|
846
885
|
/** A batch of Ops was reconciled (not applied as-sent) by the persistence adapter (ticket #24). */
|
|
847
886
|
"persistence-diagnostic": PersistenceDiagnostic;
|
|
887
|
+
/** The collaboration server has confirmed receipt of these op ids (Phase 7) — observability only; the Document was already correct via optimistic local apply before this ever fires. */
|
|
888
|
+
"collaboration-ops-acknowledged": CollaborationAckDiagnostic;
|
|
848
889
|
audit: unknown;
|
|
849
890
|
error: BoardControllerError;
|
|
850
891
|
disposed: undefined;
|
|
@@ -908,9 +949,12 @@ interface PresenceView {
|
|
|
908
949
|
readonly height: number;
|
|
909
950
|
}
|
|
910
951
|
/**
|
|
911
|
-
* A
|
|
912
|
-
*
|
|
913
|
-
*
|
|
952
|
+
* A collaborator, synced in for cursor/roster rendering only. Presence is
|
|
953
|
+
* ephemeral — it never touches the Document, Ops, undo/redo, or persistence
|
|
954
|
+
* (ADR 0006/0007). Two ways a roster gets populated (`presence.sync`
|
|
955
|
+
* directly, or a `CollaborationAdapter`'s optional presence channel —
|
|
956
|
+
* Phase 6, ADR 0015) both feed the exact same read/query capability below;
|
|
957
|
+
* a Host picks one, not both, for a given controller.
|
|
914
958
|
*/
|
|
915
959
|
interface PresenceUser {
|
|
916
960
|
readonly id: string;
|
|
@@ -919,6 +963,14 @@ interface PresenceUser {
|
|
|
919
963
|
readonly tool?: string;
|
|
920
964
|
readonly cursor?: PresenceCursor;
|
|
921
965
|
readonly view?: PresenceView;
|
|
966
|
+
/** Host-supplied extras (avatar URL, role, etc.) — opaque to Scrawl, never interpreted. */
|
|
967
|
+
readonly metadata?: Record<string, unknown>;
|
|
968
|
+
}
|
|
969
|
+
/** This client's own local presence, published via `presence.broadcast()` (Phase 6). */
|
|
970
|
+
interface LocalPresence {
|
|
971
|
+
readonly cursor?: PresenceCursor | null;
|
|
972
|
+
readonly view?: PresenceView | null;
|
|
973
|
+
readonly tool?: string;
|
|
922
974
|
}
|
|
923
975
|
/**
|
|
924
976
|
* The Custom arm wraps `CustomBoardObject` under the same `type` discriminant
|
|
@@ -1044,10 +1096,34 @@ type LoadResult = {
|
|
|
1044
1096
|
} | {
|
|
1045
1097
|
state: "missing";
|
|
1046
1098
|
};
|
|
1099
|
+
/**
|
|
1100
|
+
* Result of a whole-document `PersistenceAdapter.replace()` call (ADR 0006:
|
|
1101
|
+
* "Whole-document writes survive only for create, clear-board and import,
|
|
1102
|
+
* where replacing everything is the actual intent"). Revision-gated, unlike
|
|
1103
|
+
* `applyOps` — `conflict` means `baseRevision` was stale (someone else's
|
|
1104
|
+
* write landed first); the caller must reload and never overwrites blind.
|
|
1105
|
+
*/
|
|
1106
|
+
type ReplaceResult = {
|
|
1107
|
+
state: "applied";
|
|
1108
|
+
revision: string;
|
|
1109
|
+
} | {
|
|
1110
|
+
state: "conflict";
|
|
1111
|
+
currentRevision: string;
|
|
1112
|
+
};
|
|
1113
|
+
/**
|
|
1114
|
+
* The one sanctioned seam for persisting a Board's Document to a Host's own
|
|
1115
|
+
* storage — implement this against a database, an HTTP API, IndexedDB
|
|
1116
|
+
* (see `@scrawl-board/board/local`'s `createIndexedDBPersistence`), or
|
|
1117
|
+
* anything else. `load()` fetches the current state on connect; `applyOps()`
|
|
1118
|
+
* streams incremental Ops as edits happen; `replace()` is only for
|
|
1119
|
+
* whole-document writes (create, clear-board, import — see ADR 0006) and is
|
|
1120
|
+
* revision-gated so a stale write never silently clobbers a newer one.
|
|
1121
|
+
* Passed via `createBoardController({ adapters: { persistence } })`.
|
|
1122
|
+
*/
|
|
1047
1123
|
interface PersistenceAdapter {
|
|
1048
1124
|
load(context: DocumentContext): Promise<LoadResult>;
|
|
1049
1125
|
applyOps(context: DocumentContext, ops: readonly ControllerOp[]): Promise<ApplyOpsResult>;
|
|
1050
|
-
replace(context: DocumentContext, document: CurrentSerializedDocument, baseRevision: string): Promise<
|
|
1126
|
+
replace(context: DocumentContext, document: CurrentSerializedDocument, baseRevision: string): Promise<ReplaceResult>;
|
|
1051
1127
|
}
|
|
1052
1128
|
/**
|
|
1053
1129
|
* `"reconcile"` (ticket #24) means the server authoritatively resolved the
|
|
@@ -1071,6 +1147,10 @@ interface PersistenceDiagnostic {
|
|
|
1071
1147
|
rejectedOpIds: readonly string[];
|
|
1072
1148
|
revision: string;
|
|
1073
1149
|
}
|
|
1150
|
+
/** Emitted as `"collaboration-ops-acknowledged"` (Phase 7) — the server has confirmed receipt of these op ids on the live pipe. */
|
|
1151
|
+
interface CollaborationAckDiagnostic {
|
|
1152
|
+
opIds: readonly string[];
|
|
1153
|
+
}
|
|
1074
1154
|
interface ControllerOp {
|
|
1075
1155
|
id: string;
|
|
1076
1156
|
schemaVersion: 1;
|
|
@@ -1087,7 +1167,39 @@ interface ControllerOp {
|
|
|
1087
1167
|
| "order";
|
|
1088
1168
|
objectId: string;
|
|
1089
1169
|
payload?: unknown;
|
|
1170
|
+
/**
|
|
1171
|
+
* This op's position in its own originating client's local sequence
|
|
1172
|
+
* (Phase 7) — 1, 2, 3, ... per controller instance, distinct from `id`
|
|
1173
|
+
* (an opaque, globally-unique identifier used for dedup/ack, not
|
|
1174
|
+
* ordering) and from a server's own authoritative ordering (e.g.
|
|
1175
|
+
* `referenceCollaborationServer.ts`'s per-room `version` counter).
|
|
1176
|
+
* Present on every op this SDK originates locally; a remote peer's op
|
|
1177
|
+
* carries whatever its own origin set, unchanged — never renumbered in
|
|
1178
|
+
* transit. Absent on an op minted by decoding the legacy wire envelope
|
|
1179
|
+
* (`scrawlOpEnvelope.ts`), which predates this field and has no
|
|
1180
|
+
* per-client sequence concept of its own.
|
|
1181
|
+
*/
|
|
1182
|
+
clientSequence?: number;
|
|
1183
|
+
/**
|
|
1184
|
+
* The `CollaboratorIdentity.id` of this op's originating client (Phase
|
|
1185
|
+
* 7) — set for every op this SDK originates locally when `identity` is
|
|
1186
|
+
* configured, omitted entirely otherwise (never sent as `undefined`).
|
|
1187
|
+
* The explicit foundation for a future per-author undo filter (a local
|
|
1188
|
+
* user's own undo should only ever touch their own ops) — no undo-stack
|
|
1189
|
+
* behavior itself changes this phase.
|
|
1190
|
+
*/
|
|
1191
|
+
clientId?: string;
|
|
1090
1192
|
}
|
|
1193
|
+
/**
|
|
1194
|
+
* The one sanctioned seam for real-time multiplayer — implement this against
|
|
1195
|
+
* a Host's own collaboration backend (WebSocket relay, CRDT server, etc.).
|
|
1196
|
+
* `connect()` is called once per controller with the local user's
|
|
1197
|
+
* `identity` and a `receive` callback the adapter invokes with incoming
|
|
1198
|
+
* Ops, presence updates, acks, and connection status; it resolves with a
|
|
1199
|
+
* `CollaborationSession` the controller uses to send local Ops and presence
|
|
1200
|
+
* back out. Passed via `createBoardController({ adapters: { collaboration } })`;
|
|
1201
|
+
* omit it entirely to run single-player.
|
|
1202
|
+
*/
|
|
1091
1203
|
interface CollaborationAdapter {
|
|
1092
1204
|
connect(options: DocumentContext & {
|
|
1093
1205
|
identity: CollaboratorIdentity;
|
|
@@ -1098,14 +1210,72 @@ interface CollaboratorIdentity {
|
|
|
1098
1210
|
id: string;
|
|
1099
1211
|
name: string;
|
|
1100
1212
|
color?: string;
|
|
1213
|
+
/** Host-supplied extras (avatar URL, role, etc.) — opaque to Scrawl, forwarded into any resulting `PresenceUser` unread and never interpreted. */
|
|
1214
|
+
metadata?: Record<string, unknown>;
|
|
1101
1215
|
}
|
|
1102
1216
|
interface CollaborationReceiver {
|
|
1103
1217
|
ops(ops: readonly ControllerOp[]): void;
|
|
1218
|
+
/**
|
|
1219
|
+
* The current presence roster (Phase 6, ADR 0015) — always a full
|
|
1220
|
+
* replacement, never a delta, matching `presence.sync`'s existing
|
|
1221
|
+
* semantics exactly (an adapter that aggregates wire deltas into a full
|
|
1222
|
+
* roster before calling this is the adapter's own job, not the
|
|
1223
|
+
* controller's). Required on this interface (not optional) because a
|
|
1224
|
+
* Host only ever *consumes* `CollaborationReceiver` — never implements
|
|
1225
|
+
* it — so adding a required method here cannot break an existing custom
|
|
1226
|
+
* `CollaborationAdapter`. An adapter with no presence support simply
|
|
1227
|
+
* never calls it.
|
|
1228
|
+
*/
|
|
1229
|
+
presence(users: readonly PresenceUser[]): void;
|
|
1230
|
+
/**
|
|
1231
|
+
* The server has confirmed receipt of these op ids (Phase 7) —
|
|
1232
|
+
* distinguishes "sent" from "server accepted," which `sendOps` alone
|
|
1233
|
+
* (fire-and-forget) cannot. Required for the same reason `presence` is:
|
|
1234
|
+
* Hosts only ever consume this interface, never implement it, so this
|
|
1235
|
+
* cannot break an existing custom `CollaborationAdapter`. An adapter with
|
|
1236
|
+
* no ack support simply never calls it — the collaboration pipe still
|
|
1237
|
+
* works exactly as it did before this existed, just without the
|
|
1238
|
+
* bookkeeping/observability this enables.
|
|
1239
|
+
*/
|
|
1240
|
+
acknowledged(opIds: readonly string[]): void;
|
|
1104
1241
|
status(state: "online" | "reconnecting" | "offline"): void;
|
|
1105
1242
|
error(cause: unknown): void;
|
|
1106
1243
|
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Result of `CollaborationSession.requestSync()` (Phase 7). `"ops"` means
|
|
1246
|
+
* the adapter's own live-pipe cache fully covered the gap since the
|
|
1247
|
+
* caller's last known revision — apply `ops` and the client is caught up,
|
|
1248
|
+
* no persistence reload needed. `"unavailable"` means it couldn't (gap too
|
|
1249
|
+
* large, server restarted, or the adapter has no retained history at all)
|
|
1250
|
+
* — the caller must fall back to a persistence-backed reload. This is a
|
|
1251
|
+
* best-effort *liveness* cache, deliberately never a durable source of
|
|
1252
|
+
* truth (ADR 0006's "collaboration is never a second source of document
|
|
1253
|
+
* truth" — see ADR 0015's own extension of that principle to presence,
|
|
1254
|
+
* now extended once more, the same way, to this).
|
|
1255
|
+
*/
|
|
1256
|
+
type CollaborationSyncResult = {
|
|
1257
|
+
state: "ops";
|
|
1258
|
+
ops: readonly ControllerOp[];
|
|
1259
|
+
serverRevision: string;
|
|
1260
|
+
} | {
|
|
1261
|
+
state: "unavailable";
|
|
1262
|
+
};
|
|
1107
1263
|
interface CollaborationSession {
|
|
1108
1264
|
sendOps(ops: readonly ControllerOp[]): void;
|
|
1265
|
+
/**
|
|
1266
|
+
* Publishes this client's own local presence (Phase 6, ADR 0015) —
|
|
1267
|
+
* best-effort, unordered, never persisted, never an Op. Optional: an
|
|
1268
|
+
* adapter that doesn't support presence simply omits this method, and
|
|
1269
|
+
* `presence.broadcast()` becomes a silent no-op.
|
|
1270
|
+
*/
|
|
1271
|
+
updatePresence?(presence: LocalPresence): void;
|
|
1272
|
+
/**
|
|
1273
|
+
* Requests an incremental catch-up after a reconnect (Phase 7) — optional;
|
|
1274
|
+
* an adapter that doesn't support this simply omits the method, and the
|
|
1275
|
+
* caller (`resyncAfterReconnect`) goes straight to its existing
|
|
1276
|
+
* persistence-backed full reload, unchanged from Phase 6.
|
|
1277
|
+
*/
|
|
1278
|
+
requestSync?(): Promise<CollaborationSyncResult>;
|
|
1109
1279
|
close(): Promise<void>;
|
|
1110
1280
|
}
|
|
1111
1281
|
interface CreateBoardControllerOptions {
|
|
@@ -1145,6 +1315,87 @@ interface CreateBoardControllerOptions {
|
|
|
1145
1315
|
* doesn't use the React theme system can set this directly instead.
|
|
1146
1316
|
*/
|
|
1147
1317
|
boardTheme?: BoardThemeOptions;
|
|
1318
|
+
/**
|
|
1319
|
+
* Debounced auto-flush of pending persistence Ops after document changes
|
|
1320
|
+
* settle (Phase 5). Enabled by default (1000ms debounce) whenever
|
|
1321
|
+
* `adapters.persistence` is configured — today, without this, a Host must
|
|
1322
|
+
* call `flush()` manually after every edit for anything to persist. Pass
|
|
1323
|
+
* `false` to opt out entirely and drive `flush()` yourself, preserving
|
|
1324
|
+
* prior behavior exactly. Never fires on a per-change basis — rapid edits
|
|
1325
|
+
* coalesce into one flush of their final state (ADR 0006).
|
|
1326
|
+
*/
|
|
1327
|
+
autosave?: boolean | {
|
|
1328
|
+
debounceMs?: number;
|
|
1329
|
+
};
|
|
1330
|
+
/**
|
|
1331
|
+
* Throttle for `presence.broadcast()` (Phase 6, ADR 0015) — the minimum
|
|
1332
|
+
* interval between outgoing presence updates sent via the configured
|
|
1333
|
+
* `CollaborationAdapter`. Defaults to 50ms. A trailing throttle: the
|
|
1334
|
+
* latest value passed to `broadcast()` always eventually sends, even if
|
|
1335
|
+
* calls arrive faster than this interval.
|
|
1336
|
+
*/
|
|
1337
|
+
presenceThrottleMs?: number;
|
|
1338
|
+
/**
|
|
1339
|
+
* Caps how many `ControllerOp`s can sit queued, unsent, for the
|
|
1340
|
+
* persistence pipe (`pendingOps`) or the collaboration pipe
|
|
1341
|
+
* (`pendingCollaborationOps`) at once (Phase 7) — each pipe is capped
|
|
1342
|
+
* independently. Prevents unbounded memory growth from a long-lived
|
|
1343
|
+
* offline session or a stuck adapter. Exceeding it never fails or drops
|
|
1344
|
+
* the local edit itself (the Document already applied it optimistically)
|
|
1345
|
+
* — only queueing for that one pipe is skipped, and a
|
|
1346
|
+
* `{code:"queue-overflow", retryable:false}` error is emitted so a Host
|
|
1347
|
+
* can react. Defaults to 1000 — the Phase 9 collaboration coalescing
|
|
1348
|
+
* above (`collaborationCoalesceMs`) already keeps a busy drag from
|
|
1349
|
+
* approaching this on its own, so hitting it in practice means a pipe
|
|
1350
|
+
* has been offline/stuck for a genuinely long editing session.
|
|
1351
|
+
*
|
|
1352
|
+
* **Recovery** (Phase 9): the dropped op itself is gone from that one
|
|
1353
|
+
* pipe's queue — there is no automatic backfill, and the live
|
|
1354
|
+
* controller keeps running with that pipe now silently missing one
|
|
1355
|
+
* edit. Two things stay true regardless: (1) the in-memory Document is
|
|
1356
|
+
* never affected — a queue-overflow can never corrupt or roll back a
|
|
1357
|
+
* local edit, only skip sending it; (2) staleness is per-object, not
|
|
1358
|
+
* permanent — any *later* edit to that same object produces a brand
|
|
1359
|
+
* new, undropped Op carrying its full current state, which naturally
|
|
1360
|
+
* supersedes the gap (the Op model is already last-write-wins/
|
|
1361
|
+
* idempotent, so a superseding Op doesn't need the earlier one to have
|
|
1362
|
+
* arrived). The real risk is an object that's dropped and never edited
|
|
1363
|
+
* again before the controller is disposed or the page reloads — a Host
|
|
1364
|
+
* that needs strict durability should treat `queue-overflow` as a
|
|
1365
|
+
* signal to check `persistence.state`/`pendingOps` pressure (via
|
|
1366
|
+
* `usePersistenceStatus`/`getSnapshot().connection.persistence`)
|
|
1367
|
+
* before disposing, not assume disposing and reconnecting alone
|
|
1368
|
+
* repairs the gap (a fresh `load()` only returns what the backend
|
|
1369
|
+
* already has, which is exactly what's missing the dropped edit).
|
|
1370
|
+
*/
|
|
1371
|
+
maxPendingOps?: number;
|
|
1372
|
+
/**
|
|
1373
|
+
* Coalescing window (ms) for outgoing collaboration Ops (Phase 9) — same
|
|
1374
|
+
* trailing-throttle shape as `presenceThrottleMs`: the first Op after an
|
|
1375
|
+
* idle period sends immediately, and subsequent Ops for the *same*
|
|
1376
|
+
* object within this window replace each other (latest value wins,
|
|
1377
|
+
* matching the already-idempotent Op model) rather than each triggering
|
|
1378
|
+
* its own send. A multi-second drag that previously sent one full Op per
|
|
1379
|
+
* pointer-move now sends at most one per window per touched object.
|
|
1380
|
+
* Persistence (`pendingOps`) is unaffected — it already debounces via
|
|
1381
|
+
* `autosave`, so this option only changes live collaboration traffic.
|
|
1382
|
+
* Defaults to 50ms.
|
|
1383
|
+
*/
|
|
1384
|
+
collaborationCoalesceMs?: number;
|
|
1385
|
+
/**
|
|
1386
|
+
* Caps how many resolved objects a single `content.copy`/`content.cut`
|
|
1387
|
+
* (or their Cmd/Ctrl+C/X keyboard equivalents) will hold in the
|
|
1388
|
+
* in-memory clipboard at once (Phase 9) — `expandSelection` recursively
|
|
1389
|
+
* expands groups, so an unbounded selection (a huge group, or thousands
|
|
1390
|
+
* of individually selected strokes) could otherwise clone and retain an
|
|
1391
|
+
* arbitrarily large snapshot indefinitely, until the next copy/cut
|
|
1392
|
+
* replaces it. Exceeding it rejects the whole copy/cut (nothing is
|
|
1393
|
+
* cloned, and — for cut — nothing is removed from the Document either,
|
|
1394
|
+
* never a partial copy of an arbitrary subset) and emits a
|
|
1395
|
+
* `{code:"clipboard-overflow", retryable:false}` error. Defaults to
|
|
1396
|
+
* 5000.
|
|
1397
|
+
*/
|
|
1398
|
+
maxClipboardItems?: number;
|
|
1148
1399
|
}
|
|
1149
1400
|
interface BoardController {
|
|
1150
1401
|
readonly document: ReadonlyBoardDocument;
|
|
@@ -1176,6 +1427,15 @@ interface BoardController {
|
|
|
1176
1427
|
};
|
|
1177
1428
|
readonly view: {
|
|
1178
1429
|
fit(): void;
|
|
1430
|
+
/**
|
|
1431
|
+
* Frame the current selection (Phase 8), the same way `fit()` frames the
|
|
1432
|
+
* whole board. A no-op with nothing selected — deliberately doesn't fall
|
|
1433
|
+
* back to `fit()`'s "frame everything," which would be a surprising
|
|
1434
|
+
* result for an empty selection. On a headless board this can only
|
|
1435
|
+
* re-center the view (no viewport to compute a real zoom-to-fit from),
|
|
1436
|
+
* matching `fit()`'s own headless limitation exactly.
|
|
1437
|
+
*/
|
|
1438
|
+
zoomToSelection(): void;
|
|
1179
1439
|
zoomTo(value: number): void;
|
|
1180
1440
|
centerOn(point: BoardPoint): void;
|
|
1181
1441
|
get(): BoardView;
|
|
@@ -1247,6 +1507,14 @@ interface BoardController {
|
|
|
1247
1507
|
* aren't listed separately. `[]` when the clipboard is empty.
|
|
1248
1508
|
*/
|
|
1249
1509
|
paste(): readonly string[];
|
|
1510
|
+
/**
|
|
1511
|
+
* Select every top-level object (Phase 8) — a group's own id stands for
|
|
1512
|
+
* its children, which aren't selected separately, matching `paste`'s own
|
|
1513
|
+
* "what the user sees" id list. Hidden objects are excluded, consistent
|
|
1514
|
+
* with them already being excluded from marquee selection. Works with
|
|
1515
|
+
* no canvas/engine, same as {@link toggleSelectionVisibility}.
|
|
1516
|
+
*/
|
|
1517
|
+
selectAll(): void;
|
|
1250
1518
|
table: {
|
|
1251
1519
|
addRow(tableId: string): void;
|
|
1252
1520
|
addCol(tableId: string): void;
|
|
@@ -1265,6 +1533,21 @@ interface BoardController {
|
|
|
1265
1533
|
* another collaborator who isn't the current lock holder.
|
|
1266
1534
|
*/
|
|
1267
1535
|
toggleSelectionLock(): void;
|
|
1536
|
+
/**
|
|
1537
|
+
* Toggle hidden state for the current selection, as one undo entry
|
|
1538
|
+
* (Phase 8). If any selected object is hidden, shows every selected
|
|
1539
|
+
* object; otherwise hides them all — same "any wins" semantics as
|
|
1540
|
+
* {@link toggleSelectionLock}. Hidden objects stay fully present in the
|
|
1541
|
+
* document (they still serialize, persist, sync, undo/redo) — they just
|
|
1542
|
+
* stop rendering and stop being hit-testable/selectable via pointer
|
|
1543
|
+
* interaction. Unlike `toggleSelectionLock`, this works on a headless
|
|
1544
|
+
* board too: it only touches `selection`/the document, no canvas or
|
|
1545
|
+
* engine involved. Custom objects have no visibility concept (no
|
|
1546
|
+
* `Hideable` field) and are silently skipped, matching how
|
|
1547
|
+
* `toggleSelectionLock` already excludes them. A no-op with nothing
|
|
1548
|
+
* selected or when the selection is only custom objects.
|
|
1549
|
+
*/
|
|
1550
|
+
toggleSelectionVisibility(): void;
|
|
1268
1551
|
};
|
|
1269
1552
|
readonly query: {
|
|
1270
1553
|
get(id: string): DeepReadonly<BoardObject> | undefined;
|
|
@@ -1293,6 +1576,15 @@ interface BoardController {
|
|
|
1293
1576
|
follow(view: PresenceView): void;
|
|
1294
1577
|
/** Ease the camera to a peer's view; returns false (no-op) while mid-stroke. */
|
|
1295
1578
|
gather(view: PresenceView): boolean;
|
|
1579
|
+
/**
|
|
1580
|
+
* Publishes this client's own cursor/tool/view for other collaborators
|
|
1581
|
+
* (Phase 6, ADR 0015), via the configured `CollaborationAdapter` —
|
|
1582
|
+
* throttled internally (`presenceThrottleMs` option, default 50ms) so
|
|
1583
|
+
* a raw pointermove stream never becomes a message-per-event flood. A
|
|
1584
|
+
* no-op if no collaboration adapter is configured, or if the
|
|
1585
|
+
* configured one doesn't implement `updatePresence`.
|
|
1586
|
+
*/
|
|
1587
|
+
broadcast(local: LocalPresence): void;
|
|
1296
1588
|
};
|
|
1297
1589
|
readonly export: {
|
|
1298
1590
|
svg(): string;
|
|
@@ -1318,6 +1610,7 @@ interface BoardController {
|
|
|
1318
1610
|
}>;
|
|
1319
1611
|
dispose(): Promise<void>;
|
|
1320
1612
|
}
|
|
1613
|
+
/** @deprecated Use `BoardController.getSnapshot()`'s return type instead. */
|
|
1321
1614
|
type LocalBoardSnapshot = {
|
|
1322
1615
|
documentId: string;
|
|
1323
1616
|
selectedStrokeId: string | null;
|
|
@@ -1326,6 +1619,7 @@ type LocalBoardSnapshot = {
|
|
|
1326
1619
|
canRedo: boolean;
|
|
1327
1620
|
disposed: boolean;
|
|
1328
1621
|
};
|
|
1622
|
+
/** @deprecated Use `BoardController` (from `createBoardController`) instead — this stroke-only, single-tool surface predates the full capability-grouped controller. */
|
|
1329
1623
|
type LocalBoard = {
|
|
1330
1624
|
drawStroke(stroke: Stroke): void;
|
|
1331
1625
|
selectAt(point: BoardPoint): string | null;
|
|
@@ -1579,6 +1873,16 @@ interface ScrawlProviderProps {
|
|
|
1579
1873
|
className?: string;
|
|
1580
1874
|
style?: ThemeStyle;
|
|
1581
1875
|
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Wraps a Board `controller` you created yourself (via `createBoardController`)
|
|
1878
|
+
* so its descendants can use `useScrawlController`/`useScrawlSnapshot`/etc.
|
|
1879
|
+
* and render its default UI pieces (`DefaultBoardChrome`, `StyleShelf`, ...).
|
|
1880
|
+
* Prefer `Scrawl` unless you need to construct or own the controller's
|
|
1881
|
+
* lifecycle yourself (e.g. you create it outside React, or need it before
|
|
1882
|
+
* first render). Set `disposeOnUnmount` to have this provider call
|
|
1883
|
+
* `controller.dispose()` on unmount; otherwise disposal remains your own
|
|
1884
|
+
* responsibility.
|
|
1885
|
+
*/
|
|
1582
1886
|
declare function ScrawlProvider({ controller, children, preset, theme, portalContainer: customPortal, disposeOnUnmount, onThemeDiagnostic, className, style }: ScrawlProviderProps): react.JSX.Element;
|
|
1583
1887
|
interface ScrawlProps extends Omit<CreateBoardControllerOptions, "canvas"> {
|
|
1584
1888
|
children?: ReactNode;
|
|
@@ -1599,6 +1903,17 @@ interface ScrawlProps extends Omit<CreateBoardControllerOptions, "canvas"> {
|
|
|
1599
1903
|
*/
|
|
1600
1904
|
icons?: Partial<Record<BuiltInTool, ReactNode>>;
|
|
1601
1905
|
}
|
|
1906
|
+
/**
|
|
1907
|
+
* The fastest path to an embedded Board: creates and owns a
|
|
1908
|
+
* `BoardController` for you (constructed once, disposed on unmount) and
|
|
1909
|
+
* renders it into a canvas. Render with no `children` to get the SDK's
|
|
1910
|
+
* default toolbar/UI chrome, or supply your own `children` (using the
|
|
1911
|
+
* `useScrawlController`/`useScrawlSnapshot` hooks, or the exported
|
|
1912
|
+
* `DefaultBoardChrome`/`StyleShelf`/etc. pieces) to build a custom UI on
|
|
1913
|
+
* top of the same controller. Accepts every `CreateBoardControllerOptions`
|
|
1914
|
+
* field except `canvas` (pass `canvas={null}` for a headless board, or an
|
|
1915
|
+
* existing `<canvas>` element to control its identity yourself).
|
|
1916
|
+
*/
|
|
1602
1917
|
declare function Scrawl({ children, preset, theme, portalContainer, className, style, onReady, onError, onThemeDiagnostic, canvas: suppliedCanvas, icons, ...options }: ScrawlProps): react.JSX.Element;
|
|
1603
1918
|
interface ScrawlCanvasProps {
|
|
1604
1919
|
element?: HTMLCanvasElement;
|
|
@@ -1624,6 +1939,38 @@ declare function ScrawlPortal({ children }: {
|
|
|
1624
1939
|
declare function useScrawlController(): BoardController;
|
|
1625
1940
|
declare function useScrawlTheme(): ScrawlResolvedTheme;
|
|
1626
1941
|
declare function useScrawlSnapshot(): BoardSnapshot;
|
|
1942
|
+
/**
|
|
1943
|
+
* A thin, purely-derived convenience over
|
|
1944
|
+
* `useScrawlSnapshot().connection.persistence` (Phase 5) — for a Host
|
|
1945
|
+
* component that only cares about save status (e.g. a
|
|
1946
|
+
* "Saving…"/"Saved"/"Offline" indicator) and would otherwise re-derive
|
|
1947
|
+
* this same field access itself. Adds no state and no behavior of its
|
|
1948
|
+
* own: React still owns none of persistence, exactly as before — this
|
|
1949
|
+
* hook only re-reads what the controller already tracks.
|
|
1950
|
+
*
|
|
1951
|
+
* Deliberately does *not* go through `useScrawlSnapshot()` (Phase 9):
|
|
1952
|
+
* `changed()` rebuilds the whole `BoardSnapshot` — including a fresh
|
|
1953
|
+
* `connection.persistence` object — on every document mutation, even ones
|
|
1954
|
+
* that never touch persistence at all, so a component using only this
|
|
1955
|
+
* hook would otherwise re-render on every stroke draw. `useSyncStatus`
|
|
1956
|
+
* below memoizes on the value (`state`/`error`), not just the object
|
|
1957
|
+
* reference, and returns the same cached value across renders where
|
|
1958
|
+
* nothing relevant changed — the same shape `usePresence` already uses
|
|
1959
|
+
* for its own independently-scoped store.
|
|
1960
|
+
*/
|
|
1961
|
+
declare function usePersistenceStatus(): PersistenceSnapshot;
|
|
1962
|
+
/** The `CollaborationSnapshot` equivalent of `usePersistenceStatus` (Phase 6) — same value-memoized convenience over `useScrawlSnapshot().connection.collaboration` (Phase 9: see `usePersistenceStatus`'s doc comment for why it doesn't derive from the full snapshot). */
|
|
1963
|
+
declare function useCollaborationStatus(): CollaborationSnapshot;
|
|
1964
|
+
/**
|
|
1965
|
+
* The current presence roster (Phase 6), live-updating — wraps
|
|
1966
|
+
* `controller.presence.list()`/`subscribe` the same way `useScrawlSnapshot`
|
|
1967
|
+
* wraps the controller's main snapshot, via `useSyncExternalStore`. Does
|
|
1968
|
+
* not re-render on every remote pointer move by itself; it re-renders
|
|
1969
|
+
* whenever the roster the controller already tracks changes, at whatever
|
|
1970
|
+
* rate that arrives at (throttled adapter-side, per `presenceThrottleMs`).
|
|
1971
|
+
*/
|
|
1972
|
+
declare function usePresence(): readonly PresenceUser[];
|
|
1973
|
+
/** @deprecated Use `Scrawl` instead — this predates the full capability-grouped `BoardController` and only exposes the stroke-only `LocalBoard` surface. */
|
|
1627
1974
|
type ScrawlBoardProps = {
|
|
1628
1975
|
documentId: string;
|
|
1629
1976
|
initialDocument?: SerializedBoardDocument;
|
|
@@ -1631,7 +1978,8 @@ type ScrawlBoardProps = {
|
|
|
1631
1978
|
className?: string;
|
|
1632
1979
|
style?: CSSProperties;
|
|
1633
1980
|
};
|
|
1981
|
+
/** @deprecated Use `Scrawl` instead — this predates the full capability-grouped `BoardController` and only exposes the stroke-only `LocalBoard` surface. */
|
|
1634
1982
|
declare function ScrawlBoard({ documentId, initialDocument, onReady, className, style }: ScrawlBoardProps): react.JSX.Element;
|
|
1635
1983
|
|
|
1636
|
-
export { AssetResolutionError, DefaultBoardChrome, FocusedItemToolbar, InlineEditors, MultiplayerCursors, SUPPORTED_ASSET_MEDIA_TYPES, Scrawl, ScrawlBoard, ScrawlCanvas, ScrawlDefaultUI, ScrawlPortal, ScrawlProvider, StyleShelf, assetRef, clampAssetCacheBytes, cloneCustomObject, isAssetRef, resolveScrawlTheme, scrawlThemePresets, useScrawlController, useScrawlSnapshot, useScrawlTheme, validateScrawlTheme };
|
|
1637
|
-
export type { AssetDiagnostic, AssetIngestRequest, AssetIngestResult, AssetIngestor, AssetKind, AssetPurpose, AssetRef, AssetResolutionErrorCode, AssetResolveRequest, AssetResolveResult, AssetResolver, BoardController, BoardKeyInput, BoardPointerInput, BoardScene, BoardSlotProps, BoardSnapshot, BoardStyle, BoardThemeOptions, CommentMarker, CreateBoardControllerOptions, CustomBoardObject, CustomObjectAddInput, CustomObjectDefinition, CustomTool, CustomToolDefinition, DefaultBoardChromeProps, DefaultUIRegion, DefaultUISlot, DefaultUISlots, DialogSlotProps, ExtensionCommand, ExtensionDiagnostic, ExtensionHitResult, ExtensionId, ExtensionRequirement, FocusedItem, FocusedItemToolbarProps, InlineEditorsProps, InputModifiers, JsonObject, JsonValue, LocalBoard, LocalBoardSnapshot, Mat2x3, MultiplayerCursorsProps, ObjectDescribeContext, ObjectIntent, ObjectType, PresenceCursor, PresenceUser, PresenceView, QueryableBoardObject, ReadonlyCustomObject, SceneEllipse, SceneGroup, SceneImage, ScenePath, SceneRect, SceneText, ScrawlBoardProps, ScrawlCanvasProps, ScrawlDefaultUIProps, ScrawlDensity, ScrawlExtension, ScrawlGridMode, ScrawlProps, ScrawlProviderProps, ScrawlResolvedTheme, ScrawlSurfaceTexture, ScrawlTheme, ScrawlThemeDiagnostic, ScrawlThemePreset, StyleShelfProps, SupportedAssetMediaType, ToolCancelReason, ToolCapabilities, ToolCursor, ToolId };
|
|
1984
|
+
export { AssetResolutionError, DefaultBoardChrome, FocusedItemToolbar, InlineEditors, MultiplayerCursors, SUPPORTED_ASSET_MEDIA_TYPES, Scrawl, ScrawlBoard, ScrawlCanvas, ScrawlDefaultUI, ScrawlPortal, ScrawlProvider, StyleShelf, assetRef, clampAssetCacheBytes, cloneCustomObject, isAssetRef, resolveScrawlTheme, scrawlThemePresets, useCollaborationStatus, usePersistenceStatus, usePresence, useScrawlController, useScrawlSnapshot, useScrawlTheme, validateScrawlTheme };
|
|
1985
|
+
export type { AssetDiagnostic, AssetExportFailure, AssetIngestRequest, AssetIngestResult, AssetIngestor, AssetKind, AssetPurpose, AssetRef, AssetResolutionErrorCode, AssetResolveRequest, AssetResolveResult, AssetResolver, BoardController, BoardKeyInput, BoardPointerInput, BoardScene, BoardSlotProps, BoardSnapshot, BoardStyle, BoardThemeOptions, CollaborationSnapshot, CommentMarker, CreateBoardControllerOptions, CustomBoardObject, CustomObjectAddInput, CustomObjectDefinition, CustomTool, CustomToolDefinition, DefaultBoardChromeProps, DefaultUIRegion, DefaultUISlot, DefaultUISlots, DialogSlotProps, ExportDocumentSVGOptions, ExportDocumentSVGResult, ExtensionCommand, ExtensionDiagnostic, ExtensionHitResult, ExtensionId, ExtensionRequirement, FocusedItem, FocusedItemToolbarProps, InlineEditorsProps, InputModifiers, JsonObject, JsonValue, LocalBoard, LocalBoardSnapshot, LocalPresence, Mat2x3, MultiplayerCursorsProps, ObjectDescribeContext, ObjectIntent, ObjectType, PresenceCursor, PresenceUser, PresenceView, QueryableBoardObject, ReadonlyCustomObject, SceneEllipse, SceneGroup, SceneImage, ScenePath, SceneRect, SceneText, ScrawlBoardProps, ScrawlCanvasProps, ScrawlDefaultUIProps, ScrawlDensity, ScrawlExtension, ScrawlGridMode, ScrawlProps, ScrawlProviderProps, ScrawlResolvedTheme, ScrawlSurfaceTexture, ScrawlTheme, ScrawlThemeDiagnostic, ScrawlThemePreset, SearchHit, SearchHitKind, SearchableComment, StyleShelfProps, SupportedAssetMediaType, ToolCancelReason, ToolCapabilities, ToolCursor, ToolId };
|