@powerduck/md-editor 0.2.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/dist/react.mjs ADDED
@@ -0,0 +1,80 @@
1
+ import { jsx as R } from "react/jsx-runtime";
2
+ import { forwardRef as k, useRef as a, useLayoutEffect as y, useEffect as v, useImperativeHandle as H } from "react";
3
+ import { MarkdownEditor as N } from "./index.mjs";
4
+ const C = k(function(V, g) {
5
+ const {
6
+ value: n,
7
+ defaultValue: h,
8
+ onChange: s,
9
+ className: E,
10
+ style: M,
11
+ mode: i,
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 ?? "",
23
+ mode: i,
24
+ theme: u,
25
+ math: l,
26
+ mindmap: f,
27
+ preview: d,
28
+ autoPreview: m,
29
+ renderDebounce: w,
30
+ onChange: (t) => {
31
+ var p;
32
+ return (p = c.current) == null ? void 0 : p.call(c, t);
33
+ }
34
+ });
35
+ return r.current = e, () => {
36
+ e.destroy(), r.current = null;
37
+ };
38
+ }, [i, l, f, d, m, w]), v(() => {
39
+ const e = r.current;
40
+ !e || n === void 0 || e.getValue() !== n && e.setValue(n);
41
+ }, [n]), v(() => {
42
+ r.current && u && r.current.setTheme(u);
43
+ }, [u]), H(
44
+ g,
45
+ () => ({
46
+ getValue: () => {
47
+ var e;
48
+ return ((e = r.current) == null ? void 0 : e.getValue()) ?? "";
49
+ },
50
+ setValue: (e) => {
51
+ var t;
52
+ return (t = r.current) == null ? void 0 : t.setValue(e);
53
+ },
54
+ getHtml: () => {
55
+ var e;
56
+ return ((e = r.current) == null ? void 0 : e.getHtml()) ?? "";
57
+ },
58
+ focus: () => {
59
+ var e;
60
+ return (e = r.current) == null ? void 0 : e.focus();
61
+ },
62
+ setMode: (e) => {
63
+ var t;
64
+ return (t = r.current) == null ? void 0 : t.setMode(e);
65
+ },
66
+ setTheme: (e) => {
67
+ var t;
68
+ return (t = r.current) == null ? void 0 : t.setTheme(e);
69
+ },
70
+ renderNow: () => {
71
+ var e;
72
+ return (e = r.current) == null ? void 0 : e.renderNow();
73
+ }
74
+ }),
75
+ []
76
+ ), /* @__PURE__ */ R("div", { ref: o, className: E, style: M });
77
+ });
78
+ export {
79
+ C as MarkdownEditorReact
80
+ };
package/dist/style.css ADDED
@@ -0,0 +1 @@
1
+ .md-editor-root{--_surface: var(--color-surface, #ffffff);--_surface-subtle: var(--color-surface-subtle, #f8f9fa);--_surface-hover: var(--color-surface-hover, #f4f5f6);--_surface-active: var(--color-surface-active, #e7eaed);--_text-primary: var(--color-text-primary, #26282b);--_text-secondary: var(--color-text-secondary, #6f747c);--_text-tertiary: var(--color-text-tertiary, #989da5);--_accent: var(--color-accent, #f28c28);--_accent-bg: var(--color-accent-bg, #fff8ef);--_accent-bg-soft: var(--color-accent-bg-soft, #fff3e5);--_on-accent: var(--color-on-accent, #ffffff);--_focus-ring: var(--color-focus-ring, rgba(242, 140, 40, .28));--_border-subtle: var(--color-border-subtle, #eceff1);--_border-default: var(--color-border-default, #e0e4e8);--_border-strong: var(--color-border-strong, #ccd2d8);--_shadow-sm: var(--shadow-sm, 0 1px 2px rgba(28, 32, 36, .05));--_radius-md: var(--radius-md, 6px);--_radius-lg: var(--radius-lg, 8px);--_space-1: var(--space-1, 4px);--_space-2: var(--space-2, 8px);--_space-3: var(--space-3, 12px);--_transition-fast: var(--transition-fast, .14s ease);--_font-ui: var(--font-family-ui, Inter, ui-sans-serif, system-ui, sans-serif);--_font-size-sm: var(--font-size-sm, 13px);--_font-size-xs: var(--font-size-xs, 12px);--_control-height-sm: var(--control-height-sm, 28px);border:1px solid var(--_border-default);border-radius:var(--_radius-lg);overflow:hidden;background:var(--_surface);color:var(--_text-primary);font-family:var(--_font-ui);display:flex;flex-direction:column;box-sizing:border-box;box-shadow:var(--_shadow-sm)}.md-editor-root *{box-sizing:border-box}.md-editor-root[data-theme=dark]{--_surface: var(--color-surface, #1f2125);--_surface-subtle: var(--color-surface-subtle, #25282d);--_surface-hover: var(--color-surface-hover, #2b2f35);--_surface-active: var(--color-surface-active, #3d434c);--_text-primary: var(--color-text-primary, #edf0f3);--_text-secondary: var(--color-text-secondary, #b8bec7);--_text-tertiary: var(--color-text-tertiary, #89919c);--_accent: var(--color-accent, #f4a04a);--_accent-bg: var(--color-accent-bg, #2d2419);--_accent-bg-soft: var(--color-accent-bg-soft, #47351d);--_on-accent: var(--color-on-accent, #2a1a0c);--_focus-ring: var(--color-focus-ring, rgba(244, 160, 74, .36));--_border-subtle: var(--color-border-subtle, #2d3239);--_border-default: var(--color-border-default, #3b4149);--_border-strong: var(--color-border-strong, #525a65)}.md-editor-toolbar{display:flex;align-items:center;gap:2px;padding:var(--_space-1) var(--_space-2);border-bottom:1px solid var(--_border-default);background:var(--_surface-subtle);flex-wrap:wrap}.md-editor-toolbar-sep{width:1px;height:18px;background:var(--_border-default);margin:0 var(--_space-1);flex:0 0 auto}.md-editor-toolbar-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--_control-height-sm);height:var(--_control-height-sm);border:1px solid transparent;background:transparent;border-radius:var(--_radius-md);cursor:pointer;color:var(--_text-secondary);transition:background var(--_transition-fast),color var(--_transition-fast),border-color var(--_transition-fast)}.md-editor-toolbar-btn:hover{background:var(--_surface-hover);color:var(--_text-primary)}.md-editor-toolbar-btn:active{background:var(--_surface-active)}.md-editor-toolbar-btn:focus-visible{outline:none;box-shadow:0 0 0 3px var(--_focus-ring)}.md-editor-toolbar-btn.is-toggle.is-active{background:var(--_accent-bg-soft);color:var(--_accent)}.md-editor-body{display:flex;min-height:320px;flex:1 1 auto}.md-editor-pane{flex:1 1 50%;min-width:0;overflow:auto;padding:var(--_space-3)}.md-editor-source{border-right:1px solid var(--_border-default)}.md-editor-source .cm-editor{height:100%;outline:none}.md-editor-source .cm-editor.cm-focused{outline:none}.md-editor-source .cm-scroller{font-family:SFMono-Regular,ui-monospace,Menlo,Consolas,Courier New,monospace;font-size:var(--_font-size-sm);line-height:1.6}.md-editor-source .cm-gutters{background:transparent;border-right:1px solid var(--_border-subtle);color:var(--_text-tertiary)}.md-editor-source .cm-activeLine,.md-editor-source .cm-activeLineGutter{background:var(--_surface-subtle)}.md-editor-preview{line-height:1.7;font-size:var(--_font-size-sm)}.md-editor-preview img{max-width:100%}.md-editor-preview pre{background:var(--_surface-subtle);padding:var(--_space-3);border-radius:var(--_radius-md);overflow:auto;border:1px solid var(--_border-subtle)}.md-editor-preview code{font-family:SFMono-Regular,ui-monospace,Menlo,Consolas,Courier New,monospace;font-size:.92em}.md-editor-preview :not(pre)>code{background:var(--_surface-subtle);padding:1px 5px;border-radius:var(--radius-xs, 3px)}.md-editor-preview table{border-collapse:collapse}.md-editor-preview th,.md-editor-preview td{border:1px solid var(--_border-default);padding:4px 10px}.md-editor-preview th{background:var(--_surface-subtle)}.md-editor-preview blockquote{border-left:3px solid var(--_border-strong);margin:0;padding-left:var(--_space-3);color:var(--_text-secondary)}.md-editor-preview a{color:var(--_accent)}.md-editor-preview hr{border:none;border-top:1px solid var(--_border-default)}.md-editor-block{content-visibility:auto;contain-intrinsic-size:0 160px}.md-editor-mindmap{border:1px dashed var(--_border-default);border-radius:var(--_radius-md);margin:var(--_space-3) 0;min-height:280px}.md-editor-statusbar{display:flex;align-items:center;gap:var(--_space-3);padding:var(--_space-1) var(--_space-3);border-top:1px solid var(--_border-default);background:var(--_surface-subtle);color:var(--_text-tertiary);font-size:var(--_font-size-xs);min-height:var(--footer-height, 24px)}.md-editor-statusbar-muted{color:var(--_text-tertiary)}.md-editor-statusbar-refresh{margin-left:auto;border:1px solid var(--_border-default);background:var(--_surface);color:var(--_text-primary);border-radius:var(--_radius-md);padding:2px var(--_space-2);font-size:var(--_font-size-xs);cursor:pointer}.md-editor-statusbar-refresh:hover{background:var(--_surface-hover)}
package/package.json ADDED
@@ -0,0 +1,94 @@
1
+ {
2
+ "name": "@powerduck/md-editor",
3
+ "version": "0.2.0",
4
+ "description": "High-performance embeddable Markdown editor built on markdown-it: KaTeX math, Markmap mindmaps, native React component, block-level incremental rendering with debounced scheduling. Ships in simple mode (no toolbar) and complex mode (toolbar + status bar), styled via CSS custom properties with light/dark themes.",
5
+ "type": "module",
6
+ "main": "dist/index.cjs",
7
+ "module": "dist/index.mjs",
8
+ "types": "dist/index.d.ts",
9
+ "sideEffects": [
10
+ "*.css"
11
+ ],
12
+ "files": [
13
+ "dist",
14
+ "src/styles/tokens.css"
15
+ ],
16
+ "exports": {
17
+ ".": {
18
+ "types": "./dist/index.d.ts",
19
+ "import": "./dist/index.mjs",
20
+ "require": "./dist/index.cjs"
21
+ },
22
+ "./react": {
23
+ "types": "./dist/react/index.d.ts",
24
+ "import": "./dist/react.mjs",
25
+ "require": "./dist/react.cjs"
26
+ },
27
+ "./dist/style.css": "./dist/style.css",
28
+ "./styles/tokens.css": "./src/styles/tokens.css",
29
+ "./package.json": "./package.json"
30
+ },
31
+ "scripts": {
32
+ "dev": "vite",
33
+ "build": "vite build && tsc -p tsconfig.json --emitDeclarationOnly",
34
+ "typecheck": "tsc -p tsconfig.json --noEmit",
35
+ "typecheck:test": "tsc -p tsconfig.test.json --noEmit",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
38
+ "preview": "vite preview"
39
+ },
40
+ "keywords": [
41
+ "markdown",
42
+ "editor",
43
+ "markdown-it",
44
+ "katex",
45
+ "math",
46
+ "mindmap",
47
+ "markmap",
48
+ "codemirror",
49
+ "react",
50
+ "performance"
51
+ ],
52
+ "license": "MIT",
53
+ "dependencies": {
54
+ "@codemirror/commands": "^6.6.0",
55
+ "@codemirror/lang-markdown": "^6.2.5",
56
+ "@codemirror/language-data": "^6.5.1",
57
+ "@codemirror/state": "^6.4.1",
58
+ "@codemirror/view": "^6.28.0",
59
+ "d3": "^7.9.0",
60
+ "katex": "^0.16.11",
61
+ "markdown-it": "^14.1.0",
62
+ "markdown-it-texmath": "^1.0.0",
63
+ "markmap-lib": "^0.18.7",
64
+ "markmap-view": "^0.18.7"
65
+ },
66
+ "peerDependencies": {
67
+ "react": ">=17",
68
+ "react-dom": ">=17"
69
+ },
70
+ "peerDependenciesMeta": {
71
+ "react": {
72
+ "optional": true
73
+ },
74
+ "react-dom": {
75
+ "optional": true
76
+ }
77
+ },
78
+ "devDependencies": {
79
+ "@testing-library/dom": "^10.4.0",
80
+ "@testing-library/react": "^16.0.0",
81
+ "@types/d3": "^7.4.3",
82
+ "@types/markdown-it": "^14.2.0",
83
+ "@types/node": "^20.19.43",
84
+ "@types/react": "^18.3.3",
85
+ "@types/react-dom": "^18.3.0",
86
+ "@vitejs/plugin-react": "^4.3.1",
87
+ "jsdom": "^25.0.0",
88
+ "react": "^18.3.1",
89
+ "react-dom": "^18.3.1",
90
+ "typescript": "^5.5.4",
91
+ "vite": "^5.4.0",
92
+ "vitest": "^2.1.0"
93
+ }
94
+ }
@@ -0,0 +1,202 @@
1
+ /**
2
+ * Design token reference file.
3
+ *
4
+ * This file defines the complete color / typography / spacing / radius / shadow
5
+ * system (including the [data-theme="dark"] variant). The md-editor component
6
+ * styles (see editor.css) consume all these variables via var(--token, fallback)
7
+ * and never hard-code color values internally.
8
+ *
9
+ * Two integration modes:
10
+ * 1. Your host app already has a same-named design token system (e.g.
11
+ * --color-surface defined on :root). Skip this file entirely; the component
12
+ * reads the host variables automatically.
13
+ * 2. You do not have such a system / just want to run a standalone demo.
14
+ * Import this file once at your app entry:
15
+ * import '@powerduck/md-editor/styles/tokens.css';
16
+ */
17
+
18
+ :root {
19
+ /* Typography */
20
+ --font-family-ui:
21
+ Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
22
+ 'Segoe UI', sans-serif;
23
+
24
+ --font-size-xxs: 10px;
25
+ --font-size-xs: 12px;
26
+ --font-size-sm: 13px;
27
+ --font-size-md: 14px;
28
+
29
+ --line-height-tight: 16px;
30
+ --line-height-normal: 20px;
31
+ --line-height-cmeditor: 40px;
32
+
33
+ --font-weight-regular: 400;
34
+ --font-weight-medium: 500;
35
+ --font-weight-semibold: 600;
36
+
37
+ /* Neutral surfaces */
38
+ --color-canvas: #fafafa;
39
+ --color-surface: #ffffff;
40
+ --color-surface-subtle: #f8f9fa;
41
+ --color-surface-hover: #f4f5f6;
42
+ --color-surface-selected: #eef0f2;
43
+ --color-surface-active: #e7eaed;
44
+
45
+ /* Text */
46
+ --color-text-primary: #26282b;
47
+ --color-text-secondary: #6f747c;
48
+ --color-text-tertiary: #989da5;
49
+ --color-text-disabled: #c2c6cc;
50
+ --color-text-inverse: #ffffff;
51
+
52
+ /* Brand accent */
53
+ --color-accent: #f28c28;
54
+ --color-accent-hover: #e47c16;
55
+ --color-accent-active: #c9640d;
56
+
57
+ --color-accent-bg: #fff8ef;
58
+ --color-accent-bg-subtle: #fffaf5;
59
+ --color-accent-bg-soft: #fff3e5;
60
+ --color-accent-bg-active: #ffe7c7;
61
+
62
+ --color-accent-border: #f5c98f;
63
+ --color-accent-disabled: #f7d9b5;
64
+
65
+ --color-text-accent: #d97818;
66
+ --color-on-accent: #ffffff;
67
+
68
+ --color-focus-ring: rgba(242, 140, 40, 0.28);
69
+
70
+ /* Semantic status colors */
71
+ --color-warning: #d98a22;
72
+ --color-success: #428961;
73
+ --color-danger: #c95555;
74
+ --color-info: #4f79bf;
75
+
76
+ --color-secret: #8267c9;
77
+ --color-dynamic: #4d7ec8;
78
+
79
+ --color-warning-soft: #fff8e8;
80
+ --color-success-soft: #eff8f2;
81
+ --color-danger-soft: #fff2f1;
82
+ --color-info-soft: #f0f5ff;
83
+
84
+ /* Borders */
85
+ --color-border-subtle: #eceff1;
86
+ --color-border-default: #e0e4e8;
87
+ --color-border-strong: #ccd2d8;
88
+
89
+ /* Spacing */
90
+ --space-0: 0;
91
+ --space-1: 4px;
92
+ --space-2: 8px;
93
+ --space-3: 12px;
94
+ --space-4: 16px;
95
+ --space-5: 20px;
96
+ --space-6: 24px;
97
+ --space-8: 32px;
98
+
99
+ /* Border radius */
100
+ --radius-xs: 3px;
101
+ --radius-sm: 4px;
102
+ --radius-md: 6px;
103
+ --radius-lg: 8px;
104
+ --radius-xl: 10px;
105
+ --radius-full: 9999px;
106
+
107
+ /* Component sizing */
108
+ --header-height: 36px;
109
+ --footer-height: 24px;
110
+
111
+ --control-height-xs: 24px;
112
+ --control-height-sm: 28px;
113
+ --control-height-md: 32px;
114
+
115
+ --icon-size-xs: 12px;
116
+ --icon-size-sm: 14px;
117
+ --icon-size-md: 16px;
118
+ --icon-size-lg: 18px;
119
+
120
+ /* Motion */
121
+ --transition-fast: 140ms ease;
122
+ --transition-standard: 180ms ease;
123
+ --transition-slow: 240ms ease;
124
+
125
+ /* Elevation */
126
+ --shadow-sm:
127
+ 0 1px 2px rgba(28, 32, 36, 0.035),
128
+ 0 1px 3px rgba(28, 32, 36, 0.025);
129
+
130
+ --shadow-md:
131
+ 0 6px 18px rgba(28, 32, 36, 0.07),
132
+ 0 2px 6px rgba(28, 32, 36, 0.035);
133
+
134
+ --shadow-lg:
135
+ 0 16px 40px rgba(28, 32, 36, 0.1),
136
+ 0 4px 12px rgba(28, 32, 36, 0.05);
137
+ }
138
+
139
+ :root[data-theme='dark'] {
140
+ /* Neutral surfaces */
141
+ --color-canvas: #181a1d;
142
+ --color-surface: #1f2125;
143
+ --color-surface-subtle: #25282d;
144
+ --color-surface-hover: #2b2f35;
145
+ --color-surface-selected: #343941;
146
+ --color-surface-active: #3d434c;
147
+
148
+ /* Text */
149
+ --color-text-primary: #edf0f3;
150
+ --color-text-secondary: #b8bec7;
151
+ --color-text-tertiary: #89919c;
152
+ --color-text-disabled: #626b76;
153
+ --color-text-inverse: #202226;
154
+
155
+ /* Brand accent */
156
+ --color-accent: #f4a04a;
157
+ --color-accent-hover: #ffb764;
158
+ --color-accent-active: #df7d20;
159
+
160
+ --color-accent-bg: #2d2419;
161
+ --color-accent-bg-subtle: #382b1b;
162
+ --color-accent-bg-soft: #47351d;
163
+ --color-accent-bg-active: #5a4324;
164
+
165
+ --color-accent-border: #9b713d;
166
+ --color-accent-disabled: #765a35;
167
+
168
+ --color-text-accent: #ffc98c;
169
+ --color-on-accent: #2a1a0c;
170
+
171
+ --color-focus-ring: rgba(244, 160, 74, 0.36);
172
+
173
+ /* Semantic status colors */
174
+ --color-warning: #e7b45c;
175
+ --color-success: #67bd89;
176
+ --color-danger: #ef7c7c;
177
+ --color-info: #82aef2;
178
+
179
+ --color-secret: #ae98ef;
180
+ --color-dynamic: #7eb0f3;
181
+
182
+ --color-warning-soft: #382f19;
183
+ --color-success-soft: #1c3928;
184
+ --color-danger-soft: #402020;
185
+ --color-info-soft: #1d304f;
186
+
187
+ /* Borders */
188
+ --color-border-subtle: #2d3239;
189
+ --color-border-default: #3b4149;
190
+ --color-border-strong: #525a65;
191
+
192
+ /* Elevation */
193
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.2);
194
+
195
+ --shadow-md:
196
+ 0 8px 24px rgba(0, 0, 0, 0.3),
197
+ 0 2px 6px rgba(0, 0, 0, 0.16);
198
+
199
+ --shadow-lg:
200
+ 0 18px 44px rgba(0, 0, 0, 0.42),
201
+ 0 6px 16px rgba(0, 0, 0, 0.22);
202
+ }