@emailmaker/filemanager 1.1.95 → 1.1.102

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.
Files changed (49) hide show
  1. package/.build-meta.json +1 -1
  2. package/assets/icon-sets/lucide.json +6275 -0
  3. package/assets/icon-sets/tabler.json +19336 -0
  4. package/components/FilerobotEditor/FilerobotEditor.d.ts +1 -0
  5. package/components/FilerobotEditor/cornerRadius/CornerRadiusTool.d.ts +22 -0
  6. package/components/FilerobotEditor/cornerRadius/__tests__/cornerRadiusMath.test.d.ts +1 -0
  7. package/components/FilerobotEditor/cornerRadius/__tests__/cornerRadiusOutput.test.d.ts +1 -0
  8. package/components/FilerobotEditor/cornerRadius/__tests__/imageEditorTools.test.d.ts +1 -0
  9. package/components/FilerobotEditor/cornerRadius/cornerRadiusEraser.d.ts +17 -0
  10. package/components/FilerobotEditor/cornerRadius/cornerRadiusMath.d.ts +38 -0
  11. package/components/FilerobotEditor/cornerRadius/cornerRadiusOutput.d.ts +18 -0
  12. package/components/FilerobotEditor/cornerRadius/imageEditorTools.d.ts +11 -0
  13. package/components/FilerobotEditor/cornerRadius/useCornerRadiusSync.d.ts +23 -0
  14. package/components/ImageIcons/iconSets.d.ts +38 -0
  15. package/components/ImageIcons/iconSets.test.d.ts +1 -0
  16. package/components/ImageIcons/iconStockSearch.d.ts +3 -1
  17. package/components/ImageIcons/packagedIconSets.d.ts +9 -0
  18. package/core.d.ts +1 -0
  19. package/core.esm.js +272 -259
  20. package/core.js +1 -1
  21. package/file-manager-FilerobotEditor.js +576 -0
  22. package/file-manager-IconsTab.js +2083 -0
  23. package/{file-manager-ImageCodeGenerator-m06RVQr7.js → file-manager-ImageCodeGenerator.js} +8 -8
  24. package/{file-manager-JsBarcode-CyaffT5b.js → file-manager-JsBarcode.js} +30 -30
  25. package/{file-manager-browser-DDyRNDQk.js → file-manager-browser.js} +8 -8
  26. package/{file-manager-hooks-UP2zpv8z.js → file-manager-hooks-BDRRCedE.js} +4792 -2384
  27. package/file-manager-imageEditorCropPresets-en0_jYEY.js +76 -0
  28. package/{file-manager-rolldown-runtime-DAVfCfog.js → file-manager-rolldown-runtime-DawGUBAG.js} +2 -2
  29. package/{file-manager-useMediaListEngine-B9sz3gcs.js → file-manager-urls-rCuqY9r4.js} +139 -119
  30. package/file-manager.esm.js +2332 -2277
  31. package/file-manager.js +12 -12
  32. package/helpers/__tests__/applyImageEditorTranslations.test.d.ts +1 -0
  33. package/helpers/__tests__/imageEditorCropPresets.test.d.ts +1 -0
  34. package/helpers/__tests__/locales.test.d.ts +1 -0
  35. package/helpers/applyImageEditorTranslations.d.ts +6 -0
  36. package/helpers/imageEditorCropPresets.d.ts +8 -0
  37. package/index.d.ts +2 -0
  38. package/package.json +5 -1
  39. package/types.d.ts +18 -0
  40. package/utils/filerobotEditorConfig.d.ts +1 -0
  41. package/utils/generateId.d.ts +5 -0
  42. package/utils/imageCompression.d.ts +10 -0
  43. package/utils/imageCompression.editedImage.test.d.ts +1 -0
  44. package/utils/imageCompression.png.test.d.ts +1 -0
  45. package/utils/pngCompression.d.ts +23 -0
  46. package/utils/pngCompression.test.d.ts +1 -0
  47. package/file-manager-FilerobotEditor-WbM5WTct.js +0 -330
  48. package/file-manager-IconsTab-CCn0Q0ng.js +0 -2434
  49. package/file-manager-imageEditorTranslations-CtNVql-A.js +0 -38
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ /**
2
+ * applyImageEditorTranslations hands the editor its dictionary before the editor first renders and
3
+ * returns that dictionary for the `translations` prop. The prop alone is applied only after the
4
+ * first render, so labels that never re-render (Rotate, Flip X, Flip Y) would stay in English.
5
+ */
6
+ export declare function applyImageEditorTranslations(locale: string | undefined): Record<string, string>;
@@ -0,0 +1,8 @@
1
+ import type { FilerobotImageEditorConfig } from 'react-filerobot-image-editor';
2
+ type CropPreset = NonNullable<NonNullable<FilerobotImageEditorConfig['Crop']>['presetsItems']>[number];
3
+ /**
4
+ * IMAGE_EDITOR_CROP_PRESETS are the aspect-ratio templates added below the editor's built-in crop
5
+ * items, ordered by shape. 9:16 is absent on purpose: the built-in "Portrait" already offers it.
6
+ */
7
+ export declare const IMAGE_EDITOR_CROP_PRESETS: CropPreset[];
8
+ export {};
package/index.d.ts CHANGED
@@ -18,6 +18,8 @@ export { FileManagerApiError } from './shared/fileManagerApiError';
18
18
  export { mapHttpStatusToErrorCode } from './shared/mapHttpStatusToErrorCode';
