@particle-academy/fancy-code 0.4.7 → 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 +2 -0
- package/dist/index.cjs +225 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -1
- package/dist/index.d.ts +67 -1
- package/dist/index.js +223 -1
- package/dist/index.js.map +1 -1
- package/dist/styles.css +138 -0
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -177,6 +177,64 @@ declare const CodeEditor: typeof CodeEditorRoot & {
|
|
|
177
177
|
|
|
178
178
|
declare function useCodeEditor(): CodeEditorContextValue;
|
|
179
179
|
|
|
180
|
+
type MarkdownEditorMode = "split" | "edit" | "preview";
|
|
181
|
+
interface MarkdownEditorProps {
|
|
182
|
+
/** Controlled markdown value. */
|
|
183
|
+
value?: string;
|
|
184
|
+
/** Initial value (uncontrolled). */
|
|
185
|
+
defaultValue?: string;
|
|
186
|
+
/** Called with the new markdown whenever the document changes. */
|
|
187
|
+
onValueChange?: (markdown: string) => void;
|
|
188
|
+
/**
|
|
189
|
+
* Layout: `split` (editor + live preview side by side), `edit` (editor only),
|
|
190
|
+
* or `preview` (rendered only). Default `split`.
|
|
191
|
+
*/
|
|
192
|
+
mode?: MarkdownEditorMode;
|
|
193
|
+
/** Editor theme — `"light" | "dark" | "auto"` or a registered name. Default `auto`. */
|
|
194
|
+
theme?: string;
|
|
195
|
+
/** Prevent editing. */
|
|
196
|
+
readOnly?: boolean;
|
|
197
|
+
/** Show line numbers in the editor (default false — prose reads better without). */
|
|
198
|
+
lineNumbers?: boolean;
|
|
199
|
+
/** Wrap long lines in the editor (default true for prose). */
|
|
200
|
+
wordWrap?: boolean;
|
|
201
|
+
/** Placeholder shown when empty. */
|
|
202
|
+
placeholder?: string;
|
|
203
|
+
/** Editor height bounds (px). */
|
|
204
|
+
minHeight?: number;
|
|
205
|
+
maxHeight?: number;
|
|
206
|
+
className?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Swap the markdown → HTML renderer used by the preview pane (e.g. a full
|
|
209
|
+
* CommonMark library). Defaults to the built-in lightweight renderer.
|
|
210
|
+
*/
|
|
211
|
+
renderPreview?: (markdown: string) => string;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* A markdown-aware editor: a syntax-highlighted `CodeEditor` (the registered
|
|
215
|
+
* `markdown` language) with an optional live preview pane. Controlled via
|
|
216
|
+
* `value` + `onValueChange`. The preview renders with a small built-in
|
|
217
|
+
* dependency-free renderer; pass `renderPreview` to use your own.
|
|
218
|
+
*
|
|
219
|
+
* ```tsx
|
|
220
|
+
* <MarkdownEditor value={md} onValueChange={setMd} mode="split" minHeight={240} />
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
declare function MarkdownEditor({ value, defaultValue, onValueChange, mode, theme, readOnly, lineNumbers, wordWrap, placeholder, minHeight, maxHeight, className, renderPreview, }: MarkdownEditorProps): react.JSX.Element;
|
|
224
|
+
declare namespace MarkdownEditor {
|
|
225
|
+
var displayName: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Tiny, dependency-free Markdown → HTML renderer for the MarkdownEditor preview
|
|
230
|
+
* pane. Covers the common subset — headings, bold/italic, inline + fenced code,
|
|
231
|
+
* links, images, blockquotes, ordered/unordered lists, hr, and paragraphs. Input
|
|
232
|
+
* is HTML-escaped first, so raw HTML in the source is shown as text (safe by
|
|
233
|
+
* default). Not a full CommonMark implementation; swap in a real renderer
|
|
234
|
+
* downstream if you need one.
|
|
235
|
+
*/
|
|
236
|
+
declare function renderMarkdown(markdown: string): string;
|
|
237
|
+
|
|
180
238
|
type TokenType = "keyword" | "string" | "comment" | "number" | "operator" | "tag" | "attribute" | "attributeValue" | "punctuation" | "function" | "type" | "variable" | "plain";
|
|
181
239
|
interface Token {
|
|
182
240
|
type: TokenType;
|
|
@@ -185,6 +243,14 @@ interface Token {
|
|
|
185
243
|
}
|
|
186
244
|
type Tokenizer = (source: string) => Token[];
|
|
187
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Minimal, dependency-free Markdown tokenizer for editor highlighting. Line-based
|
|
248
|
+
* for block constructs (fences, headings, blockquotes, list markers) plus a few
|
|
249
|
+
* safe, non-overlapping inline spans (code, bold/italic, links). Good enough to
|
|
250
|
+
* read structure at a glance — not a full CommonMark parse.
|
|
251
|
+
*/
|
|
252
|
+
declare function tokenizeMarkdown(source: string): Token[];
|
|
253
|
+
|
|
188
254
|
interface LanguageDefinition {
|
|
189
255
|
/** Display name shown in UI (e.g., "JavaScript") */
|
|
190
256
|
name: string;
|
|
@@ -243,4 +309,4 @@ interface CodeEditorInputTagProps extends Omit<InputTagProps, "adapter"> {
|
|
|
243
309
|
*/
|
|
244
310
|
declare function CodeEditorInputTag(props: CodeEditorInputTagProps): react.JSX.Element;
|
|
245
311
|
|
|
246
|
-
export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type LanguageDefinition, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, registerLanguage, registerTheme, useCodeEditor, useCodeEditorInputTagAdapter };
|
|
312
|
+
export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type LanguageDefinition, MarkdownEditor, type MarkdownEditorMode, type MarkdownEditorProps, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, registerLanguage, registerTheme, renderMarkdown, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
|
package/dist/index.d.ts
CHANGED
|
@@ -177,6 +177,64 @@ declare const CodeEditor: typeof CodeEditorRoot & {
|
|
|
177
177
|
|
|
178
178
|
declare function useCodeEditor(): CodeEditorContextValue;
|
|
179
179
|
|
|
180
|
+
type MarkdownEditorMode = "split" | "edit" | "preview";
|
|
181
|
+
interface MarkdownEditorProps {
|
|
182
|
+
/** Controlled markdown value. */
|
|
183
|
+
value?: string;
|
|
184
|
+
/** Initial value (uncontrolled). */
|
|
185
|
+
defaultValue?: string;
|
|
186
|
+
/** Called with the new markdown whenever the document changes. */
|
|
187
|
+
onValueChange?: (markdown: string) => void;
|
|
188
|
+
/**
|
|
189
|
+
* Layout: `split` (editor + live preview side by side), `edit` (editor only),
|
|
190
|
+
* or `preview` (rendered only). Default `split`.
|
|
191
|
+
*/
|
|
192
|
+
mode?: MarkdownEditorMode;
|
|
193
|
+
/** Editor theme — `"light" | "dark" | "auto"` or a registered name. Default `auto`. */
|
|
194
|
+
theme?: string;
|
|
195
|
+
/** Prevent editing. */
|
|
196
|
+
readOnly?: boolean;
|
|
197
|
+
/** Show line numbers in the editor (default false — prose reads better without). */
|
|
198
|
+
lineNumbers?: boolean;
|
|
199
|
+
/** Wrap long lines in the editor (default true for prose). */
|
|
200
|
+
wordWrap?: boolean;
|
|
201
|
+
/** Placeholder shown when empty. */
|
|
202
|
+
placeholder?: string;
|
|
203
|
+
/** Editor height bounds (px). */
|
|
204
|
+
minHeight?: number;
|
|
205
|
+
maxHeight?: number;
|
|
206
|
+
className?: string;
|
|
207
|
+
/**
|
|
208
|
+
* Swap the markdown → HTML renderer used by the preview pane (e.g. a full
|
|
209
|
+
* CommonMark library). Defaults to the built-in lightweight renderer.
|
|
210
|
+
*/
|
|
211
|
+
renderPreview?: (markdown: string) => string;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* A markdown-aware editor: a syntax-highlighted `CodeEditor` (the registered
|
|
215
|
+
* `markdown` language) with an optional live preview pane. Controlled via
|
|
216
|
+
* `value` + `onValueChange`. The preview renders with a small built-in
|
|
217
|
+
* dependency-free renderer; pass `renderPreview` to use your own.
|
|
218
|
+
*
|
|
219
|
+
* ```tsx
|
|
220
|
+
* <MarkdownEditor value={md} onValueChange={setMd} mode="split" minHeight={240} />
|
|
221
|
+
* ```
|
|
222
|
+
*/
|
|
223
|
+
declare function MarkdownEditor({ value, defaultValue, onValueChange, mode, theme, readOnly, lineNumbers, wordWrap, placeholder, minHeight, maxHeight, className, renderPreview, }: MarkdownEditorProps): react.JSX.Element;
|
|
224
|
+
declare namespace MarkdownEditor {
|
|
225
|
+
var displayName: string;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Tiny, dependency-free Markdown → HTML renderer for the MarkdownEditor preview
|
|
230
|
+
* pane. Covers the common subset — headings, bold/italic, inline + fenced code,
|
|
231
|
+
* links, images, blockquotes, ordered/unordered lists, hr, and paragraphs. Input
|
|
232
|
+
* is HTML-escaped first, so raw HTML in the source is shown as text (safe by
|
|
233
|
+
* default). Not a full CommonMark implementation; swap in a real renderer
|
|
234
|
+
* downstream if you need one.
|
|
235
|
+
*/
|
|
236
|
+
declare function renderMarkdown(markdown: string): string;
|
|
237
|
+
|
|
180
238
|
type TokenType = "keyword" | "string" | "comment" | "number" | "operator" | "tag" | "attribute" | "attributeValue" | "punctuation" | "function" | "type" | "variable" | "plain";
|
|
181
239
|
interface Token {
|
|
182
240
|
type: TokenType;
|
|
@@ -185,6 +243,14 @@ interface Token {
|
|
|
185
243
|
}
|
|
186
244
|
type Tokenizer = (source: string) => Token[];
|
|
187
245
|
|
|
246
|
+
/**
|
|
247
|
+
* Minimal, dependency-free Markdown tokenizer for editor highlighting. Line-based
|
|
248
|
+
* for block constructs (fences, headings, blockquotes, list markers) plus a few
|
|
249
|
+
* safe, non-overlapping inline spans (code, bold/italic, links). Good enough to
|
|
250
|
+
* read structure at a glance — not a full CommonMark parse.
|
|
251
|
+
*/
|
|
252
|
+
declare function tokenizeMarkdown(source: string): Token[];
|
|
253
|
+
|
|
188
254
|
interface LanguageDefinition {
|
|
189
255
|
/** Display name shown in UI (e.g., "JavaScript") */
|
|
190
256
|
name: string;
|
|
@@ -243,4 +309,4 @@ interface CodeEditorInputTagProps extends Omit<InputTagProps, "adapter"> {
|
|
|
243
309
|
*/
|
|
244
310
|
declare function CodeEditorInputTag(props: CodeEditorInputTagProps): react.JSX.Element;
|
|
245
311
|
|
|
246
|
-
export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type LanguageDefinition, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, registerLanguage, registerTheme, useCodeEditor, useCodeEditorInputTagAdapter };
|
|
312
|
+
export { CodeEditor, type CodeEditorContextValue, CodeEditorInputTag, type CodeEditorInputTagProps, type CodeEditorPanelProps, type CodeEditorProps, type CodeEditorStatusBarProps, type CodeEditorToolbarProps, type LanguageDefinition, MarkdownEditor, type MarkdownEditorMode, type MarkdownEditorProps, type ThemeColors, type ThemeDefinition, type Token, type TokenType, type Tokenizer, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, registerLanguage, registerTheme, renderMarkdown, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
|
package/dist/index.js
CHANGED
|
@@ -1035,7 +1035,79 @@ var tokenizeGo = (source) => {
|
|
|
1035
1035
|
return tokens;
|
|
1036
1036
|
};
|
|
1037
1037
|
|
|
1038
|
+
// src/engine/tokenizer.ts
|
|
1039
|
+
function tok(type, s, e) {
|
|
1040
|
+
return { type, start: s, end: e };
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
// src/engine/tokenizers/markdown.ts
|
|
1044
|
+
function tokenizeMarkdown(source) {
|
|
1045
|
+
const tokens = [];
|
|
1046
|
+
const lines = source.split("\n");
|
|
1047
|
+
let offset = 0;
|
|
1048
|
+
let inFence = false;
|
|
1049
|
+
for (const line of lines) {
|
|
1050
|
+
const base = offset;
|
|
1051
|
+
const len = line.length;
|
|
1052
|
+
offset += len + 1;
|
|
1053
|
+
if (/^\s*(```|~~~)/.test(line)) {
|
|
1054
|
+
tokens.push(tok("string", base, base + len));
|
|
1055
|
+
inFence = !inFence;
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
if (inFence) {
|
|
1059
|
+
tokens.push(tok("string", base, base + len));
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
if (/^#{1,6}\s/.test(line)) {
|
|
1063
|
+
tokens.push(tok("keyword", base, base + len));
|
|
1064
|
+
continue;
|
|
1065
|
+
}
|
|
1066
|
+
if (/^\s*>/.test(line)) {
|
|
1067
|
+
tokens.push(tok("comment", base, base + len));
|
|
1068
|
+
continue;
|
|
1069
|
+
}
|
|
1070
|
+
const list = line.match(/^(\s*)([-*+]|\d+\.)\s/);
|
|
1071
|
+
if (list) {
|
|
1072
|
+
const start = base + list[1].length;
|
|
1073
|
+
tokens.push(tok("operator", start, start + list[2].length));
|
|
1074
|
+
}
|
|
1075
|
+
pushInline(line, base, tokens);
|
|
1076
|
+
}
|
|
1077
|
+
return tokens;
|
|
1078
|
+
}
|
|
1079
|
+
function pushInline(line, base, out) {
|
|
1080
|
+
const spans = [];
|
|
1081
|
+
const add = (type, start, end) => {
|
|
1082
|
+
spans.push(tok(type, base + start, base + end));
|
|
1083
|
+
};
|
|
1084
|
+
let m;
|
|
1085
|
+
const code = /`[^`]+`/g;
|
|
1086
|
+
while (m = code.exec(line)) add("string", m.index, m.index + m[0].length);
|
|
1087
|
+
const emph = /(\*\*|__)(?=\S)([\s\S]*?\S)\1|(\*|_)(?=\S)([\s\S]*?\S)\3/g;
|
|
1088
|
+
while (m = emph.exec(line)) add("type", m.index, m.index + m[0].length);
|
|
1089
|
+
const link = /!?\[[^\]]*\]\(([^)]+)\)/g;
|
|
1090
|
+
while (m = link.exec(line)) {
|
|
1091
|
+
add("tag", m.index, m.index + m[0].length - m[1].length - 1);
|
|
1092
|
+
const urlStart = m.index + m[0].length - m[1].length - 1;
|
|
1093
|
+
add("attributeValue", urlStart, urlStart + m[1].length);
|
|
1094
|
+
}
|
|
1095
|
+
spans.sort((a, b) => a.start - b.start || b.end - a.end);
|
|
1096
|
+
let lastEnd = -1;
|
|
1097
|
+
for (const s of spans) {
|
|
1098
|
+
if (s.start >= lastEnd) {
|
|
1099
|
+
out.push(s);
|
|
1100
|
+
lastEnd = s.end;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1038
1105
|
// src/languages/builtin.ts
|
|
1106
|
+
registerLanguage({
|
|
1107
|
+
name: "Markdown",
|
|
1108
|
+
aliases: ["md", "markdown", "mkd"],
|
|
1109
|
+
tokenize: tokenizeMarkdown
|
|
1110
|
+
});
|
|
1039
1111
|
registerLanguage({
|
|
1040
1112
|
name: "JavaScript",
|
|
1041
1113
|
aliases: ["js", "javascript", "jsx"],
|
|
@@ -1605,6 +1677,156 @@ var CodeEditor = Object.assign(CodeEditorRoot, {
|
|
|
1605
1677
|
Panel: CodeEditorPanel,
|
|
1606
1678
|
StatusBar: CodeEditorStatusBar
|
|
1607
1679
|
});
|
|
1680
|
+
|
|
1681
|
+
// src/engine/markdown-render.ts
|
|
1682
|
+
function escapeHtml2(s) {
|
|
1683
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
1684
|
+
}
|
|
1685
|
+
function inline(text) {
|
|
1686
|
+
return text.replace(/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g, (_m, alt, src, title) => `<img src="${src}" alt="${alt}"${title ? ` title="${title}"` : ""}>`).replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"([^"]*)")?\)/g, (_m, t, href, title) => `<a href="${href}"${title ? ` title="${title}"` : ""} rel="noopener">${t}</a>`).replace(/`([^`]+)`/g, (_m, c) => `<code>${c}</code>`).replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g, "<strong>$2</strong>").replace(/(\*|_)(?=\S)([\s\S]*?\S)\1/g, "<em>$2</em>");
|
|
1687
|
+
}
|
|
1688
|
+
function renderMarkdown(markdown) {
|
|
1689
|
+
const lines = markdown.replace(/\r\n?/g, "\n").split("\n");
|
|
1690
|
+
const out = [];
|
|
1691
|
+
let i = 0;
|
|
1692
|
+
let para = [];
|
|
1693
|
+
let listType = null;
|
|
1694
|
+
const flushPara = () => {
|
|
1695
|
+
if (para.length) {
|
|
1696
|
+
out.push(`<p>${inline(para.join(" "))}</p>`);
|
|
1697
|
+
para = [];
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
const closeList = () => {
|
|
1701
|
+
if (listType) {
|
|
1702
|
+
out.push(`</${listType}>`);
|
|
1703
|
+
listType = null;
|
|
1704
|
+
}
|
|
1705
|
+
};
|
|
1706
|
+
while (i < lines.length) {
|
|
1707
|
+
const line = lines[i];
|
|
1708
|
+
const fence = line.match(/^\s*(```|~~~)(.*)$/);
|
|
1709
|
+
if (fence) {
|
|
1710
|
+
flushPara();
|
|
1711
|
+
closeList();
|
|
1712
|
+
const lang = fence[2].trim();
|
|
1713
|
+
const body = [];
|
|
1714
|
+
i++;
|
|
1715
|
+
while (i < lines.length && !/^\s*(```|~~~)/.test(lines[i])) {
|
|
1716
|
+
body.push(lines[i]);
|
|
1717
|
+
i++;
|
|
1718
|
+
}
|
|
1719
|
+
i++;
|
|
1720
|
+
out.push(`<pre><code${lang ? ` class="language-${escapeHtml2(lang)}"` : ""}>${escapeHtml2(body.join("\n"))}</code></pre>`);
|
|
1721
|
+
continue;
|
|
1722
|
+
}
|
|
1723
|
+
const esc = escapeHtml2(line);
|
|
1724
|
+
if (/^\s*$/.test(line)) {
|
|
1725
|
+
flushPara();
|
|
1726
|
+
closeList();
|
|
1727
|
+
i++;
|
|
1728
|
+
continue;
|
|
1729
|
+
}
|
|
1730
|
+
const heading = esc.match(/^(#{1,6})\s+(.*)$/);
|
|
1731
|
+
if (heading) {
|
|
1732
|
+
flushPara();
|
|
1733
|
+
closeList();
|
|
1734
|
+
const level = heading[1].length;
|
|
1735
|
+
out.push(`<h${level}>${inline(heading[2])}</h${level}>`);
|
|
1736
|
+
i++;
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
if (/^\s*([-*_])(\s*\1){2,}\s*$/.test(line)) {
|
|
1740
|
+
flushPara();
|
|
1741
|
+
closeList();
|
|
1742
|
+
out.push("<hr>");
|
|
1743
|
+
i++;
|
|
1744
|
+
continue;
|
|
1745
|
+
}
|
|
1746
|
+
const quote = esc.match(/^\s*>\s?(.*)$/);
|
|
1747
|
+
if (quote) {
|
|
1748
|
+
flushPara();
|
|
1749
|
+
closeList();
|
|
1750
|
+
out.push(`<blockquote>${inline(quote[1])}</blockquote>`);
|
|
1751
|
+
i++;
|
|
1752
|
+
continue;
|
|
1753
|
+
}
|
|
1754
|
+
const ol = esc.match(/^\s*\d+\.\s+(.*)$/);
|
|
1755
|
+
const ul = esc.match(/^\s*[-*+]\s+(.*)$/);
|
|
1756
|
+
if (ol || ul) {
|
|
1757
|
+
flushPara();
|
|
1758
|
+
const type = ol ? "ol" : "ul";
|
|
1759
|
+
if (listType !== type) {
|
|
1760
|
+
closeList();
|
|
1761
|
+
out.push(`<${type}>`);
|
|
1762
|
+
listType = type;
|
|
1763
|
+
}
|
|
1764
|
+
out.push(`<li>${inline((ol ?? ul)[1])}</li>`);
|
|
1765
|
+
i++;
|
|
1766
|
+
continue;
|
|
1767
|
+
}
|
|
1768
|
+
closeList();
|
|
1769
|
+
para.push(esc);
|
|
1770
|
+
i++;
|
|
1771
|
+
}
|
|
1772
|
+
flushPara();
|
|
1773
|
+
closeList();
|
|
1774
|
+
return out.join("\n");
|
|
1775
|
+
}
|
|
1776
|
+
function MarkdownEditor({
|
|
1777
|
+
value,
|
|
1778
|
+
defaultValue = "",
|
|
1779
|
+
onValueChange,
|
|
1780
|
+
mode = "split",
|
|
1781
|
+
theme = "auto",
|
|
1782
|
+
readOnly = false,
|
|
1783
|
+
lineNumbers = false,
|
|
1784
|
+
wordWrap = true,
|
|
1785
|
+
placeholder,
|
|
1786
|
+
minHeight,
|
|
1787
|
+
maxHeight,
|
|
1788
|
+
className,
|
|
1789
|
+
renderPreview = renderMarkdown
|
|
1790
|
+
}) {
|
|
1791
|
+
const [content, setContent] = useControllableState(value, defaultValue, onValueChange);
|
|
1792
|
+
const showEditor = mode !== "preview";
|
|
1793
|
+
const showPreview = mode !== "edit";
|
|
1794
|
+
return /* @__PURE__ */ jsxs(
|
|
1795
|
+
"div",
|
|
1796
|
+
{
|
|
1797
|
+
"data-fancy-markdown-editor": "",
|
|
1798
|
+
"data-mode": mode,
|
|
1799
|
+
className: cn("fancy-md-editor", className),
|
|
1800
|
+
children: [
|
|
1801
|
+
showEditor && /* @__PURE__ */ jsx("div", { className: "fancy-md-editor-pane", children: /* @__PURE__ */ jsx(
|
|
1802
|
+
CodeEditor,
|
|
1803
|
+
{
|
|
1804
|
+
value: content,
|
|
1805
|
+
onChange: setContent,
|
|
1806
|
+
language: "markdown",
|
|
1807
|
+
theme,
|
|
1808
|
+
readOnly,
|
|
1809
|
+
lineNumbers,
|
|
1810
|
+
wordWrap,
|
|
1811
|
+
placeholder,
|
|
1812
|
+
minHeight,
|
|
1813
|
+
maxHeight,
|
|
1814
|
+
children: /* @__PURE__ */ jsx(CodeEditor.Panel, {})
|
|
1815
|
+
}
|
|
1816
|
+
) }),
|
|
1817
|
+
showPreview && /* @__PURE__ */ jsx(
|
|
1818
|
+
"div",
|
|
1819
|
+
{
|
|
1820
|
+
"data-fancy-markdown-preview": "",
|
|
1821
|
+
className: "fancy-md-preview",
|
|
1822
|
+
dangerouslySetInnerHTML: { __html: renderPreview(content) }
|
|
1823
|
+
}
|
|
1824
|
+
)
|
|
1825
|
+
]
|
|
1826
|
+
}
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
MarkdownEditor.displayName = "MarkdownEditor";
|
|
1608
1830
|
function useCodeEditorInputTagAdapter() {
|
|
1609
1831
|
const ctx = useCodeEditor();
|
|
1610
1832
|
return useMemo(() => textareaAdapter(ctx.textareaRef), [ctx.textareaRef]);
|
|
@@ -1614,6 +1836,6 @@ function CodeEditorInputTag(props) {
|
|
|
1614
1836
|
return /* @__PURE__ */ jsx(InputTag, { adapter, ...props });
|
|
1615
1837
|
}
|
|
1616
1838
|
|
|
1617
|
-
export { CodeEditor, CodeEditorInputTag, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, registerLanguage, registerTheme, useCodeEditor, useCodeEditorInputTagAdapter };
|
|
1839
|
+
export { CodeEditor, CodeEditorInputTag, MarkdownEditor, getLanguage, getRegisteredLanguages, getRegisteredThemes, getTheme, registerLanguage, registerTheme, renderMarkdown, tokenizeMarkdown, useCodeEditor, useCodeEditorInputTagAdapter };
|
|
1618
1840
|
//# sourceMappingURL=index.js.map
|
|
1619
1841
|
//# sourceMappingURL=index.js.map
|