/v1.0

EditableImageCropField

EditableImageCropField shows the current image as a 100×100 thumbnail in read mode (or a placeholder when no image is set). Clicking the edit icon activates ImageCropField, which provides a dropzone for image upload and an interactive crop modal. The cropped image is uploaded to the server and the resulting file path is saved. On confirmation the path is persisted via API.

Props

| Prop | Type | Required | Default | Description | |------|------|----------|---------|-------------| | name | string | Yes | — | Field name sent as the key in the update payload. | | value | string | Yes | "" | Current image file path (relative to filesBaseUrl). | | updatePath | string | Yes | — | API endpoint path used to persist the new image path. | | uploadPath | string | Yes | — | API path where the image file is uploaded. Falls back to updatePath if not provided. | | targetDir | string | Yes | — | Server directory where the uploaded file should be stored. | | label | string | No | — | Label shown above the image preview. | | description | string | No | — | Helper text shown below the label. | | apiBaseUrl | string | No | — | Base URL prepended to updatePath and uploadPath. | | filesBaseUrl | string | No | urls.filesBase | Base URL prepended to the stored file path when building the preview src. | | useAuthToken | boolean | No | false | When true, requests include the authorization token. | | maxFileSize | number | No | — | Maximum file size allowed (in bytes). | | dropzoneLabel | string | No | — | Label shown inside the dropzone. | | dropzoneIcon | string | No | — | Icon name shown inside the dropzone. | | isPublic | boolean | No | true | When true, the uploaded file is stored in the public directory. | | fileName | string | No | — | Custom filename for the uploaded file (without extension). | | aspectRatio | number | No | 1 | Crop aspect ratio (e.g. 16/9 for landscape, 1 for square). | | modalZIndex | number | No | 99999 | z-index of the crop modal. | | onChange | (newValue?: string) => void | No | — | Called locally when an image is uploaded and its path is available. | | onEditStart | () => void | No | — | Called when edit mode begins. | | onEditSuccess | (updatedValue: string, newFormData: any) => void | No | — | Called after successful save. | | onEditError | (error: any) => void | No | — | Called on API error; value is reverted. | | onEditCancel | () => void | No | — | Called when the user cancels; value is reverted. | | editIcon | string | No | "pencil" | Icon name for the edit button. | | saveIcon | string | No | "check" | Icon name for the save button. | | cancelIcon | string | No | "close" | Icon name for the cancel button. | | containerStyle | React.CSSProperties | No | — | Style for the outermost wrapper. | | inputStyle | React.CSSProperties | No | — | Style for the inner input element. | | labelStyle | React.CSSProperties | No | — | Style for the <label> element. | | descriptionStyle | React.CSSProperties | No | — | Style for the description <p> element. |

Usage

Basic — square avatar

import React, { useState } from 'react';
import EditableImageCropField from '@/components/editable-fields/EditableImageCropField';

export default function Example() {
  const [avatar, setAvatar] = useState('uploads/users/42/avatar.jpg');

  return (
    <EditableImageCropField
      label="Avatar"
      name="avatar"
      value={avatar}
      updatePath="/v1/users/42"
      uploadPath="/v1/files/upload"
      targetDir="users/42"
      apiBaseUrl="https://api.example.com"
      filesBaseUrl="https://cdn.example.com"
      aspectRatio={1}
      useAuthToken
      onEditSuccess={(updated) => setAvatar(updated)}
    />
  );
}

Landscape banner

<EditableImageCropField
  label="Banner"
  name="banner"
  value={banner}
  updatePath="/v1/organizations/3"
  uploadPath="/v1/files/upload"
  targetDir="organizations/3/banners"
  apiBaseUrl="https://api.example.com"
  filesBaseUrl="https://cdn.example.com"
  aspectRatio={16 / 9}
  maxFileSize={5 * 1024 * 1024}
  useAuthToken
  onEditSuccess={(updated) => setBanner(updated)}
/>