@mbs-dev/react-editor 1.0.5 → 1.0.7

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/dist/Editor.js CHANGED
@@ -1,4 +1,29 @@
1
1
  "use strict";
2
+ var __read = (this && this.__read) || function (o, n) {
3
+ var m = typeof Symbol === "function" && o[Symbol.iterator];
4
+ if (!m) return o;
5
+ var i = m.call(o), r, ar = [], e;
6
+ try {
7
+ while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
8
+ }
9
+ catch (error) { e = { error: error }; }
10
+ finally {
11
+ try {
12
+ if (r && !r.done && (m = i["return"])) m.call(i);
13
+ }
14
+ finally { if (e) throw e.error; }
15
+ }
16
+ return ar;
17
+ };
18
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
19
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
20
+ if (ar || !(i in from)) {
21
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
22
+ ar[i] = from[i];
23
+ }
24
+ }
25
+ return to.concat(ar || Array.prototype.slice.call(from));
26
+ };
2
27
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
28
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
29
  };
@@ -26,7 +51,7 @@ var uploaderConfig = function (apiUrl, imageUrl) { return ({
26
51
  var fn = this.jodit;
27
52
  if (e.data.files && e.data.files.length) {
28
53
  var tagName_1 = 'img';
29
- e.data.files.forEach(function (filename, index) {
54
+ e.data.files.forEach(function (filename) {
30
55
  var elm = fn.createInside.element(tagName_1);
31
56
  elm.setAttribute('src', "".concat(imageUrl, "/").concat(filename));
32
57
  fn.s.insertImage(elm, null, fn.o.imageDefaultWidth);
@@ -56,51 +81,86 @@ var uploaderConfig = function (apiUrl, imageUrl) { return ({
56
81
  },
57
82
  }); };
58
83
  exports.uploaderConfig = uploaderConfig;
59
- var config = function (includeUploader, apiUrl, imageUrl) { return ({
60
- readonly: false,
61
- placeholder: 'Start typing...',
62
- toolbarAdaptive: false,
63
- useSearch: false,
64
- language: "en",
65
- allowResizeX: false,
66
- allowResizeY: false,
67
- height: 400,
68
- enableDragAndDropFileToEditor: true,
69
- showCharsCounter: true,
70
- showWordsCounter: true,
71
- showXPathInStatusbar: false,
72
- buttons: [
73
- 'source',
74
- '|',
75
- 'bold',
76
- 'italic',
77
- 'underline',
78
- '|',
79
- 'ul',
80
- 'ol',
81
- '|',
82
- 'image',
83
- '|',
84
- 'video',
85
- '|',
86
- 'link',
87
- '|',
88
- 'undo',
89
- 'redo',
90
- '|',
91
- 'hr',
92
- '|',
93
- 'eraser',
94
- '|',
95
- 'font',
96
- 'fontsize',
97
- 'paragraph',
98
- 'brush',
99
- '|',
100
- 'table',
101
- 'fullsize',
102
- ],
103
- uploader: includeUploader ? (0, exports.uploaderConfig)(apiUrl, imageUrl) : undefined,
104
- }); };
84
+ var config = function (_a) {
85
+ var _b = _a === void 0 ? {} : _a, includeUploader = _b.includeUploader, apiUrl = _b.apiUrl, imageUrl = _b.imageUrl, onDeleteImage = _b.onDeleteImage;
86
+ return ({
87
+ readonly: false,
88
+ placeholder: 'Start typing...',
89
+ toolbarAdaptive: false,
90
+ useSearch: false,
91
+ language: 'en',
92
+ allowResizeX: false,
93
+ allowResizeY: false,
94
+ height: 400,
95
+ enableDragAndDropFileToEditor: true,
96
+ showCharsCounter: true,
97
+ showWordsCounter: true,
98
+ showXPathInStatusbar: false,
99
+ buttons: [
100
+ 'source',
101
+ '|',
102
+ 'bold',
103
+ 'italic',
104
+ 'underline',
105
+ '|',
106
+ 'ul',
107
+ 'ol',
108
+ '|',
109
+ 'image',
110
+ '|',
111
+ 'video',
112
+ '|',
113
+ 'link',
114
+ '|',
115
+ 'undo',
116
+ 'redo',
117
+ '|',
118
+ 'hr',
119
+ '|',
120
+ 'eraser',
121
+ '|',
122
+ 'font',
123
+ 'fontsize',
124
+ 'paragraph',
125
+ 'brush',
126
+ '|',
127
+ 'table',
128
+ 'fullsize',
129
+ ],
130
+ uploader: includeUploader ? (0, exports.uploaderConfig)(apiUrl, imageUrl) : undefined,
131
+ events: onDeleteImage
132
+ ? {
133
+ afterInit: function (editor) {
134
+ var root = editor.editor;
135
+ var observer = new MutationObserver(function (mutations) {
136
+ mutations.forEach(function (mutation) {
137
+ mutation.removedNodes.forEach(function (node) {
138
+ if (node.nodeType !== Node.ELEMENT_NODE)
139
+ return;
140
+ var el = node;
141
+ var imgs = __spreadArray(__spreadArray([], __read((el.matches('img') ? [el] : [])), false), __read(Array.from(el.querySelectorAll('img'))), false);
142
+ imgs.forEach(function (img) {
143
+ var src = img.getAttribute('src');
144
+ if (!src)
145
+ return;
146
+ if (imageUrl && !src.startsWith(imageUrl))
147
+ return;
148
+ onDeleteImage(src);
149
+ });
150
+ });
151
+ });
152
+ });
153
+ observer.observe(root, {
154
+ childList: true,
155
+ subtree: true,
156
+ });
157
+ editor.events.on('beforeDestruct', function () {
158
+ observer.disconnect();
159
+ });
160
+ },
161
+ }
162
+ : undefined,
163
+ });
164
+ };
105
165
  exports.config = config;
106
166
  exports.default = ReactEditor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mbs-dev/react-editor",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "react editor",
5
5
  "main": "dist/index.js",
6
6
  "types": "types/index.d.ts",
package/src/Editor.tsx CHANGED
@@ -1,13 +1,11 @@
1
+ // Editor.tsx
1
2
  import React from 'react';
2
- import JoditEditor from "jodit-react";
3
- import { EditorProps } from './Editor.types';
3
+ import JoditEditor from 'jodit-react';
4
+ import { EditorProps, OnDeleteImage } from './Editor.types';
4
5
 
5
6
  const ReactEditor: React.FC<EditorProps> = ({ onChange, onBlur, value, config }) => {
6
- // const editor = useRef(null);
7
-
8
7
  return (
9
8
  <JoditEditor
10
- // ref={ref}
11
9
  value={value}
12
10
  config={config}
13
11
  onBlur={onBlur}
@@ -16,25 +14,25 @@ const ReactEditor: React.FC<EditorProps> = ({ onChange, onBlur, value, config })
16
14
  );
17
15
  };
18
16
 
19
-
20
- export const uploaderConfig = (apiUrl: string | undefined, imageUrl: string | undefined) => ({
17
+ export const uploaderConfig = (apiUrl?: string, imageUrl?: string) => ({
21
18
  imagesExtensions: ['jpg', 'png', 'jpeg', 'gif', 'webp'],
22
- filesVariableName: function (t: number): string {
19
+ filesVariableName(t: number): string {
23
20
  return 'files[' + t + ']';
24
21
  },
25
22
  url: apiUrl,
26
23
  withCredentials: false,
27
24
  format: 'json',
28
25
  method: 'POST',
29
- prepareData: function (formdata: FormData): FormData {
26
+ prepareData(formdata: FormData): FormData {
30
27
  return formdata;
31
28
  },
32
- isSuccess: function (this: any, e: any): boolean {
33
- const fn = this.jodit
29
+ isSuccess(this: any, e: any): boolean {
30
+ const fn = this.jodit;
34
31
 
35
32
  if (e.data.files && e.data.files.length) {
36
33
  const tagName = 'img';
37
- e.data.files.forEach((filename: string, index: number) => {
34
+
35
+ e.data.files.forEach((filename: string) => {
38
36
  const elm = fn.createInside.element(tagName);
39
37
  elm.setAttribute('src', `${imageUrl}/${filename}`);
40
38
  fn.s.insertImage(elm as HTMLImageElement, null, fn.o.imageDefaultWidth);
@@ -43,37 +41,47 @@ export const uploaderConfig = (apiUrl: string | undefined, imageUrl: string | un
43
41
 
44
42
  return e.success;
45
43
  },
46
- getMessage: function (e: any): string {
44
+ getMessage(e: any): string {
47
45
  return e.data.messages && Array.isArray(e.data.messages)
48
46
  ? e.data.messages.join('')
49
47
  : '';
50
48
  },
51
- process: function (resp: any): { files: any[]; error: string; msg: string } {
52
- let files: any[] = [];
49
+ process(resp: any): { files: any[]; error: string; msg: string } {
50
+ const files: any[] = [];
53
51
  files.unshift(resp.data);
52
+
54
53
  return {
55
54
  files: resp.data,
56
55
  error: resp.msg,
57
56
  msg: resp.msg,
58
57
  };
59
58
  },
60
-
61
- error: function (this: any, e: Error): void {
59
+ error(this: any, e: Error): void {
62
60
  this.j.e.fire('errorMessage', e.message, 'error', 4000);
63
61
  },
64
-
65
- defaultHandlerError: function (this: any, e: any): void {
62
+ defaultHandlerError(this: any, e: any): void {
66
63
  this.j.e.fire('errorMessage', e.message);
67
64
  },
68
65
  });
69
66
 
67
+ type ConfigParams = {
68
+ includeUploader?: boolean;
69
+ apiUrl?: string;
70
+ imageUrl?: string;
71
+ onDeleteImage?: OnDeleteImage;
72
+ };
70
73
 
71
- export const config = (includeUploader?: boolean | undefined, apiUrl?: string | undefined, imageUrl?: string | undefined) => ({
74
+ export const config = ({
75
+ includeUploader,
76
+ apiUrl,
77
+ imageUrl,
78
+ onDeleteImage,
79
+ }: ConfigParams = {}) => ({
72
80
  readonly: false,
73
81
  placeholder: 'Start typing...',
74
82
  toolbarAdaptive: false,
75
83
  useSearch: false,
76
- language: "en",
84
+ language: 'en',
77
85
  allowResizeX: false,
78
86
  allowResizeY: false,
79
87
  height: 400,
@@ -93,7 +101,6 @@ export const config = (includeUploader?: boolean | undefined, apiUrl?: string |
93
101
  'ol',
94
102
  '|',
95
103
  'image',
96
- // 'file',
97
104
  '|',
98
105
  'video',
99
106
  '|',
@@ -114,7 +121,52 @@ export const config = (includeUploader?: boolean | undefined, apiUrl?: string |
114
121
  'table',
115
122
  'fullsize',
116
123
  ],
124
+
117
125
  uploader: includeUploader ? uploaderConfig(apiUrl, imageUrl) : undefined,
118
- })
119
126
 
120
- export default ReactEditor
127
+ // 👇 This part ensures delete callback runs when image is removed
128
+ events: onDeleteImage
129
+ ? {
130
+ afterInit(editor: any) {
131
+ const root: HTMLElement = editor.editor;
132
+
133
+ const observer = new MutationObserver((mutations) => {
134
+ mutations.forEach((mutation) => {
135
+ mutation.removedNodes.forEach((node) => {
136
+ if (node.nodeType !== Node.ELEMENT_NODE) return;
137
+
138
+ const el = node as HTMLElement;
139
+
140
+ const imgs: HTMLImageElement[] = [
141
+ ...(el.matches('img') ? [el as HTMLImageElement] : []),
142
+ ...Array.from(el.querySelectorAll('img')),
143
+ ];
144
+
145
+ imgs.forEach((img) => {
146
+ const src = img.getAttribute('src');
147
+ if (!src) return;
148
+
149
+ // Optionally restrict to your image base URL
150
+ if (imageUrl && !src.startsWith(imageUrl)) return;
151
+
152
+ onDeleteImage(src);
153
+ });
154
+ });
155
+ });
156
+ });
157
+
158
+ observer.observe(root, {
159
+ childList: true,
160
+ subtree: true,
161
+ });
162
+
163
+ // Cleanup when editor is destroyed
164
+ editor.events.on('beforeDestruct', () => {
165
+ observer.disconnect();
166
+ });
167
+ },
168
+ }
169
+ : undefined,
170
+ });
171
+
172
+ export default ReactEditor;
@@ -7,4 +7,6 @@ export interface EditorProps {
7
7
  imageUrl?: string;
8
8
  config?: any
9
9
  // ref?: any;
10
- }
10
+ }
11
+
12
+ export type OnDeleteImage = (src: string) => void | Promise<void>;
package/types/Editor.d.ts CHANGED
@@ -1,25 +1,31 @@
1
1
  import React from 'react';
2
- import { EditorProps } from './Editor.types';
2
+ import { EditorProps, OnDeleteImage } from './Editor.types';
3
3
  declare const ReactEditor: React.FC<EditorProps>;
4
- export declare const uploaderConfig: (apiUrl: string | undefined, imageUrl: string | undefined) => {
4
+ export declare const uploaderConfig: (apiUrl?: string, imageUrl?: string) => {
5
5
  imagesExtensions: string[];
6
- filesVariableName: (t: number) => string;
6
+ filesVariableName(t: number): string;
7
7
  url: string | undefined;
8
8
  withCredentials: boolean;
9
9
  format: string;
10
10
  method: string;
11
- prepareData: (formdata: FormData) => FormData;
12
- isSuccess: (this: any, e: any) => boolean;
13
- getMessage: (e: any) => string;
14
- process: (resp: any) => {
11
+ prepareData(formdata: FormData): FormData;
12
+ isSuccess(this: any, e: any): boolean;
13
+ getMessage(e: any): string;
14
+ process(resp: any): {
15
15
  files: any[];
16
16
  error: string;
17
17
  msg: string;
18
18
  };
19
- error: (this: any, e: Error) => void;
20
- defaultHandlerError: (this: any, e: any) => void;
19
+ error(this: any, e: Error): void;
20
+ defaultHandlerError(this: any, e: any): void;
21
21
  };
22
- export declare const config: (includeUploader?: boolean | undefined, apiUrl?: string | undefined, imageUrl?: string | undefined) => {
22
+ type ConfigParams = {
23
+ includeUploader?: boolean;
24
+ apiUrl?: string;
25
+ imageUrl?: string;
26
+ onDeleteImage?: OnDeleteImage;
27
+ };
28
+ export declare const config: ({ includeUploader, apiUrl, imageUrl, onDeleteImage, }?: ConfigParams) => {
23
29
  readonly: boolean;
24
30
  placeholder: string;
25
31
  toolbarAdaptive: boolean;
@@ -35,21 +41,24 @@ export declare const config: (includeUploader?: boolean | undefined, apiUrl?: st
35
41
  buttons: string[];
36
42
  uploader: {
37
43
  imagesExtensions: string[];
38
- filesVariableName: (t: number) => string;
44
+ filesVariableName(t: number): string;
39
45
  url: string | undefined;
40
46
  withCredentials: boolean;
41
47
  format: string;
42
48
  method: string;
43
- prepareData: (formdata: FormData) => FormData;
44
- isSuccess: (this: any, e: any) => boolean;
45
- getMessage: (e: any) => string;
46
- process: (resp: any) => {
49
+ prepareData(formdata: FormData): FormData;
50
+ isSuccess(this: any, e: any): boolean;
51
+ getMessage(e: any): string;
52
+ process(resp: any): {
47
53
  files: any[];
48
54
  error: string;
49
55
  msg: string;
50
56
  };
51
- error: (this: any, e: Error) => void;
52
- defaultHandlerError: (this: any, e: any) => void;
57
+ error(this: any, e: Error): void;
58
+ defaultHandlerError(this: any, e: any): void;
59
+ } | undefined;
60
+ events: {
61
+ afterInit(editor: any): void;
53
62
  } | undefined;
54
63
  };
55
64
  export default ReactEditor;
@@ -7,3 +7,4 @@ export interface EditorProps {
7
7
  imageUrl?: string;
8
8
  config?: any;
9
9
  }
10
+ export type OnDeleteImage = (src: string) => void | Promise<void>;