@scrawl-board/board 0.1.0-beta.6 → 0.1.0-beta.7
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 +4 -2
- package/dist/browser.d.ts +261 -2
- package/dist/browser.js +7390 -882
- package/dist/core.d.ts +618 -8
- package/dist/core.js +1848 -20
- package/dist/index.d.ts +740 -14
- package/dist/index.js +7592 -807
- package/dist/react.d.ts +274 -6
- package/dist/react.js +7540 -824
- package/package.json +1 -1
package/dist/react.d.ts
CHANGED
|
@@ -358,6 +358,133 @@ interface KitchenTimer extends Lockable {
|
|
|
358
358
|
runningSince?: number;
|
|
359
359
|
}
|
|
360
360
|
|
|
361
|
+
interface RectangleObject extends Lockable {
|
|
362
|
+
id: string;
|
|
363
|
+
x: number;
|
|
364
|
+
y: number;
|
|
365
|
+
width: number;
|
|
366
|
+
height: number;
|
|
367
|
+
fill?: string;
|
|
368
|
+
stroke?: string;
|
|
369
|
+
strokeWidth?: number;
|
|
370
|
+
/** Corner radius in board units; clamped to at most half the shorter side at render time. */
|
|
371
|
+
cornerRadius?: number;
|
|
372
|
+
/** `[0, 1]`; undefined means fully opaque (Phase 4). */
|
|
373
|
+
opacity?: number;
|
|
374
|
+
/**
|
|
375
|
+
* Radians, about the shape's own center `(x + width/2, y - height/2)`.
|
|
376
|
+
* Undefined means 0 (Phase 3). `x`/`y`/`width`/`height` stay in the
|
|
377
|
+
* shape's own unrotated local frame — rotation is a separate, applied-last
|
|
378
|
+
* transform, not baked into them, matching how Stroke/CustomBoardObject
|
|
379
|
+
* keep geometry and placement independent via their own `matrix`.
|
|
380
|
+
*/
|
|
381
|
+
rotation?: number;
|
|
382
|
+
}
|
|
383
|
+
interface EllipseObject extends Lockable {
|
|
384
|
+
id: string;
|
|
385
|
+
x: number;
|
|
386
|
+
y: number;
|
|
387
|
+
width: number;
|
|
388
|
+
height: number;
|
|
389
|
+
fill?: string;
|
|
390
|
+
stroke?: string;
|
|
391
|
+
strokeWidth?: number;
|
|
392
|
+
/** `[0, 1]`; undefined means fully opaque (Phase 4). */
|
|
393
|
+
opacity?: number;
|
|
394
|
+
/** Radians, about the shape's own center — see RectangleObject's `rotation` doc. */
|
|
395
|
+
rotation?: number;
|
|
396
|
+
}
|
|
397
|
+
/** `"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
|
+
type ArrowHeadStyle = "triangle" | "none";
|
|
399
|
+
interface LineObject extends Lockable {
|
|
400
|
+
id: string;
|
|
401
|
+
start: BoardPoint;
|
|
402
|
+
end: BoardPoint;
|
|
403
|
+
stroke?: string;
|
|
404
|
+
strokeWidth?: number;
|
|
405
|
+
opacity?: number;
|
|
406
|
+
}
|
|
407
|
+
interface ArrowObject extends Lockable {
|
|
408
|
+
id: string;
|
|
409
|
+
start: BoardPoint;
|
|
410
|
+
end: BoardPoint;
|
|
411
|
+
head?: ArrowHeadStyle;
|
|
412
|
+
stroke?: string;
|
|
413
|
+
strokeWidth?: number;
|
|
414
|
+
opacity?: number;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Triangle(3)/Diamond(4)/Pentagon(5)/Hexagon(6)/Octagon(8) as one shared
|
|
418
|
+
* type instead of five near-duplicate interfaces — a regular N-gon
|
|
419
|
+
* inscribed in the same `x`/`y`/`width`/`height`/`rotation` bounding box
|
|
420
|
+
* Rectangle already uses, parameterized by `sides`. Diamond is exactly a
|
|
421
|
+
* 4-sided regular polygon with vertex 0 pointing right (not up, like
|
|
422
|
+
* Triangle/Pentagon/Hexagon) — see `polygonGeometry.ts`'s
|
|
423
|
+
* `polygonStartAngle`, which encodes each side count's own vertex
|
|
424
|
+
* orientation so the outline always matches the legacy drag-preview shape.
|
|
425
|
+
*/
|
|
426
|
+
interface PolygonObject extends Lockable {
|
|
427
|
+
id: string;
|
|
428
|
+
x: number;
|
|
429
|
+
y: number;
|
|
430
|
+
width: number;
|
|
431
|
+
height: number;
|
|
432
|
+
sides: 3 | 4 | 5 | 6 | 8;
|
|
433
|
+
fill?: string;
|
|
434
|
+
stroke?: string;
|
|
435
|
+
strokeWidth?: number;
|
|
436
|
+
opacity?: number;
|
|
437
|
+
/** Radians, about the shape's own center — see RectangleObject's `rotation` doc. */
|
|
438
|
+
rotation?: number;
|
|
439
|
+
}
|
|
440
|
+
/** 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 {
|
|
442
|
+
id: string;
|
|
443
|
+
x: number;
|
|
444
|
+
y: number;
|
|
445
|
+
width: number;
|
|
446
|
+
height: number;
|
|
447
|
+
/** Vertex count; today's only shipped preset is 5, matching the legacy tool. */
|
|
448
|
+
points: number;
|
|
449
|
+
/** `(0, 1)` — inner vertex radius as a fraction of the outer radius. */
|
|
450
|
+
innerRadiusRatio: number;
|
|
451
|
+
fill?: string;
|
|
452
|
+
stroke?: string;
|
|
453
|
+
strokeWidth?: number;
|
|
454
|
+
opacity?: number;
|
|
455
|
+
rotation?: number;
|
|
456
|
+
}
|
|
457
|
+
/** 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 {
|
|
459
|
+
id: string;
|
|
460
|
+
x: number;
|
|
461
|
+
y: number;
|
|
462
|
+
width: number;
|
|
463
|
+
height: number;
|
|
464
|
+
fill?: string;
|
|
465
|
+
stroke?: string;
|
|
466
|
+
strokeWidth?: number;
|
|
467
|
+
opacity?: number;
|
|
468
|
+
rotation?: number;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* A logical grouping of other board objects (Phase 3 — Selection,
|
|
472
|
+
* Transformation & Grouping). Deliberately has no `x`/`y`/`transform` of its
|
|
473
|
+
* own — a group's bounds are always derived on demand from its (recursively
|
|
474
|
+
* resolved) children, and "moving/rotating/scaling the group" is exactly a
|
|
475
|
+
* multi-object transform applied to those children, nothing more. A group
|
|
476
|
+
* has no renderer/mesh of its own; its only visual presence is the
|
|
477
|
+
* selection gizmo's bounding box while it's the current selection.
|
|
478
|
+
*
|
|
479
|
+
* `children` may itself contain other group ids (nested groups) — expanding
|
|
480
|
+
* a group into its leaf members is always done by the caller (recursively,
|
|
481
|
+
* with cycle protection), never assumed here.
|
|
482
|
+
*/
|
|
483
|
+
interface GroupObject extends Lockable {
|
|
484
|
+
id: string;
|
|
485
|
+
children: string[];
|
|
486
|
+
}
|
|
487
|
+
|
|
361
488
|
interface BoardPoint {
|
|
362
489
|
x: number;
|
|
363
490
|
y: number;
|
|
@@ -420,6 +547,31 @@ interface SerializedDocument {
|
|
|
420
547
|
timers?: KitchenTimer[];
|
|
421
548
|
/** Absent in documents saved before Custom board objects existed (ticket #22). */
|
|
422
549
|
customObjects?: CustomBoardObject[];
|
|
550
|
+
/** Absent in documents saved before semantic Rectangle objects existed (Phase 2). */
|
|
551
|
+
rectangles?: RectangleObject[];
|
|
552
|
+
/** Absent in documents saved before semantic Ellipse objects existed (Phase 2). */
|
|
553
|
+
ellipses?: EllipseObject[];
|
|
554
|
+
/** Absent in documents saved before Groups existed (Phase 3). */
|
|
555
|
+
groups?: GroupObject[];
|
|
556
|
+
/** Absent in documents saved before semantic Line objects existed (Phase 4). */
|
|
557
|
+
lines?: LineObject[];
|
|
558
|
+
/** Absent in documents saved before semantic Arrow objects existed (Phase 4). */
|
|
559
|
+
arrows?: ArrowObject[];
|
|
560
|
+
/** Absent in documents saved before semantic Polygon objects existed (Phase 4). */
|
|
561
|
+
polygons?: PolygonObject[];
|
|
562
|
+
/** Absent in documents saved before semantic Star objects existed (Phase 4). */
|
|
563
|
+
stars?: StarObject[];
|
|
564
|
+
/** Absent in documents saved before semantic Heart objects existed (Phase 4). */
|
|
565
|
+
hearts?: HeartObject[];
|
|
566
|
+
/**
|
|
567
|
+
* Every content-object id (every type above except comments, which are
|
|
568
|
+
* host-synced and never enter this schema) in paint order, back to front.
|
|
569
|
+
* Absent in documents saved before per-object z-order existed (Phase 3) —
|
|
570
|
+
* migration synthesizes a default order preserving the old fixed-Z-band
|
|
571
|
+
* visual stacking exactly, so an existing document never visibly changes
|
|
572
|
+
* on load; only an explicit reorder action touches this from then on.
|
|
573
|
+
*/
|
|
574
|
+
objectOrder?: string[];
|
|
423
575
|
}
|
|
424
576
|
/**
|
|
425
577
|
* One collaborator's vote on a note. One per person; toggling removes it.
|
|
@@ -612,7 +764,7 @@ interface BoardSnapshot {
|
|
|
612
764
|
* here, matching the engine's own internal selection-badge behavior.
|
|
613
765
|
*/
|
|
614
766
|
interface FocusedItem {
|
|
615
|
-
readonly type: "stroke" | "note" | "text" | "table" | "image" | "timer" | "custom";
|
|
767
|
+
readonly type: "stroke" | "note" | "text" | "table" | "image" | "timer" | "rectangle" | "ellipse" | "group" | "line" | "arrow" | "polygon" | "star" | "heart" | "custom";
|
|
616
768
|
readonly id: string;
|
|
617
769
|
readonly locked: boolean;
|
|
618
770
|
readonly lockedBy?: string;
|
|
@@ -794,6 +946,22 @@ type BoardObject = ({
|
|
|
794
946
|
} & ImageBlock) | ({
|
|
795
947
|
type: "timer";
|
|
796
948
|
} & KitchenTimer) | ({
|
|
949
|
+
type: "rectangle";
|
|
950
|
+
} & RectangleObject) | ({
|
|
951
|
+
type: "ellipse";
|
|
952
|
+
} & EllipseObject) | ({
|
|
953
|
+
type: "group";
|
|
954
|
+
} & GroupObject) | ({
|
|
955
|
+
type: "line";
|
|
956
|
+
} & LineObject) | ({
|
|
957
|
+
type: "arrow";
|
|
958
|
+
} & ArrowObject) | ({
|
|
959
|
+
type: "polygon";
|
|
960
|
+
} & PolygonObject) | ({
|
|
961
|
+
type: "star";
|
|
962
|
+
} & StarObject) | ({
|
|
963
|
+
type: "heart";
|
|
964
|
+
} & HeartObject) | ({
|
|
797
965
|
type: "custom";
|
|
798
966
|
customType: ObjectType;
|
|
799
967
|
} & Omit<CustomBoardObject, "type">);
|
|
@@ -822,6 +990,30 @@ type BoardObjectInput = {
|
|
|
822
990
|
type: "timer";
|
|
823
991
|
id?: string;
|
|
824
992
|
} & Omit<KitchenTimer, "id">) | ({
|
|
993
|
+
type: "rectangle";
|
|
994
|
+
id?: string;
|
|
995
|
+
} & Omit<RectangleObject, "id">) | ({
|
|
996
|
+
type: "ellipse";
|
|
997
|
+
id?: string;
|
|
998
|
+
} & Omit<EllipseObject, "id">) | ({
|
|
999
|
+
type: "group";
|
|
1000
|
+
id?: string;
|
|
1001
|
+
} & Omit<GroupObject, "id">) | ({
|
|
1002
|
+
type: "line";
|
|
1003
|
+
id?: string;
|
|
1004
|
+
} & Omit<LineObject, "id">) | ({
|
|
1005
|
+
type: "arrow";
|
|
1006
|
+
id?: string;
|
|
1007
|
+
} & Omit<ArrowObject, "id">) | ({
|
|
1008
|
+
type: "polygon";
|
|
1009
|
+
id?: string;
|
|
1010
|
+
} & Omit<PolygonObject, "id">) | ({
|
|
1011
|
+
type: "star";
|
|
1012
|
+
id?: string;
|
|
1013
|
+
} & Omit<StarObject, "id">) | ({
|
|
1014
|
+
type: "heart";
|
|
1015
|
+
id?: string;
|
|
1016
|
+
} & Omit<HeartObject, "id">) | ({
|
|
825
1017
|
type: "custom";
|
|
826
1018
|
id?: string;
|
|
827
1019
|
customType: ObjectType;
|
|
@@ -883,7 +1075,16 @@ interface ControllerOp {
|
|
|
883
1075
|
id: string;
|
|
884
1076
|
schemaVersion: 1;
|
|
885
1077
|
kind: "upsert" | "restore" | "remove";
|
|
886
|
-
objectType: "stroke" | "note" | "text" | "table" | "image" | "timer" | "custom"
|
|
1078
|
+
objectType: "stroke" | "note" | "text" | "table" | "image" | "timer" | "rectangle" | "ellipse" | "group" | "line" | "arrow" | "polygon" | "star" | "heart" | "custom"
|
|
1079
|
+
/**
|
|
1080
|
+
* A whole-document paint-order sync (Phase 3), not a per-object type —
|
|
1081
|
+
* `objectId` is always the fixed sentinel `"order"` and `payload` is
|
|
1082
|
+
* `{ order: string[] }`. The only `objectType` with no matching
|
|
1083
|
+
* `BoardObject`/document collection; kept in this same union (rather
|
|
1084
|
+
* than a separate wire message) so it flows through the existing
|
|
1085
|
+
* `PersistenceAdapter`/`CollaborationAdapter` opaquely, unchanged.
|
|
1086
|
+
*/
|
|
1087
|
+
| "order";
|
|
887
1088
|
objectId: string;
|
|
888
1089
|
payload?: unknown;
|
|
889
1090
|
}
|
|
@@ -996,6 +1197,56 @@ interface BoardController {
|
|
|
996
1197
|
* Unknown ids are silently skipped, matching `remove`'s convention.
|
|
997
1198
|
*/
|
|
998
1199
|
duplicate(ids: readonly string[]): readonly string[];
|
|
1200
|
+
/**
|
|
1201
|
+
* Creates a new Group referencing `ids` as its children and returns its
|
|
1202
|
+
* id, as one undoable step. Unknown ids are silently skipped, matching
|
|
1203
|
+
* `duplicate`/`remove`'s convention. A child id that's itself a group
|
|
1204
|
+
* makes a nested group — expanding nested groups into their leaf
|
|
1205
|
+
* members is always the caller's job, never assumed here (matches the
|
|
1206
|
+
* document-model `GroupObject` itself).
|
|
1207
|
+
*/
|
|
1208
|
+
group(ids: readonly string[]): string;
|
|
1209
|
+
/**
|
|
1210
|
+
* Dissolves one group, returning its immediate children's ids (a nested
|
|
1211
|
+
* subgroup among them stays intact, itself still a group) — the group
|
|
1212
|
+
* record itself is removed, the children are untouched. A no-op
|
|
1213
|
+
* (returns `[]`) if `groupId` isn't a group.
|
|
1214
|
+
*/
|
|
1215
|
+
ungroup(groupId: string): readonly string[];
|
|
1216
|
+
/**
|
|
1217
|
+
* Aligns every given object's matching edge/center to the corresponding
|
|
1218
|
+
* edge/center of their combined bounding box, as one undoable step.
|
|
1219
|
+
* `"top"`/`"bottom"` follow board space's Y-up convention (`"top"` is
|
|
1220
|
+
* the larger Y). Ids that don't resolve, or resolve to a Group (which
|
|
1221
|
+
* has no position of its own), are skipped. A no-op under 2 resolvable
|
|
1222
|
+
* ids — there's nothing to align relative to.
|
|
1223
|
+
*/
|
|
1224
|
+
align(ids: readonly string[], edge: "left" | "right" | "top" | "bottom" | "centerX" | "centerY"): void;
|
|
1225
|
+
/**
|
|
1226
|
+
* Spaces the middle objects' centers evenly between the first and last
|
|
1227
|
+
* (sorted along `axis`), as one undoable step — the two endpoints don't
|
|
1228
|
+
* move. Ids that don't resolve, or resolve to a Group, are skipped. A
|
|
1229
|
+
* no-op under 3 resolvable ids — there's no "middle" to distribute.
|
|
1230
|
+
*/
|
|
1231
|
+
distribute(ids: readonly string[], axis: "x" | "y"): void;
|
|
1232
|
+
/**
|
|
1233
|
+
* Snapshots `ids` (recursively expanded through any group, same as
|
|
1234
|
+
* `duplicate`) into an internal in-memory clipboard — never
|
|
1235
|
+
* `navigator.clipboard`, scoped to this one controller instance and
|
|
1236
|
+
* replaced wholesale by the next `copy`/`cut`. Read-only; works even
|
|
1237
|
+
* on a read-only board.
|
|
1238
|
+
*/
|
|
1239
|
+
copy(ids: readonly string[]): void;
|
|
1240
|
+
/** `copy`, then removes every resolved object (recursively through any group) as one undoable step. */
|
|
1241
|
+
cut(ids: readonly string[]): void;
|
|
1242
|
+
/**
|
|
1243
|
+
* Clones the current clipboard contents onto the board as one undoable
|
|
1244
|
+
* step, offset the same small cascade `duplicate` uses (no cursor
|
|
1245
|
+
* position to paste relative to yet). Returns the new top-level ids —
|
|
1246
|
+
* a pasted group's own id stands for its (also-pasted) children, which
|
|
1247
|
+
* aren't listed separately. `[]` when the clipboard is empty.
|
|
1248
|
+
*/
|
|
1249
|
+
paste(): readonly string[];
|
|
999
1250
|
table: {
|
|
1000
1251
|
addRow(tableId: string): void;
|
|
1001
1252
|
addCol(tableId: string): void;
|
|
@@ -1006,6 +1257,14 @@ interface BoardController {
|
|
|
1006
1257
|
};
|
|
1007
1258
|
select(ids: readonly string[]): void;
|
|
1008
1259
|
import(document: SerializedBoardDocument): readonly string[];
|
|
1260
|
+
/**
|
|
1261
|
+
* Toggle lock state for the current selection (or focused note/text/
|
|
1262
|
+
* table/image/timer), matching whatever a single Host lock/unlock
|
|
1263
|
+
* control already does per object type. A no-op with nothing selected,
|
|
1264
|
+
* on a headless board, or when every actionable target is locked by
|
|
1265
|
+
* another collaborator who isn't the current lock holder.
|
|
1266
|
+
*/
|
|
1267
|
+
toggleSelectionLock(): void;
|
|
1009
1268
|
};
|
|
1010
1269
|
readonly query: {
|
|
1011
1270
|
get(id: string): DeepReadonly<BoardObject> | undefined;
|
|
@@ -1253,10 +1512,19 @@ interface FocusedItemToolbarProps {
|
|
|
1253
1512
|
snapshot: BoardSnapshot;
|
|
1254
1513
|
}
|
|
1255
1514
|
/**
|
|
1256
|
-
* Floating toolbar above the focused note, shape,
|
|
1257
|
-
* Size (note/text) or Width (shape),
|
|
1258
|
-
* Table/image/timer/
|
|
1259
|
-
*
|
|
1515
|
+
* Floating toolbar above the focused note, shape, text block, or semantic
|
|
1516
|
+
* Rectangle/Ellipse — Colour, Size (note/text) or Width (shape), Fill/Stroke
|
|
1517
|
+
* (Rectangle/Ellipse), Lock/Unlock, Duplicate, Delete. Table/image/timer/
|
|
1518
|
+
* custom objects and plain (non-shape) ink strokes never get a toolbar here
|
|
1519
|
+
* — out of scope for this destination.
|
|
1520
|
+
*
|
|
1521
|
+
* Rectangle/Ellipse (Phase 2) are a second, parallel "shape" concept from
|
|
1522
|
+
* the legacy ink-stroke shape below: both draw from the same toolbar
|
|
1523
|
+
* buttons and look the same to a user, but a Rectangle/Ellipse is a real
|
|
1524
|
+
* BoardObject with its own resize handles (independent width/height,
|
|
1525
|
+
* `ShapeResizeHandle`), while a legacy shape-stroke keeps going through the
|
|
1526
|
+
* native selection gizmo. This duality is deliberate and temporary — see
|
|
1527
|
+
* docs/reports/phase-2-document-object-model.md.
|
|
1260
1528
|
*
|
|
1261
1529
|
* Lock/Unlock carries no per-user ownership gating: nothing else in this
|
|
1262
1530
|
* SDK enforces lock ownership either (`content.update` never checks
|