Shared Types — @edv4h/usketch-shared
Key type reference for the shared package.
The @edv4h/usketch-shared package exports all type definitions used across uSketch.
Geometry
interface Point {
x: number;
y: number;
}
interface BoundingBox {
x: number;
y: number;
width: number;
height: number;
}
interface Viewport {
x: number;
y: number;
zoom: number;
}
Shape
interface ShapeStyle {
fill: string;
stroke: string;
strokeWidth: number;
opacity: number;
}
interface ShapeData {
id: string;
type: string;
x: number;
y: number;
width: number;
height: number;
style: ShapeStyle;
rotation?: number;
[key: string]: unknown;
}
type ResizeHandle = "nw" | "n" | "ne" | "e" | "se" | "s" | "sw" | "w";
const DEFAULT_STYLE: ShapeStyle = {
fill: "#ffffff",
stroke: "#1e1e1e",
strokeWidth: 2,
opacity: 1,
};
Plugin
interface UsketchPlugin {
readonly id: string;
readonly name: string;
setup(ctx: PluginContext): void | Promise<void>;
teardown?(): void;
}
interface PluginContext {
store: BoardStore;
layers: LayerManager;
tools: ToolRegistry;
shapes: ShapeRegistry;
commands: CommandRegistry;
shortcuts: ShortcutRegistry;
events: EventBus;
transient: TransientRegistry;
}
Shape System
interface ShapeDefinition {
render: (data: ShapeData) => ReactElement;
getBounds: (data: ShapeData) => BoundingBox;
hitTest: (data: ShapeData, point: Point) => boolean;
resize: (data: ShapeData, handle: ResizeHandle, delta: Point) => ShapeData;
createDefault: (params: { id: string; x: number; y: number }) => ShapeData;
renderTarget?: "svg" | "html";
minSize?: { width: number; height: number };
move?: (data: ShapeData, dx: number, dy: number) => Partial<ShapeData>;
applyBounds?: (data: ShapeData, newBounds: BoundingBox) => Partial<ShapeData>;
}
interface ShapeRegistry {
register(type: string, definition: ShapeDefinition): void;
get(type: string): ShapeDefinition | undefined;
getAll(): ReadonlyMap<string, ShapeDefinition>;
}
Tool System
interface ToolDefinition {
icon: () => ReactElement;
cursor?: string;
shortcut?: string;
order?: number;
onActivate?: (ctx: ToolContext) => void;
onDeactivate?: (ctx: ToolContext) => void;
onPointerDown?: (ctx: ToolContext, event: CanvasPointerEvent) => void;
onPointerMove?: (ctx: ToolContext, event: CanvasPointerEvent) => void;
onPointerUp?: (ctx: ToolContext, event: CanvasPointerEvent) => void;
}
interface ToolContext {
store: BoardStore;
shapes: ShapeRegistry;
commands: CommandRegistry;
events: EventBus;
}
interface CanvasPointerEvent {
worldPoint: Point;
screenPoint: Point;
shiftKey: boolean;
ctrlKey: boolean;
metaKey: boolean;
altKey: boolean;
button: number;
}
interface CanvasWheelEvent {
screenPoint: Point;
worldPoint: Point;
deltaX: number;
deltaY: number;
ctrlKey: boolean;
metaKey: boolean;
shiftKey: boolean;
}
interface ToolRegistry {
register(id: string, definition: ToolDefinition): void;
get(id: string): ToolDefinition | undefined;
getAll(): ReadonlyMap<string, ToolDefinition>;
getOrdered(): readonly { id: string; definition: ToolDefinition }[];
}
Layer System
interface Layer {
id: string;
order: number;
render: (ctx: LayerRenderContext) => ReactElement | null;
interactable?: boolean;
fixed?: boolean;
}
interface LayerRenderContext {
viewport: Viewport;
shapes: ReadonlyMap<string, ShapeData>;
selection: ReadonlySet<string>;
theme: Theme;
}
interface LayerManager {
register(layer: Layer): void;
unregister(layerId: string): void;
getLayers(): readonly Layer[];
}
Command System
interface Command {
execute(): void;
undo(): void;
}
interface CommandRegistry {
execute(command: Command): void;
undo(): void;
redo(): void;
canUndo(): boolean;
canRedo(): boolean;
getHistorySize(): number;
getCursor(): number;
}
Shortcut System
interface ShortcutRegistry {
register(combo: string, callback: () => void): () => void;
handleKeyDown(event: KeyboardEvent): boolean;
}
Event Bus
interface EventBus {
on<T = unknown>(event: string, handler: (data: T) => void): () => void;
emit<T = unknown>(event: string, data: T): void;
}
Transient System
interface TransientObject {
id: string;
type: string;
sourceUserId: string;
position: Point;
data: Record<string, unknown>;
ttl?: number;
createdAt: number;
}
interface TransientRenderer {
render: (obj: TransientObject, ctx: LayerRenderContext) => ReactElement;
}
interface TransientRegistry {
registerType(type: string, renderer: TransientRenderer): void;
getRenderer(type: string): TransientRenderer | undefined;
emit(obj: TransientObject): void;
dismiss(id: string): void;
getAll(): ReadonlyMap<string, TransientObject>;
subscribe(listener: () => void): () => void;
}
Board Store
interface BoardStore {
// Shape CRUD
getShapes(): ReadonlyMap<string, ShapeData>;
getShape(id: string): ShapeData | undefined;
addShape(shape: ShapeData): void;
updateShape(id: string, updates: Partial<ShapeData>): void;
deleteShape(id: string): void;
// Selection
getSelection(): ReadonlySet<string>;
setSelection(ids: string[]): void;
addToSelection(id: string): void;
removeFromSelection(id: string): void;
clearSelection(): void;
// Active tool
getActiveToolId(): string;
setActiveToolId(id: string): void;
// Viewport
getViewport(): Viewport;
setViewport(viewport: Viewport): void;
panBy(dx: number, dy: number): void;
zoomTo(zoom: number, center: Point): void;
// Style
getStyleSettings(): ShapeStyle;
setStyleSettings(style: Partial<ShapeStyle>): void;
// Subscriptions
subscribe(listener: () => void): () => void;
onMutation(listener: (event: StoreEvent) => void): () => void;
}
interface StoreEvent {
type: string;
payload?: unknown;
}