@powerduck/md-editor 0.2.0 → 0.5.0
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 +134 -2
- package/dist/Editor.d.ts +20 -0
- package/dist/Renderer.d.ts +20 -0
- package/dist/Toolbar.d.ts +1 -1
- package/dist/icons.d.ts +8 -0
- package/dist/index.cjs +23 -5
- package/dist/index.d.ts +48 -12
- package/dist/index.mjs +7901 -274
- package/dist/plugins/code.d.ts +16 -0
- package/dist/plugins/keyboard.d.ts +22 -0
- package/dist/plugins/math.d.ts +1 -5
- package/dist/plugins/media.d.ts +23 -0
- package/dist/plugins/mindmap.d.ts +5 -0
- package/dist/plugins/popup.d.ts +34 -0
- package/dist/plugins/tips.d.ts +2 -0
- package/dist/plugins/video.d.ts +7 -0
- package/dist/react/MarkdownEditor.d.ts +3 -3
- package/dist/react.mjs +70 -68
- package/dist/style.css +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type MarkdownIt from 'markdown-it';
|
|
2
|
+
import 'highlight.js/styles/atom-one-dark.css';
|
|
3
|
+
export interface CodeHighlightOptions {
|
|
4
|
+
/** Languages to skip (delegate to the previously-registered renderer). Default: ['mindmap']. */
|
|
5
|
+
reservedLanguages?: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Highlight code fences with highlight.js and wrap them in a macOS-style
|
|
9
|
+
* container with traffic-light dots, a language label, and a copy button.
|
|
10
|
+
*
|
|
11
|
+
* The copy button works via event delegation on the preview container
|
|
12
|
+
* (see MarkdownEditor.setupCopyHandler), so no per-button listeners are needed.
|
|
13
|
+
*
|
|
14
|
+
* Mindmap fences are delegated to the previously-registered renderer.
|
|
15
|
+
*/
|
|
16
|
+
export declare function useCodeHighlight(md: MarkdownIt, options?: CodeHighlightOptions): void;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard shortcut manager for the editor.
|
|
3
|
+
* Maps key combinations to action names. Used by the toolbar to wire up
|
|
4
|
+
* shortcuts and by the Help dialog to display them.
|
|
5
|
+
*/
|
|
6
|
+
export interface ShortcutDef {
|
|
7
|
+
action: string;
|
|
8
|
+
/** e.g. 'Mod-b' where Mod = Ctrl on Windows/Linux, Cmd on macOS */
|
|
9
|
+
key: string;
|
|
10
|
+
description: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_SHORTCUTS: readonly ShortcutDef[];
|
|
13
|
+
/**
|
|
14
|
+
* Parse a shortcut string like 'Mod-b' or 'Mod-Alt-1' into a matcher function.
|
|
15
|
+
* 'Mod' maps to Meta (Cmd) on macOS and Ctrl elsewhere.
|
|
16
|
+
*/
|
|
17
|
+
export declare function matchShortcut(shortcut: string, e: KeyboardEvent): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Format a shortcut for display in the Help dialog.
|
|
20
|
+
* e.g. 'Mod-b' -> 'Ctrl+B' (Windows) or 'Cmd+B' (macOS)
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatShortcut(shortcut: string): string;
|
package/dist/plugins/math.d.ts
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract a YouTube video ID from various URL formats.
|
|
3
|
+
* Supports: watch?v=, youtu.be/, embed/, shorts/, v/, and raw 11-char IDs.
|
|
4
|
+
* Returns null if the input is not a recognizable YouTube URL.
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractYouTubeId(input: string): string | null;
|
|
7
|
+
/**
|
|
8
|
+
* Build a markdown image link that renders as a clickable YouTube thumbnail.
|
|
9
|
+
* The thumbnail links to the YouTube watch page.
|
|
10
|
+
*/
|
|
11
|
+
export declare function youTubeEmbedMarkdown(videoId: string, alt?: string): string;
|
|
12
|
+
/** Check if a URL points to a video file based on its extension. */
|
|
13
|
+
export declare function isVideoFile(url: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Build markdown for an image insertion.
|
|
16
|
+
*/
|
|
17
|
+
export declare function imageMarkdown(url: string, alt?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Build markdown for a video file. Uses a linked image as a fallback for
|
|
20
|
+
* renderers that do not support <video> tags; the Renderer also registers
|
|
21
|
+
* a custom image rule that renders video URLs as <video> elements.
|
|
22
|
+
*/
|
|
23
|
+
export declare function videoMarkdown(url: string, alt?: string): string;
|
|
@@ -20,5 +20,10 @@ export declare function useMindmap(md: MarkdownIt): void;
|
|
|
20
20
|
* After the preview DOM is updated, render all non-hydrated mindmap nodes.
|
|
21
21
|
* markmap-lib / markmap-view are dynamically imported so they do not
|
|
22
22
|
* increase the initial bundle size when mindmaps are absent.
|
|
23
|
+
*
|
|
24
|
+
* IMPORTANT: The SVG must have explicit pixel width/height attributes before
|
|
25
|
+
* Markmap.create is called. markmap-view's d3-zoom gesture reads
|
|
26
|
+
* svg.width.baseVal.value, which throws "Could not resolve relative length"
|
|
27
|
+
* when the SVG only has percentage-based CSS dimensions (width:100%).
|
|
23
28
|
*/
|
|
24
29
|
export declare function hydrateMindmaps(root: HTMLElement): Promise<void>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface PopupField {
|
|
2
|
+
name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
type?: 'text' | 'textarea';
|
|
6
|
+
required?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface PopupConfig {
|
|
9
|
+
title: string;
|
|
10
|
+
fields: readonly PopupField[];
|
|
11
|
+
submitLabel?: string;
|
|
12
|
+
onSubmit: (values: Record<string, string>) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* A lightweight floating popup panel anchored to a toolbar button.
|
|
16
|
+
* Used for image / video / YouTube insertion dialogs.
|
|
17
|
+
* Closes on outside click, Escape key, or successful submit.
|
|
18
|
+
*/
|
|
19
|
+
export declare class Popup {
|
|
20
|
+
readonly el: HTMLDivElement;
|
|
21
|
+
private anchor;
|
|
22
|
+
private config;
|
|
23
|
+
private inputs;
|
|
24
|
+
private onOutsideClick;
|
|
25
|
+
private onKeyDown;
|
|
26
|
+
private destroyed;
|
|
27
|
+
constructor(anchor: HTMLElement, config: PopupConfig);
|
|
28
|
+
private build;
|
|
29
|
+
private submit;
|
|
30
|
+
show(): void;
|
|
31
|
+
hide(): void;
|
|
32
|
+
private position;
|
|
33
|
+
destroy(): void;
|
|
34
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type MarkdownIt from 'markdown-it';
|
|
2
|
+
/**
|
|
3
|
+
* Override the markdown-it image renderer to detect video file URLs
|
|
4
|
+
* (.mp4, .webm, .ogg, etc.) and render them as <video> elements instead
|
|
5
|
+
* of <img>. Non-video images fall through to the default renderer.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useVideo(md: MarkdownIt): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type CSSProperties } from
|
|
2
|
-
import { type EditorMode, type EditorTheme, type MarkdownEditorOptions } from
|
|
3
|
-
export interface MarkdownEditorProps extends Omit<MarkdownEditorOptions,
|
|
1
|
+
import { type CSSProperties } from 'react';
|
|
2
|
+
import { type EditorMode, type EditorTheme, type MarkdownEditorOptions } from '../index.js';
|
|
3
|
+
export interface MarkdownEditorProps extends Omit<MarkdownEditorOptions, 'value' | 'onChange'> {
|
|
4
4
|
/** Controlled value. When provided and different from internal state, syncs the editor. */
|
|
5
5
|
value?: string;
|
|
6
6
|
/** Uncontrolled initial value. Only applied on mount. */
|
package/dist/react.mjs
CHANGED
|
@@ -1,80 +1,82 @@
|
|
|
1
1
|
import { jsx as R } from "react/jsx-runtime";
|
|
2
2
|
import { forwardRef as k, useRef as a, useLayoutEffect as y, useEffect as v, useImperativeHandle as H } from "react";
|
|
3
3
|
import { MarkdownEditor as N } from "./index.mjs";
|
|
4
|
-
const C = k(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
theme: u,
|
|
13
|
-
math: l,
|
|
14
|
-
mindmap: f,
|
|
15
|
-
preview: d,
|
|
16
|
-
autoPreview: m,
|
|
17
|
-
renderDebounce: w
|
|
18
|
-
} = V, o = a(null), r = a(null), c = a(s);
|
|
19
|
-
return c.current = s, y(() => {
|
|
20
|
-
if (!o.current) return;
|
|
21
|
-
const e = new N(o.current, {
|
|
22
|
-
value: n ?? h ?? "",
|
|
4
|
+
const C = k(
|
|
5
|
+
function(V, g) {
|
|
6
|
+
const {
|
|
7
|
+
value: n,
|
|
8
|
+
defaultValue: h,
|
|
9
|
+
onChange: s,
|
|
10
|
+
className: E,
|
|
11
|
+
style: M,
|
|
23
12
|
mode: i,
|
|
24
13
|
theme: u,
|
|
25
14
|
math: l,
|
|
26
15
|
mindmap: f,
|
|
27
16
|
preview: d,
|
|
28
17
|
autoPreview: m,
|
|
29
|
-
renderDebounce: w
|
|
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
|
-
}
|
|
18
|
+
renderDebounce: w
|
|
19
|
+
} = V, o = a(null), r = a(null), c = a(s);
|
|
20
|
+
return c.current = s, y(() => {
|
|
21
|
+
if (!o.current) return;
|
|
22
|
+
const e = new N(o.current, {
|
|
23
|
+
value: n ?? h ?? "",
|
|
24
|
+
mode: i,
|
|
25
|
+
theme: u,
|
|
26
|
+
math: l,
|
|
27
|
+
mindmap: f,
|
|
28
|
+
preview: d,
|
|
29
|
+
autoPreview: m,
|
|
30
|
+
renderDebounce: w,
|
|
31
|
+
onChange: (t) => {
|
|
32
|
+
var p;
|
|
33
|
+
return (p = c.current) == null ? void 0 : p.call(c, t);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
return r.current = e, () => {
|
|
37
|
+
e.destroy(), r.current = null;
|
|
38
|
+
};
|
|
39
|
+
}, [i, l, f, d, m, w]), v(() => {
|
|
40
|
+
const e = r.current;
|
|
41
|
+
!e || n === void 0 || e.getValue() !== n && e.setValue(n);
|
|
42
|
+
}, [n]), v(() => {
|
|
43
|
+
r.current && u && r.current.setTheme(u);
|
|
44
|
+
}, [u]), H(
|
|
45
|
+
g,
|
|
46
|
+
() => ({
|
|
47
|
+
getValue: () => {
|
|
48
|
+
var e;
|
|
49
|
+
return ((e = r.current) == null ? void 0 : e.getValue()) ?? "";
|
|
50
|
+
},
|
|
51
|
+
setValue: (e) => {
|
|
52
|
+
var t;
|
|
53
|
+
return (t = r.current) == null ? void 0 : t.setValue(e);
|
|
54
|
+
},
|
|
55
|
+
getHtml: () => {
|
|
56
|
+
var e;
|
|
57
|
+
return ((e = r.current) == null ? void 0 : e.getHtml()) ?? "";
|
|
58
|
+
},
|
|
59
|
+
focus: () => {
|
|
60
|
+
var e;
|
|
61
|
+
return (e = r.current) == null ? void 0 : e.focus();
|
|
62
|
+
},
|
|
63
|
+
setMode: (e) => {
|
|
64
|
+
var t;
|
|
65
|
+
return (t = r.current) == null ? void 0 : t.setMode(e);
|
|
66
|
+
},
|
|
67
|
+
setTheme: (e) => {
|
|
68
|
+
var t;
|
|
69
|
+
return (t = r.current) == null ? void 0 : t.setTheme(e);
|
|
70
|
+
},
|
|
71
|
+
renderNow: () => {
|
|
72
|
+
var e;
|
|
73
|
+
return (e = r.current) == null ? void 0 : e.renderNow();
|
|
74
|
+
}
|
|
75
|
+
}),
|
|
76
|
+
[]
|
|
77
|
+
), /* @__PURE__ */ R("div", { ref: o, className: E, style: M });
|
|
78
|
+
}
|
|
79
|
+
);
|
|
78
80
|
export {
|
|
79
81
|
C as MarkdownEditorReact
|
|
80
82
|
};
|