@mdaemon/html-editor-react 1.3.0 → 1.4.1
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 +51 -0
- package/dist/Editor.d.ts +88 -0
- package/dist/index.d.ts +9 -168
- package/dist/index.js +162 -157
- package/dist/index.mjs +147 -157
- package/dist/useEditor.d.ts +44 -0
- package/package.json +11 -5
package/README.md
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
[](https://www.npmjs.com/package/@mdaemon/html-editor-react) [](https://packagephobia.com/result?p=@mdaemon/html-editor-react) [](https://github.com/mdaemon-technologies/MDHTMLEditor-react/blob/master/LICENSE) [](https://github.com/mdaemon-technologies/MDHTMLEditor-react/actions/workflows/ci.yml)
|
|
2
|
+
|
|
1
3
|
# MDHTMLEditor React
|
|
2
4
|
|
|
3
5
|
A React wrapper for [MDHTMLEditor](https://github.com/mdaemon-technologies/MDHTMLEditor) — a WYSIWYG HTML editor built on TipTap. Provides a drop-in replacement for `@tinymce/tinymce-react` with no license key required.
|
|
@@ -236,7 +238,18 @@ The `config` prop (or `useEditor`'s `config` option) accepts an `EditorConfig` o
|
|
|
236
238
|
| `toolbar` | `string` | *(preset)* | Custom toolbar layout string. |
|
|
237
239
|
| `toolbar_mode` | `'sliding' \| 'floating' \| 'wrap'` | `'wrap'` | Toolbar overflow behavior. |
|
|
238
240
|
| `toolbar_sticky` | `boolean` | `true` | Pin toolbar at top when scrolling. |
|
|
241
|
+
| `toolbar_narrow_breakpoint` | `number` | — | Pixel width below which the toolbar collapses into the overflow toggle. |
|
|
242
|
+
| `toolbar_priority` | `Record<string, number>` | — | Per-button overflow priority — higher values stay visible longer as the toolbar narrows. |
|
|
243
|
+
| `menubar` | `boolean` | `false` | Show a TinyMCE-style menu bar above the toolbar. |
|
|
244
|
+
| `contextmenu` | `boolean \| string` | `''` | Enable a right-click context menu. Pass a button-list string to customize its contents. |
|
|
245
|
+
| `quickbars_selection_toolbar` | `string` | `'bold italic \| quicklink blockquote'` | Inline floating toolbar shown over a text selection. |
|
|
246
|
+
| `quickbars_image_toolbar` | `boolean` | `false` | Inline floating toolbar shown when an image is selected. |
|
|
247
|
+
| `quickbars_insert_toolbar` | `boolean` | `false` | Inline floating toolbar shown on empty lines for quick insertion. |
|
|
248
|
+
| `elementpath` | `boolean` | `false` | Show a breadcrumb of the node path at the cursor in the status bar. |
|
|
249
|
+
| `valid_children` | `string` | — | TinyMCE-style rules controlling which child elements are allowed. |
|
|
239
250
|
| `auto_focus` | `string` | — | Auto-focus on init. |
|
|
251
|
+
| `setFocus` | `string` | — | CSS selector for the element to focus on init (used when `auto_focus` is not set). |
|
|
252
|
+
| `plugins` | `string` | — | Accepted for TinyMCE compatibility and ignored — all features are built in. |
|
|
240
253
|
| `browser_spellcheck` | `boolean` | `true` | Enable browser spell check. |
|
|
241
254
|
| `entity_encoding` | `'raw' \| 'named' \| 'numeric'` | `'raw'` | HTML entity encoding mode. |
|
|
242
255
|
| `paste_from_office` | `boolean` | `true` | Clean and preserve formatting when pasting from Microsoft Word/Excel. |
|
|
@@ -290,6 +303,25 @@ The `confab` / `confab-dark` skins integrate with the WorldClient theming system
|
|
|
290
303
|
/>
|
|
291
304
|
```
|
|
292
305
|
|
|
306
|
+
### Menu Bar, Context Menu & Quick Toolbars
|
|
307
|
+
|
|
308
|
+
Opt into the additional editing surfaces exposed by `@mdaemon/html-editor` 1.6.0:
|
|
309
|
+
|
|
310
|
+
```tsx
|
|
311
|
+
<Editor
|
|
312
|
+
config={{
|
|
313
|
+
menubar: true, // menu bar above the toolbar
|
|
314
|
+
contextmenu: true, // right-click context menu
|
|
315
|
+
quickbars_selection_toolbar: 'bold italic | quicklink blockquote',
|
|
316
|
+
quickbars_image_toolbar: true, // floating toolbar when an image is selected
|
|
317
|
+
elementpath: true, // breadcrumb status bar at the cursor
|
|
318
|
+
}}
|
|
319
|
+
/>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
`contextmenu` also accepts a button-list string to customize its contents, and
|
|
323
|
+
`quickbars_insert_toolbar` shows a floating insert toolbar on empty lines.
|
|
324
|
+
|
|
293
325
|
### Read-Only Mode
|
|
294
326
|
|
|
295
327
|
Start the editor read-only with `readonly: true`, or toggle it at runtime through the underlying editor instance:
|
|
@@ -636,6 +668,25 @@ npm run demo
|
|
|
636
668
|
|
|
637
669
|
This starts a Vite dev server at `http://localhost:5173` with examples of both the `<Editor>` component and `useEditor` hook.
|
|
638
670
|
|
|
671
|
+
## Development
|
|
672
|
+
|
|
673
|
+
The package is bundled with [Vite 8](https://vite.dev/) (Rolldown) and ships ES, CommonJS, and TypeScript declaration outputs.
|
|
674
|
+
|
|
675
|
+
| Script | Description |
|
|
676
|
+
|--------|-------------|
|
|
677
|
+
| `npm run build` | Production build to `dist/` (ES + CJS + `.d.ts`). |
|
|
678
|
+
| `npm run build:dev` | Development build (unminified, sourcemaps). |
|
|
679
|
+
| `npm run dev` | Rebuild on change (watch mode). |
|
|
680
|
+
| `npm test` | Run the Jest test suite. |
|
|
681
|
+
| `npm run test:coverage` | Run tests with coverage. |
|
|
682
|
+
| `npm run lint` | Lint `src` with ESLint. |
|
|
683
|
+
| `npm run typecheck` | Type-check with `tsc --noEmit`. |
|
|
684
|
+
| `npm run demo` | Launch the demo app. |
|
|
685
|
+
|
|
686
|
+
> **Node.js:** building the package requires Node `^20.19.0 || >=22.12.0` (a Vite 8 requirement). Consumers of the published package are unaffected.
|
|
687
|
+
|
|
688
|
+
Lint, typecheck, and tests run automatically in [CI](.github/workflows/ci.yml) on every push and pull request to `master` across Node 20, 22, 24, and 26.
|
|
689
|
+
|
|
639
690
|
## License
|
|
640
691
|
|
|
641
692
|
LGPL-3.0-or-later — [MDaemon Technologies, Ltd.](https://www.mdaemon.com)
|
package/dist/Editor.d.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { HTMLEditor, EditorConfig } from '@mdaemon/html-editor';
|
|
2
|
+
export interface EditorProps {
|
|
3
|
+
/**
|
|
4
|
+
* Editor configuration - TinyMCE compatible
|
|
5
|
+
*/
|
|
6
|
+
config: EditorConfig;
|
|
7
|
+
/**
|
|
8
|
+
* Initial HTML content (also known as 'body' for TinyMCE compat)
|
|
9
|
+
*/
|
|
10
|
+
body?: string;
|
|
11
|
+
/**
|
|
12
|
+
* Initial HTML content (alias for body)
|
|
13
|
+
*/
|
|
14
|
+
initialValue?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Name attribute for the hidden textarea
|
|
17
|
+
*/
|
|
18
|
+
name?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Called when content is modified
|
|
21
|
+
*/
|
|
22
|
+
onDirty?: (dirty: boolean) => void;
|
|
23
|
+
/**
|
|
24
|
+
* Called on content change (debounced)
|
|
25
|
+
*/
|
|
26
|
+
onChange?: (content: string) => void;
|
|
27
|
+
/**
|
|
28
|
+
* Called when editor is fully initialized
|
|
29
|
+
*/
|
|
30
|
+
onInit?: (editor: HTMLEditor) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Called when editor receives focus
|
|
33
|
+
*/
|
|
34
|
+
onFocus?: () => void;
|
|
35
|
+
/**
|
|
36
|
+
* Called when editor loses focus
|
|
37
|
+
*/
|
|
38
|
+
onBlur?: () => void;
|
|
39
|
+
/**
|
|
40
|
+
* Translation function
|
|
41
|
+
*/
|
|
42
|
+
translate?: (key: string) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Function to resolve file paths (like TinyMCE's tinymceScriptSrc path)
|
|
45
|
+
*/
|
|
46
|
+
getFileSrc?: (path: string) => string;
|
|
47
|
+
/**
|
|
48
|
+
* Disable the editor
|
|
49
|
+
*/
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
}
|
|
52
|
+
export interface EditorRef {
|
|
53
|
+
/**
|
|
54
|
+
* Get the underlying HTMLEditor instance
|
|
55
|
+
*/
|
|
56
|
+
getEditor: () => HTMLEditor | null;
|
|
57
|
+
/**
|
|
58
|
+
* Get the editor content as HTML
|
|
59
|
+
*/
|
|
60
|
+
getContent: () => string;
|
|
61
|
+
/**
|
|
62
|
+
* Set the editor content
|
|
63
|
+
*/
|
|
64
|
+
setContent: (html: string) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Insert content at cursor position
|
|
67
|
+
*/
|
|
68
|
+
insertContent: (html: string) => void;
|
|
69
|
+
/**
|
|
70
|
+
* Focus the editor
|
|
71
|
+
*/
|
|
72
|
+
focus: () => void;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get content from the global editor instance
|
|
76
|
+
* Note: Only works with single editor on the page
|
|
77
|
+
*/
|
|
78
|
+
export declare function getEditorContent(): string;
|
|
79
|
+
/**
|
|
80
|
+
* Set content on the global editor instance
|
|
81
|
+
* Note: Only works with single editor on the page
|
|
82
|
+
*/
|
|
83
|
+
export declare function setEditorContent(html: string): void;
|
|
84
|
+
/**
|
|
85
|
+
* MDHTMLEditor React Component
|
|
86
|
+
*/
|
|
87
|
+
export declare const Editor: import('react').ForwardRefExoticComponent<EditorProps & import('react').RefAttributes<EditorRef>>;
|
|
88
|
+
export default Editor;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,168 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import { ToolbarButtonAPI } from '@mdaemon/html-editor';
|
|
11
|
-
import { ToolbarButtonSpec } from '@mdaemon/html-editor';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* MDHTMLEditor React Component
|
|
15
|
-
*/
|
|
16
|
-
declare const Editor: ForwardRefExoticComponent<EditorProps & RefAttributes<EditorRef>>;
|
|
17
|
-
export { Editor }
|
|
18
|
-
export { Editor as MDEditor }
|
|
19
|
-
|
|
20
|
-
export { EditorConfig }
|
|
21
|
-
|
|
22
|
-
export { EditorEvents }
|
|
23
|
-
|
|
24
|
-
export declare interface EditorProps {
|
|
25
|
-
/**
|
|
26
|
-
* Editor configuration - TinyMCE compatible
|
|
27
|
-
*/
|
|
28
|
-
config: EditorConfig;
|
|
29
|
-
/**
|
|
30
|
-
* Initial HTML content (also known as 'body' for TinyMCE compat)
|
|
31
|
-
*/
|
|
32
|
-
body?: string;
|
|
33
|
-
/**
|
|
34
|
-
* Initial HTML content (alias for body)
|
|
35
|
-
*/
|
|
36
|
-
initialValue?: string;
|
|
37
|
-
/**
|
|
38
|
-
* Name attribute for the hidden textarea
|
|
39
|
-
*/
|
|
40
|
-
name?: string;
|
|
41
|
-
/**
|
|
42
|
-
* Called when content is modified
|
|
43
|
-
*/
|
|
44
|
-
onDirty?: (dirty: boolean) => void;
|
|
45
|
-
/**
|
|
46
|
-
* Called on content change (debounced)
|
|
47
|
-
*/
|
|
48
|
-
onChange?: (content: string) => void;
|
|
49
|
-
/**
|
|
50
|
-
* Called when editor is fully initialized
|
|
51
|
-
*/
|
|
52
|
-
onInit?: (editor: HTMLEditor) => void;
|
|
53
|
-
/**
|
|
54
|
-
* Called when editor receives focus
|
|
55
|
-
*/
|
|
56
|
-
onFocus?: () => void;
|
|
57
|
-
/**
|
|
58
|
-
* Called when editor loses focus
|
|
59
|
-
*/
|
|
60
|
-
onBlur?: () => void;
|
|
61
|
-
/**
|
|
62
|
-
* Translation function
|
|
63
|
-
*/
|
|
64
|
-
translate?: (key: string) => string;
|
|
65
|
-
/**
|
|
66
|
-
* Function to resolve file paths (like TinyMCE's tinymceScriptSrc path)
|
|
67
|
-
*/
|
|
68
|
-
getFileSrc?: (path: string) => string;
|
|
69
|
-
/**
|
|
70
|
-
* Disable the editor
|
|
71
|
-
*/
|
|
72
|
-
disabled?: boolean;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export declare interface EditorRef {
|
|
76
|
-
/**
|
|
77
|
-
* Get the underlying HTMLEditor instance
|
|
78
|
-
*/
|
|
79
|
-
getEditor: () => HTMLEditor | null;
|
|
80
|
-
/**
|
|
81
|
-
* Get the editor content as HTML
|
|
82
|
-
*/
|
|
83
|
-
getContent: () => string;
|
|
84
|
-
/**
|
|
85
|
-
* Set the editor content
|
|
86
|
-
*/
|
|
87
|
-
setContent: (html: string) => void;
|
|
88
|
-
/**
|
|
89
|
-
* Insert content at cursor position
|
|
90
|
-
*/
|
|
91
|
-
insertContent: (html: string) => void;
|
|
92
|
-
/**
|
|
93
|
-
* Focus the editor
|
|
94
|
-
*/
|
|
95
|
-
focus: () => void;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export { fontNames }
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Get content from the global editor instance
|
|
102
|
-
* Note: Only works with single editor on the page
|
|
103
|
-
*/
|
|
104
|
-
export declare function getEditorContent(): string;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Set content on the global editor instance
|
|
108
|
-
* Note: Only works with single editor on the page
|
|
109
|
-
*/
|
|
110
|
-
export declare function setEditorContent(html: string): void;
|
|
111
|
-
|
|
112
|
-
export { setGetFileSrc }
|
|
113
|
-
|
|
114
|
-
export { setTranslate }
|
|
115
|
-
|
|
116
|
-
export { Template }
|
|
117
|
-
|
|
118
|
-
export { ToolbarButtonAPI }
|
|
119
|
-
|
|
120
|
-
export { ToolbarButtonSpec }
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Hook for programmatic editor control
|
|
124
|
-
*/
|
|
125
|
-
export declare function useEditor(options?: UseEditorOptions): UseEditorReturn;
|
|
126
|
-
|
|
127
|
-
export declare interface UseEditorOptions {
|
|
128
|
-
config?: EditorConfig;
|
|
129
|
-
content?: string;
|
|
130
|
-
onUpdate?: (html: string) => void;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
export declare interface UseEditorReturn {
|
|
134
|
-
/**
|
|
135
|
-
* The editor instance
|
|
136
|
-
*/
|
|
137
|
-
editor: HTMLEditor | null;
|
|
138
|
-
/**
|
|
139
|
-
* Ref to attach to the container element
|
|
140
|
-
*/
|
|
141
|
-
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
142
|
-
/**
|
|
143
|
-
* Whether the editor is ready
|
|
144
|
-
*/
|
|
145
|
-
ready: boolean;
|
|
146
|
-
/**
|
|
147
|
-
* Get the current HTML content
|
|
148
|
-
*/
|
|
149
|
-
getContent: () => string;
|
|
150
|
-
/**
|
|
151
|
-
* Set the HTML content
|
|
152
|
-
*/
|
|
153
|
-
setContent: (html: string) => void;
|
|
154
|
-
/**
|
|
155
|
-
* Insert HTML at cursor
|
|
156
|
-
*/
|
|
157
|
-
insertContent: (html: string) => void;
|
|
158
|
-
/**
|
|
159
|
-
* Focus the editor
|
|
160
|
-
*/
|
|
161
|
-
focus: () => void;
|
|
162
|
-
/**
|
|
163
|
-
* Check if editor is dirty
|
|
164
|
-
*/
|
|
165
|
-
isDirty: () => boolean;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export { }
|
|
1
|
+
/**
|
|
2
|
+
* MDHTMLEditor React - Main Entry Point
|
|
3
|
+
*/
|
|
4
|
+
export { Editor as MDEditor, Editor, getEditorContent, setEditorContent } from './Editor';
|
|
5
|
+
export type { EditorProps, EditorRef } from './Editor';
|
|
6
|
+
export { useEditor } from './useEditor';
|
|
7
|
+
export type { UseEditorOptions, UseEditorReturn } from './useEditor';
|
|
8
|
+
export { fontNames, setTranslate, setGetFileSrc, } from '@mdaemon/html-editor';
|
|
9
|
+
export type { EditorConfig, EditorEvents, Template, ToolbarButtonSpec, ToolbarButtonAPI, } from '@mdaemon/html-editor';
|
package/dist/index.js
CHANGED
|
@@ -1,173 +1,178 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
let react = require("react");
|
|
3
|
+
let _mdaemon_html_editor = require("@mdaemon/html-editor");
|
|
4
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
5
|
+
//#region src/Editor.tsx
|
|
6
|
+
/**
|
|
7
|
+
* MDHTMLEditor React Component
|
|
8
|
+
* A TinyMCE-compatible React wrapper for MDHTMLEditor
|
|
9
|
+
*/
|
|
10
|
+
var globalEditor = null;
|
|
11
|
+
/**
|
|
12
|
+
* Get content from the global editor instance
|
|
13
|
+
* Note: Only works with single editor on the page
|
|
14
|
+
*/
|
|
7
15
|
function getEditorContent() {
|
|
8
|
-
|
|
16
|
+
return globalEditor?.getContent() ?? "";
|
|
9
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Set content on the global editor instance
|
|
20
|
+
* Note: Only works with single editor on the page
|
|
21
|
+
*/
|
|
10
22
|
function setEditorContent(html) {
|
|
11
|
-
|
|
23
|
+
globalEditor?.setContent(html);
|
|
12
24
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}, [disabled]);
|
|
87
|
-
react.useImperativeHandle(ref, () => ({
|
|
88
|
-
getEditor: () => editorRef.current,
|
|
89
|
-
getContent: () => editorRef.current?.getContent() ?? "",
|
|
90
|
-
setContent: (html) => editorRef.current?.setContent(html),
|
|
91
|
-
insertContent: (html) => editorRef.current?.insertContent(html),
|
|
92
|
-
focus: () => editorRef.current?.focus()
|
|
93
|
-
}), []);
|
|
94
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "md-editor-react-wrapper", children: [
|
|
95
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { ref: containerRef, className: "md-editor-container" }),
|
|
96
|
-
name && ready && /* @__PURE__ */ jsxRuntime.jsx(
|
|
97
|
-
"input",
|
|
98
|
-
{
|
|
99
|
-
type: "hidden",
|
|
100
|
-
name,
|
|
101
|
-
value: editorRef.current?.getContent() ?? ""
|
|
102
|
-
}
|
|
103
|
-
)
|
|
104
|
-
] });
|
|
25
|
+
/**
|
|
26
|
+
* MDHTMLEditor React Component
|
|
27
|
+
*/
|
|
28
|
+
var Editor = (0, react.forwardRef)(function Editor(props, ref) {
|
|
29
|
+
const { config, body, initialValue, name, onDirty, onChange, onInit, onFocus, onBlur, translate, getFileSrc, disabled } = props;
|
|
30
|
+
const containerRef = (0, react.useRef)(null);
|
|
31
|
+
const editorRef = (0, react.useRef)(null);
|
|
32
|
+
const [ready, setReady] = (0, react.useState)(false);
|
|
33
|
+
(0, react.useEffect)(() => {
|
|
34
|
+
if (translate) (0, _mdaemon_html_editor.setTranslate)(translate);
|
|
35
|
+
}, [translate]);
|
|
36
|
+
(0, react.useEffect)(() => {
|
|
37
|
+
if (getFileSrc) (0, _mdaemon_html_editor.setGetFileSrc)(getFileSrc);
|
|
38
|
+
}, [getFileSrc]);
|
|
39
|
+
(0, react.useEffect)(() => {
|
|
40
|
+
if (!containerRef.current) return;
|
|
41
|
+
const editor = new _mdaemon_html_editor.HTMLEditor(containerRef.current, {
|
|
42
|
+
...config,
|
|
43
|
+
setup: (ed) => {
|
|
44
|
+
config.setup?.(ed);
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
editorRef.current = editor;
|
|
48
|
+
globalEditor = editor;
|
|
49
|
+
const content = body ?? initialValue ?? "";
|
|
50
|
+
if (content) editor.setContent(content);
|
|
51
|
+
editor.on("init", () => {
|
|
52
|
+
setReady(true);
|
|
53
|
+
onInit?.(editor);
|
|
54
|
+
});
|
|
55
|
+
editor.on("dirty", (dirty) => {
|
|
56
|
+
onDirty?.(dirty);
|
|
57
|
+
});
|
|
58
|
+
editor.on("change", (content) => {
|
|
59
|
+
onChange?.(content);
|
|
60
|
+
editor.setDirty(false);
|
|
61
|
+
});
|
|
62
|
+
editor.on("focus", () => {
|
|
63
|
+
onFocus?.();
|
|
64
|
+
});
|
|
65
|
+
editor.on("blur", () => {
|
|
66
|
+
onBlur?.();
|
|
67
|
+
});
|
|
68
|
+
return () => {
|
|
69
|
+
editor.destroy();
|
|
70
|
+
editorRef.current = null;
|
|
71
|
+
if (globalEditor === editor) globalEditor = null;
|
|
72
|
+
};
|
|
73
|
+
}, []);
|
|
74
|
+
(0, react.useEffect)(() => {
|
|
75
|
+
if (containerRef.current) {
|
|
76
|
+
containerRef.current.style.pointerEvents = disabled ? "none" : "";
|
|
77
|
+
containerRef.current.style.opacity = disabled ? "0.6" : "";
|
|
78
|
+
}
|
|
79
|
+
}, [disabled]);
|
|
80
|
+
(0, react.useImperativeHandle)(ref, () => ({
|
|
81
|
+
getEditor: () => editorRef.current,
|
|
82
|
+
getContent: () => editorRef.current?.getContent() ?? "",
|
|
83
|
+
setContent: (html) => editorRef.current?.setContent(html),
|
|
84
|
+
insertContent: (html) => editorRef.current?.insertContent(html),
|
|
85
|
+
focus: () => editorRef.current?.focus()
|
|
86
|
+
}), []);
|
|
87
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
88
|
+
className: "md-editor-react-wrapper",
|
|
89
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
90
|
+
ref: containerRef,
|
|
91
|
+
className: "md-editor-container"
|
|
92
|
+
}), name && ready && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
93
|
+
type: "hidden",
|
|
94
|
+
name,
|
|
95
|
+
value: editorRef.current?.getContent() ?? ""
|
|
96
|
+
})]
|
|
97
|
+
});
|
|
105
98
|
});
|
|
106
99
|
Editor.displayName = "MDHTMLEditor";
|
|
100
|
+
//#endregion
|
|
101
|
+
//#region src/useEditor.ts
|
|
102
|
+
/**
|
|
103
|
+
* useEditor Hook
|
|
104
|
+
* Custom hook for advanced editor usage
|
|
105
|
+
*/
|
|
106
|
+
/**
|
|
107
|
+
* Hook for programmatic editor control
|
|
108
|
+
*/
|
|
107
109
|
function useEditor(options = {}) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
insertContent,
|
|
153
|
-
focus,
|
|
154
|
-
isDirty
|
|
155
|
-
};
|
|
110
|
+
const { config = {}, content = "", onUpdate } = options;
|
|
111
|
+
const containerRef = (0, react.useRef)(null);
|
|
112
|
+
const editorRef = (0, react.useRef)(null);
|
|
113
|
+
const [ready, setReady] = (0, react.useState)(false);
|
|
114
|
+
(0, react.useEffect)(() => {
|
|
115
|
+
if (!containerRef.current) return;
|
|
116
|
+
const editor = new _mdaemon_html_editor.HTMLEditor(containerRef.current, config);
|
|
117
|
+
editorRef.current = editor;
|
|
118
|
+
if (content) editor.setContent(content);
|
|
119
|
+
editor.on("init", () => {
|
|
120
|
+
setReady(true);
|
|
121
|
+
});
|
|
122
|
+
if (onUpdate) editor.on("change", onUpdate);
|
|
123
|
+
return () => {
|
|
124
|
+
editor.destroy();
|
|
125
|
+
editorRef.current = null;
|
|
126
|
+
setReady(false);
|
|
127
|
+
};
|
|
128
|
+
}, []);
|
|
129
|
+
const getContent = (0, react.useCallback)(() => {
|
|
130
|
+
return editorRef.current?.getContent() ?? "";
|
|
131
|
+
}, []);
|
|
132
|
+
const setContent = (0, react.useCallback)((html) => {
|
|
133
|
+
editorRef.current?.setContent(html);
|
|
134
|
+
}, []);
|
|
135
|
+
const insertContent = (0, react.useCallback)((html) => {
|
|
136
|
+
editorRef.current?.insertContent(html);
|
|
137
|
+
}, []);
|
|
138
|
+
const focus = (0, react.useCallback)(() => {
|
|
139
|
+
editorRef.current?.focus();
|
|
140
|
+
}, []);
|
|
141
|
+
const isDirty = (0, react.useCallback)(() => {
|
|
142
|
+
return editorRef.current?.isDirty() ?? false;
|
|
143
|
+
}, []);
|
|
144
|
+
return {
|
|
145
|
+
editor: editorRef.current,
|
|
146
|
+
containerRef,
|
|
147
|
+
ready,
|
|
148
|
+
getContent,
|
|
149
|
+
setContent,
|
|
150
|
+
insertContent,
|
|
151
|
+
focus,
|
|
152
|
+
isDirty
|
|
153
|
+
};
|
|
156
154
|
}
|
|
155
|
+
//#endregion
|
|
156
|
+
exports.Editor = Editor;
|
|
157
|
+
exports.MDEditor = Editor;
|
|
157
158
|
Object.defineProperty(exports, "fontNames", {
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
enumerable: true,
|
|
160
|
+
get: function() {
|
|
161
|
+
return _mdaemon_html_editor.fontNames;
|
|
162
|
+
}
|
|
160
163
|
});
|
|
164
|
+
exports.getEditorContent = getEditorContent;
|
|
165
|
+
exports.setEditorContent = setEditorContent;
|
|
161
166
|
Object.defineProperty(exports, "setGetFileSrc", {
|
|
162
|
-
|
|
163
|
-
|
|
167
|
+
enumerable: true,
|
|
168
|
+
get: function() {
|
|
169
|
+
return _mdaemon_html_editor.setGetFileSrc;
|
|
170
|
+
}
|
|
164
171
|
});
|
|
165
172
|
Object.defineProperty(exports, "setTranslate", {
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
enumerable: true,
|
|
174
|
+
get: function() {
|
|
175
|
+
return _mdaemon_html_editor.setTranslate;
|
|
176
|
+
}
|
|
168
177
|
});
|
|
169
|
-
exports.Editor = Editor;
|
|
170
|
-
exports.MDEditor = Editor;
|
|
171
|
-
exports.getEditorContent = getEditorContent;
|
|
172
|
-
exports.setEditorContent = setEditorContent;
|
|
173
178
|
exports.useEditor = useEditor;
|
package/dist/index.mjs
CHANGED
|
@@ -1,165 +1,155 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
|
2
|
+
import { HTMLEditor, fontNames, setGetFileSrc, setGetFileSrc as setGetFileSrc$1, setTranslate, setTranslate as setTranslate$1 } from "@mdaemon/html-editor";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/Editor.tsx
|
|
5
|
+
/**
|
|
6
|
+
* MDHTMLEditor React Component
|
|
7
|
+
* A TinyMCE-compatible React wrapper for MDHTMLEditor
|
|
8
|
+
*/
|
|
9
|
+
var globalEditor = null;
|
|
10
|
+
/**
|
|
11
|
+
* Get content from the global editor instance
|
|
12
|
+
* Note: Only works with single editor on the page
|
|
13
|
+
*/
|
|
6
14
|
function getEditorContent() {
|
|
7
|
-
|
|
15
|
+
return globalEditor?.getContent() ?? "";
|
|
8
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Set content on the global editor instance
|
|
19
|
+
* Note: Only works with single editor on the page
|
|
20
|
+
*/
|
|
9
21
|
function setEditorContent(html) {
|
|
10
|
-
|
|
22
|
+
globalEditor?.setContent(html);
|
|
11
23
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}, [disabled]);
|
|
86
|
-
useImperativeHandle(ref, () => ({
|
|
87
|
-
getEditor: () => editorRef.current,
|
|
88
|
-
getContent: () => editorRef.current?.getContent() ?? "",
|
|
89
|
-
setContent: (html) => editorRef.current?.setContent(html),
|
|
90
|
-
insertContent: (html) => editorRef.current?.insertContent(html),
|
|
91
|
-
focus: () => editorRef.current?.focus()
|
|
92
|
-
}), []);
|
|
93
|
-
return /* @__PURE__ */ jsxs("div", { className: "md-editor-react-wrapper", children: [
|
|
94
|
-
/* @__PURE__ */ jsx("div", { ref: containerRef, className: "md-editor-container" }),
|
|
95
|
-
name && ready && /* @__PURE__ */ jsx(
|
|
96
|
-
"input",
|
|
97
|
-
{
|
|
98
|
-
type: "hidden",
|
|
99
|
-
name,
|
|
100
|
-
value: editorRef.current?.getContent() ?? ""
|
|
101
|
-
}
|
|
102
|
-
)
|
|
103
|
-
] });
|
|
24
|
+
/**
|
|
25
|
+
* MDHTMLEditor React Component
|
|
26
|
+
*/
|
|
27
|
+
var Editor = forwardRef(function Editor(props, ref) {
|
|
28
|
+
const { config, body, initialValue, name, onDirty, onChange, onInit, onFocus, onBlur, translate, getFileSrc, disabled } = props;
|
|
29
|
+
const containerRef = useRef(null);
|
|
30
|
+
const editorRef = useRef(null);
|
|
31
|
+
const [ready, setReady] = useState(false);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (translate) setTranslate$1(translate);
|
|
34
|
+
}, [translate]);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (getFileSrc) setGetFileSrc$1(getFileSrc);
|
|
37
|
+
}, [getFileSrc]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!containerRef.current) return;
|
|
40
|
+
const editor = new HTMLEditor(containerRef.current, {
|
|
41
|
+
...config,
|
|
42
|
+
setup: (ed) => {
|
|
43
|
+
config.setup?.(ed);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
editorRef.current = editor;
|
|
47
|
+
globalEditor = editor;
|
|
48
|
+
const content = body ?? initialValue ?? "";
|
|
49
|
+
if (content) editor.setContent(content);
|
|
50
|
+
editor.on("init", () => {
|
|
51
|
+
setReady(true);
|
|
52
|
+
onInit?.(editor);
|
|
53
|
+
});
|
|
54
|
+
editor.on("dirty", (dirty) => {
|
|
55
|
+
onDirty?.(dirty);
|
|
56
|
+
});
|
|
57
|
+
editor.on("change", (content) => {
|
|
58
|
+
onChange?.(content);
|
|
59
|
+
editor.setDirty(false);
|
|
60
|
+
});
|
|
61
|
+
editor.on("focus", () => {
|
|
62
|
+
onFocus?.();
|
|
63
|
+
});
|
|
64
|
+
editor.on("blur", () => {
|
|
65
|
+
onBlur?.();
|
|
66
|
+
});
|
|
67
|
+
return () => {
|
|
68
|
+
editor.destroy();
|
|
69
|
+
editorRef.current = null;
|
|
70
|
+
if (globalEditor === editor) globalEditor = null;
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (containerRef.current) {
|
|
75
|
+
containerRef.current.style.pointerEvents = disabled ? "none" : "";
|
|
76
|
+
containerRef.current.style.opacity = disabled ? "0.6" : "";
|
|
77
|
+
}
|
|
78
|
+
}, [disabled]);
|
|
79
|
+
useImperativeHandle(ref, () => ({
|
|
80
|
+
getEditor: () => editorRef.current,
|
|
81
|
+
getContent: () => editorRef.current?.getContent() ?? "",
|
|
82
|
+
setContent: (html) => editorRef.current?.setContent(html),
|
|
83
|
+
insertContent: (html) => editorRef.current?.insertContent(html),
|
|
84
|
+
focus: () => editorRef.current?.focus()
|
|
85
|
+
}), []);
|
|
86
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
87
|
+
className: "md-editor-react-wrapper",
|
|
88
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
89
|
+
ref: containerRef,
|
|
90
|
+
className: "md-editor-container"
|
|
91
|
+
}), name && ready && /* @__PURE__ */ jsx("input", {
|
|
92
|
+
type: "hidden",
|
|
93
|
+
name,
|
|
94
|
+
value: editorRef.current?.getContent() ?? ""
|
|
95
|
+
})]
|
|
96
|
+
});
|
|
104
97
|
});
|
|
105
98
|
Editor.displayName = "MDHTMLEditor";
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/useEditor.ts
|
|
101
|
+
/**
|
|
102
|
+
* useEditor Hook
|
|
103
|
+
* Custom hook for advanced editor usage
|
|
104
|
+
*/
|
|
105
|
+
/**
|
|
106
|
+
* Hook for programmatic editor control
|
|
107
|
+
*/
|
|
106
108
|
function useEditor(options = {}) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
insertContent,
|
|
152
|
-
focus,
|
|
153
|
-
isDirty
|
|
154
|
-
};
|
|
109
|
+
const { config = {}, content = "", onUpdate } = options;
|
|
110
|
+
const containerRef = useRef(null);
|
|
111
|
+
const editorRef = useRef(null);
|
|
112
|
+
const [ready, setReady] = useState(false);
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
if (!containerRef.current) return;
|
|
115
|
+
const editor = new HTMLEditor(containerRef.current, config);
|
|
116
|
+
editorRef.current = editor;
|
|
117
|
+
if (content) editor.setContent(content);
|
|
118
|
+
editor.on("init", () => {
|
|
119
|
+
setReady(true);
|
|
120
|
+
});
|
|
121
|
+
if (onUpdate) editor.on("change", onUpdate);
|
|
122
|
+
return () => {
|
|
123
|
+
editor.destroy();
|
|
124
|
+
editorRef.current = null;
|
|
125
|
+
setReady(false);
|
|
126
|
+
};
|
|
127
|
+
}, []);
|
|
128
|
+
const getContent = useCallback(() => {
|
|
129
|
+
return editorRef.current?.getContent() ?? "";
|
|
130
|
+
}, []);
|
|
131
|
+
const setContent = useCallback((html) => {
|
|
132
|
+
editorRef.current?.setContent(html);
|
|
133
|
+
}, []);
|
|
134
|
+
const insertContent = useCallback((html) => {
|
|
135
|
+
editorRef.current?.insertContent(html);
|
|
136
|
+
}, []);
|
|
137
|
+
const focus = useCallback(() => {
|
|
138
|
+
editorRef.current?.focus();
|
|
139
|
+
}, []);
|
|
140
|
+
const isDirty = useCallback(() => {
|
|
141
|
+
return editorRef.current?.isDirty() ?? false;
|
|
142
|
+
}, []);
|
|
143
|
+
return {
|
|
144
|
+
editor: editorRef.current,
|
|
145
|
+
containerRef,
|
|
146
|
+
ready,
|
|
147
|
+
getContent,
|
|
148
|
+
setContent,
|
|
149
|
+
insertContent,
|
|
150
|
+
focus,
|
|
151
|
+
isDirty
|
|
152
|
+
};
|
|
155
153
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
Editor as MDEditor,
|
|
159
|
-
fontNames,
|
|
160
|
-
getEditorContent,
|
|
161
|
-
setEditorContent,
|
|
162
|
-
setGetFileSrc2 as setGetFileSrc,
|
|
163
|
-
setTranslate2 as setTranslate,
|
|
164
|
-
useEditor
|
|
165
|
-
};
|
|
154
|
+
//#endregion
|
|
155
|
+
export { Editor, Editor as MDEditor, fontNames, getEditorContent, setEditorContent, setGetFileSrc, setTranslate, useEditor };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { HTMLEditor, EditorConfig } from '@mdaemon/html-editor';
|
|
2
|
+
export interface UseEditorOptions {
|
|
3
|
+
config?: EditorConfig;
|
|
4
|
+
content?: string;
|
|
5
|
+
onUpdate?: (html: string) => void;
|
|
6
|
+
}
|
|
7
|
+
export interface UseEditorReturn {
|
|
8
|
+
/**
|
|
9
|
+
* The editor instance
|
|
10
|
+
*/
|
|
11
|
+
editor: HTMLEditor | null;
|
|
12
|
+
/**
|
|
13
|
+
* Ref to attach to the container element
|
|
14
|
+
*/
|
|
15
|
+
containerRef: React.RefObject<HTMLDivElement | null>;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the editor is ready
|
|
18
|
+
*/
|
|
19
|
+
ready: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Get the current HTML content
|
|
22
|
+
*/
|
|
23
|
+
getContent: () => string;
|
|
24
|
+
/**
|
|
25
|
+
* Set the HTML content
|
|
26
|
+
*/
|
|
27
|
+
setContent: (html: string) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Insert HTML at cursor
|
|
30
|
+
*/
|
|
31
|
+
insertContent: (html: string) => void;
|
|
32
|
+
/**
|
|
33
|
+
* Focus the editor
|
|
34
|
+
*/
|
|
35
|
+
focus: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Check if editor is dirty
|
|
38
|
+
*/
|
|
39
|
+
isDirty: () => boolean;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Hook for programmatic editor control
|
|
43
|
+
*/
|
|
44
|
+
export declare function useEditor(options?: UseEditorOptions): UseEditorReturn;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mdaemon/html-editor-react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "React wrapper for MDHTMLEditor",
|
|
5
5
|
"homepage": "https://github.com/mdaemon-technologies/MDHTMLEditor-react",
|
|
6
6
|
"repository": {
|
|
@@ -53,10 +53,11 @@
|
|
|
53
53
|
"react-dom": "^19.0.0 || ^18.0.0"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@mdaemon/html-editor": "^1.
|
|
56
|
+
"@mdaemon/html-editor": "^1.6.0",
|
|
57
57
|
"@tiptap/react": "^3.23.4"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|
|
60
|
+
"@eslint/js": "^9.39.4",
|
|
60
61
|
"@swc/core": "^1.11.0",
|
|
61
62
|
"@swc/jest": "^0.2.39",
|
|
62
63
|
"@testing-library/jest-dom": "^6.9.1",
|
|
@@ -64,14 +65,19 @@
|
|
|
64
65
|
"@types/jest": "^30.0.0",
|
|
65
66
|
"@types/react": "^19.2.0",
|
|
66
67
|
"@types/react-dom": "^19.2.0",
|
|
67
|
-
"@vitejs/plugin-react": "^
|
|
68
|
+
"@vitejs/plugin-react": "^6.0.2",
|
|
69
|
+
"eslint": "^9.39.4",
|
|
70
|
+
"eslint-plugin-react": "^7.37.5",
|
|
71
|
+
"eslint-plugin-react-hooks": "^5.2.0",
|
|
72
|
+
"globals": "^15.15.0",
|
|
68
73
|
"jest": "^30.3.0",
|
|
69
74
|
"jest-environment-jsdom": "^30.3.0",
|
|
70
75
|
"react": "^19.2.0",
|
|
71
76
|
"react-dom": "^19.2.0",
|
|
72
77
|
"typescript": "^6.0.2",
|
|
73
|
-
"
|
|
74
|
-
"vite
|
|
78
|
+
"typescript-eslint": "^8.61.0",
|
|
79
|
+
"vite": "^8.0.16",
|
|
80
|
+
"vite-plugin-dts": "^5.0.2"
|
|
75
81
|
},
|
|
76
82
|
"allowScripts": {
|
|
77
83
|
"@swc/core@1.15.24": true,
|