@synclineapi/mdx-editor 0.1.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/LICENSE +21 -0
- package/README.md +310 -0
- package/dist/core/editor.d.ts +61 -0
- package/dist/core/events.d.ts +8 -0
- package/dist/core/history.d.ts +12 -0
- package/dist/core/icons.d.ts +2 -0
- package/dist/core/plugin-manager.d.ts +24 -0
- package/dist/core/renderer.d.ts +28 -0
- package/dist/core/sanitize.d.ts +10 -0
- package/dist/core/toolbar.d.ts +29 -0
- package/dist/core/types.d.ts +218 -0
- package/dist/examples/badge-plugin.ts +114 -0
- package/dist/examples/setup.ts +47 -0
- package/dist/index.d.ts +28 -0
- package/dist/plugins/accordion-columns.d.ts +4 -0
- package/dist/plugins/basic-formatting.d.ts +9 -0
- package/dist/plugins/break-hr.d.ts +3 -0
- package/dist/plugins/card.d.ts +3 -0
- package/dist/plugins/copy-tooltip.d.ts +3 -0
- package/dist/plugins/embed.d.ts +3 -0
- package/dist/plugins/emoji-formula.d.ts +3 -0
- package/dist/plugins/highlight-admonition.d.ts +3 -0
- package/dist/plugins/index.d.ts +29 -0
- package/dist/plugins/insert.d.ts +6 -0
- package/dist/plugins/lists-table.d.ts +5 -0
- package/dist/plugins/mermaid.d.ts +2 -0
- package/dist/plugins/step-tip-container.d.ts +4 -0
- package/dist/plugins/tab-media.d.ts +4 -0
- package/dist/plugins/toc.d.ts +2 -0
- package/dist/shared/introduction.md +27 -0
- package/dist/style.css +1 -0
- package/dist/syncline-mdx-editor.js +2845 -0
- package/dist/syncline-mdx-editor.umd.cjs +428 -0
- package/package.json +111 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 RadhaHariharan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
# @synclineapi/mdx-editor
|
|
2
|
+
|
|
3
|
+
[](https://github.com/RadhaHariharan/syncline-mdx-editor/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@synclineapi/mdx-editor)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://www.w3.org/TR/WCAG21/)
|
|
8
|
+
|
|
9
|
+
A **framework-agnostic**, plugin-based MDX/Markdown editor with toolbar customization, live preview, and 33+ built-in features. Works with React, Vue, Angular, Next.js, Svelte, or plain JavaScript.
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @synclineapi/mdx-editor
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Vanilla JavaScript
|
|
18
|
+
|
|
19
|
+
```html
|
|
20
|
+
<div id="editor"></div>
|
|
21
|
+
|
|
22
|
+
<script type="module">
|
|
23
|
+
import { createEditor } from '@synclineapi/mdx-editor';
|
|
24
|
+
import '@synclineapi/mdx-editor/style.css';
|
|
25
|
+
|
|
26
|
+
const editor = createEditor({
|
|
27
|
+
container: '#editor',
|
|
28
|
+
value: '# Hello World',
|
|
29
|
+
onChange: (markdown) => console.log('Content changed:', markdown),
|
|
30
|
+
});
|
|
31
|
+
</script>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Custom Plugin Selection
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
import { SynclineMDXEditor, boldPlugin, italicPlugin, headingPlugin } from '@synclineapi/mdx-editor';
|
|
38
|
+
import '@synclineapi/mdx-editor/style.css';
|
|
39
|
+
|
|
40
|
+
const editor = new SynclineMDXEditor({
|
|
41
|
+
container: '#editor',
|
|
42
|
+
plugins: [headingPlugin(), boldPlugin(), italicPlugin()],
|
|
43
|
+
toolbar: [['heading', '|', 'bold', 'italic']],
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Features (33+ Built-in Plugins)
|
|
48
|
+
|
|
49
|
+
| Category | Plugins |
|
|
50
|
+
|----------|---------|
|
|
51
|
+
| **Formatting** | Heading (1–6), Bold, Italic, Strikethrough, Quote |
|
|
52
|
+
| **Links & Media** | Link, Image, Image Background, Image Frame |
|
|
53
|
+
| **Code** | Inline Code, Code Block (with syntax highlighting placeholder) |
|
|
54
|
+
| **Lists** | Unordered List, Ordered List, Task List |
|
|
55
|
+
| **Layout** | Table, Multi-Column (2–5), Tabs, Container |
|
|
56
|
+
| **Components** | Accordion, Accordion Group, Card, Card Group, Steps |
|
|
57
|
+
| **Callouts** | Admonition (Tip/Warning/Caution/Danger/Check/Info/Note), Tip (Good/Bad/Info) |
|
|
58
|
+
| **Rich Content** | Highlight (8 colors), Emoji, Formula (inline/block via KaTeX), Tooltip, Copy Text |
|
|
59
|
+
| **Embeds** | YouTube, Video file, GitHub Gist, Twitter/X, CodePen, CodeSandbox |
|
|
60
|
+
| **Diagrams** | Mermaid (Flowchart, Sequence, Class, State, ER, Journey, Gantt) |
|
|
61
|
+
| **Insert** | API Endpoint, Markdown Import, Code Snippet |
|
|
62
|
+
|
|
63
|
+
## Architecture
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
@synclineapi/mdx-editor
|
|
67
|
+
├── Core Engine (SynclineMDXEditor)
|
|
68
|
+
│ ├── EventEmitter – Pub/sub event system
|
|
69
|
+
│ ├── PluginManager – Plugin lifecycle
|
|
70
|
+
│ ├── Toolbar – Configurable toolbar renderer
|
|
71
|
+
│ ├── Renderer – Markdown/MDX → HTML engine
|
|
72
|
+
│ └── History – Undo/redo stack
|
|
73
|
+
└── Plugins (33+)
|
|
74
|
+
└── Each exports: toolbarItems, shortcuts, renderers, parsers, styles
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Plugin API
|
|
78
|
+
|
|
79
|
+
Create custom plugins:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import type { EditorPlugin } from '@synclineapi/mdx-editor';
|
|
83
|
+
|
|
84
|
+
const myPlugin: EditorPlugin = {
|
|
85
|
+
name: 'my-custom-block',
|
|
86
|
+
toolbarItems: [{
|
|
87
|
+
id: 'myBlock',
|
|
88
|
+
label: 'My Block',
|
|
89
|
+
icon: '<svg>...</svg>',
|
|
90
|
+
tooltip: 'Insert my block',
|
|
91
|
+
action: ({ editor }) => {
|
|
92
|
+
editor.insertBlock('<MyBlock>\n Content\n</MyBlock>');
|
|
93
|
+
},
|
|
94
|
+
}],
|
|
95
|
+
renderers: [{
|
|
96
|
+
name: 'myBlock',
|
|
97
|
+
pattern: /<MyBlock>([\s\S]*?)<\/MyBlock>/g,
|
|
98
|
+
render: (match) => {
|
|
99
|
+
const m = match.match(/<MyBlock>([\s\S]*?)<\/MyBlock>/);
|
|
100
|
+
return `<div class="my-block">${m?.[1] || ''}</div>`;
|
|
101
|
+
},
|
|
102
|
+
}],
|
|
103
|
+
shortcuts: [
|
|
104
|
+
{ key: 'Ctrl+Shift+m', action: ({ editor }) => editor.insertBlock('<MyBlock>\n Content\n</MyBlock>') },
|
|
105
|
+
],
|
|
106
|
+
styles: `.my-block { border: 2px solid blue; padding: 16px; border-radius: 8px; }`,
|
|
107
|
+
};
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Toolbar Customization
|
|
111
|
+
|
|
112
|
+
### Flat toolbar
|
|
113
|
+
|
|
114
|
+
```js
|
|
115
|
+
createEditor({
|
|
116
|
+
container: '#editor',
|
|
117
|
+
toolbar: [['bold', 'italic', '|', 'heading', '|', 'link', 'image']],
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Nested dropdowns
|
|
122
|
+
|
|
123
|
+
```js
|
|
124
|
+
createEditor({
|
|
125
|
+
container: '#editor',
|
|
126
|
+
toolbar: [[
|
|
127
|
+
'bold', 'italic', '|',
|
|
128
|
+
{
|
|
129
|
+
type: 'group',
|
|
130
|
+
label: 'Insert',
|
|
131
|
+
display: 'dropdown',
|
|
132
|
+
items: ['table', 'accordion', 'card', 'steps'],
|
|
133
|
+
},
|
|
134
|
+
]],
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Theming
|
|
139
|
+
|
|
140
|
+
Override CSS custom properties:
|
|
141
|
+
|
|
142
|
+
```css
|
|
143
|
+
.smdx-editor {
|
|
144
|
+
--smdx-primary: #e11d48;
|
|
145
|
+
--smdx-bg: #0f172a;
|
|
146
|
+
--smdx-text: #e2e8f0;
|
|
147
|
+
--smdx-border: #334155;
|
|
148
|
+
--smdx-font-family: 'Inter', sans-serif;
|
|
149
|
+
--smdx-font-mono: 'JetBrains Mono', monospace;
|
|
150
|
+
--smdx-radius: 12px;
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Or pass theme via config:
|
|
155
|
+
|
|
156
|
+
```js
|
|
157
|
+
createEditor({
|
|
158
|
+
container: '#editor',
|
|
159
|
+
theme: {
|
|
160
|
+
'--smdx-primary': '#e11d48',
|
|
161
|
+
'--smdx-bg': '#0f172a',
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Add `.smdx-dark` class for dark mode:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
editor.getRoot().classList.add('smdx-dark');
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Configuration
|
|
173
|
+
|
|
174
|
+
| Option | Type | Default | Description |
|
|
175
|
+
|--------|------|---------|-------------|
|
|
176
|
+
| `container` | `HTMLElement \| string` | — | **Required.** The DOM element (or CSS selector) to mount the editor into. |
|
|
177
|
+
| `value` | `string` | `''` | Initial markdown content. |
|
|
178
|
+
| `onChange` | `(value: string) => void` | — | Callback invoked every time the content changes (user input, `setValue()`, undo/redo). |
|
|
179
|
+
| `plugins` | `EditorPlugin[]` | all built-in plugins | Plugins to register. |
|
|
180
|
+
| `toolbar` | `ToolbarConfig` | default toolbar | Toolbar layout. |
|
|
181
|
+
| `theme` | `Record<string, string>` | — | CSS custom property overrides. |
|
|
182
|
+
| `mode` | `'split' \| 'editor' \| 'preview'` | `'split'` | Initial editor mode. |
|
|
183
|
+
| `placeholder` | `string` | — | Textarea placeholder text. |
|
|
184
|
+
| `readOnly` | `boolean` | `false` | Make the editor read-only. |
|
|
185
|
+
| `scrollSync` | `boolean` | `true` | Sync scroll position between editor and preview. |
|
|
186
|
+
| `renderers` | `Record<string, RendererFn>` | — | Custom renderer overrides. |
|
|
187
|
+
| `locale` | `Partial<EditorLocale>` | — | i18n overrides. |
|
|
188
|
+
|
|
189
|
+
## API Reference
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
interface EditorAPI {
|
|
193
|
+
getValue(): string;
|
|
194
|
+
setValue(value: string): void;
|
|
195
|
+
insertText(text: string): void;
|
|
196
|
+
wrapSelection(prefix: string, suffix: string): void;
|
|
197
|
+
replaceSelection(text: string): void;
|
|
198
|
+
getSelection(): SelectionState;
|
|
199
|
+
insertBlock(template: string): void;
|
|
200
|
+
focus(): void;
|
|
201
|
+
renderPreview(): void;
|
|
202
|
+
getMode(): EditorMode;
|
|
203
|
+
setMode(mode: 'split' | 'editor' | 'preview'): void;
|
|
204
|
+
registerPlugin(plugin: EditorPlugin): void;
|
|
205
|
+
unregisterPlugin(name: string): void;
|
|
206
|
+
on(event: string, handler: Function): void;
|
|
207
|
+
off(event: string, handler: Function): void;
|
|
208
|
+
undo(): void;
|
|
209
|
+
redo(): void;
|
|
210
|
+
getWordCount(): number;
|
|
211
|
+
getLineCount(): number;
|
|
212
|
+
destroy(): void;
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## Events
|
|
217
|
+
|
|
218
|
+
### `onChange` config callback (recommended)
|
|
219
|
+
|
|
220
|
+
Pass `onChange` directly in the config for the simplest way to listen for content changes:
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
const editor = createEditor({
|
|
224
|
+
container: '#editor',
|
|
225
|
+
onChange: (markdown) => {
|
|
226
|
+
console.log('Content changed:', markdown);
|
|
227
|
+
},
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Event emitter
|
|
232
|
+
|
|
233
|
+
For all events (including selection changes, mode changes, etc.) use the event emitter API:
|
|
234
|
+
|
|
235
|
+
```js
|
|
236
|
+
editor.on('change', (markdown) => console.log('Content changed:', markdown));
|
|
237
|
+
editor.on('selection-change', (sel) => console.log('Selection:', sel));
|
|
238
|
+
editor.on('mode-change', (mode) => console.log('Mode:', mode));
|
|
239
|
+
editor.on('render', (html) => console.log('Preview rendered'));
|
|
240
|
+
editor.on('toolbar-action', (id) => console.log('Toolbar clicked:', id));
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
> **Note:** The GitHub repository for this package is **private** — the source code is not publicly visible. The package is freely installable from npm, but external contributions, forks, and pull requests are not accepted.
|
|
246
|
+
>
|
|
247
|
+
> To report a bug or request a feature, open an issue at the [GitHub Issues page](https://github.com/RadhaHariharan/syncline-mdx-editor/issues).
|
|
248
|
+
>
|
|
249
|
+
> ```bash
|
|
250
|
+
> npm install @synclineapi/mdx-editor
|
|
251
|
+
> ```
|
|
252
|
+
|
|
253
|
+
Internal development commands (for maintainers only):
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
cd syncline-mdx-editor
|
|
257
|
+
npm install
|
|
258
|
+
npm run dev # Start Vite dev server
|
|
259
|
+
npm run build # Build library for production
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Bundle Size
|
|
263
|
+
|
|
264
|
+
Check the estimated npm publish size before publishing:
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
npm run build
|
|
268
|
+
npm run size
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
The core bundle (with `mermaid`, `katex`, `highlight.js` externalised) targets **< 150 kB** for both ESM and UMD outputs.
|
|
272
|
+
|
|
273
|
+
## Security
|
|
274
|
+
|
|
275
|
+
All rendered Markdown/MDX HTML is sanitized via a built-in XSS sanitizer before DOM injection. Dangerous tags (`script`, `iframe`, `object`), event handler attributes (`onclick`, `onerror`, etc.), and `javascript:` protocol URLs are all stripped. See [SECURITY.md](./SECURITY.md) for the vulnerability disclosure policy.
|
|
276
|
+
|
|
277
|
+
## Accessibility
|
|
278
|
+
|
|
279
|
+
`@synclineapi/mdx-editor` targets **WCAG 2.1 AA** compliance:
|
|
280
|
+
- All toolbar buttons have `aria-label` and `title` attributes
|
|
281
|
+
- The editor textarea has `aria-label="Markdown editor"` and `aria-multiline="true"`
|
|
282
|
+
- The preview pane has `role="region"`, `aria-label="Preview"`, and `aria-live="polite"`
|
|
283
|
+
- Mode toggle buttons expose `aria-pressed` state
|
|
284
|
+
- Toolbar dropdowns have `role="menu"` / `role="menuitem"`
|
|
285
|
+
- A skip link is provided for keyboard users
|
|
286
|
+
- All text meets WCAG AA color contrast ratios
|
|
287
|
+
|
|
288
|
+
## Testing
|
|
289
|
+
|
|
290
|
+
```bash
|
|
291
|
+
npm run test # Run all tests
|
|
292
|
+
npm run test:watch # Watch mode
|
|
293
|
+
npm run test:coverage # Coverage report (target: 80%+)
|
|
294
|
+
npm run test:ui # Visual test UI
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Peer Dependencies
|
|
298
|
+
|
|
299
|
+
`mermaid`, `katex`, and `highlight.js` are optional peer dependencies. Install them only if you use those features:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
npm install mermaid # For Mermaid diagrams
|
|
303
|
+
npm install katex # For math formulas
|
|
304
|
+
npm install highlight.js # Included by default for syntax highlighting
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
MIT
|
|
310
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { EditorConfig, EditorAPI, EditorPlugin, EditorMode, SelectionState } from './types';
|
|
2
|
+
export declare class SynclineMDXEditor implements EditorAPI {
|
|
3
|
+
private root;
|
|
4
|
+
private toolbarEl;
|
|
5
|
+
private editorPane;
|
|
6
|
+
private previewPane;
|
|
7
|
+
private textarea;
|
|
8
|
+
private previewContent;
|
|
9
|
+
private statusBar;
|
|
10
|
+
private events;
|
|
11
|
+
private pluginManager;
|
|
12
|
+
private toolbar;
|
|
13
|
+
private renderer;
|
|
14
|
+
private history;
|
|
15
|
+
private mode;
|
|
16
|
+
private config;
|
|
17
|
+
private renderTimer;
|
|
18
|
+
private historyTimer;
|
|
19
|
+
private _destroyed;
|
|
20
|
+
constructor(config: EditorConfig);
|
|
21
|
+
private init;
|
|
22
|
+
private buildDOM;
|
|
23
|
+
private registerPlugins;
|
|
24
|
+
private getDefaultToolbar;
|
|
25
|
+
private onInput;
|
|
26
|
+
private onKeyDown;
|
|
27
|
+
private matchShortcut;
|
|
28
|
+
private onSelectionChange;
|
|
29
|
+
private scheduleRender;
|
|
30
|
+
private updateStatusBar;
|
|
31
|
+
getValue(): string;
|
|
32
|
+
setValue(value: string): void;
|
|
33
|
+
insertText(text: string): void;
|
|
34
|
+
wrapSelection(prefix: string, suffix: string): void;
|
|
35
|
+
replaceSelection(text: string): void;
|
|
36
|
+
getSelection(): SelectionState;
|
|
37
|
+
setSelection(start: number, end: number): void;
|
|
38
|
+
insertBlock(template: string): void;
|
|
39
|
+
getTextarea(): HTMLTextAreaElement;
|
|
40
|
+
getPreview(): HTMLElement;
|
|
41
|
+
getRoot(): HTMLElement;
|
|
42
|
+
focus(): void;
|
|
43
|
+
renderPreview(): Promise<void>;
|
|
44
|
+
getMode(): EditorMode;
|
|
45
|
+
setMode(mode: EditorMode): void;
|
|
46
|
+
registerPlugin(plugin: EditorPlugin): void;
|
|
47
|
+
unregisterPlugin(name: string): void;
|
|
48
|
+
on(event: string, handler: (data?: unknown) => void): void;
|
|
49
|
+
off(event: string, handler: (data?: unknown) => void): void;
|
|
50
|
+
emit(event: string, data?: unknown): void;
|
|
51
|
+
destroy(): void;
|
|
52
|
+
undo(): void;
|
|
53
|
+
redo(): void;
|
|
54
|
+
getCurrentLine(): string;
|
|
55
|
+
getCurrentLineNumber(): number;
|
|
56
|
+
replaceCurrentLine(text: string): void;
|
|
57
|
+
insertAt(position: number, text: string): void;
|
|
58
|
+
getWordCount(): number;
|
|
59
|
+
getLineCount(): number;
|
|
60
|
+
private applyTheme;
|
|
61
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { EventHandler } from './types';
|
|
2
|
+
export declare class EventEmitter {
|
|
3
|
+
private listeners;
|
|
4
|
+
on(event: string, handler: EventHandler): void;
|
|
5
|
+
off(event: string, handler: EventHandler): void;
|
|
6
|
+
emit(event: string, data?: unknown): void;
|
|
7
|
+
removeAllListeners(event?: string): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Simple undo/redo history stack */
|
|
2
|
+
export declare class History {
|
|
3
|
+
private stack;
|
|
4
|
+
private pointer;
|
|
5
|
+
private maxSize;
|
|
6
|
+
constructor(maxSize?: number);
|
|
7
|
+
push(value: string): void;
|
|
8
|
+
undo(): string | undefined;
|
|
9
|
+
redo(): string | undefined;
|
|
10
|
+
current(): string | undefined;
|
|
11
|
+
clear(): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { EditorPlugin, ToolbarItemConfig, ShortcutConfig, RendererConfig, ParserConfig, EditorAPI } from './types';
|
|
2
|
+
import { EventEmitter } from './events';
|
|
3
|
+
export declare class PluginManager {
|
|
4
|
+
private editorApi;
|
|
5
|
+
private plugins;
|
|
6
|
+
private toolbarItems;
|
|
7
|
+
private shortcuts;
|
|
8
|
+
private renderers;
|
|
9
|
+
private parsers;
|
|
10
|
+
private styleElements;
|
|
11
|
+
private events;
|
|
12
|
+
constructor(editorApi: EditorAPI, events: EventEmitter);
|
|
13
|
+
register(plugin: EditorPlugin): Promise<void>;
|
|
14
|
+
unregister(name: string): void;
|
|
15
|
+
getToolbarItem(id: string): ToolbarItemConfig | undefined;
|
|
16
|
+
getAllToolbarItems(): Map<string, ToolbarItemConfig>;
|
|
17
|
+
getShortcuts(): ShortcutConfig[];
|
|
18
|
+
getRenderers(): RendererConfig[];
|
|
19
|
+
getParsers(): ParserConfig[];
|
|
20
|
+
hasPlugin(name: string): boolean;
|
|
21
|
+
private createContext;
|
|
22
|
+
private injectStyles;
|
|
23
|
+
destroy(): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RendererConfig, ParserConfig } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* The Renderer transforms markdown+MDX source into preview HTML.
|
|
4
|
+
* It runs custom parsers first, then applies marked for standard markdown,
|
|
5
|
+
* then runs custom renderers for extended blocks.
|
|
6
|
+
*/
|
|
7
|
+
export declare class Renderer {
|
|
8
|
+
private renderers;
|
|
9
|
+
private parsers;
|
|
10
|
+
setRenderers(renderers: RendererConfig[]): void;
|
|
11
|
+
setParsers(parsers: ParserConfig[]): void;
|
|
12
|
+
render(source: string): Promise<string>;
|
|
13
|
+
private applyParsers;
|
|
14
|
+
private applyRenderers;
|
|
15
|
+
/**
|
|
16
|
+
* Lightweight built-in markdown renderer.
|
|
17
|
+
* Handles standard markdown without external deps.
|
|
18
|
+
*/
|
|
19
|
+
private renderMarkdown;
|
|
20
|
+
private renderTables;
|
|
21
|
+
private parseTableRow;
|
|
22
|
+
private escapeHtml;
|
|
23
|
+
/**
|
|
24
|
+
* Validate MDX component tags — detect unclosed or mismatched tags.
|
|
25
|
+
* Only checks PascalCase tags (MDX components), not standard HTML.
|
|
26
|
+
*/
|
|
27
|
+
private validateMdxTags;
|
|
28
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight HTML sanitizer to prevent XSS.
|
|
3
|
+
* Strips dangerous tags (script, object, embed, style, base, form, input, link, meta)
|
|
4
|
+
* and dangerous attributes (on*, href=javascript:, src=javascript:, action, formaction).
|
|
5
|
+
* Iframes are allowed only when their src points to a known safe embed origin.
|
|
6
|
+
* Buttons are allowed (needed for code-block copy functionality); on* attributes are
|
|
7
|
+
* still stripped from them so no inline scripts can execute.
|
|
8
|
+
* Uses the browser's DOMParser for correctness, with a fallback regex pass for SSR/test environments.
|
|
9
|
+
*/
|
|
10
|
+
export declare function sanitizeHtml(html: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ToolbarConfig, EditorAPI } from './types';
|
|
2
|
+
import { PluginManager } from './plugin-manager';
|
|
3
|
+
import { EventEmitter } from './events';
|
|
4
|
+
export declare class Toolbar {
|
|
5
|
+
private config;
|
|
6
|
+
private pluginManager;
|
|
7
|
+
private editorApi;
|
|
8
|
+
private events;
|
|
9
|
+
private el;
|
|
10
|
+
private activeDropdown;
|
|
11
|
+
private documentClickHandler;
|
|
12
|
+
constructor(config: ToolbarConfig, pluginManager: PluginManager, editorApi: EditorAPI, events: EventEmitter);
|
|
13
|
+
render(container: HTMLElement): HTMLElement;
|
|
14
|
+
private renderRow;
|
|
15
|
+
private renderDivider;
|
|
16
|
+
private renderItem;
|
|
17
|
+
private renderGroup;
|
|
18
|
+
private renderDropdownGroup;
|
|
19
|
+
private renderDropdownItem;
|
|
20
|
+
private renderSubmenu;
|
|
21
|
+
private createButton;
|
|
22
|
+
private createMenuButton;
|
|
23
|
+
private executeAction;
|
|
24
|
+
private getActionContext;
|
|
25
|
+
private toggleDropdown;
|
|
26
|
+
private closeDropdowns;
|
|
27
|
+
updateActiveStates(): void;
|
|
28
|
+
destroy(): void;
|
|
29
|
+
}
|