# Image Editor URL: /docs/web/components/image-editor An image editor with crop, brightness, saturation, contrast, and hue adjustments, supporting rectangle and circle stencils with zoom controls. **Demo:** ```tsx 'use client'; // @custom-demo import { useCallback, useState } from 'react'; // next/image removed — using native in Vite import { type StencilShape, ImageEditor } from '@docyrus/ui/components/image-editor'; import { cn } from '@docyrus/ui/primitives/lib/utils'; import { type PropControl, PropControls } from '@/components/prop-controls'; const GALLERY_IMAGES = [ 'https://images.unsplash.com/photo-1535930749574-1399327ce78f?w=800&h=600&fit=crop', 'https://images.unsplash.com/photo-1506744038136-46273834b3fb?w=800&h=600&fit=crop', 'https://images.unsplash.com/photo-1469474968028-56623f02e42e?w=800&h=600&fit=crop', 'https://images.unsplash.com/photo-1447752875215-b2761acb3c5d?w=800&h=600&fit=crop' ]; export function ImageEditorDemo() { const [selectedIndex, setSelectedIndex] = useState(0); const [savedImage, setSavedImage] = useState(null); const [open, setOpen] = useState(false); const [stencilShape, setStencilShape] = useState('rectangle'); const [variant, setVariant] = useState<'default' | 'compact'>('default'); const [size, setSize] = useState<'sm' | 'default' | 'lg'>('default'); const [aspectRatio, setAspectRatio] = useState(0); const [disabled, setDisabled] = useState(false); const handleSave = useCallback((dataUrl: string) => { setSavedImage(dataUrl); }, []); const controls: PropControl[] = [ { type: 'select', name: 'stencilShape', label: 'Stencil Shape', value: stencilShape, onChange: v => setStencilShape(v as StencilShape), options: [{ value: 'rectangle', label: 'Rectangle' }, { value: 'circle', label: 'Circle' }] }, { type: 'select', name: 'variant', label: 'Variant', value: variant, onChange: v => setVariant(v as 'default' | 'compact'), options: [{ value: 'default', label: 'Default' }, { value: 'compact', label: 'Compact' }] }, { type: 'select', name: 'size', label: 'Size', value: size, onChange: v => setSize(v as 'sm' | 'default' | 'lg'), options: [{ value: 'sm', label: 'Small' }, { value: 'default', label: 'Default' }, { value: 'lg', label: 'Large' }] }, { type: 'number', name: 'aspectRatio', label: 'Aspect Ratio', value: aspectRatio, onChange: setAspectRatio, min: 0, max: 10, placeholder: '0 = free' }, { type: 'boolean', name: 'disabled', label: 'Disabled', value: disabled, onChange: setDisabled } ]; return (
0 ? aspectRatio : undefined} disabled={disabled} onSave={handleSave} />
{GALLERY_IMAGES.map((src, i) => ( ))}
{savedImage ? (

Saved result:

Edited
) : null}
); } ``` ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/ui-image-editor ``` **Dependencies:** - [react-advanced-cropper](https://www.npmjs.com/package/react-advanced-cropper) - [advanced-cropper](https://www.npmjs.com/package/advanced-cropper) - [class-variance-authority](https://www.npmjs.com/package/class-variance-authority) - [lucide-react](https://www.npmjs.com/package/lucide-react) ## Usage ```tsx import { ImageEditor } from '@docyrus/ui/components/image-editor'; { // dataUrl is a base64 canvas export console.log('Saved:', dataUrl); }} onUpload={(file) => { console.log('Uploaded:', file.name); }} /> ``` ### Circle Crop with Aspect Ratio ```tsx ``` ### Compact Variant ```tsx ``` ## Variants | Variant | Description | |---------|-------------| | `default` | Standard editor with full border and background. | | `compact` | Reduced visual weight with subtle border and muted background. | ## Sizes | Size | Description | |------|-------------| | `sm` | Cropper height: 300px. | | `default` | Cropper height: 400px. | | `lg` | Cropper height: 500px. | ## API Reference ### ImageEditor | Prop | Type | Default | Description | |------|------|---------|-------------| | `src` | `string` | — | Initial image URL to edit. | | `onSave` | `(dataUrl: string) => void` | — | Called with the base64 canvas data URL on save. | | `onUpload` | `(file: File) => void` | — | Called when a new file is uploaded via the file input. | | `disabled` | `boolean` | `false` | Disable all editing interactions. | | `stencilShape` | `'rectangle' \| 'circle'` | `'rectangle'` | Crop area shape. | | `aspectRatio` | `number` | — | Enforce a fixed aspect ratio for the crop area. | | `minCropWidth` | `number` | — | Minimum crop width in pixels. | | `minCropHeight` | `number` | — | Minimum crop height in pixels. | | `maxCropWidth` | `number` | — | Maximum crop width in pixels. | | `maxCropHeight` | `number` | — | Maximum crop height in pixels. | | `variant` | `'default' \| 'compact'` | `'default'` | Visual style. | | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Cropper area height. | | `className` | `string` | — | Additional CSS classes. | ## Type Reference ### EditorMode `'crop'` | `'brightness'` | `'saturation'` | `'contrast'` | `'hue'` The active editing mode. The toolbar switches between crop and adjustment sliders based on this value. ### StencilShape `'rectangle'` | `'circle'` Determines the crop stencil shape. Circle mode renders a circular crop area. ### Adjustments | Field | Type | Default | Description | |-------|------|---------|-------------| | `brightness` | `number` | `0` | Brightness adjustment (0–100 scale). | | `saturation` | `number` | `0` | Saturation adjustment (0–100 scale). | | `hue` | `number` | `0` | Hue rotation (0–100 scale). | | `contrast` | `number` | `0` | Contrast adjustment (0–100 scale). | ### Editor Controls | Control | Action | |---------|--------| | Crop mode | Drag to select crop area, resize handles to adjust. | | Adjustment sliders | Drag slider to adjust brightness/saturation/hue/contrast. | | Zoom in/out | Buttons to zoom the image (1.25x step). | | Upload | Opens file picker for a new image. | | Reset | Returns to crop mode with default adjustments. | | Save | Exports the cropped + adjusted result as a data URL. |