mdsquare 0.0.0-stage → 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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +218 -2
  3. package/dist/callout.d.ts +17 -0
  4. package/dist/callout.js +541 -0
  5. package/dist/calloutHeader.d.ts +47 -0
  6. package/dist/calloutHeader.js +75 -0
  7. package/dist/codeBlock.d.ts +78 -0
  8. package/dist/codeBlock.js +686 -0
  9. package/dist/codeTheme.d.ts +47 -0
  10. package/dist/codeTheme.js +394 -0
  11. package/dist/delimiter.d.ts +20 -0
  12. package/dist/delimiter.js +73 -0
  13. package/dist/editor.d.ts +132 -0
  14. package/dist/editor.js +225 -0
  15. package/dist/emphasis.d.ts +6 -0
  16. package/dist/emphasis.js +101 -0
  17. package/dist/escape.d.ts +4 -0
  18. package/dist/escape.js +39 -0
  19. package/dist/extensions.d.ts +74 -0
  20. package/dist/extensions.js +81 -0
  21. package/dist/footnote.d.ts +24 -0
  22. package/dist/footnote.js +456 -0
  23. package/dist/footnoteSyntax.d.ts +23 -0
  24. package/dist/footnoteSyntax.js +107 -0
  25. package/dist/hashtag.d.ts +4 -0
  26. package/dist/hashtag.js +64 -0
  27. package/dist/hashtagSyntax.d.ts +36 -0
  28. package/dist/hashtagSyntax.js +99 -0
  29. package/dist/heading.d.ts +7 -0
  30. package/dist/heading.js +159 -0
  31. package/dist/highlight.d.ts +5 -0
  32. package/dist/highlight.js +6 -0
  33. package/dist/horizontalRule.d.ts +21 -0
  34. package/dist/horizontalRule.js +142 -0
  35. package/dist/image.d.ts +58 -0
  36. package/dist/image.js +344 -0
  37. package/dist/index.d.ts +16 -0
  38. package/dist/index.js +16 -0
  39. package/dist/inlineCode.d.ts +4 -0
  40. package/dist/inlineCode.js +68 -0
  41. package/dist/link.d.ts +47 -0
  42. package/dist/link.js +217 -0
  43. package/dist/list.d.ts +14 -0
  44. package/dist/list.js +136 -0
  45. package/dist/listEnter.d.ts +20 -0
  46. package/dist/listEnter.js +72 -0
  47. package/dist/listIndent.d.ts +23 -0
  48. package/dist/listIndent.js +335 -0
  49. package/dist/markVision.d.ts +17 -0
  50. package/dist/markVision.js +56 -0
  51. package/dist/math.d.ts +45 -0
  52. package/dist/math.js +233 -0
  53. package/dist/mathSyntax.d.ts +24 -0
  54. package/dist/mathSyntax.js +179 -0
  55. package/dist/mention.d.ts +4 -0
  56. package/dist/mention.js +58 -0
  57. package/dist/mentionSyntax.d.ts +14 -0
  58. package/dist/mentionSyntax.js +71 -0
  59. package/dist/quote.d.ts +9 -0
  60. package/dist/quote.js +122 -0
  61. package/dist/setup.d.ts +13 -0
  62. package/dist/setup.js +40 -0
  63. package/dist/style.css +6 -0
  64. package/dist/style.css.d.ts +2 -0
  65. package/dist/table.d.ts +38 -0
  66. package/dist/table.js +960 -0
  67. package/dist/tableEdit.d.ts +30 -0
  68. package/dist/tableEdit.js +305 -0
  69. package/dist/tableMenu.d.ts +65 -0
  70. package/dist/tableMenu.js +1125 -0
  71. package/dist/tableModel.d.ts +168 -0
  72. package/dist/tableModel.js +433 -0
  73. package/dist/tableState.d.ts +36 -0
  74. package/dist/tableState.js +96 -0
  75. package/dist/task.d.ts +13 -0
  76. package/dist/task.js +179 -0
  77. package/dist/textMate.d.ts +49 -0
  78. package/dist/textMate.js +284 -0
  79. package/dist/tikz.d.ts +56 -0
  80. package/dist/tikz.js +343 -0
  81. package/dist/underline.d.ts +5 -0
  82. package/dist/underline.js +6 -0
  83. package/dist/utils/blockMargin.d.ts +6 -0
  84. package/dist/utils/blockMargin.js +6 -0
  85. package/dist/utils/codePoint.d.ts +13 -0
  86. package/dist/utils/codePoint.js +43 -0
  87. package/dist/utils/container.d.ts +10 -0
  88. package/dist/utils/container.js +10 -0
  89. package/dist/utils/reveal.d.ts +99 -0
  90. package/dist/utils/reveal.js +161 -0
  91. package/dist/utils/selection.d.ts +33 -0
  92. package/dist/utils/selection.js +45 -0
  93. package/dist/utils/syntaxTree.d.ts +18 -0
  94. package/dist/utils/syntaxTree.js +23 -0
  95. package/package.json +79 -4
