react-sketch-canvas
Version:
react-sketch-canvas - Freehand vector drawing tool for React using SVG as canvas
593 lines (586 loc) • 18.7 kB
TypeScript
import * as React from 'react';
/**
* Raster image format used by {@link ReactSketchCanvasRef.exportImage} and
* {@link CanvasRef.exportImage}.
*
* @remarks
* Use `"png"` when you need transparency. Use `"jpeg"` for smaller files or
* when the exported image should always include a solid background color.
*
* @public
*/
type ExportImageType = "jpeg" | "png";
/**
* Size options for raster image exports.
*
* @remarks
* When omitted, the exported image uses the rendered canvas element's current
* width and height. Provide both values to export a fixed-size image regardless
* of the on-screen canvas size.
*
* @public
*/
interface ExportImageOptions {
/**
* Width of the exported image in pixels.
*
* @defaultValue The current rendered canvas width.
*/
readonly width?: number;
/**
* Height of the exported image in pixels.
*
* @defaultValue The current rendered canvas height.
*/
readonly height?: number;
}
/**
* A two-dimensional coordinate on the canvas.
*
* @remarks
* Coordinates are measured in CSS pixels from the top-left corner of the
* rendered canvas. Pointer events, exported paths, and loaded paths all use
* this coordinate system.
*
* @public
*/
interface Point {
/**
* Horizontal coordinate in pixels from the left edge of the canvas.
*/
readonly x: number;
/**
* Vertical coordinate in pixels from the top edge of the canvas.
*/
readonly y: number;
}
/**
* A single stroke recorded by the sketch canvas.
*
* @remarks
* `CanvasPath` is the persistence format returned by
* {@link ReactSketchCanvasRef.exportPaths} and accepted by
* {@link ReactSketchCanvasRef.loadPaths}. Store this object if you want to save
* a drawing and replay it later.
*
* `drawMode` decides whether the stroke paints (`true`) or erases (`false`).
* Eraser strokes are stored as paths so exports and undo/redo can preserve the
* same visual result.
*
* @public
*/
interface CanvasPath {
/**
* Ordered points that make up this stroke.
*
* @remarks
* A stroke can contain a single point, which is rendered as a dot.
*/
readonly paths: Point[];
/**
* Stroke width in pixels.
*/
readonly strokeWidth: number;
/**
* Stroke color used when `drawMode` is `true`.
*
* @remarks
* Eraser paths are stored with an internal mask color, but consumers usually
* only need to preserve the value returned by `exportPaths`.
*/
readonly strokeColor: string;
/**
* Whether the stroke draws color (`true`) or erases existing strokes
* (`false`).
*/
readonly drawMode: boolean;
/**
* Timestamp captured when the stroke starts, in milliseconds since the Unix
* epoch.
*
* @remarks
* This is only present when `withTimestamp` is enabled.
*/
readonly startTimestamp?: number;
/**
* Timestamp captured when the stroke ends, in milliseconds since the Unix
* epoch.
*
* @remarks
* This is only present when `withTimestamp` is enabled.
*/
readonly endTimestamp?: number;
}
/**
* Pointer device class accepted by the drawing surface.
*
* @remarks
* Use `"all"` to accept mouse, pen, and touch input. Use a specific pointer
* type when the canvas should ignore other input devices, for example a
* pen-only signing flow.
*
* @public
*/
type AllowOnlyPointerType = "all" | "pen" | "mouse" | "touch";
/**
* Props for the low-level {@link Canvas} component.
*
* @remarks
* These props are primarily useful for composing a custom state manager around
* the low-level SVG canvas. Application code normally uses
* {@link ReactSketchCanvasProps}.
*
* @public
*/
interface CanvasProps {
/**
* Paths rendered on the SVG canvas.
*
* @remarks
* `Canvas` is controlled. Pass the complete path list for each render.
*/
paths: CanvasPath[];
/**
* Whether a pointer stroke is currently active.
*
* @remarks
* While this is `true`, pointer movement is forwarded to `onPointerMove`.
*/
isDrawing: boolean;
/**
* Called when the user starts a stroke.
*
* @remarks
* The callback receives the pointer coordinate normalized to the canvas and
* an eraser flag when a pen eraser button is detected.
*
* @param point - Canvas-relative point where the stroke starts.
* @param isEraser - Whether the pointer should create an eraser stroke.
* @returns Nothing.
*/
onPointerDown: (point: Point, isEraser?: boolean) => void;
/**
* Called when the active pointer moves while drawing.
*
* @param point - Canvas-relative point for the current pointer position.
* @returns Nothing.
*/
onPointerMove: (point: Point) => void;
/**
* Called when the active stroke ends.
*
* @remarks
* `Canvas` listens for `pointerup` on the document so a stroke can finish
* even when the pointer is released outside the canvas element.
*
* @returns Nothing.
*/
onPointerUp: () => void;
/**
* Pointer device class allowed to draw on the canvas.
*
* @remarks
* Other pointer devices can still interact with the page, but their drawing
* events are ignored by the canvas.
*
* @defaultValue `"all"`
*/
allowOnlyPointerType: AllowOnlyPointerType;
/**
* Background image shown behind all strokes.
*
* @remarks
* Accepts any SVG `<image>` `href` value, including a URL or data URI. When
* exporting with the background image enabled, remote images must allow
* cross-origin access.
*
* The value is treated as trusted: it is loaded directly into an SVG
* `<image>` element and, for SVG data URIs, parsed with `DOMParser` to read
* its viewBox. Do not pass attacker-controlled strings here without
* validating them first.
*
* @defaultValue `""`
*/
backgroundImage: string;
/**
* Background color shown when no background image is configured.
*
* @remarks
* `canvasColor` is also painted underneath every JPEG export, even when a
* background image is included, because JPEG cannot represent transparent
* pixels. With `preserveBackgroundImageAspectRatio="meet"` (or any value
* that letterboxes the image), the letterbox regions of a JPEG export will
* be filled with `canvasColor`.
*
* @defaultValue `"white"`
*/
canvasColor: string;
/**
* CSS class name applied to the outer canvas wrapper.
*
* @defaultValue `"react-sketch-canvas"`
*/
className?: string;
/**
* Whether exported images and SVGs include `backgroundImage`.
*
* @remarks
* Set this to `false` when the background image is only a drawing guide and
* should not be part of exported output.
*
* @defaultValue false
*/
exportWithBackgroundImage: boolean;
/**
* CSS height of the canvas wrapper.
*
* @remarks
* Accepts any valid CSS height value, such as `"400px"`, `"60vh"`, or
* `"100%"`.
*
* @defaultValue `"100%"`
*/
height: string;
/**
* DOM id applied to the rendered SVG canvas.
*
* @remarks
* Internal SVG definitions such as masks and background patterns are isolated
* per canvas instance, so multiple canvases can use the default id without
* sharing those internal references. Provide a unique id when application code
* needs to select or label a specific canvas element.
*
* @defaultValue `"react-sketch-canvas"`
*/
id?: string;
/**
* SVG `preserveAspectRatio` value used for `backgroundImage`.
*
* @remarks
* See the MDN reference for accepted values:
* {@link https://developer.mozilla.org/docs/Web/SVG/Attribute/preserveAspectRatio}.
*
* @defaultValue `"none"`
*/
preserveBackgroundImageAspectRatio?: React.SVGAttributes<HTMLImageElement>["preserveAspectRatio"];
/**
* Inline styles applied to the outer canvas wrapper.
*
* @remarks
* The component sets `userSelect: "none"` to avoid browser selection
* highlights while drawing. It sets `touchAction: "none"` for touch drawing,
* and `touchAction: "pan-x pan-y pinch-zoom"` in pen-only mode so touch can
* still scroll parent containers.
*
* @defaultValue The package default canvas border style.
*/
style: React.CSSProperties;
/**
* Inline styles applied to the internal SVG element.
*
* @defaultValue `{}`
*/
svgStyle: React.CSSProperties;
/**
* Whether the internal SVG should include a viewBox based on the latest
* measured canvas size.
*
* @remarks
* Enable this when you need SVG output that scales predictably with the
* rendered canvas dimensions.
*
* @defaultValue false
*/
withViewBox?: boolean;
/**
* CSS width of the canvas wrapper.
*
* @remarks
* Accepts any valid CSS width value, such as `"600px"`, `"100%"`, or
* `"80vw"`.
*
* @defaultValue `"100%"`
*/
width: string;
/**
* Whether pointer drawing is disabled.
*
* @remarks
* Existing paths are still rendered and ref export methods still work.
*
* @defaultValue false
*/
readOnly?: boolean;
/**
* CSS `touch-action` applied to the canvas wrapper.
*
* @remarks
* The default is `"none"` when the canvas accepts touch drawing, so single
* finger gestures draw rather than scroll. Override this when you need the
* surrounding page to remain scrollable; for example, set `"pan-y"` to let
* users scroll vertically while still drawing with one finger. The browser
* will start a native pan only when the gesture matches the configured
* axis, so single-finger drawing continues to work.
*
* @defaultValue `"none"` for touch-drawing modes; `"pan-x pan-y pinch-zoom"` for pen / mouse only modes.
*/
touchAction?: React.CSSProperties["touchAction"];
}
/**
* Imperative ref API exposed by the low-level {@link Canvas} component.
*
* @public
*/
interface CanvasRef {
/**
* Export the current canvas as a raster image data URL.
*
* @remarks
* The output includes the currently rendered strokes. Background image export
* depends on the `exportWithBackgroundImage` prop.
*
* @param imageType - Image format to create.
* @param options - Optional export dimensions.
* @returns Promise that resolves to a `data:image/*` URL.
*/
exportImage: (imageType: ExportImageType, options?: ExportImageOptions) => Promise<string>;
/**
* Export the current canvas as SVG markup.
*
* @remarks
* The returned string contains the cloned SVG element after export-specific
* background handling has been applied.
*
* @returns Promise that resolves to SVG markup.
*/
exportSvg: () => Promise<string>;
}
/**
* Low-level SVG drawing canvas.
*
* @remarks
* `Canvas` renders the SVG surface, handles pointer normalization, and exposes
* export methods through its forwarded ref. Most consumers should use
* `ReactSketchCanvas` instead, which manages drawing state and undo/redo.
*
* Use `Canvas` directly when you need full control over path state, custom
* history behavior, or integration with an external drawing state machine.
*
* @param props - Rendering, pointer, and export options for the canvas.
* @param ref - Ref exposing {@link CanvasRef} export methods.
* @returns The low-level canvas element.
*
* @public
*/
declare const Canvas: React.ForwardRefExoticComponent<CanvasProps & React.RefAttributes<CanvasRef>>;
/**
* Eraser behavior used for pointer erasing.
*
* @remarks
* `"mask"` stores eraser gestures as mask paths, preserving the historical
* export and undo/redo behavior. `"stroke"` removes whole drawing strokes
* touched by the eraser gesture instead of storing the gesture path.
*
* @public
*/
type EraserMode = "mask" | "stroke";
/**
* Props for the stateful {@link ReactSketchCanvas} component.
*
* @remarks
* `ReactSketchCanvas` composes the low-level {@link CanvasProps} with drawing
* state management. You can pass sizing, styling, background, pointer, and
* export props from `CanvasProps`; path state and pointer callbacks are managed
* internally by the component.
*
* @public
*/
interface ReactSketchCanvasProps extends Partial<Omit<CanvasProps, "paths" | "isDrawing" | "onPointerDown" | "onPointerMove" | "onPointerUp">> {
/**
* Width of eraser strokes in pixels.
*
* @remarks
* This width is used when `eraseMode(true)` is active or when a pen eraser
* button is detected.
*
* @defaultValue `8`
*/
eraserWidth?: number;
/**
* Eraser behavior used when `eraseMode(true)` is active or a pen eraser
* button is detected.
*
* @remarks
* Use `"mask"` to preserve eraser gestures as SVG mask paths. Use `"stroke"`
* when erasing should delete whole drawing strokes touched by the eraser.
*
* @defaultValue `"mask"`
*/
eraserMode?: EraserMode;
/**
* Called whenever the rendered path list changes.
*
* @remarks
* Use this callback to persist drawings as the user sketches. The callback is
* invoked after strokes, undo, redo, clear, reset, and `loadPaths` updates.
*
* @param updatedPaths - Complete current path list.
* @returns Nothing.
*/
onChange?: (updatedPaths: CanvasPath[]) => void;
/**
* Called when the user completes a stroke.
*
* @remarks
* This callback fires for both drawing and erasing strokes. It is intended
* for event-style handling; use `onChange` when you need the complete drawing
* state.
*
* @param path - Stroke that was just completed.
* @param isEraser - Whether the completed stroke erased existing content.
* @returns Nothing.
*/
onStroke?: (path: CanvasPath, isEraser: boolean) => void;
/**
* Color used for drawing strokes.
*
* @remarks
* Accepts any SVG stroke color value, including named colors, hex colors,
* RGB values, and CSS variables.
*
* @defaultValue "red"
*/
strokeColor?: string;
/**
* Width of drawing strokes in pixels.
*
* @remarks
* Eraser strokes use `eraserWidth` instead.
*
* @defaultValue `4`
*/
strokeWidth?: number;
/**
* Whether strokes should include start and end timestamps.
*
* @remarks
* Enable this before drawing if you want `CanvasPath.startTimestamp`,
* `CanvasPath.endTimestamp`, and `getSketchingTime()` to report active
* drawing time.
*
* @defaultValue false
*/
withTimestamp?: boolean;
}
/**
* Imperative ref API exposed by {@link ReactSketchCanvas}.
*
* @remarks
* Use this ref to control drawing mode, history, exports, and path loading
* from parent components.
*
* @public
*/
interface ReactSketchCanvasRef extends CanvasRef {
/**
* Switch between drawing and erasing.
*
* @remarks
* Passing `true` enables erasing for future strokes. Passing `false` returns
* to normal drawing mode. Existing paths are not changed.
*
* @param erase - Whether future pointer strokes should erase.
* @returns Nothing.
*/
eraseMode: (erase: boolean) => void;
/**
* Remove all paths from the canvas while preserving history.
*
* @remarks
* Users can still undo back to the previous drawing after `clearCanvas()`.
* Use `resetCanvas()` when you want to remove paths and clear undo/redo
* history.
*
* @returns Nothing.
*/
clearCanvas: () => void;
/**
* Restore the previous history entry.
*
* @remarks
* Calling `undo()` when there is no earlier history entry leaves the canvas
* unchanged.
*
* @returns Nothing.
*/
undo: () => void;
/**
* Restore the next history entry after an undo.
*
* @remarks
* Calling `redo()` when there is no later history entry leaves the canvas
* unchanged.
*
* @returns Nothing.
*/
redo: () => void;
/**
* Export the current path data.
*
* @remarks
* The returned paths can be stored and later passed to `loadPaths()`.
*
* @returns Promise that resolves with the current path list.
*/
exportPaths: () => Promise<CanvasPath[]>;
/**
* Append paths to the canvas.
*
* @remarks
* Existing paths are preserved. The provided paths are appended to the end
* of the current path list and become part of undo/redo history.
*
* @param paths - Paths to append to the current drawing.
* @returns Nothing.
*/
loadPaths: (paths: CanvasPath[]) => void;
/**
* Get the total active drawing time in milliseconds.
*
* @remarks
* This only works when `withTimestamp` is enabled before drawing. Idle time
* between strokes is not included.
*
* @returns Promise that resolves with the total sketching time.
*/
getSketchingTime: () => Promise<number>;
/**
* Remove all paths and clear undo/redo history.
*
* @remarks
* Use `clearCanvas()` instead when the user should be able to undo the
* clearing action.
*
* @returns Nothing.
*/
resetCanvas: () => void;
}
/**
* Stateful sketch canvas component for freehand SVG drawing.
*
* @remarks
* `ReactSketchCanvas` manages paths, draw/erase mode, undo/redo history,
* timestamp capture, and public imperative methods. It is the primary component
* intended for application use.
*
* Use a ref when you need to export images or paths, toggle erasing from a
* toolbar, or control history from parent UI.
*
* @param props - Public drawing, styling, export, and callback options.
* @param ref - Ref exposing {@link ReactSketchCanvasRef} methods.
* @returns The sketch canvas component.
*
* @public
*/
declare const ReactSketchCanvas: React.ForwardRefExoticComponent<ReactSketchCanvasProps & React.RefAttributes<ReactSketchCanvasRef>>;
export { type AllowOnlyPointerType, Canvas, type CanvasPath, type CanvasProps, type CanvasRef, type EraserMode, type ExportImageOptions, type ExportImageType, type Point, ReactSketchCanvas, type ReactSketchCanvasProps, type ReactSketchCanvasRef };