@leancodepl/image-uploader 10.5.1 → 10.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,18 @@
3
3
  All notable changes to this project will be documented in this file. See
4
4
  [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [10.5.2](https://github.com/leancodepl/js_corelibrary/compare/v10.5.1...v10.5.2) (2026-07-02)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **image-uploader:** turn FileWithId into a union with all file states
11
+ ([4db50e9](https://github.com/leancodepl/js_corelibrary/commit/4db50e92a3bf9a65fc4b5099be1e9e179c8d1840))
12
+
13
+ # Change Log
14
+
15
+ All notable changes to this project will be documented in this file. See
16
+ [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
17
+
6
18
  ## [10.5.1](https://github.com/leancodepl/js_corelibrary/compare/v10.4.0...v10.5.1) (2026-07-01)
7
19
 
8
20
  **Note:** Version bump only for package @leancodepl/image-uploader
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ErrorCode as I, useDropzone as O } from "react-dropzone";
2
- import { useContext as Y, createContext as B, useCallback as m, useState as x, useEffect as V } from "react";
2
+ import { useContext as Y, createContext as B, useCallback as f, useState as x, useEffect as V } from "react";
3
3
  import { jsx as h, jsxs as _ } from "react/jsx-runtime";
4
4
  import X from "react-easy-crop";
5
5
  import { v4 as $ } from "uuid";
@@ -52,42 +52,42 @@ function ne({ children: e }) {
52
52
  editorImage: n,
53
53
  acceptImage: i,
54
54
  closeImage: r,
55
- config: c,
56
- cropArea: a,
57
- zoom: f,
55
+ config: a,
56
+ cropArea: s,
57
+ zoom: u,
58
58
  rotation: g,
59
59
  setCropArea: F,
60
60
  setCrop: w,
61
61
  setZoom: v,
62
62
  setRotation: y
63
- } = o, p = m(() => {
63
+ } = o, d = f(() => {
64
64
  r(), w(N), v(Z), y(b), F(void 0);
65
- }, [r, w, F, y, v]), l = m(() => {
65
+ }, [r, w, F, y, v]), c = f(() => {
66
66
  if (!n) return;
67
- const d = document.createElement("canvas"), u = document.createElement("canvas"), s = d.getContext("2d"), R = u.getContext("2d"), D = new Image();
67
+ const p = document.createElement("canvas"), m = document.createElement("canvas"), l = p.getContext("2d"), R = m.getContext("2d"), D = new Image();
68
68
  D.onload = function() {
69
69
  const { naturalWidth: M, naturalHeight: P } = D, S = g * (Math.PI / 180), A = Math.abs(Math.sin(S)), z = Math.abs(Math.cos(S)), T = M * z + P * A, U = P * z + M * A;
70
- d.width = T, d.height = U, s.fillStyle = "#fff", s.fillRect(0, 0, T, U);
70
+ p.width = T, p.height = U, l.fillStyle = "#fff", l.fillRect(0, 0, T, U);
71
71
  const H = T / 2, L = U / 2;
72
- s.translate(H, L), s.rotate(S), s.translate(-H, -L);
72
+ l.translate(H, L), l.rotate(S), l.translate(-H, -L);
73
73
  const W = (T - M) / 2, j = (U - P) / 2;
74
- s.drawImage(D, 0, 0, M, P, W, j, M, P), u.width = Math.min(
75
- (a?.width ?? 100) / 100 * T,
76
- c.maxWidth ?? Number.POSITIVE_INFINITY
77
- ), u.height = Math.min(
78
- (a?.height ?? 100) / 100 * U,
79
- c.maxHeight ?? Number.POSITIVE_INFINITY
74
+ l.drawImage(D, 0, 0, M, P, W, j, M, P), m.width = Math.min(
75
+ (s?.width ?? 100) / 100 * T,
76
+ a.maxWidth ?? Number.POSITIVE_INFINITY
77
+ ), m.height = Math.min(
78
+ (s?.height ?? 100) / 100 * U,
79
+ a.maxHeight ?? Number.POSITIVE_INFINITY
80
80
  ), R.drawImage(
81
- d,
82
- (a?.x ?? 0) / 100 * T,
83
- (a?.y ?? 0) / 100 * U,
84
- (a?.width ?? 100) / 100 * T,
85
- (a?.height ?? 100) / 100 * U,
81
+ p,
82
+ (s?.x ?? 0) / 100 * T,
83
+ (s?.y ?? 0) / 100 * U,
84
+ (s?.width ?? 100) / 100 * T,
85
+ (s?.height ?? 100) / 100 * U,
86
86
  0,
87
87
  0,
88
- u.width,
89
- u.height
90
- ), u.toBlob((k) => {
88
+ m.width,
89
+ m.height
90
+ ), m.toBlob((k) => {
91
91
  if (!t)
92
92
  return;
93
93
  const Q = {
@@ -97,16 +97,16 @@ function ne({ children: e }) {
97
97
  id: t.id
98
98
  };
99
99
  i(Q);
100
- }), p();
100
+ }), d();
101
101
  }, D.src = n;
102
- }, [p, c, a, t, n, g, i]);
103
- return typeof e == "function" ? e({ zoom: f, rotation: g, setZoom: v, setRotation: y, accept: l, close: p }) : e;
102
+ }, [d, a, s, t, n, g, i]);
103
+ return typeof e == "function" ? e({ zoom: u, rotation: g, setZoom: v, setRotation: y, accept: c, close: d }) : e;
104
104
  }
105
105
  function ie({ style: e, ...o }) {
106
106
  const { cropper: t } = C();
107
107
  if (!t)
108
108
  throw new Error("Cropper config is not defined");
109
- const { editorImage: n, config: i, zoom: r, rotation: c, crop: a, setCropArea: f, setCrop: g, setZoom: F, setRotation: w } = t;
109
+ const { editorImage: n, config: i, zoom: r, rotation: a, crop: s, setCropArea: u, setCrop: g, setZoom: F, setRotation: w } = t;
110
110
  return /* @__PURE__ */ h(
111
111
  "div",
112
112
  {
@@ -121,12 +121,12 @@ function ie({ style: e, ...o }) {
121
121
  X,
122
122
  {
123
123
  aspect: i.aspect,
124
- crop: a,
124
+ crop: s,
125
125
  image: n,
126
- rotation: c,
126
+ rotation: a,
127
127
  zoom: r,
128
128
  onCropChange: g,
129
- onCropComplete: f,
129
+ onCropComplete: u,
130
130
  onRotationChange: w,
131
131
  onZoomChange: F
132
132
  }
@@ -142,13 +142,15 @@ const ae = (e) => new Promise((o, t) => {
142
142
  n.readAsDataURL(e), n.onload = () => o(String(n.result)), n.onerror = (i) => t(i);
143
143
  });
144
144
  function se({ children: e, file: o, ...t }) {
145
- const { removeFile: n } = C(), [i, r] = x();
145
+ const { removeFile: n } = C(), [i, r] = x(), a = "url" in o ? o.url : void 0;
146
146
  return V(() => {
147
+ if (a)
148
+ return;
147
149
  (async () => {
148
- const a = await re(o.originalFile);
149
- r(a);
150
+ const u = await re(o.originalFile);
151
+ r(u);
150
152
  })();
151
- }, [o.originalFile]), /* @__PURE__ */ h("div", { ...t, children: typeof e == "function" ? e({ file: o, preview: i, remove: () => n(o.id) }) : e });
153
+ }, [a, o.originalFile]), /* @__PURE__ */ h("div", { ...t, children: typeof e == "function" ? e({ file: o, preview: a ?? i, remove: () => n(o.id) }) : e });
152
154
  }
153
155
  function le({ children: e, ...o }) {
154
156
  const { value: t } = C();
@@ -157,56 +159,56 @@ function le({ children: e, ...o }) {
157
159
  function ce({ uploader: e, ...o }) {
158
160
  return /* @__PURE__ */ h(te, { uploader: e, children: /* @__PURE__ */ h("div", { ...o }) });
159
161
  }
160
- function pe({ children: e, ...o }) {
162
+ function de({ children: e, ...o }) {
161
163
  const {
162
- dropzone: { getRootProps: t, getInputProps: n, isDragActive: i, isFocused: r, isFileDialogActive: c }
164
+ dropzone: { getRootProps: t, getInputProps: n, isDragActive: i, isFocused: r, isFileDialogActive: a }
163
165
  } = C();
164
166
  return /* @__PURE__ */ _("div", { ...t(), ...o, children: [
165
167
  /* @__PURE__ */ h("input", { ...n() }),
166
- typeof e == "function" ? e({ isDragActive: i, isFocused: r, isFileDialogActive: c }) : e
168
+ typeof e == "function" ? e({ isDragActive: i, isFocused: r, isFileDialogActive: a }) : e
167
169
  ] });
168
170
  }
169
171
  const ye = {
170
172
  Root: ce,
171
- Zone: pe,
173
+ Zone: de,
172
174
  Files: le,
173
175
  File: se,
174
176
  Cropper: ne,
175
177
  CropperEditor: ie
176
178
  };
177
- function de(e, o) {
179
+ function pe(e, o) {
178
180
  return e.name === o.name && e.size === o.size && e.lastModified === o.lastModified;
179
181
  }
180
182
  function ue({ value: e, onChange: o }) {
181
- const [t, n] = x([]), [i, r] = x(), [c, a] = x(), [f, g] = x(N), [F, w] = x(Z), [v, y] = x(b), p = t.at(0), l = !!p;
182
- G(p, (s) => {
183
- if (r(void 0), !s)
183
+ const [t, n] = x([]), [i, r] = x(), [a, s] = x(), [u, g] = x(N), [F, w] = x(Z), [v, y] = x(b), d = t.at(0), c = !!d;
184
+ G(d, (l) => {
185
+ if (r(void 0), !l)
184
186
  return;
185
187
  const R = new FileReader();
186
188
  R.addEventListener("load", () => {
187
189
  typeof R.result == "string" && r(R.result);
188
- }), R.readAsDataURL(s.originalFile);
190
+ }), R.readAsDataURL(l.originalFile);
189
191
  });
190
- const d = m(() => {
191
- n(t.filter(({ id: s }) => s !== p?.id));
192
- }, [t, p?.id]), u = m((s) => o?.([...e ?? [], s]), [o, e]);
192
+ const p = f(() => {
193
+ n(t.filter(({ id: l }) => l !== d?.id));
194
+ }, [t, d?.id]), m = f((l) => o?.([...e ?? [], l]), [o, e]);
193
195
  return {
194
196
  fileQueue: t,
195
- file: p,
197
+ file: d,
196
198
  editorImage: i,
197
- cropArea: c,
198
- crop: f,
199
+ cropArea: a,
200
+ crop: u,
199
201
  zoom: F,
200
202
  rotation: v,
201
- isOpen: l,
203
+ isOpen: c,
202
204
  setFileQueue: n,
203
205
  setEditorImage: r,
204
- setCropArea: a,
206
+ setCropArea: s,
205
207
  setCrop: g,
206
208
  setZoom: w,
207
209
  setRotation: y,
208
- closeImage: d,
209
- acceptImage: u
210
+ closeImage: p,
211
+ acceptImage: m
210
212
  };
211
213
  }
212
214
  function Te({
@@ -216,54 +218,54 @@ function Te({
216
218
  onError: n,
217
219
  onChange: i
218
220
  }) {
219
- const { setFileQueue: r, ...c } = ue({ value: e, onChange: i }), a = m(
220
- (l) => {
221
- t ? r(l) : i?.([...e ?? [], ...l]);
221
+ const { setFileQueue: r, ...a } = ue({ value: e, onChange: i }), s = f(
222
+ (c) => {
223
+ t ? r(c) : i?.([...e ?? [], ...c]);
222
224
  },
223
225
  [t, i, e, r]
224
- ), f = m(
225
- (l) => {
226
- const d = l.filter(
227
- (u) => !e?.some((s) => de(s.originalFile, u.originalFile))
226
+ ), u = f(
227
+ (c) => {
228
+ const p = c.filter(
229
+ (m) => !e?.some((l) => pe(l.originalFile, m.originalFile))
228
230
  );
229
- a(d);
231
+ s(p);
230
232
  },
231
- [a, e]
232
- ), g = m(
233
- (l) => {
234
- i?.(e?.filter((d) => d.id !== l) ?? []);
233
+ [s, e]
234
+ ), g = f(
235
+ (c) => {
236
+ i?.(e?.filter((p) => p.id !== c) ?? []);
235
237
  },
236
238
  [e, i]
237
- ), F = m(() => {
239
+ ), F = f(() => {
238
240
  i?.([]);
239
- }, [i]), w = m(
240
- (l) => {
241
- f(l.map((d) => ({ originalFile: d, id: $() })));
241
+ }, [i]), w = f(
242
+ (c) => {
243
+ u(c.map((p) => ({ originalFile: p, id: $() })));
242
244
  },
243
- [f]
244
- ), v = m(
245
- (l) => {
246
- n?.(ee(l));
245
+ [u]
246
+ ), v = f(
247
+ (c) => {
248
+ n?.(ee(c));
247
249
  },
248
250
  [n]
249
251
  ), y = O({
250
252
  onDrop: w,
251
253
  onDropRejected: v,
252
254
  accept: o
253
- }), p = {
255
+ }), d = {
254
256
  value: e,
255
257
  dropzone: y,
256
- addFiles: f,
258
+ addFiles: u,
257
259
  removeFile: g,
258
260
  clearFiles: F,
259
261
  cropper: t && {
260
262
  config: t,
261
- ...c
263
+ ...a
262
264
  }
263
265
  };
264
266
  return {
265
- ...p,
266
- uploader: p
267
+ ...d,
268
+ uploader: d
267
269
  };
268
270
  }
269
271
  export {
@@ -1 +1 @@
1
- (function(l,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("react-dropzone"),require("react"),require("react/jsx-runtime"),require("react-easy-crop"),require("uuid"),require("@leancodepl/utils")):typeof define=="function"&&define.amd?define(["exports","react-dropzone","react","react/jsx-runtime","react-easy-crop","uuid","@leancodepl/utils"],u):(l=typeof globalThis<"u"?globalThis:l||self,u(l["@leancodepl/image-uploader"]={},l.reactDropzone,l.react,l.jsxRuntime,l.EasyCrop,l.uuid,l.utils))})(this,(function(l,u,a,F,Z,D,O){"use strict";var E=(e=>(e[e.FileTooLarge=u.ErrorCode.FileTooLarge]="FileTooLarge",e[e.FileTooSmall=u.ErrorCode.FileTooSmall]="FileTooSmall",e[e.FileInvalidType=u.ErrorCode.FileInvalidType]="FileInvalidType",e[e.TooManyFiles=u.ErrorCode.TooManyFiles]="TooManyFiles",e.Unknown="unknown",e))(E||{});function Q(e){return e.flatMap(o=>o.errors.map(t=>t.code))}function z(e){return e.includes(u.ErrorCode.FileTooLarge)?E.FileTooLarge:e.includes(u.ErrorCode.FileTooSmall)?E.FileTooSmall:e.includes(u.ErrorCode.FileInvalidType)?E.FileInvalidType:e.includes(u.ErrorCode.TooManyFiles)?E.TooManyFiles:"unknown"}function Y(e){return z(Q(e))}async function B(e,o){if("url"in e)return e;if(!e.originalFile)throw new Error("Image is not defined");try{const t=await o(e);if(!t)throw new Error("Upload params are not defined");const{uri:i,method:n,requiredHeaders:r}=t;if(!(await fetch(i,{method:n,headers:r,body:e.originalFile})).ok)throw new Error("Failed to upload image");return{...e,url:i}}catch{throw new Error("Failed to upload image")}}const V={"image/*":[]},q={x:0,y:0},A=1,R=0,j=a.createContext(void 0);function _({children:e,uploader:o}){return F.jsx(j.Provider,{value:o,children:e})}function x(){const e=a.useContext(j);if(!e)throw new Error("All UploadImages components must be wrapped in an UploadImages.Root component");return e}function X({children:e}){const{cropper:o}=x();if(!o)throw new Error("Cropper config is not defined");const{file:t,editorImage:i,acceptImage:n,closeImage:r,config:p,cropArea:s,zoom:h,rotation:I,setCropArea:w,setCrop:y,setZoom:v,setRotation:C}=o,f=a.useCallback(()=>{r(),y(q),v(A),C(R),w(void 0)},[r,y,w,C,v]),d=a.useCallback(()=>{if(!i)return;const m=document.createElement("canvas"),g=document.createElement("canvas"),c=m.getContext("2d"),S=g.getContext("2d"),k=new Image;k.onload=function(){const{naturalWidth:P,naturalHeight:M}=k,b=I*(Math.PI/180),H=Math.abs(Math.sin(b)),L=Math.abs(Math.cos(b)),T=P*L+M*H,U=M*L+P*H;m.width=T,m.height=U,c.fillStyle="#fff",c.fillRect(0,0,T,U);const N=T/2,W=U/2;c.translate(N,W),c.rotate(b),c.translate(-N,-W);const se=(T-P)/2,le=(U-M)/2;c.drawImage(k,0,0,P,M,se,le,P,M),g.width=Math.min((s?.width??100)/100*T,p.maxWidth??Number.POSITIVE_INFINITY),g.height=Math.min((s?.height??100)/100*U,p.maxHeight??Number.POSITIVE_INFINITY),S.drawImage(m,(s?.x??0)/100*T,(s?.y??0)/100*U,(s?.width??100)/100*T,(s?.height??100)/100*U,0,0,g.width,g.height),g.toBlob(ce=>{if(!t)return;const de={originalFile:new File([ce],t.originalFile.name??"image.png",{type:t.originalFile.type??"image/png"}),id:t.id};n(de)}),f()},k.src=i},[f,p,s,t,i,I,n]);return typeof e=="function"?e({zoom:h,rotation:I,setZoom:v,setRotation:C,accept:d,close:f}):e}function G({style:e,...o}){const{cropper:t}=x();if(!t)throw new Error("Cropper config is not defined");const{editorImage:i,config:n,zoom:r,rotation:p,crop:s,setCropArea:h,setCrop:I,setZoom:w,setRotation:y}=t;return F.jsx("div",{...o,style:{position:"relative",width:"100%",height:"300px",...e},children:F.jsx(Z,{aspect:n.aspect,crop:s,image:i,rotation:p,zoom:r,onCropChange:I,onCropComplete:h,onRotationChange:y,onZoomChange:w})})}async function J(e){return e?await K(e):""}const K=e=>new Promise((o,t)=>{const i=new FileReader;i.readAsDataURL(e),i.onload=()=>o(String(i.result)),i.onerror=n=>t(n)});function $({children:e,file:o,...t}){const{removeFile:i}=x(),[n,r]=a.useState();return a.useEffect(()=>{(async()=>{const s=await J(o.originalFile);r(s)})()},[o.originalFile]),F.jsx("div",{...t,children:typeof e=="function"?e({file:o,preview:n,remove:()=>i(o.id)}):e})}function ee({children:e,...o}){const{value:t}=x();return F.jsx("div",{...o,children:typeof e=="function"?e({files:t}):e})}function oe({uploader:e,...o}){return F.jsx(_,{uploader:e,children:F.jsx("div",{...o})})}function te({children:e,...o}){const{dropzone:{getRootProps:t,getInputProps:i,isDragActive:n,isFocused:r,isFileDialogActive:p}}=x();return F.jsxs("div",{...t(),...o,children:[F.jsx("input",{...i()}),typeof e=="function"?e({isDragActive:n,isFocused:r,isFileDialogActive:p}):e]})}const ie={Root:oe,Zone:te,Files:ee,File:$,Cropper:X,CropperEditor:G};function ne(e,o){return e.name===o.name&&e.size===o.size&&e.lastModified===o.lastModified}function ae({value:e,onChange:o}){const[t,i]=a.useState([]),[n,r]=a.useState(),[p,s]=a.useState(),[h,I]=a.useState(q),[w,y]=a.useState(A),[v,C]=a.useState(R),f=t.at(0),d=!!f;O.useSyncState(f,c=>{if(r(void 0),!c)return;const S=new FileReader;S.addEventListener("load",()=>{typeof S.result=="string"&&r(S.result)}),S.readAsDataURL(c.originalFile)});const m=a.useCallback(()=>{i(t.filter(({id:c})=>c!==f?.id))},[t,f?.id]),g=a.useCallback(c=>o?.([...e??[],c]),[o,e]);return{fileQueue:t,file:f,editorImage:n,cropArea:p,crop:h,zoom:w,rotation:v,isOpen:d,setFileQueue:i,setEditorImage:r,setCropArea:s,setCrop:I,setZoom:y,setRotation:C,closeImage:m,acceptImage:g}}function re({value:e,accept:o=V,cropper:t,onError:i,onChange:n}){const{setFileQueue:r,...p}=ae({value:e,onChange:n}),s=a.useCallback(d=>{t?r(d):n?.([...e??[],...d])},[t,n,e,r]),h=a.useCallback(d=>{const m=d.filter(g=>!e?.some(c=>ne(c.originalFile,g.originalFile)));s(m)},[s,e]),I=a.useCallback(d=>{n?.(e?.filter(m=>m.id!==d)??[])},[e,n]),w=a.useCallback(()=>{n?.([])},[n]),y=a.useCallback(d=>{h(d.map(m=>({originalFile:m,id:D.v4()})))},[h]),v=a.useCallback(d=>{i?.(Y(d))},[i]),C=u.useDropzone({onDrop:y,onDropRejected:v,accept:o}),f={value:e,dropzone:C,addFiles:h,removeFile:I,clearFiles:w,cropper:t&&{config:t,...p}};return{...f,uploader:f}}l.ErrorCode=E,l.UploadImages=ie,l.tryUploadWithUploadParams=B,l.useUploadImages=re,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(l,p){typeof exports=="object"&&typeof module<"u"?p(exports,require("react-dropzone"),require("react"),require("react/jsx-runtime"),require("react-easy-crop"),require("uuid"),require("@leancodepl/utils")):typeof define=="function"&&define.amd?define(["exports","react-dropzone","react","react/jsx-runtime","react-easy-crop","uuid","@leancodepl/utils"],p):(l=typeof globalThis<"u"?globalThis:l||self,p(l["@leancodepl/image-uploader"]={},l.reactDropzone,l.react,l.jsxRuntime,l.EasyCrop,l.uuid,l.utils))})(this,(function(l,p,r,h,Z,D,O){"use strict";var E=(e=>(e[e.FileTooLarge=p.ErrorCode.FileTooLarge]="FileTooLarge",e[e.FileTooSmall=p.ErrorCode.FileTooSmall]="FileTooSmall",e[e.FileInvalidType=p.ErrorCode.FileInvalidType]="FileInvalidType",e[e.TooManyFiles=p.ErrorCode.TooManyFiles]="TooManyFiles",e.Unknown="unknown",e))(E||{});function Q(e){return e.flatMap(o=>o.errors.map(t=>t.code))}function z(e){return e.includes(p.ErrorCode.FileTooLarge)?E.FileTooLarge:e.includes(p.ErrorCode.FileTooSmall)?E.FileTooSmall:e.includes(p.ErrorCode.FileInvalidType)?E.FileInvalidType:e.includes(p.ErrorCode.TooManyFiles)?E.TooManyFiles:"unknown"}function Y(e){return z(Q(e))}async function B(e,o){if("url"in e)return e;if(!e.originalFile)throw new Error("Image is not defined");try{const t=await o(e);if(!t)throw new Error("Upload params are not defined");const{uri:i,method:n,requiredHeaders:a}=t;if(!(await fetch(i,{method:n,headers:a,body:e.originalFile})).ok)throw new Error("Failed to upload image");return{...e,url:i}}catch{throw new Error("Failed to upload image")}}const V={"image/*":[]},q={x:0,y:0},A=1,R=0,j=r.createContext(void 0);function _({children:e,uploader:o}){return h.jsx(j.Provider,{value:o,children:e})}function x(){const e=r.useContext(j);if(!e)throw new Error("All UploadImages components must be wrapped in an UploadImages.Root component");return e}function X({children:e}){const{cropper:o}=x();if(!o)throw new Error("Cropper config is not defined");const{file:t,editorImage:i,acceptImage:n,closeImage:a,config:s,cropArea:c,zoom:g,rotation:I,setCropArea:w,setCrop:y,setZoom:v,setRotation:C}=o,f=r.useCallback(()=>{a(),y(q),v(A),C(R),w(void 0)},[a,y,w,C,v]),u=r.useCallback(()=>{if(!i)return;const m=document.createElement("canvas"),F=document.createElement("canvas"),d=m.getContext("2d"),S=F.getContext("2d"),k=new Image;k.onload=function(){const{naturalWidth:P,naturalHeight:M}=k,b=I*(Math.PI/180),H=Math.abs(Math.sin(b)),L=Math.abs(Math.cos(b)),T=P*L+M*H,U=M*L+P*H;m.width=T,m.height=U,d.fillStyle="#fff",d.fillRect(0,0,T,U);const N=T/2,W=U/2;d.translate(N,W),d.rotate(b),d.translate(-N,-W);const se=(T-P)/2,le=(U-M)/2;d.drawImage(k,0,0,P,M,se,le,P,M),F.width=Math.min((c?.width??100)/100*T,s.maxWidth??Number.POSITIVE_INFINITY),F.height=Math.min((c?.height??100)/100*U,s.maxHeight??Number.POSITIVE_INFINITY),S.drawImage(m,(c?.x??0)/100*T,(c?.y??0)/100*U,(c?.width??100)/100*T,(c?.height??100)/100*U,0,0,F.width,F.height),F.toBlob(ce=>{if(!t)return;const de={originalFile:new File([ce],t.originalFile.name??"image.png",{type:t.originalFile.type??"image/png"}),id:t.id};n(de)}),f()},k.src=i},[f,s,c,t,i,I,n]);return typeof e=="function"?e({zoom:g,rotation:I,setZoom:v,setRotation:C,accept:u,close:f}):e}function G({style:e,...o}){const{cropper:t}=x();if(!t)throw new Error("Cropper config is not defined");const{editorImage:i,config:n,zoom:a,rotation:s,crop:c,setCropArea:g,setCrop:I,setZoom:w,setRotation:y}=t;return h.jsx("div",{...o,style:{position:"relative",width:"100%",height:"300px",...e},children:h.jsx(Z,{aspect:n.aspect,crop:c,image:i,rotation:s,zoom:a,onCropChange:I,onCropComplete:g,onRotationChange:y,onZoomChange:w})})}async function J(e){return e?await K(e):""}const K=e=>new Promise((o,t)=>{const i=new FileReader;i.readAsDataURL(e),i.onload=()=>o(String(i.result)),i.onerror=n=>t(n)});function $({children:e,file:o,...t}){const{removeFile:i}=x(),[n,a]=r.useState(),s="url"in o?o.url:void 0;return r.useEffect(()=>{if(s)return;(async()=>{const g=await J(o.originalFile);a(g)})()},[s,o.originalFile]),h.jsx("div",{...t,children:typeof e=="function"?e({file:o,preview:s??n,remove:()=>i(o.id)}):e})}function ee({children:e,...o}){const{value:t}=x();return h.jsx("div",{...o,children:typeof e=="function"?e({files:t}):e})}function oe({uploader:e,...o}){return h.jsx(_,{uploader:e,children:h.jsx("div",{...o})})}function te({children:e,...o}){const{dropzone:{getRootProps:t,getInputProps:i,isDragActive:n,isFocused:a,isFileDialogActive:s}}=x();return h.jsxs("div",{...t(),...o,children:[h.jsx("input",{...i()}),typeof e=="function"?e({isDragActive:n,isFocused:a,isFileDialogActive:s}):e]})}const ie={Root:oe,Zone:te,Files:ee,File:$,Cropper:X,CropperEditor:G};function ne(e,o){return e.name===o.name&&e.size===o.size&&e.lastModified===o.lastModified}function re({value:e,onChange:o}){const[t,i]=r.useState([]),[n,a]=r.useState(),[s,c]=r.useState(),[g,I]=r.useState(q),[w,y]=r.useState(A),[v,C]=r.useState(R),f=t.at(0),u=!!f;O.useSyncState(f,d=>{if(a(void 0),!d)return;const S=new FileReader;S.addEventListener("load",()=>{typeof S.result=="string"&&a(S.result)}),S.readAsDataURL(d.originalFile)});const m=r.useCallback(()=>{i(t.filter(({id:d})=>d!==f?.id))},[t,f?.id]),F=r.useCallback(d=>o?.([...e??[],d]),[o,e]);return{fileQueue:t,file:f,editorImage:n,cropArea:s,crop:g,zoom:w,rotation:v,isOpen:u,setFileQueue:i,setEditorImage:a,setCropArea:c,setCrop:I,setZoom:y,setRotation:C,closeImage:m,acceptImage:F}}function ae({value:e,accept:o=V,cropper:t,onError:i,onChange:n}){const{setFileQueue:a,...s}=re({value:e,onChange:n}),c=r.useCallback(u=>{t?a(u):n?.([...e??[],...u])},[t,n,e,a]),g=r.useCallback(u=>{const m=u.filter(F=>!e?.some(d=>ne(d.originalFile,F.originalFile)));c(m)},[c,e]),I=r.useCallback(u=>{n?.(e?.filter(m=>m.id!==u)??[])},[e,n]),w=r.useCallback(()=>{n?.([])},[n]),y=r.useCallback(u=>{g(u.map(m=>({originalFile:m,id:D.v4()})))},[g]),v=r.useCallback(u=>{i?.(Y(u))},[i]),C=p.useDropzone({onDrop:y,onDropRejected:v,accept:o}),f={value:e,dropzone:C,addFiles:g,removeFile:I,clearFiles:w,cropper:t&&{config:t,...s}};return{...f,uploader:f}}l.ErrorCode=E,l.UploadImages=ie,l.tryUploadWithUploadParams=B,l.useUploadImages=ae,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"})}));
@@ -1,11 +1,11 @@
1
1
  import { HTMLAttributes, ReactNode } from 'react';
2
- import { FileWithId, UploadFileItemChildProps } from '../types';
2
+ import { UploadFileItemChildProps } from '../types';
3
3
  /**
4
4
  * Props for individual file item component.
5
5
  */
6
6
  export type UploadImagesFileItemProps = Omit<HTMLAttributes<HTMLDivElement>, "children"> & {
7
7
  children: ((props: UploadFileItemChildProps) => ReactNode) | ReactNode;
8
- file: FileWithId;
8
+ file: UploadFileItemChildProps["file"];
9
9
  };
10
10
  /**
11
11
  * Individual file item component with preview and removal functionality.
@@ -1 +1 @@
1
- {"version":3,"file":"File.d.ts","sourceRoot":"","sources":["../../../src/lib/UploadImages/File.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAA;AAEtE,OAAO,EAAE,UAAU,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAG/D;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACzF,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,wBAAwB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAA;IACtE,IAAI,EAAE,UAAU,CAAA;CACjB,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,yBAAyB,+BAqB3F"}
1
+ {"version":3,"file":"File.d.ts","sourceRoot":"","sources":["../../../src/lib/UploadImages/File.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAA;AAEtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,UAAU,CAAA;AAGnD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC,GAAG;IACzF,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,wBAAwB,KAAK,SAAS,CAAC,GAAG,SAAS,CAAA;IACtE,IAAI,EAAE,wBAAwB,CAAC,MAAM,CAAC,CAAA;CACvC,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,KAAK,EAAE,EAAE,yBAAyB,+BA2B3F"}
@@ -21,5 +21,5 @@ import { FileWithId, UploadedFileWithId, UploadParams } from '../types';
21
21
  * }));
22
22
  * ```
23
23
  */
24
- export declare function tryUploadWithUploadParams(image: FileWithId | UploadedFileWithId, getUploadParams: (image: FileWithId) => Promise<UploadParams | null | undefined>): Promise<UploadedFileWithId>;
24
+ export declare function tryUploadWithUploadParams(image: FileWithId, getUploadParams: (image: FileWithId) => Promise<UploadParams | null | undefined>): Promise<UploadedFileWithId>;
25
25
  //# sourceMappingURL=tryUploadWithUploadParams.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"tryUploadWithUploadParams.d.ts","sourceRoot":"","sources":["../../../src/lib/_utils/tryUploadWithUploadParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,UAAU,GAAG,kBAAkB,EACtC,eAAe,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,GAC/E,OAAO,CAAC,kBAAkB,CAAC,CA4B7B"}
1
+ {"version":3,"file":"tryUploadWithUploadParams.d.ts","sourceRoot":"","sources":["../../../src/lib/_utils/tryUploadWithUploadParams.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEvE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,YAAY,GAAG,IAAI,GAAG,SAAS,CAAC,GAC/E,OAAO,CAAC,kBAAkB,CAAC,CA4B7B"}
@@ -1,11 +1,12 @@
1
1
  export type { Accept, FileRejection } from 'react-dropzone';
2
- export type FileWithId = {
2
+ type BaseFileWithId = {
3
3
  originalFile: File;
4
4
  id: string;
5
5
  };
6
- export type UploadedFileWithId = FileWithId & {
6
+ export type UploadedFileWithId = BaseFileWithId & {
7
7
  url: string;
8
8
  };
9
+ export type FileWithId = BaseFileWithId | UploadedFileWithId;
9
10
  export type UploadParams = {
10
11
  uri: string;
11
12
  method: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE3D,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,EAAE,IAAI,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG;IAC5C,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,OAAO,CAAA;IACrB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAAA"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAA;AAE3D,KAAK,cAAc,GAAG;IACpB,YAAY,EAAE,IAAI,CAAA;IAClB,EAAE,EAAE,MAAM,CAAA;CACX,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG,cAAc,GAAG;IAChD,GAAG,EAAE,MAAM,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,kBAAkB,CAAA;AAE5D,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;CACrB,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,IAAI,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,EAAE,OAAO,CAAA;IACrB,kBAAkB,EAAE,OAAO,CAAA;IAC3B,SAAS,EAAE,OAAO,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,mCAAmC,GAAG;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,KAAK,EAAE,MAAM,IAAI,CAAA;CAClB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leancodepl/image-uploader",
3
- "version": "10.5.1",
3
+ "version": "10.5.2",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "node": ">=22.0.0"
23
23
  },
24
24
  "dependencies": {
25
- "@leancodepl/utils": "10.5.1",
25
+ "@leancodepl/utils": "10.5.2",
26
26
  "react-dropzone": "^15.0.0",
27
27
  "react-easy-crop": "^6.0.0",
28
28
  "uuid": "^14.0.1"