npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@leancodepl/image-uploader

v9.6.6

Published

React component for uploading images

Downloads

133

Readme

@leancodepl/image-uploader

React component for image uploads.

Installation

npm install @leancodepl/image-uploader
yarn add @leancodepl/image-uploader

API

useUploadImages(value, accept, cropper, onError, onChange)

Manages image upload state and provides drag-and-drop functionality. Creates a complete image upload solution with file validation, drag-and-drop support, optional cropping, and duplicate detection. Returns upload state and control functions.

Parameters:

  • value?: FileWithId[] - Current array of uploaded files with IDs
  • accept?: Accept - File types to accept (defaults to image types)
  • cropper?: CropperConfig - Optional cropper configuration for image editing
  • onError?: (errorCode: ErrorCode) => void - Callback for handling upload errors
  • onChange?: (files: FileWithId[]) => void - Callback when file list changes

Returns: Upload state and control functions including dropzone props

tryUploadWithUploadParams(image, getUploadParams)

Uploads an image file using provided upload parameters. Handles file upload by calling the getUploadParams function to retrieve upload configuration, then performs a fetch request to upload the file. Returns early if the image is already uploaded.

Parameters:

  • image: FileWithId | UploadedFileWithId - Image file with ID or already uploaded image with URL
  • getUploadParams: (image: FileWithId) => Promise<UploadParams | null | undefined> - Function that returns upload parameters (URI, method, headers) for the image

Returns: Promise resolving to uploaded image with URL

Throws: Error - When upload params are not defined, image is not defined, or upload fails

UploadImages.Root

Root wrapper component for image upload functionality. Provides upload context to all child UploadImages components and renders a div container. Must wrap all other UploadImages components to provide shared state.

Parameters:

  • uploader: ReturnType<typeof useUploadImages> - Upload state and functions from useUploadImages hook
  • props: HTMLAttributes<HTMLDivElement> - Additional HTML div attributes

Returns: JSX element wrapping children with upload context

UploadImages.Zone

Drag-and-drop zone component for file uploads. Creates an interactive drop zone with file input capabilities. Supports both click-to-select and drag-and-drop file uploads. Provides drag state to children for visual feedback.

Parameters:

  • children: ((props: UploadZoneChildProps) => ReactNode) | ReactNode - Content or render function receiving drag state props
  • props: HTMLAttributes<HTMLDivElement> - Additional HTML div attributes

Returns: JSX element with drag-and-drop upload functionality

UploadImages.Files

Container component for displaying uploaded files. Renders a container for uploaded files and provides current file list to children. Used to display and manage the collection of uploaded images.

Parameters:

  • children: ((props: UploadFilesChildProps) => ReactNode) | ReactNode - Content or render function receiving files array
  • props: HTMLAttributes<HTMLDivElement> - Additional HTML div attributes

Returns: JSX element containing uploaded files

UploadImages.File

Individual file item component with preview and removal functionality. Displays a single uploaded file with preview image generation and removal capability. Automatically generates image preview data and provides remove function to children.

Parameters:

  • children: ((props: UploadFileItemChildProps) => ReactNode) | ReactNode - Content or render function receiving file, preview, and remove function
  • file: FileWithId - File object with ID to display
  • props: HTMLAttributes<HTMLDivElement> - Additional HTML div attributes

Returns: JSX element for individual file with preview and controls

UploadImages.Cropper

Image cropper component with editing controls. Provides image cropping functionality with zoom, rotation, and crop area controls. Processes cropped images and integrates with the upload state management.

Parameters:

  • children: ((props: UploadImagesCropperEditorChildProps) => ReactNode) | ReactNode - Content or render function receiving cropper controls

Returns: JSX element with cropper editing interface

Throws: Error - When cropper config is not defined in context

UploadImages.CropperEditor

Visual editor component for image cropping. Renders the interactive crop editor interface using "react-easy-crop". Provides visual feedback for crop area, zoom, and rotation adjustments.

Parameters:

  • style?: CSSProperties - CSS style object, merged with default positioning styles
  • props: HTMLAttributes<HTMLDivElement> - Additional HTML div attributes

Returns: JSX element with interactive crop editor

Throws: Error - When cropper config is not defined in context

Render Prop Types

The following types define the props passed to render functions in various components:

UploadZoneChildProps

Props passed to the render function of UploadImages.Zone component.

Properties:

  • isDragActive: boolean - True when files are being dragged over the drop zone
  • isFileDialogActive: boolean - True when the native file dialog is open
  • isFocused: boolean - True when the drop zone is focused (keyboard navigation)

