@orchard9ai/cropper
v0.8.0
Published
A React image cropping component with aspect ratio controls
Readme
@orchard9ai/cropper
A React image cropping component with aspect ratio controls, built on top of react-image-crop.
Features
- 🖼️ Image cropping with visual selection
- 📐 Multiple aspect ratio presets (Freeform, Square, Landscape, Portrait, Original)
- 👁️ Optional preview panel
- 🌍 Internationalization support with customizable labels
- 🎨 Dark theme with Tailwind CSS
- ⌨️ Keyboard support (ESC to close)
- 📱 Responsive design
- 🔄 Loading states
- 💾 State management with Zustand
Installation
npm install @orchard9ai/cropper react-image-crop
# or
yarn add @orchard9ai/cropper react-image-crop
# or
pnpm add @orchard9ai/cropper react-image-cropNote: react-image-crop is now a peer dependency and must be installed separately for SSR compatibility.
Peer Dependencies
This package requires the following peer dependencies:
{
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-image-crop": "^11.0.0"
}Usage
Basic Example
import { CropModal, CropData } from '@orchard9ai/cropper';
import '@orchard9ai/cropper/styles'; // Import CSS styles
function App() {
const [showCropper, setShowCropper] = useState(false);
const handleCrop = async (cropData: CropData) => {
console.log('Crop data:', cropData);
// Send crop data to your API
await api.cropImage(imageId, cropData);
};
return (
<>
<button onClick={() => setShowCropper(true)}>Open Cropper</button>
{showCropper && (
<CropModal
imageUrl="https://example.com/image.jpg"
onClose={() => setShowCropper(false)}
onCrop={handleCrop}
/>
)}
</>
);
}With Preview
<CropModal
imageUrl="https://example.com/image.jpg"
previewUrl="https://example.com/preview.jpg"
onClose={() => setShowCropper(false)}
onCrop={handleCrop}
/>With Initial Aspect Ratio
<CropModal
imageUrl="https://example.com/image.jpg"
aspectRatio={1} // Square aspect ratio
onClose={() => setShowCropper(false)}
onCrop={handleCrop}
/>With Custom Labels (i18n)
<CropModal
imageUrl="https://example.com/image.jpg"
onClose={() => setShowCropper(false)}
onCrop={handleCrop}
labels={{
title: 'Recortar Imagen',
cancel: 'Cancelar',
apply: 'Aplicar',
loading: 'Procesando...',
loadingImage: 'Cargando imagen...',
original: 'Original',
selection: 'Selección',
aspectRatios: {
freeform: 'Libre',
square: 'Cuadrado',
landscape: 'Horizontal',
portrait: 'Vertical',
original: 'Original',
},
}}
/>API
CropModal Props
| Prop | Type | Required | Description |
| ------------- | --------------------------------------- | -------- | ----------------------------------------- |
| imageUrl | string | Yes | URL of the image to crop |
| onClose | () => void | Yes | Callback when modal is closed |
| onCrop | (cropData: CropData) => Promise<void> | Yes | Callback with crop data |
| previewUrl | string | No | Optional preview image URL |
| isLoading | boolean | No | Shows loading state |
| aspectRatio | number | No | Initial aspect ratio (e.g., 1 for square) |
| labels | Labels | No | Custom labels for i18n |
CropData Interface
interface CropData {
x: number; // X coordinate of crop area
y: number; // Y coordinate of crop area
width: number; // Width of crop area
height: number; // Height of crop area
original_width: number; // Original image width
original_height: number; // Original image height
regenerate_variants?: boolean;
}Labels Interface
interface Labels {
title?: string;
cancel?: string;
apply?: string;
loading?: string;
loadingImage?: string;
original?: string;
selection?: string;
aspectRatios?: {
freeform?: string;
square?: string;
landscape?: string;
portrait?: string;
original?: string;
};
}Styling
This component uses Tailwind CSS for styling. Make sure to include the styles in your application:
import '@orchard9ai/cropper/styles';If you're using Tailwind CSS in your project, ensure the package's files are included in your content configuration:
// tailwind.config.js
module.exports = {
content: [
// ... your other content paths
'./node_modules/@orchard9ai/cropper/dist/**/*.{js,mjs}',
],
// ... rest of your config
};Advanced Usage
Accessing the Store
For advanced use cases, you can access the crop store directly:
import { useCropStore } from '@orchard9ai/cropper';
function MyComponent() {
const { crop, aspectRatio, setAspectRatio } = useCropStore();
// Use store values and methods
}Utility Functions
The package exports several utility functions:
import {
formatDimensions,
getAspectRatioLabel,
percentCropToPixelCrop,
pixelCropToPercentCrop,
constrainCrop,
debounce,
} from '@orchard9ai/cropper';Migration from Original Component
If you're migrating from the original BulkUploadReview CropModal:
Import Changes:
// Before import { CropModal } from '@/pages/BulkUploadReview/components/CropModal'; // After import { CropModal } from '@orchard9ai/cropper'; import '@orchard9ai/cropper/styles';Type Import Changes:
// Before import { CropData } from '@/types/CropTypes'; // After import { CropData } from '@orchard9ai/cropper';Props: The component API remains the same, so no changes needed.
Development
Running Storybook
npm run storybookBuilding
npm run buildType Checking
npm run typecheckLicense
MIT
