UNPKG

react-sketch-canvas

Version:

react-sketch-canvas - Freehand vector drawing tool for React using SVG as canvas

593 lines (586 loc) 18.7 kB
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 };