dn-react-text-editor 0.1.1 → 0.1.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/README.md +2 -221
- package/dist/attach_file.d.mts +5 -1
- package/dist/attach_file.d.ts +5 -1
- package/dist/attach_file.js +18 -9
- package/dist/attach_file.mjs +17 -9
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +43 -39
- package/dist/index.mjs +46 -40
- package/dist/text_editor.js +41 -39
- package/dist/text_editor.mjs +45 -40
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,222 +1,3 @@
|
|
|
1
|
-
# React
|
|
1
|
+
# React Text Editor
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
It eliminates repetitive code required to implement state changes and subscriptions for input elements, and provides a simple interface.
|
|
6
|
-
|
|
7
|
-
At the same time, it allows you to use all the attributes originally provided by the input tag as-is, without needing to learn this package.
|
|
8
|
-
|
|
9
|
-
## Get Started
|
|
10
|
-
|
|
11
|
-
This is a simple example of how to use this package.
|
|
12
|
-
|
|
13
|
-
```tsx
|
|
14
|
-
import { useFormStore } from "dn-react-input";
|
|
15
|
-
|
|
16
|
-
export default function App() {
|
|
17
|
-
const store = useFormStore({
|
|
18
|
-
email: "",
|
|
19
|
-
password: "",
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
const submit = async () => {
|
|
23
|
-
const { email, password } = store.state;
|
|
24
|
-
|
|
25
|
-
alert(`Email: ${email}\nPassword: ${password}`);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
<form
|
|
30
|
-
onSubmit={(e) => {
|
|
31
|
-
e.preventDefault();
|
|
32
|
-
submit();
|
|
33
|
-
}}
|
|
34
|
-
>
|
|
35
|
-
<store.input name="email" type="email" />
|
|
36
|
-
<store.input name="password" type="password" />
|
|
37
|
-
<button type="submit">Submit</button>
|
|
38
|
-
</form>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## How to define state?
|
|
44
|
-
|
|
45
|
-
You can define any state you want as an object when calling `useStore`.
|
|
46
|
-
|
|
47
|
-
```tsx
|
|
48
|
-
function Component() {
|
|
49
|
-
...
|
|
50
|
-
|
|
51
|
-
const store = useStore({
|
|
52
|
-
email: "",
|
|
53
|
-
password: "",
|
|
54
|
-
rememberMe: false,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
...
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
It's a single source of truth for your form state.
|
|
62
|
-
|
|
63
|
-
## How to get input values?
|
|
64
|
-
|
|
65
|
-
You can access the current values of the input elements through the `state` property of the store.
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
function Component() {
|
|
69
|
-
...
|
|
70
|
-
|
|
71
|
-
const submit = () => {
|
|
72
|
-
const { email, password, rememberMe } = store.state;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
...
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
## How to add input elements?
|
|
80
|
-
|
|
81
|
-
You can add input elements using the `Input` component provided by the store. There are 'Select' and 'Textarea' components as well.
|
|
82
|
-
|
|
83
|
-
```tsx
|
|
84
|
-
import { Input } from "dn-react-input";
|
|
85
|
-
|
|
86
|
-
function Component() {
|
|
87
|
-
...
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<form>
|
|
91
|
-
<Input store={store} name="email" type="email" />
|
|
92
|
-
<Input store={store} name="password" type="password" />
|
|
93
|
-
<Input store={store} name="rememberMe" type="checkbox" />
|
|
94
|
-
</form>
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
If you want to avoid passing the store to each input component, use `useStoreInput`. This hook provides input components that are already connected to the store.
|
|
100
|
-
|
|
101
|
-
```tsx
|
|
102
|
-
import { useStoreInput } from "dn-react-input";
|
|
103
|
-
|
|
104
|
-
function Component() {
|
|
105
|
-
...
|
|
106
|
-
const Input = useStoreInput(store);
|
|
107
|
-
|
|
108
|
-
return (
|
|
109
|
-
<form>
|
|
110
|
-
<Input.input name="email" type="email" />
|
|
111
|
-
<Input.input name="password" type="password" />
|
|
112
|
-
<Input.input name="rememberMe" type="checkbox" />
|
|
113
|
-
</form>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
`useFormStore` is a facade that combines `useStore` and `useStoreInput` for convenience.
|
|
119
|
-
|
|
120
|
-
```tsx
|
|
121
|
-
import { useFormStore } from "dn-react-input";
|
|
122
|
-
|
|
123
|
-
function Component() {
|
|
124
|
-
...
|
|
125
|
-
const store = useFormStore({
|
|
126
|
-
email: "",
|
|
127
|
-
password: "",
|
|
128
|
-
rememberMe: false,
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
return (
|
|
132
|
-
<form>
|
|
133
|
-
<store.input name="email" type="email" />
|
|
134
|
-
<store.input name="password" type="password" />
|
|
135
|
-
<store.input name="rememberMe" type="checkbox" />
|
|
136
|
-
</form>
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
## How to render components on state changes?
|
|
142
|
-
|
|
143
|
-
If you want to render a component only when specific parts of the state change, use the `useSelector` hook.
|
|
144
|
-
|
|
145
|
-
```tsx
|
|
146
|
-
import { useSelector } from "dn-react-input";
|
|
147
|
-
|
|
148
|
-
function Component() {
|
|
149
|
-
...
|
|
150
|
-
const email = useSelector(store, (state) => state.email);
|
|
151
|
-
|
|
152
|
-
return <div>Your email is: {email}</div>;
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
If you want to render components in an inline manner, use the `createRender` function. By using this, you can avoid creating separate components for each part of the state you want to track.
|
|
157
|
-
|
|
158
|
-
```tsx
|
|
159
|
-
import { createRender } from "dn-react-input";
|
|
160
|
-
|
|
161
|
-
function Component() {
|
|
162
|
-
...
|
|
163
|
-
return (
|
|
164
|
-
<div>
|
|
165
|
-
{createRender(store, (state) => <p>{state.email}</p>)}
|
|
166
|
-
{createRender(store, (state) => <p>{state.password}</p>)}
|
|
167
|
-
</div>
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
## How to subscribe to state changes?
|
|
173
|
-
|
|
174
|
-
You can subscribe to state changes using the `subscribe` method of the store.
|
|
175
|
-
|
|
176
|
-
```tsx
|
|
177
|
-
function Component() {
|
|
178
|
-
...
|
|
179
|
-
useEffect(() => {
|
|
180
|
-
const unsubscribe = store.subscribe((state) => {
|
|
181
|
-
console.log(`State changed`, state);
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
return () => {
|
|
185
|
-
unsubscribe();
|
|
186
|
-
};
|
|
187
|
-
}, []);
|
|
188
|
-
|
|
189
|
-
...
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
## How to update state manually?
|
|
194
|
-
|
|
195
|
-
You can update the state manually using the `dispatch` method of the store.
|
|
196
|
-
|
|
197
|
-
```tsx
|
|
198
|
-
function Component() {
|
|
199
|
-
...
|
|
200
|
-
const updateEmail = () => {
|
|
201
|
-
store.dispatch({ email: "ohjinsu98@icloud.com" });
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
return <button onClick={updateEmail}>Update Email</button>;
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
The `dispatch` method uses immerjs internally to update the state, so you can also use a function to update the state based on the previous state.
|
|
209
|
-
|
|
210
|
-
```tsx
|
|
211
|
-
function Component() {
|
|
212
|
-
...
|
|
213
|
-
|
|
214
|
-
const updateEmail = () => {
|
|
215
|
-
store.dispatch((state) => {
|
|
216
|
-
state.email = "ohjinsu98@icloud.com";
|
|
217
|
-
});
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
return <button onClick={updateEmail}>Update Email</button>;
|
|
221
|
-
}
|
|
222
|
-
```
|
|
3
|
+
A rich text editor component for React built on ProseMirror.
|
package/dist/attach_file.d.mts
CHANGED
|
@@ -23,6 +23,10 @@ type AttachFileOptions = {
|
|
|
23
23
|
alt?: string;
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
|
+
declare const base64ImageUploader: (file: File) => Promise<{
|
|
27
|
+
src: string;
|
|
28
|
+
alt: string;
|
|
29
|
+
}>;
|
|
26
30
|
declare function createAttachFile({ schema, generateMetadata, uploadFile, }: AttachFileOptions): AttachFile;
|
|
27
31
|
|
|
28
|
-
export { type AttachFile, createAttachFile };
|
|
32
|
+
export { type AttachFile, base64ImageUploader, createAttachFile };
|
package/dist/attach_file.d.ts
CHANGED
|
@@ -23,6 +23,10 @@ type AttachFileOptions = {
|
|
|
23
23
|
alt?: string;
|
|
24
24
|
};
|
|
25
25
|
};
|
|
26
|
+
declare const base64ImageUploader: (file: File) => Promise<{
|
|
27
|
+
src: string;
|
|
28
|
+
alt: string;
|
|
29
|
+
}>;
|
|
26
30
|
declare function createAttachFile({ schema, generateMetadata, uploadFile, }: AttachFileOptions): AttachFile;
|
|
27
31
|
|
|
28
|
-
export { type AttachFile, createAttachFile };
|
|
32
|
+
export { type AttachFile, base64ImageUploader, createAttachFile };
|
package/dist/attach_file.js
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/attach_file.tsx
|
|
21
21
|
var attach_file_exports = {};
|
|
22
22
|
__export(attach_file_exports, {
|
|
23
|
+
base64ImageUploader: () => base64ImageUploader,
|
|
23
24
|
createAttachFile: () => createAttachFile
|
|
24
25
|
});
|
|
25
26
|
module.exports = __toCommonJS(attach_file_exports);
|
|
@@ -91,15 +92,24 @@ var findPlaceholder = (state, id) => {
|
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
// src/attach_file.tsx
|
|
95
|
+
var base64ImageUploader = async (file) => {
|
|
96
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
97
|
+
const reader = new FileReader();
|
|
98
|
+
reader.onload = () => {
|
|
99
|
+
resolve(reader.result);
|
|
100
|
+
};
|
|
101
|
+
reader.onerror = reject;
|
|
102
|
+
reader.readAsDataURL(file);
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
src: base64,
|
|
106
|
+
alt: file.name
|
|
107
|
+
};
|
|
108
|
+
};
|
|
94
109
|
function createAttachFile({
|
|
95
110
|
schema,
|
|
96
111
|
generateMetadata,
|
|
97
|
-
uploadFile =
|
|
98
|
-
return {
|
|
99
|
-
src: URL.createObjectURL(file),
|
|
100
|
-
alt: file.name
|
|
101
|
-
};
|
|
102
|
-
}
|
|
112
|
+
uploadFile = base64ImageUploader
|
|
103
113
|
}) {
|
|
104
114
|
const attachEachFile = async (view, file, pos) => {
|
|
105
115
|
const metadata = generateMetadata ? await generateMetadata(file) : {};
|
|
@@ -151,9 +161,7 @@ function createAttachFile({
|
|
|
151
161
|
}
|
|
152
162
|
view.dispatch(tr2.replaceWith($pos, $pos, node));
|
|
153
163
|
} catch (e) {
|
|
154
|
-
view.dispatch(
|
|
155
|
-
tr.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
|
156
|
-
);
|
|
164
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
157
165
|
}
|
|
158
166
|
};
|
|
159
167
|
return async (view, files, pos) => {
|
|
@@ -165,5 +173,6 @@ function createAttachFile({
|
|
|
165
173
|
}
|
|
166
174
|
// Annotate the CommonJS export names for ESM import in node:
|
|
167
175
|
0 && (module.exports = {
|
|
176
|
+
base64ImageUploader,
|
|
168
177
|
createAttachFile
|
|
169
178
|
});
|
package/dist/attach_file.mjs
CHANGED
|
@@ -67,15 +67,24 @@ var findPlaceholder = (state, id) => {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// src/attach_file.tsx
|
|
70
|
+
var base64ImageUploader = async (file) => {
|
|
71
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
72
|
+
const reader = new FileReader();
|
|
73
|
+
reader.onload = () => {
|
|
74
|
+
resolve(reader.result);
|
|
75
|
+
};
|
|
76
|
+
reader.onerror = reject;
|
|
77
|
+
reader.readAsDataURL(file);
|
|
78
|
+
});
|
|
79
|
+
return {
|
|
80
|
+
src: base64,
|
|
81
|
+
alt: file.name
|
|
82
|
+
};
|
|
83
|
+
};
|
|
70
84
|
function createAttachFile({
|
|
71
85
|
schema,
|
|
72
86
|
generateMetadata,
|
|
73
|
-
uploadFile =
|
|
74
|
-
return {
|
|
75
|
-
src: URL.createObjectURL(file),
|
|
76
|
-
alt: file.name
|
|
77
|
-
};
|
|
78
|
-
}
|
|
87
|
+
uploadFile = base64ImageUploader
|
|
79
88
|
}) {
|
|
80
89
|
const attachEachFile = async (view, file, pos) => {
|
|
81
90
|
const metadata = generateMetadata ? await generateMetadata(file) : {};
|
|
@@ -127,9 +136,7 @@ function createAttachFile({
|
|
|
127
136
|
}
|
|
128
137
|
view.dispatch(tr2.replaceWith($pos, $pos, node));
|
|
129
138
|
} catch (e) {
|
|
130
|
-
view.dispatch(
|
|
131
|
-
tr.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
|
132
|
-
);
|
|
139
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
133
140
|
}
|
|
134
141
|
};
|
|
135
142
|
return async (view, files, pos) => {
|
|
@@ -140,5 +147,6 @@ function createAttachFile({
|
|
|
140
147
|
};
|
|
141
148
|
}
|
|
142
149
|
export {
|
|
150
|
+
base64ImageUploader,
|
|
143
151
|
createAttachFile
|
|
144
152
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { TextEditorController, TextEditorProps, createTextEditor } from './text_editor.mjs';
|
|
2
2
|
export { createSchema } from './schema.mjs';
|
|
3
|
-
export { AttachFile, createAttachFile } from './attach_file.mjs';
|
|
3
|
+
export { AttachFile, base64ImageUploader, createAttachFile } from './attach_file.mjs';
|
|
4
4
|
import 'orderedmap';
|
|
5
5
|
import 'prosemirror-model';
|
|
6
6
|
import 'react';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { TextEditorController, TextEditorProps, createTextEditor } from './text_editor.js';
|
|
2
2
|
export { createSchema } from './schema.js';
|
|
3
|
-
export { AttachFile, createAttachFile } from './attach_file.js';
|
|
3
|
+
export { AttachFile, base64ImageUploader, createAttachFile } from './attach_file.js';
|
|
4
4
|
import 'orderedmap';
|
|
5
5
|
import 'prosemirror-model';
|
|
6
6
|
import 'react';
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
base64ImageUploader: () => base64ImageUploader,
|
|
33
34
|
createAttachFile: () => createAttachFile,
|
|
34
35
|
createSchema: () => createSchema,
|
|
35
36
|
createTextEditor: () => createTextEditor
|
|
@@ -472,15 +473,24 @@ function cn(...classes) {
|
|
|
472
473
|
|
|
473
474
|
// src/attach_file.tsx
|
|
474
475
|
var import_prosemirror_view3 = require("prosemirror-view");
|
|
476
|
+
var base64ImageUploader = async (file) => {
|
|
477
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
478
|
+
const reader = new FileReader();
|
|
479
|
+
reader.onload = () => {
|
|
480
|
+
resolve(reader.result);
|
|
481
|
+
};
|
|
482
|
+
reader.onerror = reject;
|
|
483
|
+
reader.readAsDataURL(file);
|
|
484
|
+
});
|
|
485
|
+
return {
|
|
486
|
+
src: base64,
|
|
487
|
+
alt: file.name
|
|
488
|
+
};
|
|
489
|
+
};
|
|
475
490
|
function createAttachFile({
|
|
476
491
|
schema,
|
|
477
492
|
generateMetadata,
|
|
478
|
-
uploadFile =
|
|
479
|
-
return {
|
|
480
|
-
src: URL.createObjectURL(file),
|
|
481
|
-
alt: file.name
|
|
482
|
-
};
|
|
483
|
-
}
|
|
493
|
+
uploadFile = base64ImageUploader
|
|
484
494
|
}) {
|
|
485
495
|
const attachEachFile = async (view, file, pos) => {
|
|
486
496
|
const metadata = generateMetadata ? await generateMetadata(file) : {};
|
|
@@ -532,9 +542,7 @@ function createAttachFile({
|
|
|
532
542
|
}
|
|
533
543
|
view.dispatch(tr2.replaceWith($pos, $pos, node));
|
|
534
544
|
} catch (e) {
|
|
535
|
-
view.dispatch(
|
|
536
|
-
tr.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
|
537
|
-
);
|
|
545
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
538
546
|
}
|
|
539
547
|
};
|
|
540
548
|
return async (view, files, pos) => {
|
|
@@ -573,12 +581,9 @@ function createTextEditor(options = {}) {
|
|
|
573
581
|
} = {}) {
|
|
574
582
|
const containerRef = (0, import_react2.useRef)(null);
|
|
575
583
|
const inputRef = (0, import_react2.useRef)(null);
|
|
576
|
-
(0, import_react2.
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
const subject = new import_rxjs.Subject();
|
|
584
|
+
const controllerRef = (0, import_react2.useRef)(null);
|
|
585
|
+
const subject = (0, import_react.useMemo)(() => new import_rxjs.Subject(), []);
|
|
586
|
+
(0, import_react.useImperativeHandle)(ref, () => {
|
|
582
587
|
const wrapper = document.createElement("div");
|
|
583
588
|
const toInnerHTML = (value) => {
|
|
584
589
|
if (mode === "html") {
|
|
@@ -587,7 +592,7 @@ function createTextEditor(options = {}) {
|
|
|
587
592
|
return value.split("\n").map((line) => `<p>${line}</p>`).join("");
|
|
588
593
|
};
|
|
589
594
|
wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
|
|
590
|
-
const view = new import_prosemirror_view4.EditorView(
|
|
595
|
+
const view = new import_prosemirror_view4.EditorView(containerRef.current, {
|
|
591
596
|
...editor,
|
|
592
597
|
attributes: (state2) => {
|
|
593
598
|
const propsAttributes = (() => {
|
|
@@ -662,23 +667,6 @@ function createTextEditor(options = {}) {
|
|
|
662
667
|
const state2 = view.state;
|
|
663
668
|
return state2.doc.textBetween(0, state2.doc.content.size, "\n");
|
|
664
669
|
}
|
|
665
|
-
const sub = subject.pipe(
|
|
666
|
-
(0, import_rxjs.filter)((tr) => tr.docChanged),
|
|
667
|
-
(0, import_rxjs.debounceTime)(updateDelay)
|
|
668
|
-
).subscribe(() => {
|
|
669
|
-
if (inputRef.current) {
|
|
670
|
-
switch (mode) {
|
|
671
|
-
case "text":
|
|
672
|
-
inputRef.current.value = toTextContent();
|
|
673
|
-
break;
|
|
674
|
-
default:
|
|
675
|
-
inputRef.current.value = toHTML();
|
|
676
|
-
break;
|
|
677
|
-
}
|
|
678
|
-
const event = new Event("input", { bubbles: true });
|
|
679
|
-
inputRef.current.dispatchEvent(event);
|
|
680
|
-
}
|
|
681
|
-
});
|
|
682
670
|
if (autoFocus) {
|
|
683
671
|
view.focus();
|
|
684
672
|
}
|
|
@@ -699,15 +687,30 @@ function createTextEditor(options = {}) {
|
|
|
699
687
|
},
|
|
700
688
|
clear
|
|
701
689
|
};
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
690
|
+
controllerRef.current = textEditorController;
|
|
691
|
+
return textEditorController;
|
|
692
|
+
});
|
|
693
|
+
(0, import_react2.useEffect)(() => {
|
|
694
|
+
const controller = controllerRef.current;
|
|
695
|
+
if (!controller) {
|
|
696
|
+
return;
|
|
697
|
+
}
|
|
698
|
+
const sub = controller.subject.pipe(
|
|
699
|
+
(0, import_rxjs.filter)((tr) => tr.docChanged),
|
|
700
|
+
(0, import_rxjs.debounceTime)(updateDelay)
|
|
701
|
+
).subscribe(() => {
|
|
702
|
+
if (inputRef.current) {
|
|
703
|
+
inputRef.current.value = controller.value;
|
|
704
|
+
const event = new Event("input", { bubbles: true });
|
|
705
|
+
inputRef.current.dispatchEvent(event);
|
|
706
|
+
}
|
|
707
|
+
});
|
|
708
|
+
if (autoFocus) {
|
|
709
|
+
controller.view.focus();
|
|
706
710
|
}
|
|
707
711
|
return () => {
|
|
708
712
|
sub.unsubscribe();
|
|
709
|
-
view.destroy();
|
|
710
|
-
element.innerHTML = "";
|
|
713
|
+
controller.view.destroy();
|
|
711
714
|
};
|
|
712
715
|
}, []);
|
|
713
716
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { ref: containerRef, className: container, ...props }), /* @__PURE__ */ import_react.default.createElement("input", { ref: inputRef, type: "hidden", name, onInput: onChange }));
|
|
@@ -720,6 +723,7 @@ function createTextEditor(options = {}) {
|
|
|
720
723
|
}
|
|
721
724
|
// Annotate the CommonJS export names for ESM import in node:
|
|
722
725
|
0 && (module.exports = {
|
|
726
|
+
base64ImageUploader,
|
|
723
727
|
createAttachFile,
|
|
724
728
|
createSchema,
|
|
725
729
|
createTextEditor
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/text_editor.tsx
|
|
2
|
-
import React
|
|
2
|
+
import React, {
|
|
3
|
+
useImperativeHandle,
|
|
4
|
+
useMemo
|
|
5
|
+
} from "react";
|
|
3
6
|
import {
|
|
4
7
|
EditorState as EditorState2
|
|
5
8
|
} from "prosemirror-state";
|
|
@@ -436,15 +439,24 @@ function cn(...classes) {
|
|
|
436
439
|
|
|
437
440
|
// src/attach_file.tsx
|
|
438
441
|
import "prosemirror-view";
|
|
442
|
+
var base64ImageUploader = async (file) => {
|
|
443
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
444
|
+
const reader = new FileReader();
|
|
445
|
+
reader.onload = () => {
|
|
446
|
+
resolve(reader.result);
|
|
447
|
+
};
|
|
448
|
+
reader.onerror = reject;
|
|
449
|
+
reader.readAsDataURL(file);
|
|
450
|
+
});
|
|
451
|
+
return {
|
|
452
|
+
src: base64,
|
|
453
|
+
alt: file.name
|
|
454
|
+
};
|
|
455
|
+
};
|
|
439
456
|
function createAttachFile({
|
|
440
457
|
schema,
|
|
441
458
|
generateMetadata,
|
|
442
|
-
uploadFile =
|
|
443
|
-
return {
|
|
444
|
-
src: URL.createObjectURL(file),
|
|
445
|
-
alt: file.name
|
|
446
|
-
};
|
|
447
|
-
}
|
|
459
|
+
uploadFile = base64ImageUploader
|
|
448
460
|
}) {
|
|
449
461
|
const attachEachFile = async (view, file, pos) => {
|
|
450
462
|
const metadata = generateMetadata ? await generateMetadata(file) : {};
|
|
@@ -496,9 +508,7 @@ function createAttachFile({
|
|
|
496
508
|
}
|
|
497
509
|
view.dispatch(tr2.replaceWith($pos, $pos, node));
|
|
498
510
|
} catch (e) {
|
|
499
|
-
view.dispatch(
|
|
500
|
-
tr.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
|
501
|
-
);
|
|
511
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
502
512
|
}
|
|
503
513
|
};
|
|
504
514
|
return async (view, files, pos) => {
|
|
@@ -537,12 +547,9 @@ function createTextEditor(options = {}) {
|
|
|
537
547
|
} = {}) {
|
|
538
548
|
const containerRef = useRef(null);
|
|
539
549
|
const inputRef = useRef(null);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
const subject = new Subject();
|
|
550
|
+
const controllerRef = useRef(null);
|
|
551
|
+
const subject = useMemo(() => new Subject(), []);
|
|
552
|
+
useImperativeHandle(ref, () => {
|
|
546
553
|
const wrapper = document.createElement("div");
|
|
547
554
|
const toInnerHTML = (value) => {
|
|
548
555
|
if (mode === "html") {
|
|
@@ -551,7 +558,7 @@ function createTextEditor(options = {}) {
|
|
|
551
558
|
return value.split("\n").map((line) => `<p>${line}</p>`).join("");
|
|
552
559
|
};
|
|
553
560
|
wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
|
|
554
|
-
const view = new EditorView3(
|
|
561
|
+
const view = new EditorView3(containerRef.current, {
|
|
555
562
|
...editor,
|
|
556
563
|
attributes: (state2) => {
|
|
557
564
|
const propsAttributes = (() => {
|
|
@@ -626,23 +633,6 @@ function createTextEditor(options = {}) {
|
|
|
626
633
|
const state2 = view.state;
|
|
627
634
|
return state2.doc.textBetween(0, state2.doc.content.size, "\n");
|
|
628
635
|
}
|
|
629
|
-
const sub = subject.pipe(
|
|
630
|
-
filter((tr) => tr.docChanged),
|
|
631
|
-
debounceTime(updateDelay)
|
|
632
|
-
).subscribe(() => {
|
|
633
|
-
if (inputRef.current) {
|
|
634
|
-
switch (mode) {
|
|
635
|
-
case "text":
|
|
636
|
-
inputRef.current.value = toTextContent();
|
|
637
|
-
break;
|
|
638
|
-
default:
|
|
639
|
-
inputRef.current.value = toHTML();
|
|
640
|
-
break;
|
|
641
|
-
}
|
|
642
|
-
const event = new Event("input", { bubbles: true });
|
|
643
|
-
inputRef.current.dispatchEvent(event);
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
636
|
if (autoFocus) {
|
|
647
637
|
view.focus();
|
|
648
638
|
}
|
|
@@ -663,15 +653,30 @@ function createTextEditor(options = {}) {
|
|
|
663
653
|
},
|
|
664
654
|
clear
|
|
665
655
|
};
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
656
|
+
controllerRef.current = textEditorController;
|
|
657
|
+
return textEditorController;
|
|
658
|
+
});
|
|
659
|
+
useEffect(() => {
|
|
660
|
+
const controller = controllerRef.current;
|
|
661
|
+
if (!controller) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const sub = controller.subject.pipe(
|
|
665
|
+
filter((tr) => tr.docChanged),
|
|
666
|
+
debounceTime(updateDelay)
|
|
667
|
+
).subscribe(() => {
|
|
668
|
+
if (inputRef.current) {
|
|
669
|
+
inputRef.current.value = controller.value;
|
|
670
|
+
const event = new Event("input", { bubbles: true });
|
|
671
|
+
inputRef.current.dispatchEvent(event);
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
if (autoFocus) {
|
|
675
|
+
controller.view.focus();
|
|
670
676
|
}
|
|
671
677
|
return () => {
|
|
672
678
|
sub.unsubscribe();
|
|
673
|
-
view.destroy();
|
|
674
|
-
element.innerHTML = "";
|
|
679
|
+
controller.view.destroy();
|
|
675
680
|
};
|
|
676
681
|
}, []);
|
|
677
682
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { ref: containerRef, className: container, ...props }), /* @__PURE__ */ React.createElement("input", { ref: inputRef, type: "hidden", name, onInput: onChange }));
|
|
@@ -683,6 +688,7 @@ function createTextEditor(options = {}) {
|
|
|
683
688
|
};
|
|
684
689
|
}
|
|
685
690
|
export {
|
|
691
|
+
base64ImageUploader,
|
|
686
692
|
createAttachFile,
|
|
687
693
|
createSchema,
|
|
688
694
|
createTextEditor
|
package/dist/text_editor.js
CHANGED
|
@@ -468,15 +468,24 @@ function cn(...classes) {
|
|
|
468
468
|
|
|
469
469
|
// src/attach_file.tsx
|
|
470
470
|
var import_prosemirror_view3 = require("prosemirror-view");
|
|
471
|
+
var base64ImageUploader = async (file) => {
|
|
472
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
473
|
+
const reader = new FileReader();
|
|
474
|
+
reader.onload = () => {
|
|
475
|
+
resolve(reader.result);
|
|
476
|
+
};
|
|
477
|
+
reader.onerror = reject;
|
|
478
|
+
reader.readAsDataURL(file);
|
|
479
|
+
});
|
|
480
|
+
return {
|
|
481
|
+
src: base64,
|
|
482
|
+
alt: file.name
|
|
483
|
+
};
|
|
484
|
+
};
|
|
471
485
|
function createAttachFile({
|
|
472
486
|
schema,
|
|
473
487
|
generateMetadata,
|
|
474
|
-
uploadFile =
|
|
475
|
-
return {
|
|
476
|
-
src: URL.createObjectURL(file),
|
|
477
|
-
alt: file.name
|
|
478
|
-
};
|
|
479
|
-
}
|
|
488
|
+
uploadFile = base64ImageUploader
|
|
480
489
|
}) {
|
|
481
490
|
const attachEachFile = async (view, file, pos) => {
|
|
482
491
|
const metadata = generateMetadata ? await generateMetadata(file) : {};
|
|
@@ -528,9 +537,7 @@ function createAttachFile({
|
|
|
528
537
|
}
|
|
529
538
|
view.dispatch(tr2.replaceWith($pos, $pos, node));
|
|
530
539
|
} catch (e) {
|
|
531
|
-
view.dispatch(
|
|
532
|
-
tr.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
|
533
|
-
);
|
|
540
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
534
541
|
}
|
|
535
542
|
};
|
|
536
543
|
return async (view, files, pos) => {
|
|
@@ -569,12 +576,9 @@ function createTextEditor(options = {}) {
|
|
|
569
576
|
} = {}) {
|
|
570
577
|
const containerRef = (0, import_react2.useRef)(null);
|
|
571
578
|
const inputRef = (0, import_react2.useRef)(null);
|
|
572
|
-
(0, import_react2.
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
const subject = new import_rxjs.Subject();
|
|
579
|
+
const controllerRef = (0, import_react2.useRef)(null);
|
|
580
|
+
const subject = (0, import_react.useMemo)(() => new import_rxjs.Subject(), []);
|
|
581
|
+
(0, import_react.useImperativeHandle)(ref, () => {
|
|
578
582
|
const wrapper = document.createElement("div");
|
|
579
583
|
const toInnerHTML = (value) => {
|
|
580
584
|
if (mode === "html") {
|
|
@@ -583,7 +587,7 @@ function createTextEditor(options = {}) {
|
|
|
583
587
|
return value.split("\n").map((line) => `<p>${line}</p>`).join("");
|
|
584
588
|
};
|
|
585
589
|
wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
|
|
586
|
-
const view = new import_prosemirror_view4.EditorView(
|
|
590
|
+
const view = new import_prosemirror_view4.EditorView(containerRef.current, {
|
|
587
591
|
...editor,
|
|
588
592
|
attributes: (state2) => {
|
|
589
593
|
const propsAttributes = (() => {
|
|
@@ -658,23 +662,6 @@ function createTextEditor(options = {}) {
|
|
|
658
662
|
const state2 = view.state;
|
|
659
663
|
return state2.doc.textBetween(0, state2.doc.content.size, "\n");
|
|
660
664
|
}
|
|
661
|
-
const sub = subject.pipe(
|
|
662
|
-
(0, import_rxjs.filter)((tr) => tr.docChanged),
|
|
663
|
-
(0, import_rxjs.debounceTime)(updateDelay)
|
|
664
|
-
).subscribe(() => {
|
|
665
|
-
if (inputRef.current) {
|
|
666
|
-
switch (mode) {
|
|
667
|
-
case "text":
|
|
668
|
-
inputRef.current.value = toTextContent();
|
|
669
|
-
break;
|
|
670
|
-
default:
|
|
671
|
-
inputRef.current.value = toHTML();
|
|
672
|
-
break;
|
|
673
|
-
}
|
|
674
|
-
const event = new Event("input", { bubbles: true });
|
|
675
|
-
inputRef.current.dispatchEvent(event);
|
|
676
|
-
}
|
|
677
|
-
});
|
|
678
665
|
if (autoFocus) {
|
|
679
666
|
view.focus();
|
|
680
667
|
}
|
|
@@ -695,15 +682,30 @@ function createTextEditor(options = {}) {
|
|
|
695
682
|
},
|
|
696
683
|
clear
|
|
697
684
|
};
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
685
|
+
controllerRef.current = textEditorController;
|
|
686
|
+
return textEditorController;
|
|
687
|
+
});
|
|
688
|
+
(0, import_react2.useEffect)(() => {
|
|
689
|
+
const controller = controllerRef.current;
|
|
690
|
+
if (!controller) {
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
const sub = controller.subject.pipe(
|
|
694
|
+
(0, import_rxjs.filter)((tr) => tr.docChanged),
|
|
695
|
+
(0, import_rxjs.debounceTime)(updateDelay)
|
|
696
|
+
).subscribe(() => {
|
|
697
|
+
if (inputRef.current) {
|
|
698
|
+
inputRef.current.value = controller.value;
|
|
699
|
+
const event = new Event("input", { bubbles: true });
|
|
700
|
+
inputRef.current.dispatchEvent(event);
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
if (autoFocus) {
|
|
704
|
+
controller.view.focus();
|
|
702
705
|
}
|
|
703
706
|
return () => {
|
|
704
707
|
sub.unsubscribe();
|
|
705
|
-
view.destroy();
|
|
706
|
-
element.innerHTML = "";
|
|
708
|
+
controller.view.destroy();
|
|
707
709
|
};
|
|
708
710
|
}, []);
|
|
709
711
|
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { ref: containerRef, className: container, ...props }), /* @__PURE__ */ import_react.default.createElement("input", { ref: inputRef, type: "hidden", name, onInput: onChange }));
|
package/dist/text_editor.mjs
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
// src/text_editor.tsx
|
|
2
|
-
import React
|
|
2
|
+
import React, {
|
|
3
|
+
useImperativeHandle,
|
|
4
|
+
useMemo
|
|
5
|
+
} from "react";
|
|
3
6
|
import {
|
|
4
7
|
EditorState as EditorState2
|
|
5
8
|
} from "prosemirror-state";
|
|
@@ -436,15 +439,24 @@ function cn(...classes) {
|
|
|
436
439
|
|
|
437
440
|
// src/attach_file.tsx
|
|
438
441
|
import "prosemirror-view";
|
|
442
|
+
var base64ImageUploader = async (file) => {
|
|
443
|
+
const base64 = await new Promise((resolve, reject) => {
|
|
444
|
+
const reader = new FileReader();
|
|
445
|
+
reader.onload = () => {
|
|
446
|
+
resolve(reader.result);
|
|
447
|
+
};
|
|
448
|
+
reader.onerror = reject;
|
|
449
|
+
reader.readAsDataURL(file);
|
|
450
|
+
});
|
|
451
|
+
return {
|
|
452
|
+
src: base64,
|
|
453
|
+
alt: file.name
|
|
454
|
+
};
|
|
455
|
+
};
|
|
439
456
|
function createAttachFile({
|
|
440
457
|
schema,
|
|
441
458
|
generateMetadata,
|
|
442
|
-
uploadFile =
|
|
443
|
-
return {
|
|
444
|
-
src: URL.createObjectURL(file),
|
|
445
|
-
alt: file.name
|
|
446
|
-
};
|
|
447
|
-
}
|
|
459
|
+
uploadFile = base64ImageUploader
|
|
448
460
|
}) {
|
|
449
461
|
const attachEachFile = async (view, file, pos) => {
|
|
450
462
|
const metadata = generateMetadata ? await generateMetadata(file) : {};
|
|
@@ -496,9 +508,7 @@ function createAttachFile({
|
|
|
496
508
|
}
|
|
497
509
|
view.dispatch(tr2.replaceWith($pos, $pos, node));
|
|
498
510
|
} catch (e) {
|
|
499
|
-
view.dispatch(
|
|
500
|
-
tr.setMeta(uploadPlaceholderPlugin, { remove: { id } })
|
|
501
|
-
);
|
|
511
|
+
view.dispatch(tr.setMeta(uploadPlaceholderPlugin, { remove: { id } }));
|
|
502
512
|
}
|
|
503
513
|
};
|
|
504
514
|
return async (view, files, pos) => {
|
|
@@ -537,12 +547,9 @@ function createTextEditor(options = {}) {
|
|
|
537
547
|
} = {}) {
|
|
538
548
|
const containerRef = useRef(null);
|
|
539
549
|
const inputRef = useRef(null);
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
const subject = new Subject();
|
|
550
|
+
const controllerRef = useRef(null);
|
|
551
|
+
const subject = useMemo(() => new Subject(), []);
|
|
552
|
+
useImperativeHandle(ref, () => {
|
|
546
553
|
const wrapper = document.createElement("div");
|
|
547
554
|
const toInnerHTML = (value) => {
|
|
548
555
|
if (mode === "html") {
|
|
@@ -551,7 +558,7 @@ function createTextEditor(options = {}) {
|
|
|
551
558
|
return value.split("\n").map((line) => `<p>${line}</p>`).join("");
|
|
552
559
|
};
|
|
553
560
|
wrapper.innerHTML = toInnerHTML(defaultValue ? String(defaultValue) : "");
|
|
554
|
-
const view = new EditorView3(
|
|
561
|
+
const view = new EditorView3(containerRef.current, {
|
|
555
562
|
...editor,
|
|
556
563
|
attributes: (state2) => {
|
|
557
564
|
const propsAttributes = (() => {
|
|
@@ -626,23 +633,6 @@ function createTextEditor(options = {}) {
|
|
|
626
633
|
const state2 = view.state;
|
|
627
634
|
return state2.doc.textBetween(0, state2.doc.content.size, "\n");
|
|
628
635
|
}
|
|
629
|
-
const sub = subject.pipe(
|
|
630
|
-
filter((tr) => tr.docChanged),
|
|
631
|
-
debounceTime(updateDelay)
|
|
632
|
-
).subscribe(() => {
|
|
633
|
-
if (inputRef.current) {
|
|
634
|
-
switch (mode) {
|
|
635
|
-
case "text":
|
|
636
|
-
inputRef.current.value = toTextContent();
|
|
637
|
-
break;
|
|
638
|
-
default:
|
|
639
|
-
inputRef.current.value = toHTML();
|
|
640
|
-
break;
|
|
641
|
-
}
|
|
642
|
-
const event = new Event("input", { bubbles: true });
|
|
643
|
-
inputRef.current.dispatchEvent(event);
|
|
644
|
-
}
|
|
645
|
-
});
|
|
646
636
|
if (autoFocus) {
|
|
647
637
|
view.focus();
|
|
648
638
|
}
|
|
@@ -663,15 +653,30 @@ function createTextEditor(options = {}) {
|
|
|
663
653
|
},
|
|
664
654
|
clear
|
|
665
655
|
};
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
656
|
+
controllerRef.current = textEditorController;
|
|
657
|
+
return textEditorController;
|
|
658
|
+
});
|
|
659
|
+
useEffect(() => {
|
|
660
|
+
const controller = controllerRef.current;
|
|
661
|
+
if (!controller) {
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
const sub = controller.subject.pipe(
|
|
665
|
+
filter((tr) => tr.docChanged),
|
|
666
|
+
debounceTime(updateDelay)
|
|
667
|
+
).subscribe(() => {
|
|
668
|
+
if (inputRef.current) {
|
|
669
|
+
inputRef.current.value = controller.value;
|
|
670
|
+
const event = new Event("input", { bubbles: true });
|
|
671
|
+
inputRef.current.dispatchEvent(event);
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
if (autoFocus) {
|
|
675
|
+
controller.view.focus();
|
|
670
676
|
}
|
|
671
677
|
return () => {
|
|
672
678
|
sub.unsubscribe();
|
|
673
|
-
view.destroy();
|
|
674
|
-
element.innerHTML = "";
|
|
679
|
+
controller.view.destroy();
|
|
675
680
|
};
|
|
676
681
|
}, []);
|
|
677
682
|
return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { ref: containerRef, className: container, ...props }), /* @__PURE__ */ React.createElement("input", { ref: inputRef, type: "hidden", name, onInput: onChange }));
|