import React from 'react'; import type { CropperRef } from 'react-advanced-cropper'; import { ImageRestriction } from 'react-advanced-cropper'; import type { Meta, StoryObj } from '@storybook/react-vite'; import { cropImageToFile } from '../../utils/cropImage'; import { generateSvgPlaceholder } from '../../utils/storybook'; import { Button } from '../Button/Button'; import { Stack } from '../Stack/Stack'; import { Paragraph } from '../Typography/Paragraph/Paragraph'; import { Text } from '../Typography/Text/Text'; import { ImageCrop } from './ImageCrop'; const SOURCE_IMAGE = generateSvgPlaceholder(1200, 800); const SaveableImageCrop: React.FC> = props => { const cropperRef = React.useRef(null); const [savedFile, setSavedFile] = React.useState(null); const [savedUrl, setSavedUrl] = React.useState(null); const [isSaving, setIsSaving] = React.useState(false); const [errorMessage, setErrorMessage] = React.useState(null); React.useEffect(() => { return () => { if (savedUrl) { URL.revokeObjectURL(savedUrl); } }; }, [savedUrl]); const handleSave = async () => { const coordinates = cropperRef.current?.getCoordinates(); if (!coordinates || coordinates.width <= 0 || coordinates.height <= 0) { setErrorMessage('Adjust the crop first so there is an area to export.'); return; } setIsSaving(true); setErrorMessage(null); const result = await cropImageToFile( props.image, { x: coordinates.left, y: coordinates.top, width: coordinates.width, height: coordinates.height, }, { fileName: 'advanced-image-crop-demo.jpg', } ); setIsSaving(false); if (!result.success) { setErrorMessage(result.error.message); return; } const file = result.data; const nextUrl = URL.createObjectURL(file); setSavedFile(file); setSavedUrl(previousUrl => { if (previousUrl) { URL.revokeObjectURL(previousUrl); } return nextUrl; }); }; return ( {savedFile && {`${savedFile.name} (${Math.round(savedFile.size / 1024)} kB)`}} {errorMessage && {errorMessage}} {savedUrl && ( Exported preview Saved cropped preview )} ); }; const meta: Meta = { title: 'UI kit/ImageCrop', component: ImageCrop, tags: ['autodocs'], parameters: { docs: { description: { component: 'To export the selected crop area to a `File`, `Blob`, or `HTMLCanvasElement`, use the bundled crop utilities. See the [CropImage utils docs](?path=/docs/utils-cropimage--docs) page for the full API reference and code examples.', }, }, }, argTypes: { imageRestriction: { control: { type: 'select' }, defaultValue: ImageRestriction.fitArea, options: [ImageRestriction.fillArea, ImageRestriction.fitArea, ImageRestriction.stencil, ImageRestriction.none], }, }, args: { image: SOURCE_IMAGE, aspect: 16 / 9, height: 320, width: 520, }, }; export default meta; type Story = StoryObj; export const Default: Story = {}; export const RoundStencil: Story = { args: { aspect: 1, cropShape: 'round', }, }; export const FreeAspect: Story = { args: { aspect: undefined, imageRestriction: ImageRestriction.fitArea, }, }; export const SaveCroppedImage: Story = { render: args => , };