@mbs-dev/react-editor 1.0.1 β 1.0.3
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/README.md +139 -1
- package/dist/Editor.js +106 -0
- package/dist/Editor.types.js +2 -0
- package/dist/index.js +7 -100
- package/package.json +4 -2
- package/src/Editor.tsx +120 -0
- package/src/Editor.types.ts +10 -0
- package/src/index.ts +3 -0
- package/tsconfig.json +26 -9
- package/types/Editor.d.ts +55 -0
- package/types/Editor.types.d.ts +9 -0
- package/types/index.d.ts +3 -1
- package/src/index.tsx +0 -132
package/README.md
CHANGED
|
@@ -1 +1,139 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
# @mbs-dev/react-editor
|
|
3
|
+
|
|
4
|
+
A lightweight, typed React wrapper around **Jodit** rich-text editor, designed for real-world CRUD forms (blogs, products, CMS pages, etc.).
|
|
5
|
+
|
|
6
|
+
It provides:
|
|
7
|
+
|
|
8
|
+
- A **simple React component** `<ReactEditor />`
|
|
9
|
+
- A reusable **`config()` helper** for configuration
|
|
10
|
+
- An optional **`uploaderConfig()` helper** to handle image uploads and automatic insertion into the editor
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
[](https://www.npmjs.com/package/@mbs-dev/react-editor)
|
|
15
|
+
[](https://www.npmjs.com/package/@mbs-dev/react-editor)
|
|
16
|
+
[](https://bundlephobia.com/package/@mbs-dev/react-editor)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## β¨ Features
|
|
21
|
+
|
|
22
|
+
- π§© **Simple React API**: controlled `value` + `onChange`
|
|
23
|
+
- βοΈ **Helper config**: `config()` to quickly build configuration
|
|
24
|
+
- πΌοΈ **Image upload integration**: optional `uploaderConfig()` for file uploading + auto-insert `<img />`
|
|
25
|
+
- π§ͺ **TypeScript-ready**: ships with types & TSX-friendly usage
|
|
26
|
+
- π§± **Library-friendly**: minimal surface area, built to be reused across apps
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## π¦ Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install @mbs-dev/react-editor
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## π Quick Start
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import React, { useMemo, useState } from 'react';
|
|
42
|
+
import ReactEditor, { config } from '@mbs-dev/react-editor';
|
|
43
|
+
|
|
44
|
+
const MyPage = () => {
|
|
45
|
+
const [content, setContent] = useState('');
|
|
46
|
+
|
|
47
|
+
const editorConfig = useMemo(() => config(false), []);
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<ReactEditor
|
|
51
|
+
config={editorConfig}
|
|
52
|
+
value={content}
|
|
53
|
+
onChange={(value) => setContent(value)}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
};
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## π§ Configuration Helpers
|
|
62
|
+
|
|
63
|
+
### `config(includeUploader?: boolean, apiUrl?: string, imageUrl?: string)`
|
|
64
|
+
|
|
65
|
+
### `uploaderConfig(apiUrl?: string, imageUrl?: string)`
|
|
66
|
+
|
|
67
|
+
Both helpers simplify setting up configuration and upload support.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## π§© Symfony API Platform Example (Recommended Integration)
|
|
72
|
+
|
|
73
|
+
If your backend is **Symfony + API Platform**, here is the **most common realβworld setup**:
|
|
74
|
+
|
|
75
|
+
### **π 1. Expose your upload endpoint**
|
|
76
|
+
|
|
77
|
+
In your Symfony API (`config/routes.yaml`):
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
upload_image:
|
|
81
|
+
path: /upload
|
|
82
|
+
controller: App\Controller\ImageUploadController
|
|
83
|
+
methods: [POST]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### **π 2. Store uploaded images in `/public/uploads/images`**
|
|
87
|
+
|
|
88
|
+
```php
|
|
89
|
+
// App/Controller/ImageUploadController.php
|
|
90
|
+
|
|
91
|
+
public function __invoke(Request $request): JsonResponse
|
|
92
|
+
{
|
|
93
|
+
$files = $request->files->get('files');
|
|
94
|
+
$storedFiles = [];
|
|
95
|
+
|
|
96
|
+
foreach ($files as $file) {
|
|
97
|
+
$newName = uniqid().'.'.$file->guessExtension();
|
|
98
|
+
$file->move($this->getParameter('kernel.project_dir').'/public/uploads/images', $newName);
|
|
99
|
+
$storedFiles[] = $newName;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return new JsonResponse([
|
|
103
|
+
'success' => true,
|
|
104
|
+
'data' => [
|
|
105
|
+
'files' => $storedFiles,
|
|
106
|
+
'messages' => [],
|
|
107
|
+
],
|
|
108
|
+
'msg' => 'Upload successful'
|
|
109
|
+
]);
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### **π 3. Front-end React configuration**
|
|
114
|
+
|
|
115
|
+
```ts
|
|
116
|
+
export const uploadUrl = `${apiUrl}/upload`;
|
|
117
|
+
export const blogPostImgUrl = `${uploadUrl}/images`;
|
|
118
|
+
|
|
119
|
+
const editorConfig = useMemo(
|
|
120
|
+
() => config(
|
|
121
|
+
true, // enable uploader
|
|
122
|
+
`${apiUrl}/upload`, // Symfony upload endpoint
|
|
123
|
+
blogPostImgUrl // URL to access public images
|
|
124
|
+
),
|
|
125
|
+
[]
|
|
126
|
+
);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
This will automatically insert images as:
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<img src="https://your-domain.com/uploads/images/filename.webp" />
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## π License
|
|
138
|
+
|
|
139
|
+
MIT β feel free to use it in commercial and private applications.
|
package/dist/Editor.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.config = exports.uploaderConfig = void 0;
|
|
7
|
+
var react_1 = __importDefault(require("react"));
|
|
8
|
+
var jodit_react_1 = __importDefault(require("jodit-react"));
|
|
9
|
+
var ReactEditor = function (_a) {
|
|
10
|
+
var onChange = _a.onChange, onBlur = _a.onBlur, value = _a.value, config = _a.config;
|
|
11
|
+
return (react_1.default.createElement(jodit_react_1.default, { value: value, config: config, onBlur: onBlur, onChange: onChange }));
|
|
12
|
+
};
|
|
13
|
+
var uploaderConfig = function (apiUrl, imageUrl) { return ({
|
|
14
|
+
imagesExtensions: ['jpg', 'png', 'jpeg', 'gif', 'webp'],
|
|
15
|
+
filesVariableName: function (t) {
|
|
16
|
+
return 'files[' + t + ']';
|
|
17
|
+
},
|
|
18
|
+
url: apiUrl,
|
|
19
|
+
withCredentials: false,
|
|
20
|
+
format: 'json',
|
|
21
|
+
method: 'POST',
|
|
22
|
+
prepareData: function (formdata) {
|
|
23
|
+
return formdata;
|
|
24
|
+
},
|
|
25
|
+
isSuccess: function (e) {
|
|
26
|
+
var fn = this.jodit;
|
|
27
|
+
if (e.data.files && e.data.files.length) {
|
|
28
|
+
var tagName_1 = 'img';
|
|
29
|
+
e.data.files.forEach(function (filename, index) {
|
|
30
|
+
var elm = fn.createInside.element(tagName_1);
|
|
31
|
+
elm.setAttribute('src', "".concat(imageUrl, "/").concat(filename));
|
|
32
|
+
fn.s.insertImage(elm, null, fn.o.imageDefaultWidth);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return e.success;
|
|
36
|
+
},
|
|
37
|
+
getMessage: function (e) {
|
|
38
|
+
return e.data.messages && Array.isArray(e.data.messages)
|
|
39
|
+
? e.data.messages.join('')
|
|
40
|
+
: '';
|
|
41
|
+
},
|
|
42
|
+
process: function (resp) {
|
|
43
|
+
var files = [];
|
|
44
|
+
files.unshift(resp.data);
|
|
45
|
+
return {
|
|
46
|
+
files: resp.data,
|
|
47
|
+
error: resp.msg,
|
|
48
|
+
msg: resp.msg,
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
error: function (e) {
|
|
52
|
+
this.j.e.fire('errorMessage', e.message, 'error', 4000);
|
|
53
|
+
},
|
|
54
|
+
defaultHandlerError: function (e) {
|
|
55
|
+
this.j.e.fire('errorMessage', e.message);
|
|
56
|
+
},
|
|
57
|
+
}); };
|
|
58
|
+
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
|
+
}); };
|
|
105
|
+
exports.config = config;
|
|
106
|
+
exports.default = ReactEditor;
|
package/dist/index.js
CHANGED
|
@@ -3,103 +3,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
filesVariableName: function (t) {
|
|
14
|
-
return 'files[' + t + ']';
|
|
15
|
-
},
|
|
16
|
-
url: apiUrl,
|
|
17
|
-
withCredentials: false,
|
|
18
|
-
format: 'json',
|
|
19
|
-
method: 'POST',
|
|
20
|
-
prepareData: function (formdata) {
|
|
21
|
-
return formdata;
|
|
22
|
-
},
|
|
23
|
-
isSuccess: function (e) {
|
|
24
|
-
const fn = this.jodit;
|
|
25
|
-
if (e.data.files && e.data.files.length) {
|
|
26
|
-
const tagName = 'img';
|
|
27
|
-
e.data.files.forEach((filename, index) => {
|
|
28
|
-
const elm = fn.createInside.element(tagName);
|
|
29
|
-
elm.setAttribute('src', `${imageUrl}/${filename}`);
|
|
30
|
-
fn.s.insertImage(elm, null, fn.o.imageDefaultWidth);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
return e.success;
|
|
34
|
-
},
|
|
35
|
-
getMessage: function (e) {
|
|
36
|
-
return e.data.messages && Array.isArray(e.data.messages)
|
|
37
|
-
? e.data.messages.join('')
|
|
38
|
-
: '';
|
|
39
|
-
},
|
|
40
|
-
process: function (resp) {
|
|
41
|
-
let files = [];
|
|
42
|
-
files.unshift(resp.data);
|
|
43
|
-
return {
|
|
44
|
-
files: resp.data,
|
|
45
|
-
error: resp.msg,
|
|
46
|
-
msg: resp.msg,
|
|
47
|
-
};
|
|
48
|
-
},
|
|
49
|
-
error: function (e) {
|
|
50
|
-
this.j.e.fire('errorMessage', e.message, 'error', 4000);
|
|
51
|
-
},
|
|
52
|
-
defaultHandlerError: function (e) {
|
|
53
|
-
this.j.e.fire('errorMessage', e.message);
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
const config = (0, react_1.useMemo)(() => ({
|
|
57
|
-
readonly: false,
|
|
58
|
-
placeholder: 'Start typing...',
|
|
59
|
-
toolbarAdaptive: false,
|
|
60
|
-
useSearch: false,
|
|
61
|
-
language: "en",
|
|
62
|
-
allowResizeX: false,
|
|
63
|
-
allowResizeY: false,
|
|
64
|
-
height: 400,
|
|
65
|
-
enableDragAndDropFileToEditor: true,
|
|
66
|
-
showCharsCounter: true,
|
|
67
|
-
showWordsCounter: true,
|
|
68
|
-
showXPathInStatusbar: false,
|
|
69
|
-
buttons: [
|
|
70
|
-
'source',
|
|
71
|
-
'|',
|
|
72
|
-
'bold',
|
|
73
|
-
'italic',
|
|
74
|
-
'underline',
|
|
75
|
-
'|',
|
|
76
|
-
'ul',
|
|
77
|
-
'ol',
|
|
78
|
-
'|',
|
|
79
|
-
`${useUploadImage ? 'image' : ''}`,
|
|
80
|
-
'file',
|
|
81
|
-
'|',
|
|
82
|
-
'video',
|
|
83
|
-
'|',
|
|
84
|
-
'link',
|
|
85
|
-
'|',
|
|
86
|
-
'undo',
|
|
87
|
-
'redo',
|
|
88
|
-
'|',
|
|
89
|
-
'hr',
|
|
90
|
-
'|',
|
|
91
|
-
'eraser',
|
|
92
|
-
'|',
|
|
93
|
-
'font',
|
|
94
|
-
'fontsize',
|
|
95
|
-
'paragraph',
|
|
96
|
-
'brush',
|
|
97
|
-
'|',
|
|
98
|
-
'table',
|
|
99
|
-
'fullsize',
|
|
100
|
-
],
|
|
101
|
-
uploader: useUploadImage ? uploaderConfig : undefined,
|
|
102
|
-
}), []);
|
|
103
|
-
return (react_2.default.createElement(jodit_react_1.default, { ref: editor, value: value, config: config, onBlur: onBlur, onChange: onChange }));
|
|
104
|
-
};
|
|
105
|
-
exports.default = ReactEditor;
|
|
6
|
+
exports.uploaderConfig = exports.config = exports.default = void 0;
|
|
7
|
+
var Editor_1 = require("./Editor");
|
|
8
|
+
Object.defineProperty(exports, "default", { enumerable: true, get: function () { return __importDefault(Editor_1).default; } });
|
|
9
|
+
var Editor_2 = require("./Editor");
|
|
10
|
+
Object.defineProperty(exports, "config", { enumerable: true, get: function () { return Editor_2.config; } });
|
|
11
|
+
var Editor_3 = require("./Editor");
|
|
12
|
+
Object.defineProperty(exports, "uploaderConfig", { enumerable: true, get: function () { return Editor_3.uploaderConfig; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mbs-dev/react-editor",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "react editor",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -23,10 +23,12 @@
|
|
|
23
23
|
"homepage": "https://github.com/MOHAMMED-BE/react-editor#readme",
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/react": "^18.2.60",
|
|
26
|
+
"tsc-hooks": "^1.1.2",
|
|
26
27
|
"typescript": "^5.3.3"
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"jodit-react": "^1.3.39",
|
|
30
|
-
"react": "^18.2.0"
|
|
31
|
+
"react": "^18.2.0",
|
|
32
|
+
"tslib": "^2.6.2"
|
|
31
33
|
}
|
|
32
34
|
}
|
package/src/Editor.tsx
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import JoditEditor from "jodit-react";
|
|
3
|
+
import { EditorProps } from './Editor.types';
|
|
4
|
+
|
|
5
|
+
const ReactEditor: React.FC<EditorProps> = ({ onChange, onBlur, value, config }) => {
|
|
6
|
+
// const editor = useRef(null);
|
|
7
|
+
|
|
8
|
+
return (
|
|
9
|
+
<JoditEditor
|
|
10
|
+
// ref={ref}
|
|
11
|
+
value={value}
|
|
12
|
+
config={config}
|
|
13
|
+
onBlur={onBlur}
|
|
14
|
+
onChange={onChange}
|
|
15
|
+
/>
|
|
16
|
+
);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
export const uploaderConfig = (apiUrl: string | undefined, imageUrl: string | undefined) => ({
|
|
21
|
+
imagesExtensions: ['jpg', 'png', 'jpeg', 'gif', 'webp'],
|
|
22
|
+
filesVariableName: function (t: number): string {
|
|
23
|
+
return 'files[' + t + ']';
|
|
24
|
+
},
|
|
25
|
+
url: apiUrl,
|
|
26
|
+
withCredentials: false,
|
|
27
|
+
format: 'json',
|
|
28
|
+
method: 'POST',
|
|
29
|
+
prepareData: function (formdata: FormData): FormData {
|
|
30
|
+
return formdata;
|
|
31
|
+
},
|
|
32
|
+
isSuccess: function (this: any, e: any): boolean {
|
|
33
|
+
const fn = this.jodit
|
|
34
|
+
|
|
35
|
+
if (e.data.files && e.data.files.length) {
|
|
36
|
+
const tagName = 'img';
|
|
37
|
+
e.data.files.forEach((filename: string, index: number) => {
|
|
38
|
+
const elm = fn.createInside.element(tagName);
|
|
39
|
+
elm.setAttribute('src', `${imageUrl}/${filename}`);
|
|
40
|
+
fn.s.insertImage(elm as HTMLImageElement, null, fn.o.imageDefaultWidth);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return e.success;
|
|
45
|
+
},
|
|
46
|
+
getMessage: function (e: any): string {
|
|
47
|
+
return e.data.messages && Array.isArray(e.data.messages)
|
|
48
|
+
? e.data.messages.join('')
|
|
49
|
+
: '';
|
|
50
|
+
},
|
|
51
|
+
process: function (resp: any): { files: any[]; error: string; msg: string } {
|
|
52
|
+
let files: any[] = [];
|
|
53
|
+
files.unshift(resp.data);
|
|
54
|
+
return {
|
|
55
|
+
files: resp.data,
|
|
56
|
+
error: resp.msg,
|
|
57
|
+
msg: resp.msg,
|
|
58
|
+
};
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
error: function (this: any, e: Error): void {
|
|
62
|
+
this.j.e.fire('errorMessage', e.message, 'error', 4000);
|
|
63
|
+
},
|
|
64
|
+
|
|
65
|
+
defaultHandlerError: function (this: any, e: any): void {
|
|
66
|
+
this.j.e.fire('errorMessage', e.message);
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
export const config = (includeUploader?: boolean | undefined, apiUrl?: string | undefined, imageUrl?: string | undefined) => ({
|
|
72
|
+
readonly: false,
|
|
73
|
+
placeholder: 'Start typing...',
|
|
74
|
+
toolbarAdaptive: false,
|
|
75
|
+
useSearch: false,
|
|
76
|
+
language: "en",
|
|
77
|
+
allowResizeX: false,
|
|
78
|
+
allowResizeY: false,
|
|
79
|
+
height: 400,
|
|
80
|
+
enableDragAndDropFileToEditor: true,
|
|
81
|
+
showCharsCounter: true,
|
|
82
|
+
showWordsCounter: true,
|
|
83
|
+
showXPathInStatusbar: false,
|
|
84
|
+
|
|
85
|
+
buttons: [
|
|
86
|
+
'source',
|
|
87
|
+
'|',
|
|
88
|
+
'bold',
|
|
89
|
+
'italic',
|
|
90
|
+
'underline',
|
|
91
|
+
'|',
|
|
92
|
+
'ul',
|
|
93
|
+
'ol',
|
|
94
|
+
'|',
|
|
95
|
+
'image',
|
|
96
|
+
// 'file',
|
|
97
|
+
'|',
|
|
98
|
+
'video',
|
|
99
|
+
'|',
|
|
100
|
+
'link',
|
|
101
|
+
'|',
|
|
102
|
+
'undo',
|
|
103
|
+
'redo',
|
|
104
|
+
'|',
|
|
105
|
+
'hr',
|
|
106
|
+
'|',
|
|
107
|
+
'eraser',
|
|
108
|
+
'|',
|
|
109
|
+
'font',
|
|
110
|
+
'fontsize',
|
|
111
|
+
'paragraph',
|
|
112
|
+
'brush',
|
|
113
|
+
'|',
|
|
114
|
+
'table',
|
|
115
|
+
'fullsize',
|
|
116
|
+
],
|
|
117
|
+
uploader: includeUploader ? uploaderConfig(apiUrl, imageUrl) : undefined,
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
export default ReactEditor
|
package/src/index.ts
ADDED
package/tsconfig.json
CHANGED
|
@@ -1,17 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"jsx": "react",
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
4
|
+
"esModuleInterop": true,
|
|
5
|
+
"skipLibCheck": true,
|
|
6
|
+
"declaration": true,
|
|
7
|
+
"declarationDir": "types",
|
|
8
|
+
"outDir": "./dist",
|
|
9
|
+
// "rootDir": "./src",
|
|
10
|
+
"target": "es5",
|
|
11
|
+
"moduleResolution": "node",
|
|
12
|
+
"removeComments": true,
|
|
13
|
+
"strict": true,
|
|
14
|
+
"alwaysStrict": true,
|
|
15
|
+
"downlevelIteration": true,
|
|
16
|
+
"strictNullChecks": true,
|
|
17
|
+
"strictFunctionTypes": true,
|
|
18
|
+
"strictBindCallApply": true,
|
|
19
|
+
"strictPropertyInitialization": true,
|
|
20
|
+
"experimentalDecorators": true,
|
|
21
|
+
"allowJs": true,
|
|
22
|
+
"noImplicitAny": true,
|
|
23
|
+
"noImplicitReturns": true,
|
|
24
|
+
"noUnusedLocals": true,
|
|
25
|
+
"noImplicitOverride": true,
|
|
26
|
+
"noImplicitThis": true,
|
|
27
|
+
"resolveJsonModule": true,
|
|
28
|
+
"lib": ["es5", "esnext", "dom", "scripthost", "es2015.iterable"],
|
|
11
29
|
},
|
|
12
30
|
"include": [
|
|
13
|
-
"src"
|
|
14
|
-
"types/**/*.d.ts"
|
|
31
|
+
"src"
|
|
15
32
|
],
|
|
16
33
|
"exclude": [
|
|
17
34
|
"node_modules"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { EditorProps } from './Editor.types';
|
|
3
|
+
declare const ReactEditor: React.FC<EditorProps>;
|
|
4
|
+
export declare const uploaderConfig: (apiUrl: string | undefined, imageUrl: string | undefined) => {
|
|
5
|
+
imagesExtensions: string[];
|
|
6
|
+
filesVariableName: (t: number) => string;
|
|
7
|
+
url: string | undefined;
|
|
8
|
+
withCredentials: boolean;
|
|
9
|
+
format: string;
|
|
10
|
+
method: string;
|
|
11
|
+
prepareData: (formdata: FormData) => FormData;
|
|
12
|
+
isSuccess: (this: any, e: any) => boolean;
|
|
13
|
+
getMessage: (e: any) => string;
|
|
14
|
+
process: (resp: any) => {
|
|
15
|
+
files: any[];
|
|
16
|
+
error: string;
|
|
17
|
+
msg: string;
|
|
18
|
+
};
|
|
19
|
+
error: (this: any, e: Error) => void;
|
|
20
|
+
defaultHandlerError: (this: any, e: any) => void;
|
|
21
|
+
};
|
|
22
|
+
export declare const config: (includeUploader?: boolean | undefined, apiUrl?: string | undefined, imageUrl?: string | undefined) => {
|
|
23
|
+
readonly: boolean;
|
|
24
|
+
placeholder: string;
|
|
25
|
+
toolbarAdaptive: boolean;
|
|
26
|
+
useSearch: boolean;
|
|
27
|
+
language: string;
|
|
28
|
+
allowResizeX: boolean;
|
|
29
|
+
allowResizeY: boolean;
|
|
30
|
+
height: number;
|
|
31
|
+
enableDragAndDropFileToEditor: boolean;
|
|
32
|
+
showCharsCounter: boolean;
|
|
33
|
+
showWordsCounter: boolean;
|
|
34
|
+
showXPathInStatusbar: boolean;
|
|
35
|
+
buttons: string[];
|
|
36
|
+
uploader: {
|
|
37
|
+
imagesExtensions: string[];
|
|
38
|
+
filesVariableName: (t: number) => string;
|
|
39
|
+
url: string | undefined;
|
|
40
|
+
withCredentials: boolean;
|
|
41
|
+
format: string;
|
|
42
|
+
method: string;
|
|
43
|
+
prepareData: (formdata: FormData) => FormData;
|
|
44
|
+
isSuccess: (this: any, e: any) => boolean;
|
|
45
|
+
getMessage: (e: any) => string;
|
|
46
|
+
process: (resp: any) => {
|
|
47
|
+
files: any[];
|
|
48
|
+
error: string;
|
|
49
|
+
msg: string;
|
|
50
|
+
};
|
|
51
|
+
error: (this: any, e: Error) => void;
|
|
52
|
+
defaultHandlerError: (this: any, e: any) => void;
|
|
53
|
+
} | undefined;
|
|
54
|
+
};
|
|
55
|
+
export default ReactEditor;
|
package/types/index.d.ts
CHANGED
package/src/index.tsx
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { FC, useMemo, useRef } from 'react';
|
|
2
|
-
import JoditEditor from "jodit-react";
|
|
3
|
-
import React from 'react';
|
|
4
|
-
|
|
5
|
-
interface EditorProps {
|
|
6
|
-
onChange?: any;
|
|
7
|
-
onBlur?: any;
|
|
8
|
-
value?: any;
|
|
9
|
-
useUploadImage?: boolean;
|
|
10
|
-
apiUrl?: string;
|
|
11
|
-
imageUrl?: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const ReactEditor: FC<EditorProps> = ({ onChange, onBlur, value, useUploadImage, apiUrl, imageUrl }) => {
|
|
15
|
-
const editor = useRef(null);
|
|
16
|
-
|
|
17
|
-
const uploaderConfig = {
|
|
18
|
-
imagesExtensions: ['jpg', 'png', 'jpeg', 'gif', 'webp'],
|
|
19
|
-
filesVariableName: function (t: number): string {
|
|
20
|
-
return 'files[' + t + ']';
|
|
21
|
-
},
|
|
22
|
-
url: apiUrl,
|
|
23
|
-
withCredentials: false,
|
|
24
|
-
format: 'json',
|
|
25
|
-
method: 'POST',
|
|
26
|
-
prepareData: function (formdata: FormData): FormData {
|
|
27
|
-
return formdata;
|
|
28
|
-
},
|
|
29
|
-
isSuccess: function (this: any, e: any): boolean {
|
|
30
|
-
const fn = this.jodit
|
|
31
|
-
|
|
32
|
-
if (e.data.files && e.data.files.length) {
|
|
33
|
-
const tagName = 'img';
|
|
34
|
-
e.data.files.forEach((filename: string, index: number) => {
|
|
35
|
-
const elm = fn.createInside.element(tagName);
|
|
36
|
-
elm.setAttribute('src', `${imageUrl}/${filename}`);
|
|
37
|
-
fn.s.insertImage(elm as HTMLImageElement, null, fn.o.imageDefaultWidth);
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return e.success;
|
|
42
|
-
},
|
|
43
|
-
getMessage: function (e: any): string {
|
|
44
|
-
return e.data.messages && Array.isArray(e.data.messages)
|
|
45
|
-
? e.data.messages.join('')
|
|
46
|
-
: '';
|
|
47
|
-
},
|
|
48
|
-
process: function (resp: any): { files: any[]; error: string; msg: string } {
|
|
49
|
-
let files: any[] = [];
|
|
50
|
-
files.unshift(resp.data);
|
|
51
|
-
return {
|
|
52
|
-
files: resp.data,
|
|
53
|
-
error: resp.msg,
|
|
54
|
-
msg: resp.msg,
|
|
55
|
-
};
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
error: function (this: any, e: Error): void {
|
|
59
|
-
this.j.e.fire('errorMessage', e.message, 'error', 4000);
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
defaultHandlerError: function (this: any, e: any): void {
|
|
63
|
-
this.j.e.fire('errorMessage', e.message);
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const config = useMemo(
|
|
69
|
-
() => ({
|
|
70
|
-
readonly: false,
|
|
71
|
-
placeholder: 'Start typing...',
|
|
72
|
-
toolbarAdaptive: false,
|
|
73
|
-
useSearch: false,
|
|
74
|
-
language: "en",
|
|
75
|
-
allowResizeX: false,
|
|
76
|
-
allowResizeY: false,
|
|
77
|
-
height: 400,
|
|
78
|
-
enableDragAndDropFileToEditor: true,
|
|
79
|
-
showCharsCounter: true,
|
|
80
|
-
showWordsCounter: true,
|
|
81
|
-
showXPathInStatusbar: false,
|
|
82
|
-
|
|
83
|
-
buttons: [
|
|
84
|
-
'source',
|
|
85
|
-
'|',
|
|
86
|
-
'bold',
|
|
87
|
-
'italic',
|
|
88
|
-
'underline',
|
|
89
|
-
'|',
|
|
90
|
-
'ul',
|
|
91
|
-
'ol',
|
|
92
|
-
'|',
|
|
93
|
-
`${useUploadImage ? 'image' : ''}`,
|
|
94
|
-
'file',
|
|
95
|
-
'|',
|
|
96
|
-
'video',
|
|
97
|
-
'|',
|
|
98
|
-
'link',
|
|
99
|
-
'|',
|
|
100
|
-
'undo',
|
|
101
|
-
'redo',
|
|
102
|
-
'|',
|
|
103
|
-
'hr',
|
|
104
|
-
'|',
|
|
105
|
-
'eraser',
|
|
106
|
-
'|',
|
|
107
|
-
'font',
|
|
108
|
-
'fontsize',
|
|
109
|
-
'paragraph',
|
|
110
|
-
'brush',
|
|
111
|
-
'|',
|
|
112
|
-
'table',
|
|
113
|
-
'fullsize',
|
|
114
|
-
],
|
|
115
|
-
uploader: useUploadImage ? uploaderConfig : undefined,
|
|
116
|
-
}),
|
|
117
|
-
[]
|
|
118
|
-
);
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
return (
|
|
122
|
-
<JoditEditor
|
|
123
|
-
ref={editor}
|
|
124
|
-
value={value}
|
|
125
|
-
config={config}
|
|
126
|
-
onBlur={onBlur}
|
|
127
|
-
onChange={onChange}
|
|
128
|
-
/>
|
|
129
|
-
);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
export default ReactEditor
|