19
19
  export { buildAssetsPath, joinUrls, getAssetsBase } from './helpers/urls';
20
20
  export { getImageEditorTranslations } from './helpers/imageEditorTranslations';
21
+ export { applyImageEditorTranslations } from './helpers/applyImageEditorTranslations';
22
+ export { IMAGE_EDITOR_CROP_PRESETS } from './helpers/imageEditorCropPresets';
21
23
  export { FailedRequestCache } from './adapters/FailedRequestCache';
22
24
  export { MutationRegistry } from './adapters/MutationRegistry';
23
25
  export { compareFileSystemItems, defaultChildrenViewFilterMatch, defaultFileSystemItemComparator, defaultHasSortValue, hasComparableSortValue, matchesChildrenViewFilter, resolveSortParams, resolveViewStrategyOptions, } from './adapters/cacheViewStrategy';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emailmaker/filemanager",
3
- "version": "1.1.95",
3
+ "version": "1.1.102",
4
4
  "main": "./file-manager.js",
5
5
  "module": "./file-manager.esm.js",
6
6
  "types": "./index.d.ts",
@@ -24,6 +24,10 @@
24
24
  "./notification": {
25
25
  "types": "./notification.d.ts"
26
26
  },
27
+ "./image-editor": {
28
+ "types": "./components/FilerobotEditor/FilerobotEditor.d.ts",
29
+ "import": "./file-manager-FilerobotEditor.js"
30
+ },
27
31
  "./package.json": "./package.json",
28
32
  "./*": "./*"
29
33
  },
package/types.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import React, { ReactNode, RefObject } from 'react';
2
2
  import type { FormInstance } from 'antd';
3
+ import type { IconifyJSON } from '@iconify/types';
3
4
  import { MY_FILES, GIF, STOCK_IMAGES, ICONS, AI, IMAGE_CODES, EDITOR, IMAGE_EXTENSIONS } from './constants';
4
5
  import type { InputRef } from 'antd';
5
6
  import type { TextAreaRef } from 'antd/es/input/TextArea';