UploadFilesChildProps

Props passed to the render function of UploadImages.Files component.

Properties:

  • files?: FileWithId[] - Array of currently uploaded files with unique IDs

UploadFileItemChildProps

Props passed to the render function of UploadImages.File component.

Properties:

  • file: FileWithId - The file object containing the original File and unique ID
  • preview?: string - Base64 data URL of the image preview (undefined while loading)
  • remove: () => void - Function to remove this file from the upload list

UploadImagesCropperEditorChildProps

Props passed to the render function of UploadImages.Cropper component.

Properties:

  • zoom: number - Current zoom level (1.0 = no zoom)
  • rotation: number - Current rotation angle in degrees
  • setZoom: (zoom: number) => void - Function to update zoom level
  • setRotation: (rotation: number) => void - Function to update rotation angle
  • accept: () => void - Function to accept the current crop and add to files
  • close: () => void - Function to cancel cropping and close the editor

Usage Examples

Basic Upload

import { useState } from "react";
import { UploadImages, useUploadImages, FileWithId } from "@leancodepl/image-uploader";

function BasicUpload() {
  const [files, setFiles] = useState<FileWithId[]>([]);

  const uploader = useUploadImages({
    value: files,
    onChange: setFiles,
    onError: (error) => console.error("Upload error:", error),
    accept: { "image/*": [".jpg", ".png", ".gif"] }
  });

  return (
    <UploadImages.Root uploader={uploader}>
      <UploadImages.Zone>
        {({ isDragActive }) => (
          <div>
            {isDragActive ? "Drop files here" : "Click or drag files to upload"}
          </div>
        )}
      </UploadImages.Zone>

      <UploadImages.Files>
        {({ files }) => (
          <div>
            {files?.map(file => (
              <UploadImages.File key={file.id} file={file}>
                {({ preview, remove }) => (
                  <div>
                    <img src={preview} alt="Preview" />
                    <p>{file.originalFile.name}</p>
                    <button onClick={remove}>Remove</button>
                  </div>
                )}
              </UploadImages.File>
            ))}
          </div>
        )}
      </UploadImages.Files>
    </UploadImages.Root>
  );
}

Server Upload Integration

import { tryUploadWithUploadParams } from "@leancodepl/image-uploader"

async function uploadToServer(image: FileWithId) {
  try {
    const uploadedImage = await tryUploadWithUploadParams(image, async img => {
      // Get upload URL from your API
      const response = await fetch("/api/upload-url", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          fileName: img.originalFile.name,
          fileType: img.originalFile.type,
        }),
      })

      const { uploadUrl, headers } = await response.json()

      return {
        uri: uploadUrl,
        method: "PUT",
        requiredHeaders: headers,
      }
    })

    console.log("Upload successful:", uploadedImage.url)
    return uploadedImage
  } catch (error) {
    console.error("Upload failed:", error)
    throw error
  }
}

Error Handling

import { ErrorCode } from "@leancodepl/image-uploader"

function handleUploadError(errorCode: ErrorCode) {
  switch (errorCode) {
    case ErrorCode.FileTooLarge:
      alert("File is too large. Please choose a smaller file.")
      break
    case ErrorCode.FileInvalidType:
      alert("Invalid file type. Please upload an image file.")
      break
    case ErrorCode.TooManyFiles:
      alert("Too many files selected. Please choose fewer files.")
      break
    default:
      alert("An error occurred while uploading the file.")
  }
}

const uploader = useUploadImages({
  value: files,
  onChange: setFiles,
  onError: handleUploadError,
})

Features

  • Drag-and-Drop Support: Built on "react-dropzone" for intuitive file selection
  • Image Cropping: Optional cropping with zoom and rotation using "react-easy-crop"
  • File Validation: Automatic validation with customizable error handling
  • Preview Generation: Automatic image preview generation for uploaded files
  • Duplicate Detection: Prevents uploading the same file multiple times
  • TypeScript Support: Full TypeScript definitions included
  • Flexible UI: Render prop pattern for complete UI customization
  • Server Integration: Helper utilities for uploading to any backend service

Configuration

Cropper Configuration

type CropperConfig = {
  aspect: number // Aspect ratio (e.g., 16/9, 1, 4/3)
  maxWidth?: number // Maximum output width in pixels
  maxHeight?: number // Maximum output height in pixels
  withRotation?: boolean // Enable rotation controls
  withZoom?: boolean // Enable zoom controls
}

File Accept Types

