@molecule/app-image-crop
Core interface · image-crop · App (browser) · v1.0.2 · Apache-2.0
Image crop core interface for molecule.dev.
npm install @molecule/app-image-cropHow it works
@molecule/app-image-crop is the image-crop core interface on the app (browser) side: the API your app calls, with no vendor inside.
Choose the implementation by bonding one of its 1 provider: @molecule/app-image-crop-cropperjs.
import { setProvider, requireProvider } from '@molecule/app-image-crop'
import { provider } from '@molecule/app-image-crop-cropperjs'
setProvider(provider) // once, at app startup (bonds.ts)
const cropper = requireProvider().createCropper({
src: '/photos/avatar.jpg',
aspectRatio: 1,
circular: true,
})
const canvas = cropper.getCroppedCanvas({ width: 200, height: 200 })
canvas.toBlob((blob) => uploadAvatar(blob))Providers (1): @molecule/app-image-crop-cropperjs
Works with: @molecule/app-bond
Live demos
Running apps built with Molecule that install this package — open the app or study the template.
Reference
Image crop core interface for molecule.dev.
Framework-agnostic contract for image cropping: crop-region state
(rect, rotation, zoom) plus cropped-canvas output. Bond a provider (e.g.
@molecule/app-image-crop-cropperjs) to supply the crop math; your UI
renders the preview and drag handles and feeds gestures into the instance.
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
Quick Start
import { setProvider, requireProvider } from '@molecule/app-image-crop'
import { provider } from '@molecule/app-image-crop-cropperjs'
setProvider(provider) // once, at app startup (bonds.ts)
const cropper = requireProvider().createCropper({
src: '/photos/avatar.jpg',
aspectRatio: 1,
circular: true,
})
const canvas = cropper.getCroppedCanvas({ width: 200, height: 200 })
canvas.toBlob((blob) => uploadAvatar(blob))
Type
core
Installation
npm install @molecule/app-image-crop @molecule/app-bond
API
Interfaces
CropData
Crop region data describing the selected area and transformations.
interface CropData {
/** X coordinate of the crop area origin. */
x: number
/** Y coordinate of the crop area origin. */
y: number
/** Width of the crop area. */
width: number
/** Height of the crop area. */
height: number
/** Rotation angle in degrees. */
rotate: number
/** Horizontal scale factor. */
scaleX: number
/** Vertical scale factor. */
scaleY: number
}
OutputOptions
Output options for generating the cropped image.
interface OutputOptions {
/** Output width in pixels. */
width?: number
/** Output height in pixels. */
height?: number
/** Fill color for empty areas (e.g. after rotation). Defaults to `'transparent'`. */
fillColor?: string
/** Image quality for lossy formats (0-1). Defaults to `1`. */
quality?: number
}
CropperOptions
Configuration options for creating an image cropper.
interface CropperOptions {
/** Source image URL or data URI. */
src: string
/** Fixed aspect ratio (width / height). `undefined` for free-form. */
aspectRatio?: number
/** Minimum crop width in pixels. */
minWidth?: number
/** Minimum crop height in pixels. */
minHeight?: number
/** Maximum crop width in pixels. */
maxWidth?: number
/** Maximum crop height in pixels. */
maxHeight?: number
/** Whether the crop area should be circular. Defaults to `false`. */
circular?: boolean
/** Whether to show crop guide lines. Defaults to `true`. */
guides?: boolean
}
CropperInstance
A live cropper instance returned by the provider.
interface CropperInstance {
/**
* Generates a canvas element containing the cropped image.
*
* @param options - Optional output configuration.
* @returns An HTMLCanvasElement with the cropped result.
*/
getCroppedCanvas(options?: OutputOptions): HTMLCanvasElement
/**
* Returns the current crop region data.
*
* @returns The current crop data.
*/
getCropData(): CropData
/**
* Sets the crop region programmatically.
*
* @param data - The crop data to apply.
*/
setCropData(data: CropData): void
/**
* Resets the cropper to its initial state.
*/
reset(): void
/**
* Rotates the image by the specified degrees.
*
* @param degrees - Rotation angle in degrees (positive = clockwise).
*/
rotate(degrees: number): void
/**
* Zooms the image by the specified ratio.
*
* @param ratio - Zoom ratio (positive to zoom in, negative to zoom out).
*/
zoom(ratio: number): void
/**
* Destroys the cropper instance and cleans up resources.
*/
destroy(): void
}
ImageCropProvider
Image crop provider interface.
All image crop providers must implement this interface to create and manage image cropping UI.
interface ImageCropProvider {
/** Provider name identifier. */
readonly name: string
/**
* Creates a new cropper instance.
*
* @param options - Configuration for the cropper.
* @returns A cropper instance for managing the crop operation.
*/
createCropper(options: CropperOptions): CropperInstance
}
Functions
setProvider(provider)
Registers an image crop provider as the active singleton.
function setProvider(provider: ImageCropProvider): void
provider— The image crop provider implementation to bond.
getProvider()
Retrieves the bonded image crop provider, or null if none is bonded.
function getProvider(): ImageCropProvider | null
Returns: The active image crop provider, or null.
hasProvider()
Checks whether an image crop provider has been bonded.
function hasProvider(): boolean
Returns: true if an image crop provider is available.
requireProvider()
Retrieves the bonded image crop provider, throwing if none is configured.
function requireProvider(): ImageCropProvider
Returns: The active image crop provider.
Available Providers
| Provider | Package |
|---|---|
| Image Crop | @molecule/app-image-crop-cropperjs |
Injection Notes
Requirements
Peer dependencies:
@molecule/app-bond^1.0.1
Runtime Dependencies
-
@molecule/app-bond -
The instance is headless — no crop UI mounts anywhere. Render the image, crop-box overlay, and handles yourself (styled via
getClassMap()/cm.*) and translate drag/resize gestures intosetCropData()/rotate()/zoom(); readgetCropData()to draw the overlay. -
Verify the cropped output end-to-end before shipping — draw the returned canvas into the page or upload-and-render it; an empty/blank result means the bonded provider does not implement canvas output, which is an integration bug to fix, not to skip.
-
Wire with THIS package's
setProvider()orbond('image-crop', …)—setProvider()delegates into the shared@molecule/app-bondregistry, so both write the same slot;requireProvider()throws until one has run. -
Upload the result as a Blob (
canvas.toBlob) through your upload path; the server must re-validate the file (type/size) — client cropping is UX, not a boundary.
E2E Tests
Integration checklist — drive the real UI (live preview, no mocks), adapt each item to this app's actual crop screen (avatar/photo upload, etc.), and check every box off one by one. A box you can't check is an integration bug to fix — not a skip. The cropper is headless, so verify the UI YOU rendered:
- Opening the crop screen loads the source image (
createCropper({ src })) and renders it with a visible crop-box overlay + drag handles drawn fromgetCropData()— not a blank or full-bleed image with no selection. - Dragging/resizing the crop box feeds the gesture into
setCropData(),getCropData()reflects the new x/y/width/height, and the on-page preview (thegetCroppedCanvas()output drawn into the page) updates to show ONLY the selected area, not the whole image. - With an aspect-ratio lock (e.g.
aspectRatio: 1for an avatar) the crop box stays that ratio while you resize —getCropData()width == height for 1:1 — andcircular: trueclips the preview to a circle. -
rotate()/zoom()transform the source and the crop overlay follows:getCropData().rotate/scaleXchange and the preview re-renders the transformed region — the selection isn't stranded on the old orientation. - Applying the crop OUTPUTS the cropped image:
getCroppedCanvas()pixels match the selected region (not the full source), and downstream the SAVED file is the cropped Blob (canvas.toBlob→ upload) — re-fetch and render the stored image and confirm it shows the crop, never the original. - Min/max crop size is enforced — you cannot drag the box smaller than
minWidth/minHeightor larger thanmaxWidth/maxHeight. - Cancel/close discards without mutating the source: the original image is unchanged and no cropped result is saved.