@scrawl-board/board 0.1.0-beta.4 → 0.1.0-beta.6

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/react.d.ts CHANGED
@@ -587,6 +587,7 @@ interface BoardSnapshot {
587
587
  readonly zoom: number;
588
588
  readonly readOnly: boolean;
589
589
  readonly selection: readonly string[];
590
+ readonly focusedItem: FocusedItem | null;
590
591
  readonly strokeCount: number;
591
592
  readonly objectCount: number;
592
593
  readonly canUndo: boolean;
@@ -597,6 +598,27 @@ interface BoardSnapshot {
597
598
  readonly collaboration: CollaborationSnapshot;
598
599
  };
599
600
  }
601
+ /**
602
+ * `selection` collapsed into the one thing a selected-object toolbar needs:
603
+ * what's selected, its lock state, and where to anchor above it. `null`
604
+ * when nothing is selected, or when the selection mixes types/objects that
605
+ * don't resolve to a single focus (anything but one object, or several
606
+ * strokes sharing a `clusterId` — a multi-stroke shape).
607
+ *
608
+ * Raw lock fields, not a derived `canUnlock` — this API has no notion of
609
+ * "the local user" to judge that against (see `canUnlockItem` in `../core`,
610
+ * which takes a `userId` the Host already owns). A Custom object's lock
611
+ * shape doesn't carry a holder name, so it always reports `locked: false`
612
+ * here, matching the engine's own internal selection-badge behavior.
613
+ */
614
+ interface FocusedItem {
615
+ readonly type: "stroke" | "note" | "text" | "table" | "image" | "timer" | "custom";
616
+ readonly id: string;
617
+ readonly locked: boolean;
618
+ readonly lockedBy?: string;
619
+ readonly lockedByName?: string;
620
+ readonly screenPosition?: ScreenPoint;
621
+ }
600
622
  interface BoardControllerError {
601
623
  source: "controller" | "renderer" | "persistence" | "collaboration";
602
624
  code: string;
@@ -963,6 +985,17 @@ interface BoardController {
963
985
  add(input: BoardObjectInput): string;
964
986
  update(id: string, patch: BoardObjectPatch): void;
965
987
  remove(ids: readonly string[]): void;
988
+ /**
989
+ * Clone each given object as a new, unlocked copy offset by a small
990
+ * fixed cascade (matching the Duplicate affordance's established Host
991
+ * convention), as one undoable step. Order-preserving: `result[i]` is
992
+ * the clone of `ids[i]`. Strokes that share a `clusterId` among the
993
+ * given ids get a single fresh shared `clusterId` in the result, so
994
+ * duplicating a whole multi-stroke shape (e.g. an arrow's shaft + head)
995
+ * keeps it one shape — pass every member's id together, not just one.
996
+ * Unknown ids are silently skipped, matching `remove`'s convention.
997
+ */
998
+ duplicate(ids: readonly string[]): readonly string[];
966
999
  table: {
967
1000
  addRow(tableId: string): void;
968
1001
  addCol(tableId: string): void;
@@ -1162,7 +1195,7 @@ interface DefaultBoardChromeProps {
1162
1195
  */
1163
1196
  icons?: Partial<Record<BuiltInTool, ReactNode>>;
1164
1197
  }
1165
- type DefaultUIRegion = "tools" | "history" | "view" | "style" | "search" | "import" | "export" | "inlineEditing" | "styleShelf";
1198
+ type DefaultUIRegion = "tools" | "history" | "view" | "style" | "search" | "import" | "export" | "inlineEditing" | "styleShelf" | "focusedItemToolbar";
1166
1199
  /** Props for the toolbar/topBar/stylePanel/contextMenu slots. */
1167
1200
  interface BoardSlotProps {
1168
1201
  controller: BoardController;
@@ -1215,12 +1248,56 @@ interface MultiplayerCursorsProps {
1215
1248
  */
1216
1249
  declare function MultiplayerCursors({ controller, onSelectUser, onJumpToUser }: MultiplayerCursorsProps): react.JSX.Element | null;
1217
1250
 
1251
+ interface FocusedItemToolbarProps {
1252
+ controller: BoardController;
1253
+ snapshot: BoardSnapshot;
1254
+ }
1255
+ /**
1256
+ * Floating toolbar above the focused note, shape, or text block — Colour,
1257
+ * Size (note/text) or Width (shape), Lock/Unlock, Duplicate, Delete.
1258
+ * Table/image/timer/custom objects and plain (non-shape) ink strokes never
1259
+ * get a toolbar here — out of scope for this destination.
1260
+ *
1261
+ * Lock/Unlock carries no per-user ownership gating: nothing else in this
1262
+ * SDK enforces lock ownership either (`content.update` never checks
1263
+ * `locked`, and the engine's own internal unlock check has no way for a
1264
+ * Host to ever supply a real user id) — locking is advisory UI state
1265
+ * throughout, and this toolbar matches that rather than inventing an
1266
+ * enforcement story alone.
1267
+ *
1268
+ * A shape can be several strokes sharing one `clusterId` (e.g. an arrow's
1269
+ * shaft + head) — every action here applies to the whole cluster. Resolved
1270
+ * via `query.all()` + `clusterId`, not `snapshot.selection`: a canvas click
1271
+ * on one member selects every member internally, but the public selection
1272
+ * bridge only ever reports one id (`FocusedItem.id` is singular by design),
1273
+ * so reconstructing the cluster from the document is the reliable path
1274
+ * regardless of how the selection was made.
1275
+ *
1276
+ * A focused note also gets drag-to-resize corner handles — notes have no
1277
+ * gizmo of their own (the native selection gizmo is ink-stroke/shape-only),
1278
+ * so this is that capability's default-ui-owned equivalent. Proportional
1279
+ * (always-square) resize from the note's own centre, clamped to
1280
+ * `[MIN_SIZE, MAX_SIZE]`, independent of which corner is grabbed.
1281
+ */
1282
+ declare function FocusedItemToolbar({ controller, snapshot }: FocusedItemToolbarProps): react.JSX.Element | null;
1283
+
1218
1284
  interface StyleShelfProps {
1219
1285
  controller: BoardController;
1220
1286
  snapshot: BoardSnapshot;
1287
+ /**
1288
+ * Root-relative screen point (e.g. the active tool button's own position)
1289
+ * to anchor above instead of the default: centred over the whole
1290
+ * `.scrawl-board__tools` toolbar. `DefaultBoardChrome` supplies this
1291
+ * automatically; omit it when rendering `StyleShelf` standalone (its own
1292
+ * layout has no toolbar button to anchor to) to keep the centred default.
1293
+ */
1294
+ anchor?: {
1295
+ x: number;
1296
+ y: number;
1297
+ };
1221
1298
  }
1222
1299
  /** Contextual per-tool style controls — visible while a styleable tool is active. */
1223
- declare function StyleShelf({ controller, snapshot }: StyleShelfProps): react.JSX.Element | null;
1300
+ declare function StyleShelf({ controller, snapshot, anchor }: StyleShelfProps): react.JSX.Element | null;
1224
1301
 
1225
1302
  type ThemeStyle = CSSProperties & Record<`--scrawl-${string}`, string | number | undefined>;
1226
1303
  interface ScrawlProviderProps {
@@ -1288,5 +1365,5 @@ type ScrawlBoardProps = {
1288
1365
  };
1289
1366
  declare function ScrawlBoard({ documentId, initialDocument, onReady, className, style }: ScrawlBoardProps): react.JSX.Element;
1290
1367
 
1291
- export { AssetResolutionError, DefaultBoardChrome, InlineEditors, MultiplayerCursors, SUPPORTED_ASSET_MEDIA_TYPES, Scrawl, ScrawlBoard, ScrawlCanvas, ScrawlDefaultUI, ScrawlPortal, ScrawlProvider, StyleShelf, assetRef, clampAssetCacheBytes, cloneCustomObject, isAssetRef, resolveScrawlTheme, scrawlThemePresets, useScrawlController, useScrawlSnapshot, useScrawlTheme, validateScrawlTheme };
1292
- 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, 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 };
1368
+ 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 };
1369
+ 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 };