@@ -556,6 +557,18 @@ export interface Config {
556
557
  elementId?: string;
557
558
  baseUrl?: string;
558
559
  assetsUrl?: string;
560
+ /**
561
+ * Directory with the icon sets (`lucide.json`, `tabler.json`), relative to `baseUrl`.
562
+ *
563
+ * The sets are fetched, not bundled: together they are 2.7 MB of data that a bundler can
564
+ * neither split nor shake. Defaults to `static/media/icon-sets`.
565
+ */
566
+ iconSetsUrl?: string;
567
+ /**
568
+ * Host loader of an icon set (`lucide`, `tabler`). When given, `iconSetsUrl` and the packaged files are not used:
569
+ * the host delivers the sets as its own modules and nothing is fetched.
570
+ */
571
+ loadIconSet?: (prefix: 'lucide' | 'tabler') => Promise<IconifyJSON>;
559
572
  /** Counters and limits */
560
573
  counters?: Counters;
561
574
  limits?: Limits;
@@ -579,6 +592,11 @@ export interface Config {
579
592
  rememberLastFolder?: boolean;
580
593
  compressMaxSize?: number;
581
594
  compressMaxWidthOrHeight?: number;
595
+ /**
596
+ * Squeeze image editor results to `compressMaxSize` too. Off by default: the result is only downscaled
597
+ * beyond `compressMaxWidthOrHeight`, otherwise every save would shrink the image again.
598
+ */
599
+ compressEditedImages?: boolean;
582
600
  /** URL локальной копии browser-image-compression для web worker. */
583
601
  compessorUrl?: string;
584
602
  /** Alias для compessorUrl с корректным написанием. */
@@ -10,6 +10,7 @@ export interface FilerobotEditorConfigOptions {
10
10
  assetsUrl?: string;
11
11
  compressMaxSize?: Config['compressMaxSize'];
12
12
  compressMaxWidthOrHeight?: Config['compressMaxWidthOrHeight'];
13
+ compressEditedImages?: Config['compressEditedImages'];
13
14
  compessorUrl?: string;
14
15
  compressorUrl?: string;
15
16
  showNotifications?: boolean;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * generateId returns a random unique id: a v4 UUID where `crypto.randomUUID` exists (secure contexts),
3
+ * otherwise random hex. Callers use it as an opaque key, never parse it.
4
+ */
5
+ export declare function generateId(): string;
@@ -10,3 +10,13 @@ export interface PrepareImageForUploadOptions {
10
10
  }
11
11
  export declare function prepareImageForUpload(file: File, options?: PrepareImageForUploadOptions): Promise<File>;
12
12
  export declare const compressImageWithLimits: typeof prepareImageForUpload;
13
+ /** Options of `prepareEditedImageForUpload`. */
14
+ export interface PrepareEditedImageOptions extends PrepareImageForUploadOptions {
15
+ /** Squeeze the result to `maxSizeMB` like a new upload; set when the host configured the limit explicitly. */
16
+ compressBySize?: boolean;
17
+ }
18
+ /**
19
+ * Prepares an image editor result for upload: by default downscales only beyond maxWidthOrHeight and ignores the size limit,
20
+ * because re-running the upload compression on every save shrank the resolution and coarsened PNGs each time.
21
+ */
22
+ export declare function prepareEditedImageForUpload(file: File, options?: PrepareEditedImageOptions): Promise<File>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,23 @@
1
+ /**
2
+ * PNG compression rule shared by the file manager and the app: how many colours an uploaded PNG keeps
3
+ * and which PNGs are left alone. Pure functions — the compression library itself is not imported here.
4
+ */
5
+ /** PNG_COMPRESSION_COLORS is the palette an uploaded PNG is quantized to on the first pass. */
6
+ export declare const PNG_COMPRESSION_COLORS = 1024;
7
+ /**
8
+ * PNG_INITIAL_QUALITY is the `initialQuality` for `browser-image-compression`: its PNG encoder (UPNG)
9
+ * keeps 4096 × quality colours.
10
+ */
11
+ export declare const PNG_INITIAL_QUALITY: number;
12
+ /**
13
+ * isAnimatedPng tells an animated PNG by its `acTL` chunk, which the format places before the first
14
+ * `IDAT`. Reads only within the buffer, so a truncated or broken file counts as still.
15
+ */
16
+ export declare function isAnimatedPng(bytes: Uint8Array): boolean;
17
+ /** isAnimatedPngFile reads the start of the file and checks it with `isAnimatedPng`. */
18
+ export declare function isAnimatedPngFile(file: Blob): Promise<boolean>;
19
+ /**
20
+ * keepSmallerPng returns the compressed PNG only when it is smaller. The library never falls back to
21
+ * the original: it keeps cutting colours and may still hand back a larger file.
22
+ */
23
+ export declare function keepSmallerPng<T extends Blob>(original: T, compressed: T): T;
@@ -0,0 +1 @@
1
+ export {};
@@ -1,330 +0,0 @@
1
- import { D as e, E as t, L as n, T as r, V as i, Z as a, f as o, it as s, nt as c, y as ee, yt as l } from "./file-manager-hooks-UP2zpv8z.js";
2
- import { n as u, t as d } from "./file-manager-imageEditorTranslations-CtNVql-A.js";
3
- import f from "react";
4
- import { Button as p, Modal as m } from "antd";
5
- import { jsx as h, jsxs as g } from "react/jsx-runtime";
6
- import _, { TABS as v } from "react-filerobot-image-editor";
7
- var y = {
8
- "em-filemanager": "em-filemanager",
9
- emFilemanager: "em-filemanager",
10
- filerobotEditorModal: "filerobotEditorModal",
11
- filerobotEditorContainer: "filerobotEditorContainer",
12
- filerobotEditorBody: "filerobotEditorBody"
13
- }, b = {
14
- container: y.filerobotEditorContainer,
15
- body: y.filerobotEditorBody
16
- }, x = (e, t = "image/png") => fetch(`data:${t};base64,${e}`).then((e) => e.blob());
17
- function S(e, t) {
18
- if (e === "json") return new Blob([t], { type: "application/json" });
19
- if (e === "svg") return new Blob([t], { type: "image/svg+xml" });
20
- let n = `image/${e}`;
21
- if (t.startsWith("data:")) {
22
- let e = c(t);
23
- return e && e.startsWith("image/") && (n = e), x(t.replace(/data:image\/[^;]+;base64,/, ""), s(n));
24
- }
25
- return x(t, s(n));
26
- }
27
- function C(e) {
28
- return new Promise((t, n) => {
29
- let r = new FileReader();
30
- r.onload = () => t(r.result), r.onerror = () => n(r.error ?? /* @__PURE__ */ Error("Failed to convert blob to data URL")), r.readAsDataURL(e);
31
- });
32
- }
33
- var w = [
34
- {
35
- label: "Arial",
36
- value: "Arial"
37
- },
38
- {
39
- label: "Helvetica",
40
- value: "Helvetica"
41
- },
42
- {
43
- label: "Verdana",
44
- value: "Verdana"
45
- },
46
- {
47
- label: "Tahoma",
48
- value: "Tahoma"
49
- },
50
- {
51
- label: "Trebuchet MS",
52
- value: "Trebuchet MS"
53
- },
54
- {
55
- label: "Times New Roman",
56
- value: "Times New Roman"
57
- },
58
- {
59
- label: "Georgia",
60
- value: "Georgia"
61
- },
62
- {
63
- label: "Courier New",
64
- value: "Courier New"
65
- },
66
- {
67
- label: "Impact",
68
- value: "Impact"
69
- },
70
- {
71
- label: "Comic Sans MS",
72
- value: "Comic Sans MS"
73
- }
74
- ], T = ({ visible: c, onClose: x, file: T, onSave: E, onSaveCopy: te }) => {
75
- let { t: D } = a(), O = n(), k = o(), { options: A } = i(), { i18n: ne } = a(), { config: j } = A, { getFileData: M, resolveFileForEditByUrl: N } = k, [P, F] = f.useState(!1), [I, re] = f.useState(null), [L, R] = f.useState(""), [z, B] = f.useState(!1), [V, H] = f.useState(null), [U, W] = f.useState(null), G = f.useRef(void 0), K = f.useRef(void 0), q = f.useRef(void 0), J = f.useRef(void 0);
76
- G.current = E, K.current = te, f.useEffect(() => {
77
- T && (async () => {
78
- if (J.current !== T) {
79
- if (typeof T == "object") {
80
- H(T);
81
- return;
82
- }
83
- J.current = T, F(!0);
84
- try {
85
- if (T.startsWith("data:")) H({
86
- thumbnail: T,
87
- saveWithoutFolder: !0
88
- });
89
- else {
90
- let e = await N(T);
91
- J.current === T && H(e);
92
- }
93
- } catch (e) {
94
- console.error("Failed to load file for editor:", e), J.current === T && (J.current = null), x?.();
95
- } finally {
96
- F(!1);
97
- }
98
- }
99
- })();
100
- }, [
101
- T,
102
- x,
103
- N
104
- ]);
105
- let Y = f.useCallback(async (e) => {
106
- if (typeof e.thumbnail == "string" && e.thumbnail.startsWith("data:")) return e.thumbnail;
107
- let t = await M(e.id, !0);
108
- if (!t) throw Error(D("Error loading image"));
109
- return new Promise((e) => {
110
- let n = new FileReader();
111
- n.onload = () => e(n.result), n.readAsDataURL(t);
112
- });
113
- }, [M, D]);
114
- f.useEffect(() => {
115
- if (!I && c && V) {
116
- let e = !1;
117
- return (async () => {
118
- F(!0);
119
- try {
120
- let n = await Y(V);
121
- if (!e) {
122
- re(n);
123
- let e = t(V, "image/png");
124
- R(e.mimeType);
125
- }
126
- } catch (t) {
127
- e || (O.error({
128
- id: "IMAGE_DOWNLOAD_FAILED",
129
- innerException: t,
130
- message: D("Error loading image"),
131
- placement: "bottomRight",
132
- data: {}
133
- }), x?.());
134
- } finally {
135
- F(!1);
136
- }
137
- })(), () => {
138
- e = !0;
139
- };
140
- }
141
- }, [
142
- V,
143
- Y,
144
- I,
145
- x,
146
- D,
147
- c
148
- ]);
149
- let X = f.useCallback(async (t, n, r) => {
150
- let i = await S(r, t), a = s(i.type || `image/${r}`), o = j?.compessorUrl ?? j?.compressorUrl;
151
- if (a.startsWith("image/")) try {
152
- let t = await ee(new File([i], n, { type: a }), {
153
- maxSizeMB: j?.compressMaxSize,
154
- maxWidthOrHeight: j?.compressMaxWidthOrHeight,
155
- mimeType: a,
156
- fileName: n,
157
- libURL: o,
158
- enableCompression: e(j, a)
159
- });
160
- i = t, a = t.type;
161
- } catch (e) {
162
- console.warn("Image preparation failed, using original:", e);
163
- }
164
- return {
165
- blob: i,
166
- mimeType: a,
167
- thumbnailDataUrl: await C(i)
168
- };
169
- }, [j]), Z = f.useCallback(async (e, t, n, r) => {
170
- let i = r === "save" ? G.current : K.current;
171
- if (!(!V || !i)) try {
172
- F(!0);
173
- let { blob: a, mimeType: o, thumbnailDataUrl: s } = await X(e, t, n), c = await i({
174
- ...V,
175
- thumbnail: s,
176
- size: a.size,
177
- date: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
178
- type: o,
179
- folderId: V.folderId || "",
180
- name: V.name || t,
181
- extension: V.extension || (V.name || t).split(".").pop()?.toLowerCase() || ""
182
- }, {
183
- blob: a,
184
- mimeType: o,
185
- thumbnail: s,
186
- mode: r
187
- });
188
- return F(!1), c;
189
- } catch (e) {
190
- console.error("Error saving:", e), W(String(e?.message || e)), F(!1);
191
- }
192
- }, [V, X]), Q = f.useCallback((e) => {
193
- if (!q.current || !V) {
194
- console.error("FIE getCurrentImgData недоступен или файл не загружен");
195
- return;
196
- }
197
- let n = V.name || "edited-image", i = t(V, L);
198
- try {
199
- let { imageData: t, designState: a } = q.current({
200
- name: n.replace(/\.[^/.]+$/, ""),
201
- extension: i.extension,
202
- quality: r.QUALITY
203
- }, void 0, !1);
204
- console.log("[FIE PoC] getCurrentImgData ->", t, a);
205
- let o = t.imageBase64 ?? (t.imageCanvas ? t.imageCanvas.toDataURL(i.mimeType) : void 0);
206
- if (!o) throw Error("FIE не вернул ни imageBase64, ни imageCanvas");
207
- Z(o, n, i.extension, e);
208
- } catch (e) {
209
- console.error("🎨 Ошибка получения данных из FIE:", e), W(String(e?.message || e));
210
- }
211
- }, [
212
- V,
213
- L,
214
- Z
215
- ]), $ = j?.locale ? j?.locale.replace("_", "-") : "en";
216
- matchMedia(l).matches, j?.theme === "system" || j?.theme;
217
- let ie = {
218
- theme: void 0,
219
- useBackendTranslations: !1,
220
- language: $.split("-")[0] || "en",
221
- translations: d($),
222
- tabsIds: [
223
- v.ADJUST,
224
- v.FINETUNE,
225
- v.FILTERS,
226
- v.ANNOTATE,
227
- v.RESIZE
228
- ],
229
- defaultTabId: v.ADJUST,
230
- savingPixelRatio: 1,
231
- previewPixelRatio: 1,
232
- avoidChangesNotSavedAlertOnLeave: !0,
233
- defaultSavedImageName: V?.name?.replace(/\.[^/.]+$/, "") || "image",
234
- removeSaveButton: !0,
235
- observePluginContainerSize: !0,
236
- Text: {
237
- fontFamily: "Arial",
238
- fonts: w
239
- },
240
- getCurrentImgDataFnRef: q,
241
- onModify: () => {}
242
- }, ae = !!V?.id && j?.features?.enableUpdateFile !== !1;
243
- return /* @__PURE__ */ h(m, {
244
- title: V?.name ? D("Editing: {{name}}", { name: V.name }) : D("Editing image"),
245
- open: c,
246
- closeIcon: null,
247
- onCancel: x,
248
- afterOpenChange: (e) => B(e),
249
- forceRender: !0,
250
- width: "100%",
251
- getContainer: A.getModalContainer,
252
- className: y.filerobotEditorModal,
253
- classNames: b,
254
- footer: [
255
- /* @__PURE__ */ h(p, {
256
- onClick: x,
257
- disabled: !z || P,
258
- children: D("Cancel")
259
- }, "cancel"),
260
- /* @__PURE__ */ h(p, {
261
- type: "primary",
262
- onClick: () => Q("saveCopy"),
263
- loading: P,
264
- children: D("Save as copy and choose")
265
- }, "save-copy"),
266
- ...ae ? [/* @__PURE__ */ h(p, {
267
- type: "primary",
268
- onClick: () => Q("save"),
269
- loading: P,
270
- children: D("Save and choose")
271
- }, "save")] : []
272
- ],
273
- mask: { closable: !1 },
274
- destroyOnHidden: !1,
275
- children: /* @__PURE__ */ g("div", {
276
- style: {
277
- position: "relative",
278
- width: "100%",
279
- height: "100%"
280
- },
281
- children: [
282
- c && z && I ? /* @__PURE__ */ h(_, {
283
- source: I,
284
- ...ie
285
- }) : /* @__PURE__ */ h("div", {
286
- style: {
287
- position: "absolute",
288
- inset: 0,
289
- display: "flex",
290
- alignItems: "center",
291
- justifyContent: "center"
292
- },
293
- children: /* @__PURE__ */ h("span", {
294
- style: {
295
- fontSize: 14,
296
- color: "#555"
297
- },
298
- children: D("Loading editor...")
299
- })
300
- }),
301
- U && /* @__PURE__ */ g("div", {
302
- style: {
303
- position: "absolute",
304
- bottom: 8,
305
- left: 8,
306
- right: 8,
307
- background: "#fff1f0",
308
- border: "1px solid #ffa39e",
309
- color: "#a8071a",
310
- padding: 8,
311
- fontSize: 12,
312
- zIndex: 100
313
- },
314
- children: ["[FIE PoC] ", U]
315
- }),
316
- P && /* @__PURE__ */ h(u, { style: {
317
- position: "absolute",
318
- top: 0,
319
- background: "var(--em-colorBgLayout)",
320
- zIndex: 100,
321
- opacity: .7
322
- } })
323
- ]
324
- })
325
- });
326
- };
327
- //#endregion
328
- export { T as FilerobotEditor };
329
-
330
- //# sourceMappingURL=file-manager-FilerobotEditor-WbM5WTct.js.map