BoardKitCore
Elements
The Element discriminated union — 7 element types for the whiteboard canvas
All canvas content is represented as elements. The Element type is a discriminated union over the type field, with 7 variants.
Common Types
type ElementType = 'stroke' | 'shape' | 'text' | 'image' | 'stickyNote' | 'group' | 'connector';
interface Point {
x: number;
y: number;
}
interface Rect {
x: number;
y: number;
width: number;
height: number;
}
type AnchorPosition = 'top' | 'right' | 'bottom' | 'left' | 'center';ElementBase
All element types share this base interface:
interface ElementBase {
id: string;
pageId: string;
type: ElementType;
zIndex: number;
lockedBy?: string;
createdBy: string;
createdAt: string;
updatedAt: string;
}| Field | Description |
|---|---|
id | Unique element identifier |
pageId | ID of the page this element belongs to |
type | Discriminator for the element variant |
zIndex | Rendering order (higher = on top) |
lockedBy | User ID that has locked this element (optional) |
createdBy | User ID that created this element |
createdAt / updatedAt | ISO 8601 timestamps (used for LWW merge) |
StrokeElement
A freehand drawing stroke created by the Pen tool.
interface StrokeElement extends ElementBase {
type: 'stroke';
data: {
points: Point[];
pressures?: number[];
style: StrokeStyle;
bounds: Rect;
};
}ShapeElement
A geometric shape (rectangle, ellipse, line, arrow, triangle).
interface ShapeElement extends ElementBase {
type: 'shape';
data: {
shapeType: 'rectangle' | 'ellipse' | 'line' | 'arrow' | 'triangle';
position: Point;
size: { width: number; height: number };
rotation: number;
style: ShapeStyle;
bounds: Rect;
};
}TextElement
A text box with rich text styling.
interface TextElement extends ElementBase {
type: 'text';
data: {
content: string;
position: Point;
size: { width: number; height: number };
rotation: number;
style: TextStyle;
bounds: Rect;
};
}ImageElement
An uploaded image placed on the canvas.
interface ImageElement extends ElementBase {
type: 'image';
data: {
assetId: string;
url: string;
position: Point;
size: { width: number; height: number };
rotation: number;
bounds: Rect;
};
}StickyNoteElement
A colored sticky note with text.
interface StickyNoteElement extends ElementBase {
type: 'stickyNote';
data: {
content: string;
position: Point;
size: { width: number; height: number };
color: string;
style: TextStyle;
bounds: Rect;
};
}GroupElement
A virtual container grouping child elements.
interface GroupElement extends ElementBase {
type: 'group';
data: {
childIds: string[];
bounds: Rect;
};
}ConnectorElement
A line connecting two elements with optional arrows.
interface ConnectorElement extends ElementBase {
type: 'connector';
data: {
startElementId: string;
endElementId: string;
startAnchor: AnchorPosition;
endAnchor: AnchorPosition;
waypoints: Point[];
style: StrokeStyle;
arrowStart: boolean;
arrowEnd: boolean;
bounds: Rect;
};
}The Element Union
type Element =
| StrokeElement
| ShapeElement
| TextElement
| ImageElement
| StickyNoteElement
| GroupElement
| ConnectorElement;Use the type field to discriminate:
function getElementLabel(element: Element): string {
switch (element.type) {
case 'stroke': return 'Drawing';
case 'shape': return element.data.shapeType;
case 'text': return element.data.content.slice(0, 20);
case 'image': return 'Image';
case 'stickyNote': return 'Sticky Note';
case 'group': return `Group (${element.data.childIds.length})`;
case 'connector': return 'Connector';
}
}