package/dist/editor.js ADDED
@@ -0,0 +1,225 @@
1
+ import { LanguageDescription } from "@codemirror/language";
2
+ import { languages as languageData } from "@codemirror/language-data";
3
+ import { Compartment, EditorState } from "@codemirror/state";
4
+ import { EditorView, placeholder as placeholderExtension } from "@codemirror/view";
5
+ import { callout } from "./callout.js";
6
+ import { codeBlock } from "./codeBlock.js";
7
+ import { emphasis } from "./emphasis.js";
8
+ import { escape } from "./escape.js";
9
+ import { extendedMarkdown } from "./extensions.js";
10
+ import { footnote } from "./footnote.js";
11
+ import { hashtag } from "./hashtag.js";
12
+ import { heading } from "./heading.js";
13
+ import { horizontalRule } from "./horizontalRule.js";
14
+ import { image } from "./image.js";
15
+ import { inlineCode } from "./inlineCode.js";
16
+ import { link } from "./link.js";
17
+ import { list } from "./list.js";
18
+ import { listIndent } from "./listIndent.js";
19
+ import { markVision } from "./markVision.js";
20
+ import { math } from "./math.js";
21
+ import { mention } from "./mention.js";
22
+ import { quote } from "./quote.js";
23
+ import { basicSetup } from "./setup.js";
24
+ import { table } from "./table.js";
25
+ import { task } from "./task.js";
26
+ import { tikz, tikzjaxRenderer } from "./tikz.js";
27
+ // ---------------------------------------------------------------------------
28
+ // 테마
29
+ // ---------------------------------------------------------------------------
30
+ const lightTheme = EditorView.theme({
31
+ "&": { color: "#1f2328", backgroundColor: "#ffffff" },
32
+ ".cm-content": { caretColor: "#1f2328" },
33
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "#1f2328" },
34
+ "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { backgroundColor: "#cfe3ff" },
35
+ ".cm-gutters": { backgroundColor: "#ffffff", color: "#8c959f", border: "none" },
36
+ ".cm-activeLineGutter": { backgroundColor: "#f3f4f6" },
37
+ }, { dark: false });
38
+ const darkTheme = EditorView.theme({
39
+ "&": { color: "#d4d4d4", backgroundColor: "#1e1e1e" },
40
+ ".cm-content": { caretColor: "#e5e5e5" },
41
+ ".cm-cursor, .cm-dropCursor": { borderLeftColor: "#e5e5e5" },
42
+ "&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": { backgroundColor: "#264f78" },
43
+ ".cm-gutters": { backgroundColor: "#1e1e1e", color: "#6e7681", border: "none" },
44
+ ".cm-activeLineGutter": { backgroundColor: "#2a2d2e" },
45
+ ".cm-panels": { backgroundColor: "#252526", color: "#d4d4d4" },
46
+ }, { dark: true });
47
+ const darkQuery = "(prefers-color-scheme: dark)";
48
+ const prefersDark = () => typeof matchMedia === "function" && matchMedia(darkQuery).matches;
49
+ // ---------------------------------------------------------------------------
50
+ // 에디터
51
+ // ---------------------------------------------------------------------------
52
+ /** codeBlock 옵션의 기본 언어: language-data (쓸 때 불러옴). tikz 블록은 LaTeX로 강조 */
53
+ const defaultLanguages = (lang) => LanguageDescription.matchLanguageName(languageData, lang === "tikz" ? "latex" : lang, true);
54
+ /**
55
+ * 하이브리드 마크다운 에디터 (CodeMirror 6 기반).
56
+ *
57
+ * ```ts
58
+ * import MDSquareEditor from "mdsquare";
59
+ * import "mdsquare/style.css";
60
+ *
61
+ * const editor = new MDSquareEditor({ parent: document.getElementById("editor")!, value: "# 안녕하세요" });
62
+ * editor.getValue();
63
+ * ```
64
+ */
65
+ export class MDSquareEditor {
66
+ /** CodeMirror 뷰 (확장을 직접 다룰 때) */
67
+ view;
68
+ themeSlot = new Compartment();
69
+ readOnlySlot = new Compartment();
70
+ theme;
71
+ media = null;
72
+ onMediaChange = () => this.applyTheme();
73
+ /** 옵션으로 정해지는 확장들. 파일을 새로 열 때도 같은 것을 써서 렌더링 캐시(수식, TikZ 등)를 이어 씁니다. */
74
+ extensions;
75
+ readOnly;
76
+ constructor(options = {}) {
77
+ this.theme = options.theme ?? "auto";
78
+ this.readOnly = options.readOnly ?? false;
79
+ const onChange = options.onChange;
80
+ this.extensions = [
81
+ basicSetup({ lineNumbers: options.lineNumbers ?? false }),
82
+ EditorView.lineWrapping,
83
+ options.placeholder ? placeholderExtension(options.placeholder) : [],
84
+ markdownExtensions(options),
85
+ onChange
86
+ ? EditorView.updateListener.of((update) => {
87
+ if (update.docChanged)
88
+ onChange(update.state.doc.toString(), this);
89
+ })
90
+ : [],
91
+ options.extensions ?? [],
92
+ ];
93
+ this.view = new EditorView({ state: this.createState(options.value ?? ""), parent: options.parent });
94
+ this.watchSystemTheme();
95
+ }
96
+ /** 지금 설정(테마, 읽기 전용)으로 새 상태를 만듭니다. */
97
+ createState(doc) {
98
+ return EditorState.create({
99
+ doc,
100
+ extensions: [
101
+ this.themeSlot.of(this.themeExtension()),
102
+ this.readOnlySlot.of(readOnlyExtension(this.readOnly)),
103
+ this.extensions,
104
+ ],
105
+ });
106
+ }
107
+ /** 에디터 바깥 요소 (`.cm-editor`) */
108
+ get dom() {
109
+ return this.view.dom;
110
+ }
111
+ /** 지금 문서 (마크다운) */
112
+ getValue() {
113
+ return this.view.state.doc.toString();
114
+ }
115
+ /**
116
+ * 다른 파일(문서)을 엽니다. 처음 연 것처럼 새로 시작합니다.
117
+ * - 실행 취소 기록을 새로 시작합니다. (Ctrl+Z로 이전 파일 내용으로 돌아가지 않음)
118
+ * - onChange를 부르지 않습니다. (방금 연 파일을 바로 저장하지 않음)
119
+ * - 커서는 문서 처음, 스크롤은 맨 위. 접기·열린 메뉴 등 화면 상태도 초기화합니다.
120
+ * - 테마, 읽기 전용 등 설정은 그대로입니다.
121
+ *
122
+ * 같은 문서 안에서 내용을 바꾸는 것(실행 취소할 수 있어야 하는 편집)은 setValue를 쓰세요.
123
+ */
124
+ open(value) {
125
+ this.view.setState(this.createState(value));
126
+ this.view.scrollDOM.scrollTop = 0;
127
+ this.view.scrollDOM.scrollLeft = 0;
128
+ }
129
+ /**
130
+ * 지금 문서의 내용을 바꿉니다. 편집처럼 다뤄 실행 취소할 수 있고 onChange도 호출됩니다. 커서는 문서 처음으로.
131
+ * 다른 파일을 여는 것이라면 open을 쓰세요.
132
+ */
133
+ setValue(value) {
134
+ this.view.dispatch({
135
+ changes: { from: 0, to: this.view.state.doc.length, insert: value },
136
+ selection: { anchor: 0 },
137
+ });
138
+ }
139
+ focus() {
140
+ this.view.focus();
141
+ }
142
+ /** 테마 바꾸기 ("auto": 시스템 설정을 따르고, 설정이 바뀌면 함께 바뀜) */
143
+ setTheme(theme) {
144
+ this.theme = theme;
145
+ this.watchSystemTheme();
146
+ this.applyTheme();
147
+ }
148
+ setReadOnly(readOnly) {
149
+ this.readOnly = readOnly;
150
+ this.view.dispatch({ effects: this.readOnlySlot.reconfigure(readOnlyExtension(readOnly)) });
151
+ }
152
+ /** 에디터를 없애고 이벤트를 정리합니다. */
153
+ destroy() {
154
+ this.media?.removeEventListener("change", this.onMediaChange);
155
+ this.media = null;
156
+ this.view.destroy();
157
+ }
158
+ themeExtension() {
159
+ const dark = this.theme === "dark" || (this.theme === "auto" && prefersDark());
160
+ return dark ? darkTheme : lightTheme;
161
+ }
162
+ applyTheme() {
163
+ this.view.dispatch({ effects: this.themeSlot.reconfigure(this.themeExtension()) });
164
+ }
165
+ watchSystemTheme() {
166
+ const wanted = this.theme === "auto" && typeof matchMedia === "function";
167
+ if (wanted && !this.media) {
168
+ this.media = matchMedia(darkQuery);
169
+ this.media.addEventListener("change", this.onMediaChange);
170
+ }
171
+ else if (!wanted && this.media) {
172
+ this.media.removeEventListener("change", this.onMediaChange);
173
+ this.media = null;
174
+ }
175
+ }
176
+ }
177
+ function readOnlyExtension(readOnly) {
178
+ return [EditorState.readOnly.of(readOnly), EditorView.editable.of(!readOnly)];
179
+ }
180
+ /** 옵션에 따라 마크다운 확장들을 고릅니다. */
181
+ export function markdownExtensions(options = {}) {
182
+ const on = (name) => options.features?.[name] ?? true;
183
+ const out = [extendedMarkdown(options.markdown), markVision()];
184
+ if (on("emphasis"))
185
+ out.push(emphasis());
186
+ if (on("heading"))
187
+ out.push(heading());
188
+ if (on("hashtag"))
189
+ out.push(hashtag());
190
+ if (on("escape"))
191
+ out.push(escape());
192
+ if (on("inlineCode"))
193
+ out.push(inlineCode());
194
+ if (on("mention"))
195
+ out.push(mention());
196
+ if (on("list"))
197
+ out.push(list(), listIndent());
198
+ if (on("task"))
199
+ out.push(task());
200
+ if (on("link"))
201
+ out.push(link(options.link));
202
+ if (on("image"))
203
+ out.push(image(options.image));
204
+ if (on("horizontalRule"))
205
+ out.push(horizontalRule());
206
+ if (on("footnote"))
207
+ out.push(footnote());
208
+ // callout()은 quote()를 포함합니다.
209
+ if (on("callout"))
210
+ out.push(callout());
211
+ else if (on("quote"))
212
+ out.push(quote());
213
+ if (on("codeBlock"))
214
+ out.push(codeBlock({ languages: defaultLanguages, ...options.codeBlock }));
215
+ if (on("math"))
216
+ out.push(math(options.math));
217
+ if (on("table"))
218
+ out.push(table());
219
+ if (options.tikz) {
220
+ const { tikzjax, render, ...rest } = options.tikz;
221
+ out.push(tikz({ ...rest, render: render ?? tikzjaxRenderer(tikzjax) }));
222
+ }
223
+ return out;
224
+ }
225
+ export default MDSquareEditor;
@@ -0,0 +1,6 @@
1
+ import type { Extension } from "@codemirror/state";
2
+ export declare const emphasisPlugin: import("@codemirror/view").ViewPlugin<import("./extensions.js").RevealPluginValue, undefined>;
3
+ /**
4
+ * 강조 문법(*, **, ~~, ==, --)의 기호를 커서가 해당 문법에 닿아 있을 때만 보여주는 확장입니다.
5
+ */
6
+ export declare function emphasis(): Extension;
@@ -0,0 +1,101 @@
1
+ import { Decoration, EditorView } from "@codemirror/view";
2
+ import { createRevealPlugin } from "./utils/reveal.js";
3
+ // 데코레이션 객체는 모듈 로드 시 한 번만 만들고 재사용합니다.
4
+ function defineConstruct(className, mark) {
5
+ return {
6
+ mark,
7
+ content: Decoration.mark({ class: `cm-${className}` }),
8
+ formatting: Decoration.mark({
9
+ class: `cm-formatting cm-formatting-${className} cm-${className}`,
10
+ }),
11
+ };
12
+ }
13
+ const CONSTRUCTS = new Map([
14
+ ["Emphasis", defineConstruct("emphasis", "EmphasisMark")], // *, _
15
+ ["StrongEmphasis", defineConstruct("strong-emphasis", "EmphasisMark")], // **, __
16
+ ["Strikethrough", defineConstruct("strikethrough", "StrikethroughMark")], // ~~
17
+ ["Highlight", defineConstruct("highlight", "HighlightMark")], // ==
18
+ ["Underline", defineConstruct("underline", "UnderlineMark")], // --
19
+ ]);
20
+ /** 내부에 강조 문법이 올 수 없으므로 자식 순회를 생략하는 노드 */
21
+ const SKIP_CHILDREN = new Set(["FencedCode", "CodeBlock", "InlineCode"]);
22
+ const hiddenMark = Decoration.replace({});
23
+ export const emphasisPlugin = createRevealPlugin({
24
+ // 내용 데코레이션은 leave에서 추가되어 순서가 섞이므로 정렬합니다.
25
+ sort: true,
26
+ visit({ decorations, isRevealed }) {
27
+ const stack = [];
28
+ return {
29
+ enter(node) {
30
+ const spec = CONSTRUCTS.get(node.name);
31
+ if (spec) {
32
+ stack.push({
33
+ spec,
34
+ from: node.from,
35
+ to: node.to,
36
+ revealed: isRevealed(node.from, node.to),
37
+ contentFrom: node.from,
38
+ contentTo: node.to,
39
+ });
40
+ return;
41
+ }
42
+ const frame = stack[stack.length - 1];
43
+ if (frame && node.name === frame.spec.mark) {
44
+ // 기호 위치는 트리의 Mark 노드에서 그대로 가져옵니다.
45
+ if (node.from === frame.from)
46
+ frame.contentFrom = node.to;
47
+ if (node.to === frame.to)
48
+ frame.contentTo = node.from;
49
+ decorations.push((frame.revealed ? frame.spec.formatting : hiddenMark).range(node.from, node.to));
50
+ return;
51
+ }
52
+ if (SKIP_CHILDREN.has(node.name))
53
+ return false;
54
+ },
55
+ leave(node) {
56
+ if (!CONSTRUCTS.has(node.name))
57
+ return;
58
+ const frame = stack.pop();
59
+ if (frame.contentFrom < frame.contentTo) {
60
+ decorations.push(frame.spec.content.range(frame.contentFrom, frame.contentTo));
61
+ }
62
+ },
63
+ };
64
+ },
65
+ });
66
+ // ---------------------------------------------------------------------------
67
+ // 테마
68
+ // ---------------------------------------------------------------------------
69
+ const highlightTheme = EditorView.baseTheme({
70
+ ".cm-highlight": {
71
+ backgroundColor: "rgba(255, 177, 80, 0.3)",
72
+ },
73
+ ".cm-highlight:has(+ .cm-formatting-highlight)": {
74
+ padding: "1px 0",
75
+ },
76
+ ".cm-highlight:not(.cm-formatting-highlight):not(:has(+ .cm-formatting-highlight))": {
77
+ borderRadius: "2px",
78
+ padding: "1px 4px",
79
+ },
80
+ ".cm-formatting-highlight:has(+ .cm-highlight)": {
81
+ borderTopLeftRadius: "2px",
82
+ borderBottomLeftRadius: "2px",
83
+ padding: "1px 0 1px 4px",
84
+ },
85
+ ".cm-highlight + .cm-formatting-highlight": {
86
+ borderTopRightRadius: "2px",
87
+ borderBottomRightRadius: "2px",
88
+ padding: "1px 4px 1px 0",
89
+ },
90
+ });
91
+ const underlineTheme = EditorView.baseTheme({
92
+ ".cm-underline": {
93
+ textDecoration: "underline",
94
+ },
95
+ });
96
+ /**
97
+ * 강조 문법(*, **, ~~, ==, --)의 기호를 커서가 해당 문법에 닿아 있을 때만 보여주는 확장입니다.
98
+ */
99
+ export function emphasis() {
100
+ return [emphasisPlugin, highlightTheme, underlineTheme];
101
+ }
@@ -0,0 +1,4 @@
1
+ import type { Extension } from "@codemirror/state";
2
+ export declare const escapePlugin: import("@codemirror/view").ViewPlugin<import("./extensions.js").RevealPluginValue, undefined>;
3
+ /** 이스케이프(`\*`)의 `\`를 커서가 닿아 있을 때만 보여주는 확장입니다. */
4
+ export declare function escape(): Extension;
package/dist/escape.js ADDED
@@ -0,0 +1,39 @@
1
+ import { Decoration } from "@codemirror/view";
2
+ import { createRevealPlugin } from "./utils/reveal.js";
3
+ // 데코레이션 객체는 모듈 로드 시 한 번만 만들고 재사용합니다.
4
+ const hiddenBackslash = Decoration.replace({});
5
+ const revealedBackslash = Decoration.mark({
6
+ class: "cm-formatting cm-formatting-escape cm-escape",
7
+ });
8
+ /** 이스케이프가 올 수 없으므로 자식 순회를 생략하는 노드 */
9
+ const SKIP_CHILDREN = new Set([
10
+ "FencedCode",
11
+ "CodeBlock",
12
+ "InlineCode",
13
+ "HTMLBlock",
14
+ "CommentBlock",
15
+ "URL",
16
+ "Autolink",
17
+ ]);
18
+ export const escapePlugin = createRevealPlugin({
19
+ // 이스케이프는 서로 겹치지 않고 문서 순서대로 추가되므로 정렬이 필요 없습니다.
20
+ visit({ decorations, isRevealed }) {
21
+ return {
22
+ enter(node) {
23
+ if (node.name === "Escape") {
24
+ // Lezer의 Escape 노드는 항상 `\` + ASCII 구두점 2글자입니다.
25
+ // (`\` + 줄바꿈은 HardBreak이므로 줄바꿈을 숨기는 일은 없습니다.)
26
+ const revealed = isRevealed(node.from, node.to);
27
+ decorations.push((revealed ? revealedBackslash : hiddenBackslash).range(node.from, node.from + 1));
28
+ return false;
29
+ }
30
+ if (SKIP_CHILDREN.has(node.name))
31
+ return false;
32
+ },
33
+ };
34
+ },
35
+ });
36
+ /** 이스케이프(`\*`)의 `\`를 커서가 닿아 있을 때만 보여주는 확장입니다. */
37
+ export function escape() {
38
+ return escapePlugin;
39
+ }
@@ -0,0 +1,74 @@
1
+ import { markdown } from "@codemirror/lang-markdown";
2
+ import { type Extension } from "@codemirror/state";
3
+ import type { MarkdownConfig, MarkdownExtension } from "@lezer/markdown";
4
+ import { Highlight, markTag } from "./highlight.js";
5
+ import { Underline, underlineTag } from "./underline.js";
6
+ import { Hashtag, hashtagTag } from "./hashtagSyntax.js";
7
+ import { Mention, mentionTag } from "./mentionSyntax.js";
8
+ import { Footnote } from "./footnoteSyntax.js";
9
+ import { MathSyntax } from "./mathSyntax.js";
10
+ import { TableSyntax } from "./tableModel.js";
11
+ export { Highlight, markTag, Underline, underlineTag, Hashtag, hashtagTag, Mention, mentionTag, Footnote, MathSyntax, TableSyntax, };
12
+ export { basicSetup, type BasicSetupOptions } from "./setup.js";
13
+ export { parseHashtag, type HashtagInfo } from "./hashtagSyntax.js";
14
+ export { doubleDelimiterSyntax, type DoubleDelimiterSpec } from "./delimiter.js";
15
+ export { MarkVisionPlugin, markVisionPlugin, markVision, activeLineClass, } from "./markVision.js";
16
+ export { emphasis, emphasisPlugin } from "./emphasis.js";
17
+ export { heading, headingPlugin } from "./heading.js";
18
+ export { hashtag, hashtagPlugin } from "./hashtag.js";
19
+ export { escape, escapePlugin } from "./escape.js";
20
+ export { inlineCode, inlineCodePlugin } from "./inlineCode.js";
21
+ export { mention, mentionPlugin } from "./mention.js";
22
+ export { listIndent, listKeymap, indentListItem, outdentListItem } from "./listIndent.js";
23
+ export { endListWithBlankLine } from "./listEnter.js";
24
+ export { list, listPlugin, taskMarkersHandled } from "./list.js";
25
+ export { task, taskPlugin, toggleTask } from "./task.js";
26
+ export { isSafeUrl, link, linkPlugin, openLinkSafely, readInlineLink, type InlineLink, type LinkOptions, } from "./link.js";
27
+ export { image, parseImageAlt, readImage, type ImageAlign, type ImageAltOptions, type ImageInfo, type ImageOptions, } from "./image.js";
28
+ export { horizontalRule, horizontalRuleField } from "./horizontalRule.js";
29
+ export { quote, quotePlugin } from "./quote.js";
30
+ export { math, readMath, type MathInfo, type MathOptions } from "./math.js";
31
+ export { parseTikz, sanitizeSvg, tikz, tikzjaxRenderer, type TikzDocument, type TikzJaxOptions, type TikzOptions, type TikzRenderer, } from "./tikz.js";
32
+ export { table, tablesHandled, cellAt, insertTableRow, nextTableCell, previousTableCell, } from "./table.js";
33
+ export { editTableColumn, editTableRow, moveTableColumn, moveTableRow, setCellColor, clearCells, type TableColumnAction, type TableRowAction, } from "./tableEdit.js";
34
+ export { tablesField, tableBlockAt, setTableSelection, tableSelectionField, selectedCells, type TableCellRange, type TableSelection, } from "./tableState.js";
35
+ export { readTableRow, readTableRows, scanTables, setTableOption, setTableColor, TABLE_COLORS, setColumnAlign, delimiterCells, DEFAULT_TABLE_OPTIONS, type TableAlign, type TableAxis, type TableBlock, type TableColor, type TableColorName, type TableColorPair, type TableColors, type TableCellInfo, type CellMarker, type TableComment, type TableOptions, type TableRowInfo, } from "./tableModel.js";
36
+ export { callout, calloutPlugin } from "./callout.js";
37
+ export { codeBlock, languageLabel, readFencedCode, renderedCodeLanguages, type CodeBlockOptions, type CodeLanguages, type FencedCodeInfo, } from "./codeBlock.js";
38
+ export { defaultCodeTheme, vscodeTheme, type CodeTheme, type VSCodeThemeJson, type VSCodeThemeOptions, } from "./codeTheme.js";
39
+ export { parseJsonc, textMateTheme, type TextMateTheme, type TokenColorRule, type TokenStyle } from "./textMate.js";
40
+ export { calloutsHandled, defaultCalloutTitle, readCalloutHeader, type CalloutHeader, type CalloutType, } from "./calloutHeader.js";
41
+ export { footnote, footnotePlugin, footnoteDefinitions, footnoteTooltipAt, renderFootnoteDefinition, type FootnoteDefinitionInfo, } from "./footnote.js";
42
+ export { createRevealField, createRevealPlugin, RevealPluginValue, type RevealContext, type RevealFieldSpec, type RevealFieldValue, type RevealPluginSpec, } from "./utils/reveal.js";
43
+ /** 이 플러그인이 제공하는 Lezer Markdown 문법 확장 목록 */
44
+ export declare const extendedMarkdownSyntax: MarkdownExtension[];
45
+ export interface ExtendedMarkdownOptions {
46
+ /** `markdown()`에 전달할 추가 옵션 (codeLanguages 등) */
47
+ markdownConfig?: Parameters<typeof markdown>[0];
48
+ /**
49
+ * 목록의 두 번째 항목이 비어 있을 때 Enter를 누르면, 목록을 끝내는 대신
50
+ * 빈 줄을 넣어 느슨한(loose) 목록으로 바꾸는 lang-markdown 기본 동작을 사용할지 여부.
51
+ * 기본값 false: 다른 항목과 마찬가지로 빈 항목에서 Enter를 누르면 목록을 끝내거나 한 단계 내어씁니다.
52
+ */
53
+ nonTightLists?: boolean;
54
+ /**
55
+ * 가장 바깥 목록의 마지막 빈 항목에서 Enter를 누르면 목록을 끝내고 빈 줄을 넣어
56
+ * 다음 글이 새 문단이 되게 합니다. (기본값 true)
57
+ * false이면 빈 줄 없이 목록 기호만 지웁니다. 이 경우 다음 줄은 마크다운 규칙상
58
+ * 바로 위 항목의 이어지는 줄이 됩니다.
59
+ */
60
+ blankLineAfterList?: boolean;
61
+ /**
62
+ * Setext 제목(`제목` 다음 줄의 `===`, `---`)을 쓸지 여부. 기본값 false (쓰지 않음).
63
+ * 끄면 `===` 줄은 그냥 글이고, 문단 바로 아래의 `---`는 수평선입니다.
64
+ * (`---`가 의도와 달리 윗줄을 제목으로 만드는 일을 막습니다. 제목은 `#`를 씁니다)
65
+ */
66
+ setextHeadings?: boolean;
67
+ }
68
+ /** Setext 제목(`===`, `---` 밑줄)을 끄는 문법 설정 */
69
+ export declare const NoSetextHeading: MarkdownConfig;
70
+ /**
71
+ * 확장 마크다운 문법(파서)을 활성화하는 CodeMirror 확장입니다.
72
+ * 시각 스타일(하이라이트 배경, 기호 숨김 등)은 `emphasis()`가 담당합니다.
73
+ */
74
+ export declare function extendedMarkdown(options?: ExtendedMarkdownOptions): Extension;
@@ -0,0 +1,81 @@
1
+ import { deleteMarkupBackward, insertNewlineContinueMarkupCommand, markdown, markdownLanguage, } from "@codemirror/lang-markdown";
2
+ import { Prec } from "@codemirror/state";
3
+ import { keymap } from "@codemirror/view";
4
+ import { Highlight, markTag } from "./highlight.js";
5
+ import { Underline, underlineTag } from "./underline.js";
6
+ import { Hashtag, hashtagTag } from "./hashtagSyntax.js";
7
+ import { Mention, mentionTag } from "./mentionSyntax.js";
8
+ import { Footnote } from "./footnoteSyntax.js";
9
+ import { MathSyntax } from "./mathSyntax.js";
10
+ import { TableSyntax } from "./tableModel.js";
11
+ import { endListWithBlankLine } from "./listEnter.js";
12
+ export { Highlight, markTag, Underline, underlineTag, Hashtag, hashtagTag, Mention, mentionTag, Footnote, MathSyntax, TableSyntax, };
13
+ export { basicSetup } from "./setup.js";
14
+ export { parseHashtag } from "./hashtagSyntax.js";
15
+ export { doubleDelimiterSyntax } from "./delimiter.js";
16
+ export { MarkVisionPlugin, markVisionPlugin, markVision, activeLineClass, } from "./markVision.js";
17
+ export { emphasis, emphasisPlugin } from "./emphasis.js";
18
+ export { heading, headingPlugin } from "./heading.js";
19
+ export { hashtag, hashtagPlugin } from "./hashtag.js";
20
+ export { escape, escapePlugin } from "./escape.js";
21
+ export { inlineCode, inlineCodePlugin } from "./inlineCode.js";
22
+ export { mention, mentionPlugin } from "./mention.js";
23
+ export { listIndent, listKeymap, indentListItem, outdentListItem } from "./listIndent.js";
24
+ export { endListWithBlankLine } from "./listEnter.js";
25
+ export { list, listPlugin, taskMarkersHandled } from "./list.js";
26
+ export { task, taskPlugin, toggleTask } from "./task.js";
27
+ export { isSafeUrl, link, linkPlugin, openLinkSafely, readInlineLink, } from "./link.js";
28
+ export { image, parseImageAlt, readImage, } from "./image.js";
29
+ export { horizontalRule, horizontalRuleField } from "./horizontalRule.js";
30
+ export { quote, quotePlugin } from "./quote.js";
31
+ export { math, readMath } from "./math.js";
32
+ export { parseTikz, sanitizeSvg, tikz, tikzjaxRenderer, } from "./tikz.js";
33
+ export { table, tablesHandled, cellAt, insertTableRow, nextTableCell, previousTableCell, } from "./table.js";
34
+ export { editTableColumn, editTableRow, moveTableColumn, moveTableRow, setCellColor, clearCells, } from "./tableEdit.js";
35
+ export { tablesField, tableBlockAt, setTableSelection, tableSelectionField, selectedCells, } from "./tableState.js";
36
+ export { readTableRow, readTableRows, scanTables, setTableOption, setTableColor, TABLE_COLORS, setColumnAlign, delimiterCells, DEFAULT_TABLE_OPTIONS, } from "./tableModel.js";
37
+ export { callout, calloutPlugin } from "./callout.js";
38
+ export { codeBlock, languageLabel, readFencedCode, renderedCodeLanguages, } from "./codeBlock.js";
39
+ export { defaultCodeTheme, vscodeTheme, } from "./codeTheme.js";
40
+ export { parseJsonc, textMateTheme } from "./textMate.js";
41
+ export { calloutsHandled, defaultCalloutTitle, readCalloutHeader, } from "./calloutHeader.js";
42
+ export { footnote, footnotePlugin, footnoteDefinitions, footnoteTooltipAt, renderFootnoteDefinition, } from "./footnote.js";
43
+ export { createRevealField, createRevealPlugin, RevealPluginValue, } from "./utils/reveal.js";
44
+ /** 이 플러그인이 제공하는 Lezer Markdown 문법 확장 목록 */
45
+ export const extendedMarkdownSyntax = [
46
+ Highlight,
47
+ Underline,
48
+ Hashtag,
49
+ Mention,
50
+ Footnote,
51
+ MathSyntax,
52
+ TableSyntax,
53
+ ];
54
+ /** Setext 제목(`===`, `---` 밑줄)을 끄는 문법 설정 */
55
+ export const NoSetextHeading = { remove: ["SetextHeading"] };
56
+ /**
57
+ * 확장 마크다운 문법(파서)을 활성화하는 CodeMirror 확장입니다.
58
+ * 시각 스타일(하이라이트 배경, 기호 숨김 등)은 `emphasis()`가 담당합니다.
59
+ */
60
+ export function extendedMarkdown(options = {}) {
61
+ const { markdownConfig = {}, nonTightLists = false, blankLineAfterList = true, setextHeadings = false } = options;
62
+ const userExtensions = markdownConfig.extensions ?? [];
63
+ const addKeymap = markdownConfig.addKeymap ?? true;
64
+ return [
65
+ markdown({
66
+ base: markdownLanguage,
67
+ ...markdownConfig,
68
+ extensions: [extendedMarkdownSyntax, setextHeadings ? [] : NoSetextHeading, userExtensions],
69
+ // 기본 키맵은 Enter 동작을 바꿀 수 없으므로 끄고, 아래에서 같은 우선순위로 다시 등록합니다.
70
+ addKeymap: false,
71
+ }),
72
+ addKeymap
73
+ ? Prec.high(keymap.of([
74
+ // 목록 끝내기(빈 줄 추가)가 해당하지 않으면 다음 바인딩(기본 Enter 동작)으로 넘어갑니다.
75
+ ...(blankLineAfterList ? [{ key: "Enter", run: endListWithBlankLine }] : []),
76
+ { key: "Enter", run: insertNewlineContinueMarkupCommand({ nonTightLists }) },
77
+ { key: "Backspace", run: deleteMarkupBackward },
78
+ ]))
79
+ : [],
80
+ ];
81
+ }
@@ -0,0 +1,24 @@
1
+ import { type EditorState, type Extension } from "@codemirror/state";
2
+ import { type Tooltip } from "@codemirror/view";
3
+ export interface FootnoteDefinitionInfo {
4
+ readonly label: string;
5
+ /** 정의 전체 범위 */
6
+ readonly from: number;
7
+ readonly to: number;
8
+ /** 내용 시작 위치 ("]:" 뒤 공백 다음) */
9
+ readonly contentFrom: number;
10
+ /** 툴팁용 내용 (앞뒤 공백 제거, 길면 자름) */
11
+ readonly text: string;
12
+ }
13
+ /**
14
+ * 문서의 각주 정의를 라벨별로 찾습니다. (같은 라벨이 여러 번 정의되면 첫 번째)
15
+ * 정의는 최상위 블록에만 오므로 최상위 블록만 확인하고, 결과는 구문 트리별로 캐시합니다.
16
+ * (커서만 움직이는 동안에는 다시 계산하지 않습니다)
17
+ */
18
+ export declare function footnoteDefinitions(state: EditorState): ReadonlyMap<string, FootnoteDefinitionInfo>;
19
+ export declare const footnotePlugin: import("@codemirror/view").ViewPlugin<import("./extensions.js").RevealPluginValue, undefined>;
20
+ /** 각주 정의 내용을 서식이 반영된 DOM으로 그립니다. 정의가 없으면 null */
21
+ export declare function renderFootnoteDefinition(state: EditorState, label: string): HTMLElement | null;
22
+ /** pos(마우스 위치)에 각주 참조가 있으면 그 정의를 보여주는 툴팁 */
23
+ export declare function footnoteTooltipAt(state: EditorState, pos: number, side?: -1 | 1): Tooltip | null;
24
+ export declare function footnote(): Extension;