@poly67/react
v0.1.0
Published
React bindings for react-image-optimizer: an <ImageOptimizer> dropzone component and useImageOptimizer hook that shrink uploads to fit strict size/dimension requirements, entirely in the browser.
Downloads
89
Maintainers
Readme
@poly67/react
React bindings for @poly67/core:
a drag-and-drop <ImageOptimizer> component and a useImageOptimizer hook
that shrink uploaded images to fit strict size/dimension requirements —
entirely in the browser, no server round-trip.
See the root README for the full guide and the algorithm explanation.
Install
npm install @poly67/reactreact and react-dom (18 or 19) are peer dependencies.
<ImageOptimizer />
import { ImageOptimizer } from "@poly67/react";
function ProfilePhotoUpload() {
return (
<ImageOptimizer
maxSizeKB={20}
maxWidth={200}
maxHeight={200}
format="jpeg"
quality={0.9}
autoOptimize
preview
onProgress={(p) => console.log(p.stage, p.progress)}
onSuccess={(result) => {
const formData = new FormData();
formData.append("photo", result.file);
fetch("/api/upload", { method: "POST", body: formData });
}}
onError={(error) => console.error(error)}
/>
);
}Ships with a minimal, accessible default UI (dropzone + native file input + preview + status text), which you can fully replace with a render-prop:
<ImageOptimizer maxSizeKB={20} maxWidth={200} maxHeight={200}>
{({ isDragActive, isOptimizing, previewUrl, result, error, openFileDialog }) => (
<div className={isDragActive ? "dropzone--active" : "dropzone"}>
{previewUrl && <img src={previewUrl} alt="" />}
<button type="button" onClick={openFileDialog} disabled={isOptimizing}>
{isOptimizing ? "Optimizing…" : "Choose photo"}
</button>
{result && <p>{result.sizeKB.toFixed(1)}KB, ready to upload</p>}
{error && <p role="alert">Couldn't process that image.</p>}
</div>
)}
</ImageOptimizer>Props
All OptimizeOptions fields (maxSizeKB, maxWidth, maxHeight, format,
quality, minQuality, background, preserveAspectRatio, fit, crop,
correctOrientation) are accepted directly, plus:
| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| autoOptimize | boolean | true | Optimize as soon as a file is selected/dropped. |
| preview | boolean | true | Show an object-URL preview of the selected file. |
| multiple | boolean | false | Allow selecting more than one file. |
| accept | string | "image/*" | Forwarded to the file input. |
| disabled | boolean | false | Disable interaction. |
| className / style | — | — | Applied to the root element. |
| children | ReactNode \| (state) => ReactNode | — | Custom UI / render prop. |
| onProgress | (p: OptimizeProgress) => void | — | Pipeline progress updates. |
| onSuccess | (r: OptimizeResult) => void | — | Called once optimization finishes. |
| onError | (e: unknown) => void | — | Called if optimization throws. |
Ref API
When autoOptimize is false, trigger optimization imperatively:
const ref = useRef<ImageOptimizerHandle>(null);
<ImageOptimizer ref={ref} autoOptimize={false} maxSizeKB={20} />
<button onClick={() => ref.current?.optimize()}>Optimize</button>ImageOptimizerHandle: { optimize(), reset(), openFileDialog() }.
useImageOptimizer(options?)
For fully custom UIs:
import { useImageOptimizer } from "@poly67/react";
function Uploader() {
const { optimize, isOptimizing, progress, result, error } = useImageOptimizer({
maxSizeKB: 20,
maxWidth: 200,
maxHeight: 200,
});
return (
<input
type="file"
accept="image/*"
onChange={(e) => e.target.files?.[0] && optimize(e.target.files[0])}
/>
);
}Returns { optimize, isOptimizing, progress, result, error, reset, abort }.
Calling optimize() again automatically aborts a still-running previous call.
Direct core usage
optimizeImage is re-exported for one-off calls that don't need component
state:
import { optimizeImage } from "@poly67/react";
const { file } = await optimizeImage(rawFile, { maxSizeKB: 20 });License
MIT