// Accept only JPEG and PNG
const accept = {
  "image/jpeg": [".jpg", ".jpeg"],
  "image/png": [".png"],
}

// Accept all image types (default)
const accept = { "image/*": [] }

Upload with Cropping

import { useState } from "react";
import { UploadImages, useUploadImages, FileWithId } from "@leancodepl/image-uploader";

function CroppableUpload() {
  const [files, setFiles] = useState<FileWithId[]>([]);

  const uploader = useUploadImages({
    value: files,
    onChange: setFiles,
    cropper: {
      aspect: 16 / 9,
      maxWidth: 800,
      maxHeight: 450,
      withRotation: true,
      withZoom: true
    }
  });

  return (
    <UploadImages.Root uploader={uploader}>
      <UploadImages.Zone>
        Drop images to crop
      </UploadImages.Zone>

      <UploadImages.Cropper>
        {({ zoom, rotation, setZoom, setRotation, accept, close }) => (
          <div>
            <UploadImages.CropperEditor />
            <div>
              <label>
                Zoom: <input
                  type="range"
                  min={1}
                  max={3}
                  step={0.1}
                  value={zoom}
                  onChange={(e) => setZoom(Number(e.target.value))}
                />
              </label>
              <label>
                Rotation: <input
                  type="range"
                  min={-180}
                  max={180}
                  value={rotation}
                  onChange={(e) => setRotation(Number(e.target.value))}
                />
              </label>
              <div>
                <button onClick={accept}>Accept</button>
                <button onClick={close}>Cancel</button>
              </div>
            </div>
          </div>
        )}
      </UploadImages.Cropper>

      <UploadImages.Files>
        {({ files }) => (
          <div>
            {files?.map(file => (
              <UploadImages.File key={file.id} file={file}>
                {({ preview, remove }) => (
                  <div>
                    <img src={preview} alt="Cropped" />
                    <button onClick={remove}>Remove</button>
                  </div>
                )}
              </UploadImages.File>
            ))}
          </div>
        )}
      </UploadImages.Files>
    </UploadImages.Root>
  );
}

Server Upload Integration

import { tryUploadWithUploadParams } from "@leancodepl/image-uploader"

async function uploadToServer(image: FileWithId) {
  try {
    const uploadedImage = await tryUploadWithUploadParams(image, async img => {
      // Get upload URL from your API
      const response = await fetch("/api/upload-url", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          fileName: img.originalFile.name,
          fileType: img.originalFile.type,
        }),
      })

      const { uploadUrl, headers } = await response.json()

      return {
        uri: uploadUrl,
        method: "PUT",
        requiredHeaders: headers,
      }
    })

    console.log("Upload successful:", uploadedImage.url)
    return uploadedImage
  } catch (error) {
    console.error("Upload failed:", error)
    throw error
  }
}

Error Handling

import { ErrorCode } from "@leancodepl/image-uploader"

function handleUploadError(errorCode: ErrorCode) {
  switch (errorCode) {
    case ErrorCode.FileTooLarge:
      alert("File is too large. Please choose a smaller file.")
      break
    case ErrorCode.FileInvalidType:
      alert("Invalid file type. Please upload an image file.")
      break
    case ErrorCode.TooManyFiles:
      alert("Too many files selected. Please choose fewer files.")
      break
    default:
      alert("An error occurred while uploading the file.")
  }
}

const uploader = useUploadImages({
  value: files,
  onChange: setFiles,
  onError: handleUploadError,
})

Features

  • Drag-and-Drop Support: Built on "react-dropzone" for intuitive file selection
  • Image Cropping: Optional cropping with zoom and rotation using "react-easy-crop"
  • File Validation: Automatic validation with customizable error handling
  • Preview Generation: Automatic image preview generation for uploaded files
  • Duplicate Detection: Prevents uploading the same file multiple times
  • TypeScript Support: Full TypeScript definitions included
  • Flexible UI: Render prop pattern for complete UI customization
  • Server Integration: Helper utilities for uploading to any backend service

Configuration

Cropper Configuration

type CropperConfig = {
  aspect: number // Aspect ratio (e.g., 16/9, 1, 4/3)
  maxWidth?: number // Maximum output width in pixels
  maxHeight?: number // Maximum output height in pixels
  withRotation?: boolean // Enable rotation controls
  withZoom?: boolean // Enable zoom controls
}

File Accept Types

// Accept only JPEG and PNG
const accept = {
  "image/jpeg": [".jpg", ".jpeg"],
  "image/png": [".png"],
}

// Accept all image types (default)
const accept = { "image/*": [] }