kc-plate-editor 0.3.0 → 0.3.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 +261 -62
- package/dist/components/configurator/CodeDrawer.d.ts +10 -0
- package/dist/components/configurator/ConfiguratorTab.d.ts +1 -0
- package/dist/components/configurator/EditorPreview.d.ts +9 -0
- package/dist/components/configurator/ExamplesDrawer.d.ts +6 -0
- package/dist/components/configurator/FeatureSelector.d.ts +10 -0
- package/dist/components/editor/plate-editor.d.ts +58 -10
- package/dist/components/editor/plugins/configurable-toolbar-kit.d.ts +17 -1
- package/dist/components/editor/standalone-toolbar.d.ts +52 -0
- package/dist/components/editor/table-of-contents.d.ts +21 -0
- package/dist/components/{ui → editor/toolbars}/configurable-toolbar.d.ts +1 -1
- package/dist/components/editor/toolbars/export-button.d.ts +6 -0
- package/dist/components/editor/toolbars/find-replace-button.d.ts +1 -0
- package/dist/components/ui/button.d.ts +5 -2
- package/dist/components/ui/fixed-toolbar-buttons.d.ts +2 -1
- package/dist/components/ui/floating-toolbar-buttons.d.ts +2 -1
- package/dist/{index-BEIMyJvn.js → index-B9jFBuVJ.cjs} +1 -1
- package/dist/{index-DXE99mkF.js → index-Bh8w1JAM.cjs} +339 -320
- package/dist/{index-Drawy4im.mjs → index-BqmOwSZO.js} +30842 -30671
- package/dist/{index-CKsqR2Kp.mjs → index-CI-um7kw.js} +1 -1
- package/dist/{index-CQ9MhVRi.mjs → index-D5R9tPIM.js} +2 -2
- package/dist/{index-Cjpf2atD.js → index-hCIdZ_Vi.cjs} +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +34 -6
- package/dist/index.mjs +109 -72
- package/dist/lib/config-provider.d.ts +11 -1
- package/dist/lib/toc.d.ts +14 -0
- package/dist/lib/toolbar-presets.d.ts +15 -15
- package/dist/locales/en-US.d.ts +28 -2
- package/dist/locales/index.d.ts +71 -4
- package/dist/locales/zh-CN.d.ts +43 -2
- package/dist/{react-CZcIaMtb.mjs → react-Bc9tMIHF.js} +2 -2
- package/dist/{react-CYElXqmt.mjs → react-LIndOFtY.js} +2 -2
- package/dist/react-U07OTDVt.cjs +16 -0
- package/dist/react-tGwRm5U-.cjs +11 -0
- package/dist/stores/editor-store.d.ts +28 -2
- package/dist/style.css +1 -1
- package/dist/types/editor-types.d.ts +34 -0
- package/dist/types/toolbar-config.d.ts +15 -3
- package/package.json +28 -10
- package/dist/components/ui/fullscreen-toolbar-button.d.ts +0 -3
- package/dist/lib/fullscreen.d.ts +0 -5
- package/dist/pages/ApiDemo.d.ts +0 -1
- package/dist/pages/Configurator.d.ts +0 -1
- package/dist/pages/Editor.d.ts +0 -1
- package/dist/pages/Examples.d.ts +0 -1
- package/dist/pages/FeatureShowcase.d.ts +0 -1
- package/dist/pages/Home.d.ts +0 -1
- package/dist/react-C-6r15yv.js +0 -16
- package/dist/react-hxgauqI7.js +0 -11
- /package/dist/{Preview-BGDe7OsV.js → Preview-BGDe7OsV.cjs} +0 -0
- /package/dist/{Preview-ckip2XGc.mjs → Preview-ckip2XGc.js} +0 -0
- /package/dist/{custom-media-element-B4vskoi6.mjs → custom-media-element-B4vskoi6.js} +0 -0
- /package/dist/{custom-media-element-CiqdUTcd.js → custom-media-element-CiqdUTcd.cjs} +0 -0
- /package/dist/{dash.all.min-VODXcrvW.js → dash.all.min-VODXcrvW.cjs} +0 -0
- /package/dist/{dash.all.min-mZ3IpU_5.mjs → dash.all.min-mZ3IpU_5.js} +0 -0
- /package/dist/{hls-C54ON8N6.js → hls-C54ON8N6.cjs} +0 -0
- /package/dist/{hls-Cn4MnxsU.mjs → hls-Cn4MnxsU.js} +0 -0
- /package/dist/{html2canvas-pro.esm-B7aTk6co.js → html2canvas-pro.esm-B7aTk6co.cjs} +0 -0
- /package/dist/{html2canvas-pro.esm-CQOXKWpT.mjs → html2canvas-pro.esm-CQOXKWpT.js} +0 -0
- /package/dist/{react-0OewwyjJ.mjs → react-0OewwyjJ.js} +0 -0
- /package/dist/{react-1jldl5V6.js → react-1jldl5V6.cjs} +0 -0
- /package/dist/{react-4oo9GGvM.js → react-4oo9GGvM.cjs} +0 -0
- /package/dist/{react-B6p7WDog.mjs → react-B6p7WDog.js} +0 -0
- /package/dist/{react-BB71DO7H.js → react-BB71DO7H.cjs} +0 -0
- /package/dist/{react-BhxJwm-d.js → react-BhxJwm-d.cjs} +0 -0
- /package/dist/{react-Bv-bWJKt.mjs → react-Bv-bWJKt.js} +0 -0
- /package/dist/{react-C-QUBeUY.js → react-C-QUBeUY.cjs} +0 -0
- /package/dist/{react-CbduCSo9.mjs → react-CbduCSo9.js} +0 -0
- /package/dist/{react-D2Xlskb3.mjs → react-D2Xlskb3.js} +0 -0
- /package/dist/{react-DE-5wXKn.mjs → react-DE-5wXKn.js} +0 -0
- /package/dist/{react-DGu3YNSU.js → react-DGu3YNSU.cjs} +0 -0
- /package/dist/{server.browser-BzSRCBp5.js → server.browser-BzSRCBp5.cjs} +0 -0
- /package/dist/{server.browser-DNro-WMz.mjs → server.browser-DNro-WMz.js} +0 -0
package/README.md
CHANGED
|
@@ -20,19 +20,21 @@ A powerful and customizable rich text editor built on [Plate](https://platejs.or
|
|
|
20
20
|
- 🔧 **Granular Control**: Fine-grained control over individual toolbar features
|
|
21
21
|
|
|
22
22
|
### 扩展功能
|
|
23
|
-
- 🔍 **Find & Replace**:
|
|
24
|
-
- 📊 **Word Count**: Real-time word, character, and paragraph counting
|
|
23
|
+
- 🔍 **Find & Replace API**: Powerful find and replace API for building custom search functionality
|
|
24
|
+
- 📊 **Word Count**: Real-time word, character, and paragraph counting with Chinese/English mixed text support
|
|
25
25
|
- 📑 **Outline Navigation**: Automatic document outline generation
|
|
26
|
-
- 📤 **Export**: Export to HTML, Markdown, PDF, and Image formats
|
|
26
|
+
- 📤 **Export**: Export to HTML, Markdown, PDF (multi-page support), and Image formats with progress indicators
|
|
27
27
|
- 🖥️ **Fullscreen Mode**: Distraction-free fullscreen editing
|
|
28
|
+
- 🔧 **Extensible Toolbar**: Add custom buttons to the toolbar with `customToolbarButtons` prop
|
|
28
29
|
|
|
29
30
|
### 开发体验
|
|
30
31
|
- 🔌 **Extended API**: Comprehensive API with 30+ methods for content manipulation
|
|
31
|
-
- 🛡️ **Error Handling**: Unified error handling with error boundaries
|
|
32
|
-
- 📦 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
33
|
-
- 🚀 **Performance**: Optimized rendering with
|
|
32
|
+
- 🛡️ **Error Handling**: Unified error handling with error boundaries and detailed error logging
|
|
33
|
+
- 📦 **TypeScript**: Full TypeScript support with comprehensive type definitions and strict type safety
|
|
34
|
+
- 🚀 **Performance**: Optimized rendering with debouncing, max match limits, and efficient algorithms
|
|
34
35
|
- 🔧 **Plugin System**: Flexible plugin architecture with helper utilities
|
|
35
36
|
- ⚡ **Modern Stack**: Built with React 19, Vite, and Tailwind CSS
|
|
37
|
+
- 💾 **Config Persistence**: Automatic configuration persistence to localStorage
|
|
36
38
|
|
|
37
39
|
## Installation
|
|
38
40
|
|
|
@@ -93,7 +95,47 @@ const editorConfig = {
|
|
|
93
95
|
|
|
94
96
|
function App() {
|
|
95
97
|
return (
|
|
96
|
-
<ConfigProvider
|
|
98
|
+
<ConfigProvider
|
|
99
|
+
config={editorConfig}
|
|
100
|
+
persistKey="my-editor-config" // Custom localStorage key
|
|
101
|
+
enablePersist={true} // Enable auto-save to localStorage
|
|
102
|
+
>
|
|
103
|
+
<PlateEditor />
|
|
104
|
+
</ConfigProvider>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Configuration Persistence
|
|
110
|
+
|
|
111
|
+
The editor automatically saves configuration to localStorage:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { PlateEditor, ConfigProvider, useEditorConfig } from 'kc-plate-editor';
|
|
115
|
+
|
|
116
|
+
function EditorSettings() {
|
|
117
|
+
const { config, updateConfig, resetConfig } = useEditorConfig();
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div>
|
|
121
|
+
<h3>Settings</h3>
|
|
122
|
+
<select
|
|
123
|
+
value={config.locale}
|
|
124
|
+
onChange={(e) => updateConfig({ locale: e.target.value as 'zh-CN' | 'en-US' })}
|
|
125
|
+
>
|
|
126
|
+
<option value="zh-CN">中文</option>
|
|
127
|
+
<option value="en-US">English</option>
|
|
128
|
+
</select>
|
|
129
|
+
|
|
130
|
+
<button onClick={resetConfig}>Reset to Default</button>
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function App() {
|
|
136
|
+
return (
|
|
137
|
+
<ConfigProvider enablePersist={true}>
|
|
138
|
+
<EditorSettings />
|
|
97
139
|
<PlateEditor />
|
|
98
140
|
</ConfigProvider>
|
|
99
141
|
);
|
|
@@ -109,11 +151,8 @@ import {
|
|
|
109
151
|
PlateEditor,
|
|
110
152
|
MINIMAL_TOOLBAR,
|
|
111
153
|
BASIC_TOOLBAR,
|
|
112
|
-
RICH_TEXT_TOOLBAR,
|
|
113
|
-
MARKDOWN_TOOLBAR,
|
|
114
|
-
BLOG_TOOLBAR,
|
|
115
154
|
DOCUMENT_TOOLBAR,
|
|
116
|
-
|
|
155
|
+
FULL_TOOLBAR,
|
|
117
156
|
getToolbarPreset,
|
|
118
157
|
} from 'kc-plate-editor';
|
|
119
158
|
import type { ToolbarConfig } from 'kc-plate-editor';
|
|
@@ -122,26 +161,17 @@ function App() {
|
|
|
122
161
|
// Use preset configurations
|
|
123
162
|
return (
|
|
124
163
|
<>
|
|
125
|
-
{/* Minimal editor */}
|
|
164
|
+
{/* Minimal editor - for simple text input */}
|
|
126
165
|
<PlateEditor toolbarConfig={MINIMAL_TOOLBAR} />
|
|
127
166
|
|
|
128
|
-
{/* Basic editor */}
|
|
167
|
+
{/* Basic editor - for general editing */}
|
|
129
168
|
<PlateEditor toolbarConfig={BASIC_TOOLBAR} />
|
|
130
169
|
|
|
131
|
-
{/*
|
|
132
|
-
<PlateEditor toolbarConfig={RICH_TEXT_TOOLBAR} />
|
|
133
|
-
|
|
134
|
-
{/* Markdown editor */}
|
|
135
|
-
<PlateEditor toolbarConfig={MARKDOWN_TOOLBAR} />
|
|
136
|
-
|
|
137
|
-
{/* Blog editor */}
|
|
138
|
-
<PlateEditor toolbarConfig={BLOG_TOOLBAR} />
|
|
139
|
-
|
|
140
|
-
{/* Document editor */}
|
|
170
|
+
{/* Document editor - for rich documents */}
|
|
141
171
|
<PlateEditor toolbarConfig={DOCUMENT_TOOLBAR} />
|
|
142
172
|
|
|
143
|
-
{/*
|
|
144
|
-
<PlateEditor toolbarConfig={
|
|
173
|
+
{/* Full editor - all features */}
|
|
174
|
+
<PlateEditor toolbarConfig={FULL_TOOLBAR} />
|
|
145
175
|
|
|
146
176
|
{/* Or use getToolbarPreset */}
|
|
147
177
|
<PlateEditor toolbarConfig={getToolbarPreset('minimal')} />
|
|
@@ -182,6 +212,51 @@ Available feature groups:
|
|
|
182
212
|
- **extraFormat**: Superscript, Subscript, Keyboard
|
|
183
213
|
- **blockOps**: Indent, Outdent, Toggle
|
|
184
214
|
|
|
215
|
+
### Custom Toolbar Buttons
|
|
216
|
+
|
|
217
|
+
Extend the editor toolbar with your own custom buttons:
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import { useRef } from 'react';
|
|
221
|
+
import { PlateEditor, type PlateEditorRef, type CustomToolbarButtons } from 'kc-plate-editor';
|
|
222
|
+
|
|
223
|
+
function CustomButton({ editorRef }: { editorRef: React.RefObject<PlateEditorRef> }) {
|
|
224
|
+
const handleClick = () => {
|
|
225
|
+
if (!editorRef.current) return;
|
|
226
|
+
|
|
227
|
+
// Use editor API
|
|
228
|
+
const text = editorRef.current.getText();
|
|
229
|
+
alert(`Editor has ${text.length} characters`);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<button onClick={handleClick} className="h-8 px-2 hover:bg-muted rounded-md">
|
|
234
|
+
Custom
|
|
235
|
+
</button>
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function App() {
|
|
240
|
+
const editorRef = useRef<PlateEditorRef>(null);
|
|
241
|
+
|
|
242
|
+
const customButtons: CustomToolbarButtons = {
|
|
243
|
+
before: <CustomButton editorRef={editorRef} />, // Add to toolbar start
|
|
244
|
+
after: <CustomButton editorRef={editorRef} />, // Add to toolbar end
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
return (
|
|
248
|
+
<PlateEditor
|
|
249
|
+
ref={editorRef}
|
|
250
|
+
customToolbarButtons={customButtons}
|
|
251
|
+
/>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Examples:**
|
|
257
|
+
- 📁 [Custom Find & Replace Example](src/pages/CustomFindReplaceExample.tsx) - Complete example with UI
|
|
258
|
+
- 📖 See the `/examples` route in the playground for more interactive examples
|
|
259
|
+
|
|
185
260
|
### Controlled Mode
|
|
186
261
|
|
|
187
262
|
```tsx
|
|
@@ -197,9 +272,9 @@ function App() {
|
|
|
197
272
|
]);
|
|
198
273
|
|
|
199
274
|
return (
|
|
200
|
-
<PlateEditor
|
|
201
|
-
value={content}
|
|
202
|
-
onChange={setContent}
|
|
275
|
+
<PlateEditor
|
|
276
|
+
value={content}
|
|
277
|
+
onChange={setContent}
|
|
203
278
|
/>
|
|
204
279
|
);
|
|
205
280
|
}
|
|
@@ -215,6 +290,7 @@ function App() {
|
|
|
215
290
|
| onChange | (value: Value) => void | - | Content change callback |
|
|
216
291
|
| plugins | EditorPluginKit | - | Custom plugin list |
|
|
217
292
|
| toolbarConfig | ToolbarConfig | - | Toolbar configuration (see below) |
|
|
293
|
+
| customToolbarButtons | CustomToolbarButtons | - | Custom toolbar buttons (see below) |
|
|
218
294
|
| className | string | - | Custom CSS class |
|
|
219
295
|
| disabled | boolean | false | Disable editor |
|
|
220
296
|
| readOnly | boolean | false | Read-only mode |
|
|
@@ -222,8 +298,8 @@ function App() {
|
|
|
222
298
|
| showToolbar | boolean | true | Show/hide toolbar |
|
|
223
299
|
| toolbarSticky | boolean | true | Make toolbar sticky |
|
|
224
300
|
| mode | 'edit' \| 'view' \| 'suggestion' | 'edit' | Editor mode |
|
|
301
|
+
| showSettings | boolean | true | Show/hide settings button |
|
|
225
302
|
| onModifiedChange | (isModified: boolean) => void | - | Modified state callback |
|
|
226
|
-
| onFullscreenChange | (isFullscreen: boolean) => void | - | Fullscreen state callback |
|
|
227
303
|
|
|
228
304
|
### ToolbarConfig
|
|
229
305
|
|
|
@@ -243,18 +319,36 @@ interface ToolbarConfig {
|
|
|
243
319
|
}
|
|
244
320
|
```
|
|
245
321
|
|
|
322
|
+
### CustomToolbarButtons
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
interface CustomToolbarButtons {
|
|
326
|
+
before?: React.ReactNode; // Buttons to insert at the start of the toolbar
|
|
327
|
+
after?: React.ReactNode; // Buttons to insert at the end of the toolbar
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Example:**
|
|
332
|
+
|
|
333
|
+
```tsx
|
|
334
|
+
const customButtons: CustomToolbarButtons = {
|
|
335
|
+
before: <MyCustomButton />, // Appears at the start
|
|
336
|
+
after: <AnotherButton />, // Appears at the end
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
<PlateEditor customToolbarButtons={customButtons} />
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
See [Custom Toolbar Buttons](#custom-toolbar-buttons) section for complete examples.
|
|
343
|
+
|
|
246
344
|
**Toolbar Presets:**
|
|
247
345
|
|
|
248
346
|
| Preset | Description | Use Case |
|
|
249
347
|
|--------|-------------|----------|
|
|
250
|
-
| `FULL_TOOLBAR` | All features enabled | Full-featured editor |
|
|
251
|
-
| `BASIC_TOOLBAR` | Common text editing features | General purpose editing |
|
|
252
|
-
| `MINIMAL_TOOLBAR` | Minimal feature set | Simple text input |
|
|
253
|
-
| `
|
|
254
|
-
| `MARKDOWN_TOOLBAR` | Markdown-focused features | Markdown editing |
|
|
255
|
-
| `BLOG_TOOLBAR` | Blog post editing features | Blog/article writing |
|
|
256
|
-
| `DOCUMENT_TOOLBAR` | Formal document features | Professional documents |
|
|
257
|
-
| `COMMENT_TOOLBAR` | Comment/annotation features | Comments and notes |
|
|
348
|
+
| `FULL_TOOLBAR` | All features enabled | Full-featured editor with all capabilities |
|
|
349
|
+
| `BASIC_TOOLBAR` | Common text editing features | General purpose editing and content creation |
|
|
350
|
+
| `MINIMAL_TOOLBAR` | Minimal feature set | Simple text input, comments, and notes |
|
|
351
|
+
| `DOCUMENT_TOOLBAR` | Rich document features | Professional documents and formal writing |
|
|
258
352
|
|
|
259
353
|
**Examples:**
|
|
260
354
|
|
|
@@ -354,6 +448,20 @@ interface EditorConfig {
|
|
|
354
448
|
authorization?: string; // Authorization header
|
|
355
449
|
baseURL?: string; // Base URL for API calls
|
|
356
450
|
}
|
|
451
|
+
|
|
452
|
+
interface ConfigProviderProps {
|
|
453
|
+
children: ReactNode;
|
|
454
|
+
config?: EditorConfig;
|
|
455
|
+
persistKey?: string; // localStorage key for persistence (default: 'kc-plate-editor-config')
|
|
456
|
+
enablePersist?: boolean; // Enable config persistence (default: true)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Config context methods
|
|
460
|
+
interface ConfigContextType {
|
|
461
|
+
config: EditorConfig;
|
|
462
|
+
updateConfig: (newConfig: Partial<EditorConfig>) => void; // Update config
|
|
463
|
+
resetConfig: () => void; // Reset to default
|
|
464
|
+
}
|
|
357
465
|
```
|
|
358
466
|
|
|
359
467
|
### Exported Types
|
|
@@ -507,12 +615,34 @@ configureErrorHandler({
|
|
|
507
615
|
});
|
|
508
616
|
```
|
|
509
617
|
|
|
510
|
-
### Find & Replace
|
|
618
|
+
### Find & Replace API
|
|
619
|
+
|
|
620
|
+
The editor provides powerful find and replace APIs that you can use to build custom search functionality.
|
|
621
|
+
|
|
622
|
+
**Core APIs:**
|
|
623
|
+
|
|
624
|
+
```tsx
|
|
625
|
+
// Find text and return match positions
|
|
626
|
+
const matches = editorRef.current?.find('search text', {
|
|
627
|
+
caseSensitive: false, // Optional: case-sensitive search (default: false)
|
|
628
|
+
});
|
|
629
|
+
|
|
630
|
+
// Replace text and return replacement count
|
|
631
|
+
const count = editorRef.current?.replace(
|
|
632
|
+
'old text',
|
|
633
|
+
'new text',
|
|
634
|
+
{
|
|
635
|
+
replaceAll: true, // Optional: replace all matches (default: false)
|
|
636
|
+
caseSensitive: false, // Optional: case-sensitive search (default: false)
|
|
637
|
+
}
|
|
638
|
+
);
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
**Basic Example:**
|
|
511
642
|
|
|
512
643
|
```tsx
|
|
513
644
|
import { useRef } from 'react';
|
|
514
|
-
import { PlateEditor } from 'kc-plate-editor';
|
|
515
|
-
import type { PlateEditorRef } from 'kc-plate-editor';
|
|
645
|
+
import { PlateEditor, type PlateEditorRef } from 'kc-plate-editor';
|
|
516
646
|
|
|
517
647
|
function App() {
|
|
518
648
|
const editorRef = useRef<PlateEditorRef>(null);
|
|
@@ -543,6 +673,38 @@ function App() {
|
|
|
543
673
|
}
|
|
544
674
|
```
|
|
545
675
|
|
|
676
|
+
**Custom Find & Replace UI Example:**
|
|
677
|
+
|
|
678
|
+
For a complete example of building a custom find & replace UI with match highlighting, navigation, and more, see:
|
|
679
|
+
- 📁 [Custom Find Replace Example](src/pages/CustomFindReplaceExample.tsx)
|
|
680
|
+
- 🎮 Run the playground (`pnpm dev`) and visit the examples page
|
|
681
|
+
|
|
682
|
+
**API Reference:**
|
|
683
|
+
|
|
684
|
+
| Method | Parameters | Returns | Description |
|
|
685
|
+
|--------|-----------|---------|-------------|
|
|
686
|
+
| `find()` | `searchText: string`<br/>`options?: FindOptions` | `MatchPosition[]` | Find all matches in the editor |
|
|
687
|
+
| `replace()` | `searchText: string`<br/>`replaceText: string`<br/>`options?: ReplaceOptions` | `number` | Replace text and return count |
|
|
688
|
+
|
|
689
|
+
**Types:**
|
|
690
|
+
|
|
691
|
+
```typescript
|
|
692
|
+
interface FindOptions {
|
|
693
|
+
caseSensitive?: boolean; // Default: false
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
interface ReplaceOptions {
|
|
697
|
+
caseSensitive?: boolean; // Default: false
|
|
698
|
+
replaceAll?: boolean; // Default: false
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
interface MatchPosition {
|
|
702
|
+
path: number[]; // Node path in the editor
|
|
703
|
+
offset: number; // Character offset
|
|
704
|
+
length: number; // Match length
|
|
705
|
+
}
|
|
706
|
+
```
|
|
707
|
+
|
|
546
708
|
### Word Count & Outline
|
|
547
709
|
|
|
548
710
|
```tsx
|
|
@@ -595,6 +757,36 @@ function App() {
|
|
|
595
757
|
|
|
596
758
|
### Export Functions
|
|
597
759
|
|
|
760
|
+
The editor provides comprehensive export functionality with the following improvements:
|
|
761
|
+
|
|
762
|
+
**HTML Export:**
|
|
763
|
+
- ✅ Complete styling with Tailwind CSS and KaTeX
|
|
764
|
+
- ✅ Embedded fonts (Inter, JetBrains Mono)
|
|
765
|
+
- ✅ Responsive design
|
|
766
|
+
- ✅ Error handling with user feedback
|
|
767
|
+
|
|
768
|
+
**PDF Export:**
|
|
769
|
+
- ✅ **Multi-page support**: Automatically splits long documents into multiple pages
|
|
770
|
+
- ✅ **A4 page size**: Standard A4 format (595 x 842 points)
|
|
771
|
+
- ✅ **Page margins**: 40pt margins on all sides
|
|
772
|
+
- ✅ **High quality**: 2x scale for crisp text and images
|
|
773
|
+
- ✅ **Auto-scaling**: Content automatically scaled to fit page width
|
|
774
|
+
|
|
775
|
+
**Image Export:**
|
|
776
|
+
- ✅ **High resolution**: 2x scale for better quality
|
|
777
|
+
- ✅ **PNG format**: Lossless compression
|
|
778
|
+
- ✅ **Full content**: Captures entire editor content
|
|
779
|
+
|
|
780
|
+
**Markdown Export:**
|
|
781
|
+
- ✅ Uses Plate.js native serialization
|
|
782
|
+
- ✅ Preserves formatting and structure
|
|
783
|
+
|
|
784
|
+
**All exports include:**
|
|
785
|
+
- ⏳ **Loading indicators**: Shows "Exporting..." during export
|
|
786
|
+
- ❌ **Error handling**: Displays error messages if export fails
|
|
787
|
+
- 📝 **Console logging**: Detailed error logs for debugging
|
|
788
|
+
- 🔒 **Type safety**: Full TypeScript support
|
|
789
|
+
|
|
598
790
|
```tsx
|
|
599
791
|
import { useRef } from 'react';
|
|
600
792
|
import { PlateEditor } from 'kc-plate-editor';
|
|
@@ -604,19 +796,26 @@ function App() {
|
|
|
604
796
|
const editorRef = useRef<PlateEditorRef>(null);
|
|
605
797
|
|
|
606
798
|
const handleExport = async (format: 'html' | 'markdown' | 'pdf' | 'image') => {
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
799
|
+
try {
|
|
800
|
+
switch (format) {
|
|
801
|
+
case 'html':
|
|
802
|
+
await editorRef.current?.exportAsHtml('document.html');
|
|
803
|
+
break;
|
|
804
|
+
case 'markdown':
|
|
805
|
+
await editorRef.current?.exportAsMarkdown('document.md');
|
|
806
|
+
break;
|
|
807
|
+
case 'pdf':
|
|
808
|
+
// Now supports multi-page PDF export!
|
|
809
|
+
await editorRef.current?.exportAsPdf('document.pdf');
|
|
810
|
+
break;
|
|
811
|
+
case 'image':
|
|
812
|
+
// High-quality 2x resolution
|
|
813
|
+
await editorRef.current?.exportAsImage('document.png');
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
console.log(`${format.toUpperCase()} export successful!`);
|
|
817
|
+
} catch (error) {
|
|
818
|
+
console.error(`${format.toUpperCase()} export failed:`, error);
|
|
620
819
|
}
|
|
621
820
|
};
|
|
622
821
|
|
|
@@ -624,8 +823,8 @@ function App() {
|
|
|
624
823
|
<>
|
|
625
824
|
<button onClick={() => handleExport('html')}>Export HTML</button>
|
|
626
825
|
<button onClick={() => handleExport('markdown')}>Export Markdown</button>
|
|
627
|
-
<button onClick={() => handleExport('pdf')}>Export PDF</button>
|
|
628
|
-
<button onClick={() => handleExport('image')}>Export Image</button>
|
|
826
|
+
<button onClick={() => handleExport('pdf')}>Export PDF (Multi-page)</button>
|
|
827
|
+
<button onClick={() => handleExport('image')}>Export Image (2x)</button>
|
|
629
828
|
<PlateEditor ref={editorRef} />
|
|
630
829
|
</>
|
|
631
830
|
);
|
|
@@ -792,17 +991,17 @@ Built with [Plate](https://platejs.org/) - a plugin framework for building rich
|
|
|
792
991
|
|
|
793
992
|
### Usage Guides
|
|
794
993
|
|
|
795
|
-
- 📖 [
|
|
796
|
-
-
|
|
797
|
-
- 🔧 [
|
|
798
|
-
- 🔌 [
|
|
994
|
+
- 📖 [使用手册](./docs/使用手册.md) - 完整的使用指南
|
|
995
|
+
- 📦 [发包指南](./docs/发包指南.md) - NPM 发布指南
|
|
996
|
+
- 🔧 [后端接口实现指南](./docs/后端接口实现指南.md) - Backend API implementation guide
|
|
997
|
+
- 🔌 [后端接口描述](./docs/后端接口描述.md) - Backend API documentation
|
|
799
998
|
|
|
800
999
|
### Examples
|
|
801
1000
|
|
|
802
1001
|
For complete examples, check out:
|
|
803
|
-
-
|
|
804
|
-
- `
|
|
805
|
-
-
|
|
1002
|
+
- Run the playground with `pnpm dev` and explore the examples page
|
|
1003
|
+
- Check `src/pages/` directory for example implementations
|
|
1004
|
+
- See the documentation in `docs/` directory
|
|
806
1005
|
|
|
807
1006
|
## Support
|
|
808
1007
|
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type CodeFormat = 'typescript' | 'javascript' | 'json';
|
|
2
|
+
interface CodeDrawerProps {
|
|
3
|
+
isOpen: boolean;
|
|
4
|
+
onClose: () => void;
|
|
5
|
+
code: string;
|
|
6
|
+
codeFormat: CodeFormat;
|
|
7
|
+
onCodeFormatChange: (format: CodeFormat) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function CodeDrawer({ isOpen, onClose, code, codeFormat, onCodeFormatChange, }: CodeDrawerProps): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function ConfiguratorTab(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ToolbarConfig } from '../../types/toolbar-config';
|
|
2
|
+
import { Locale } from '../../locales';
|
|
3
|
+
interface EditorPreviewProps {
|
|
4
|
+
config: ToolbarConfig;
|
|
5
|
+
locale: Locale;
|
|
6
|
+
editorKey: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function EditorPreview({ config, locale, editorKey }: EditorPreviewProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
interface FeatureSelectorProps {
|
|
2
|
+
selectedFeatures: Set<string>;
|
|
3
|
+
onToggleFeature: (featureId: string) => void;
|
|
4
|
+
onToggleGroupFeatures: (groupId: string) => void;
|
|
5
|
+
onSelectAll: () => void;
|
|
6
|
+
expandedGroups: Set<string>;
|
|
7
|
+
onToggleGroup: (groupId: string) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function FeatureSelector({ selectedFeatures, onToggleFeature, onToggleGroupFeatures, onSelectAll, expandedGroups, onToggleGroup, }: FeatureSelectorProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
@@ -1,9 +1,29 @@
|
|
|
1
1
|
import { Value } from 'platejs';
|
|
2
2
|
import { TPlateEditor } from 'platejs/react';
|
|
3
3
|
import { EditorPluginKit } from '../../types/plugin-types';
|
|
4
|
-
import { ToolbarConfig } from '../../types/toolbar-config';
|
|
4
|
+
import { ToolbarConfig, ToolbarAlign } from '../../types/toolbar-config';
|
|
5
5
|
import { EditorMode, WordCountResult, OutlineItem, FindOptions, ReplaceOptions, MatchPosition } from '../../types/editor-types';
|
|
6
6
|
import * as React from 'react';
|
|
7
|
+
/**
|
|
8
|
+
* 自定义工具栏按钮配置
|
|
9
|
+
*/
|
|
10
|
+
export interface CustomToolbarButtons {
|
|
11
|
+
/** 在工具栏开始位置插入的按钮 */
|
|
12
|
+
before?: React.ReactNode;
|
|
13
|
+
/** 在工具栏末尾插入的按钮 */
|
|
14
|
+
after?: React.ReactNode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* 工具栏引用接口
|
|
18
|
+
*/
|
|
19
|
+
export interface ToolbarRef {
|
|
20
|
+
/** 获取工具栏容器元素 */
|
|
21
|
+
getElement: () => HTMLDivElement | null;
|
|
22
|
+
/** 设置工具栏可见性 */
|
|
23
|
+
setVisible: (visible: boolean) => void;
|
|
24
|
+
/** 获取工具栏可见性 */
|
|
25
|
+
isVisible: () => boolean;
|
|
26
|
+
}
|
|
7
27
|
/**
|
|
8
28
|
* PlateEditor 组件属性
|
|
9
29
|
*/
|
|
@@ -30,16 +50,50 @@ export interface PlateEditorProps {
|
|
|
30
50
|
toolbarSticky?: boolean;
|
|
31
51
|
/** 编辑器模式:'edit' | 'view' | 'suggestion' */
|
|
32
52
|
mode?: EditorMode;
|
|
53
|
+
/** 是否显示右侧设置按钮,默认 true */
|
|
54
|
+
showSettings?: boolean;
|
|
33
55
|
/** 修改状态变化回调 */
|
|
34
56
|
onModifiedChange?: (isModified: boolean) => void;
|
|
35
|
-
/**
|
|
36
|
-
|
|
57
|
+
/** 自定义工具栏按钮 */
|
|
58
|
+
customToolbarButtons?: CustomToolbarButtons;
|
|
59
|
+
/** 工具栏按钮对齐方式:left | center | right,默认 left */
|
|
60
|
+
toolbarAlign?: ToolbarAlign;
|
|
61
|
+
/** 工具栏是否占据全宽(不受内容区域宽度限制),默认 false */
|
|
62
|
+
toolbarFullWidth?: boolean;
|
|
63
|
+
/** 自定义工具栏的 CSS 类名 */
|
|
64
|
+
toolbarClassName?: string;
|
|
65
|
+
/** 自定义工具栏的内联样式对象 */
|
|
66
|
+
toolbarStyle?: React.CSSProperties;
|
|
67
|
+
/** 自定义渲染工具栏的函数 */
|
|
68
|
+
renderToolbar?: (toolbar: React.ReactNode) => React.ReactNode;
|
|
69
|
+
/** 编辑器内容区域的最大宽度 */
|
|
70
|
+
contentMaxWidth?: string | number;
|
|
71
|
+
/** 是否显示目录,默认 false */
|
|
72
|
+
showToc?: boolean;
|
|
73
|
+
/** 目录位置,默认 'left' */
|
|
74
|
+
tocPosition?: import('../../types/editor-types').TocPosition;
|
|
75
|
+
/** 目录宽度(当位置为 left/right 时),默认 '240px' */
|
|
76
|
+
tocWidth?: string | number;
|
|
77
|
+
/** 自定义目录的 CSS 类名 */
|
|
78
|
+
tocClassName?: string;
|
|
79
|
+
/** 自定义目录的内联样式对象 */
|
|
80
|
+
tocStyle?: React.CSSProperties;
|
|
81
|
+
/** 自定义渲染目录的函数 */
|
|
82
|
+
renderToc?: (toc: React.ReactNode) => React.ReactNode;
|
|
37
83
|
}
|
|
38
84
|
/**
|
|
39
85
|
* PlateEditor 组件引用接口
|
|
40
86
|
* 提供编辑器的所有操作方法
|
|
41
87
|
*/
|
|
42
88
|
export interface PlateEditorRef {
|
|
89
|
+
/** 获取工具栏实例或引用 */
|
|
90
|
+
getToolbar: () => ToolbarRef | null;
|
|
91
|
+
/** 设置工具栏的显示/隐藏状态 */
|
|
92
|
+
setToolbarVisible: (visible: boolean) => void;
|
|
93
|
+
/** 获取目录实例或引用 */
|
|
94
|
+
getToc: () => import('../../types/editor-types').TocRef | null;
|
|
95
|
+
/** 设置目录的显示/隐藏状态 */
|
|
96
|
+
setTocVisible: (visible: boolean) => void;
|
|
43
97
|
/** 获取编辑器内容(JSON 格式) */
|
|
44
98
|
getContent: () => Value;
|
|
45
99
|
/** 设置编辑器内容 */
|
|
@@ -52,7 +106,7 @@ export interface PlateEditorRef {
|
|
|
52
106
|
getMarkdown: () => string;
|
|
53
107
|
/** 从 Markdown 加载内容 */
|
|
54
108
|
setMarkdown: (markdown: string) => void;
|
|
55
|
-
/** 导出为 HTML
|
|
109
|
+
/** 导出为 HTML 文件 */
|
|
56
110
|
getHtml: () => Promise<string>;
|
|
57
111
|
/** 从 HTML 加载内容 */
|
|
58
112
|
setHtml: (html: string) => void;
|
|
@@ -98,11 +152,5 @@ export interface PlateEditorRef {
|
|
|
98
152
|
getOutline: () => OutlineItem[];
|
|
99
153
|
/** 获取字数统计 */
|
|
100
154
|
getWordCount: () => WordCountResult;
|
|
101
|
-
/** 进入全屏模式 */
|
|
102
|
-
enterFullscreen: () => Promise<void>;
|
|
103
|
-
/** 退出全屏模式 */
|
|
104
|
-
exitFullscreen: () => Promise<void>;
|
|
105
|
-
/** 检查是否处于全屏模式 */
|
|
106
|
-
isFullscreen: () => boolean;
|
|
107
155
|
}
|
|
108
156
|
export declare const PlateEditor: React.ForwardRefExoticComponent<PlateEditorProps & React.RefAttributes<PlateEditorRef>>;
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import { ToolbarConfig } from '../../../types/toolbar-config';
|
|
1
|
+
import { ToolbarConfig, ToolbarAlign } from '../../../types/toolbar-config';
|
|
2
|
+
import { default as React } from 'react';
|
|
2
3
|
export interface ConfigurableToolbarKitOptions {
|
|
3
4
|
/** 是否显示工具栏,默认 true */
|
|
4
5
|
showToolbar?: boolean;
|
|
5
6
|
/** 工具栏是否吸顶,默认 true */
|
|
6
7
|
toolbarSticky?: boolean;
|
|
8
|
+
/** 工具栏对齐方式(可选,当前仅预留,不影响渲染) */
|
|
9
|
+
toolbarAlign?: ToolbarAlign;
|
|
10
|
+
/** 是否全宽(可选,当前仅预留,不影响渲染) */
|
|
11
|
+
toolbarFullWidth?: boolean;
|
|
12
|
+
/** 自定义类名(可选) */
|
|
13
|
+
toolbarClassName?: string;
|
|
14
|
+
/** 内联样式(可选) */
|
|
15
|
+
toolbarStyle?: React.CSSProperties;
|
|
16
|
+
/** 自定义渲染函数(可选) */
|
|
17
|
+
renderToolbar?: (toolbar: React.ReactNode) => React.ReactNode;
|
|
18
|
+
/** 自定义按钮插槽(可选,当前仅预留,不影响渲染) */
|
|
19
|
+
customButtons?: {
|
|
20
|
+
before?: React.ReactNode;
|
|
21
|
+
after?: React.ReactNode;
|
|
22
|
+
};
|
|
7
23
|
}
|
|
8
24
|
export declare function createConfigurableToolbarKit(config: ToolbarConfig, options?: ConfigurableToolbarKitOptions): any[];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ToolbarConfig, ToolbarAlign } from '../../types/toolbar-config';
|
|
2
|
+
import { CustomToolbarButtons } from './plate-editor';
|
|
3
|
+
import { EditorPluginKit } from '../../types/plugin-types';
|
|
4
|
+
import * as React from 'react';
|
|
5
|
+
/**
|
|
6
|
+
* 独立工具栏组件的属性
|
|
7
|
+
*/
|
|
8
|
+
export interface StandaloneToolbarProps {
|
|
9
|
+
/** 工具栏配置 */
|
|
10
|
+
config: ToolbarConfig;
|
|
11
|
+
/** 编辑器实例(可选,如果不提供则创建一个内部实例) */
|
|
12
|
+
editor?: any;
|
|
13
|
+
/** 自定义插件列表(可选) */
|
|
14
|
+
plugins?: EditorPluginKit;
|
|
15
|
+
/** 是否显示工具栏,默认 true */
|
|
16
|
+
showToolbar?: boolean;
|
|
17
|
+
/** 工具栏是否吸顶,默认 true */
|
|
18
|
+
sticky?: boolean;
|
|
19
|
+
/** 工具栏按钮对齐方式,默认 left */
|
|
20
|
+
align?: ToolbarAlign;
|
|
21
|
+
/** 工具栏是否占据全宽,默认 false */
|
|
22
|
+
fullWidth?: boolean;
|
|
23
|
+
/** 自定义工具栏的 CSS 类名 */
|
|
24
|
+
className?: string;
|
|
25
|
+
/** 自定义工具栏的内联样式对象 */
|
|
26
|
+
style?: React.CSSProperties;
|
|
27
|
+
/** 自定义工具栏按钮 */
|
|
28
|
+
customButtons?: CustomToolbarButtons;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 独立工具栏组件
|
|
32
|
+
* 可以在编辑器组件外部独立使用,提供完整的工具栏功能
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```tsx
|
|
36
|
+
* // 基础使用
|
|
37
|
+
* <StandaloneToolbar config={FULL_TOOLBAR} />
|
|
38
|
+
*
|
|
39
|
+
* // 自定义样式和对齐
|
|
40
|
+
* <StandaloneToolbar
|
|
41
|
+
* config={BASIC_TOOLBAR}
|
|
42
|
+
* align="center"
|
|
43
|
+
* className="my-custom-toolbar"
|
|
44
|
+
* style={{ backgroundColor: '#f0f0f0' }}
|
|
45
|
+
* />
|
|
46
|
+
*
|
|
47
|
+
* // 与编辑器实例关联
|
|
48
|
+
* const editor = usePlateEditor({ plugins: EditorKit });
|
|
49
|
+
* <StandaloneToolbar config={FULL_TOOLBAR} editor={editor} />
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare const StandaloneToolbar: React.ForwardRefExoticComponent<StandaloneToolbarProps & React.RefAttributes<HTMLDivElement>>;
|