leepi 0.0.2 → 0.0.3

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 (53) hide show
  1. package/dist/core/active-marks.d.ts +15 -0
  2. package/dist/core/active-marks.js +57 -0
  3. package/dist/core/commands.d.ts +39 -0
  4. package/dist/core/commands.js +415 -0
  5. package/dist/core/editor.d.ts +25 -0
  6. package/dist/core/editor.js +102 -0
  7. package/dist/core/field-notifier.d.ts +21 -0
  8. package/dist/core/field-notifier.js +56 -0
  9. package/dist/core/highlight-style.js +60 -0
  10. package/dist/core/highlight.d.ts +8 -0
  11. package/dist/core/highlight.js +34 -0
  12. package/dist/core/plugins/blockquote.d.ts +11 -0
  13. package/dist/core/plugins/blockquote.js +78 -0
  14. package/dist/core/plugins/bracket.d.ts +6 -0
  15. package/dist/core/plugins/bracket.js +38 -0
  16. package/dist/core/plugins/code-block.d.ts +27 -0
  17. package/dist/core/plugins/code-block.js +207 -0
  18. package/dist/core/plugins/heading.d.ts +13 -0
  19. package/dist/core/plugins/heading.js +111 -0
  20. package/dist/core/plugins/inline.d.ts +14 -0
  21. package/dist/core/plugins/inline.js +103 -0
  22. package/dist/core/plugins/link.d.ts +25 -0
  23. package/dist/core/plugins/link.js +104 -0
  24. package/dist/core/plugins/list.d.ts +14 -0
  25. package/dist/core/plugins/list.js +91 -0
  26. package/dist/core/plugins/table.d.ts +12 -0
  27. package/dist/core/plugins/table.js +161 -0
  28. package/dist/core/plugins.d.ts +9 -0
  29. package/dist/core/plugins.js +9 -0
  30. package/dist/core/popover.d.ts +9 -0
  31. package/dist/core/popover.js +16 -0
  32. package/dist/core/registry.d.ts +10 -0
  33. package/dist/core/registry.js +8 -0
  34. package/dist/core/types.d.ts +25 -0
  35. package/dist/core/types.js +0 -0
  36. package/dist/core/utils.d.ts +13 -0
  37. package/dist/core/utils.js +32 -0
  38. package/dist/leepi.css +461 -0
  39. package/dist/react/code-block-popover.d.ts +76 -0
  40. package/dist/react/code-block-popover.js +223 -0
  41. package/dist/react/context.d.ts +42 -0
  42. package/dist/react/context.js +88 -0
  43. package/dist/react/editor.d.ts +30 -0
  44. package/dist/react/editor.js +60 -0
  45. package/dist/react/floating-toolbar.d.ts +30 -0
  46. package/dist/react/floating-toolbar.js +87 -0
  47. package/dist/react/link-popover.d.ts +70 -0
  48. package/dist/react/link-popover.js +222 -0
  49. package/dist/react/preview.d.ts +13 -0
  50. package/dist/react/preview.js +56 -0
  51. package/dist/react/toolbar.d.ts +51 -0
  52. package/dist/react/toolbar.js +161 -0
  53. package/package.json +1 -1
@@ -0,0 +1,56 @@
1
+ import { ViewPlugin } from "@codemirror/view";
2
+ //#region src/core/field-notifier.ts
3
+ const fieldListeners = /* @__PURE__ */ new WeakMap();
4
+ const fieldSnapshots = /* @__PURE__ */ new WeakMap();
5
+ /**
6
+ * Subscribe to changes of a StateField on a given EditorView.
7
+ * Returns an unsubscribe function.
8
+ */
9
+ function subscribeToField(view, field, cb) {
10
+ let viewMap = fieldListeners.get(view);
11
+ if (!viewMap) {
12
+ viewMap = /* @__PURE__ */ new Map();
13
+ fieldListeners.set(view, viewMap);
14
+ }
15
+ let listeners = viewMap.get(field);
16
+ if (!listeners) {
17
+ listeners = /* @__PURE__ */ new Set();
18
+ viewMap.set(field, listeners);
19
+ }
20
+ listeners.add(cb);
21
+ return () => {
22
+ listeners.delete(cb);
23
+ };
24
+ }
25
+ /** Get the current snapshot of a StateField for useSyncExternalStore */
26
+ function getFieldSnapshot(view, field) {
27
+ return fieldSnapshots.get(view)?.get(field);
28
+ }
29
+ /**
30
+ * ViewPlugin that watches all StateFields with subscribers and notifies
31
+ * when their values change (by reference).
32
+ */
33
+ const fieldNotifierPlugin = ViewPlugin.fromClass(class {
34
+ update(update) {
35
+ const viewMap = fieldListeners.get(update.view);
36
+ if (!viewMap) return;
37
+ let snapMap = fieldSnapshots.get(update.view);
38
+ if (!snapMap) {
39
+ snapMap = /* @__PURE__ */ new Map();
40
+ fieldSnapshots.set(update.view, snapMap);
41
+ }
42
+ for (const [field, listeners] of viewMap) {
43
+ const newVal = update.state.field(field);
44
+ if (newVal !== snapMap.get(field)) {
45
+ snapMap.set(field, newVal);
46
+ for (const cb of listeners) cb();
47
+ }
48
+ }
49
+ }
50
+ });
51
+ /** Extension to include in createEditorState */
52
+ function fieldNotifier() {
53
+ return fieldNotifierPlugin;
54
+ }
55
+ //#endregion
56
+ export { fieldNotifier, fieldNotifierPlugin, getFieldSnapshot, subscribeToField };
@@ -0,0 +1,60 @@
1
+ import { EditorView } from "@codemirror/view";
2
+ import { HighlightStyle } from "@codemirror/language";
3
+ import { tags } from "@lezer/highlight";
4
+ //#region src/core/highlight-style.ts
5
+ /** Shared highlight style for faded markdown syntax tokens (e.g. `#`, `>`, `-`, `` ` ``). */
6
+ const highlightStyle = HighlightStyle.define([
7
+ {
8
+ tag: tags.processingInstruction,
9
+ color: "var(--lp-color-text-faded)",
10
+ opacity: "0.4",
11
+ fontFamily: "var(--lp-font-mono)"
12
+ },
13
+ {
14
+ tag: tags.meta,
15
+ color: "var(--lp-color-text-faded)",
16
+ opacity: "0.4",
17
+ fontFamily: "var(--lp-font-mono)"
18
+ },
19
+ {
20
+ tag: tags.labelName,
21
+ color: "var(--lp-color-text-faded)",
22
+ opacity: "0.4",
23
+ fontFamily: "var(--lp-font-mono)"
24
+ },
25
+ {
26
+ tag: tags.contentSeparator,
27
+ color: "var(--lp-color-text-faded)",
28
+ opacity: "0.4",
29
+ fontFamily: "var(--lp-font-mono)"
30
+ }
31
+ ]);
32
+ const editorTheme = EditorView.theme({
33
+ "&": {
34
+ height: "100%",
35
+ flex: "1",
36
+ fontSize: "var(--lp-font-size, 0.875rem)",
37
+ fontFamily: "var(--lp-font-body, system-ui, -apple-system, sans-serif)"
38
+ },
39
+ ".cm-scroller": {
40
+ overflow: "auto",
41
+ fontFamily: "inherit",
42
+ lineHeight: "var(--lp-line-height, 1.6)"
43
+ },
44
+ ".cm-content": {
45
+ maxWidth: "var(--lp-content-max-width, 48rem)",
46
+ margin: "0 auto",
47
+ padding: "1.5rem var(--lp-content-padding, 2rem)",
48
+ caretColor: "var(--lp-color-caret, currentColor)"
49
+ },
50
+ "&.cm-focused": { outline: "none" },
51
+ ".cm-activeLine": { backgroundColor: "transparent" },
52
+ ".cm-gutters": { display: "none" },
53
+ ".cm-has-deco span[class]": {
54
+ backgroundColor: "transparent",
55
+ padding: "0",
56
+ borderRadius: "0"
57
+ }
58
+ });
59
+ //#endregion
60
+ export { editorTheme, highlightStyle };
@@ -0,0 +1,8 @@
1
+ //#region src/core/highlight.d.ts
2
+ /**
3
+ * Highlight code using Lezer parsers (same ones CodeMirror uses).
4
+ * Returns HTML string with `tok-*` classes for styling.
5
+ */
6
+ declare function highlightCode(code: string, lang: string): Promise<string>;
7
+ //#endregion
8
+ export { highlightCode };
@@ -0,0 +1,34 @@
1
+ import { LanguageDescription } from "@codemirror/language";
2
+ import { classHighlighter, highlightTree } from "@lezer/highlight";
3
+ //#region src/core/highlight.ts
4
+ let languageList = null;
5
+ async function getLanguages() {
6
+ if (languageList) return languageList;
7
+ const { languages } = await import("@codemirror/language-data");
8
+ languageList = languages;
9
+ return languages;
10
+ }
11
+ /**
12
+ * Highlight code using Lezer parsers (same ones CodeMirror uses).
13
+ * Returns HTML string with `tok-*` classes for styling.
14
+ */
15
+ async function highlightCode(code, lang) {
16
+ const languages = await getLanguages();
17
+ const desc = LanguageDescription.matchLanguageName(languages, lang, true);
18
+ if (!desc) return escapeHtml(code);
19
+ const tree = (await desc.load()).language.parser.parse(code);
20
+ let pos = 0;
21
+ let result = "";
22
+ highlightTree(tree, classHighlighter, (from, to, classes) => {
23
+ if (from > pos) result += escapeHtml(code.slice(pos, from));
24
+ result += `<span class="${classes}">${escapeHtml(code.slice(from, to))}</span>`;
25
+ pos = to;
26
+ });
27
+ if (pos < code.length) result += escapeHtml(code.slice(pos));
28
+ return result;
29
+ }
30
+ function escapeHtml(text) {
31
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
32
+ }
33
+ //#endregion
34
+ export { highlightCode };
@@ -0,0 +1,11 @@
1
+ import { Extension } from "@codemirror/state";
2
+
3
+ //#region src/core/plugins/blockquote.d.ts
4
+ interface BlockquotePluginOptions {
5
+ shortcuts?: {
6
+ blockquote?: string;
7
+ };
8
+ }
9
+ declare function blockquotePlugin(options?: BlockquotePluginOptions): Extension;
10
+ //#endregion
11
+ export { BlockquotePluginOptions, blockquotePlugin };
@@ -0,0 +1,78 @@
1
+ import { markRegistry, shortcutRegistry } from "../registry.js";
2
+ import { toggleBlockquote } from "../commands.js";
3
+ import { Decoration, EditorView, ViewPlugin, keymap } from "@codemirror/view";
4
+ import { HighlightStyle, syntaxHighlighting, syntaxTree } from "@codemirror/language";
5
+ import { RangeSetBuilder } from "@codemirror/state";
6
+ import { tags } from "@lezer/highlight";
7
+ //#region src/core/plugins/blockquote.ts
8
+ const defaultShortcuts = { blockquote: "Mod-Shift-b" };
9
+ const blockquoteDecoration = Decoration.line({ class: "cm-blockquote-line" });
10
+ function buildBlockquoteDecorations(state) {
11
+ const builder = new RangeSetBuilder();
12
+ const tree = syntaxTree(state);
13
+ const seen = /* @__PURE__ */ new Set();
14
+ tree.iterate({ enter(node) {
15
+ if (node.name === "Blockquote") {
16
+ const from = state.doc.lineAt(node.from).number;
17
+ const to = state.doc.lineAt(node.to).number;
18
+ for (let i = from; i <= to; i++) if (!seen.has(i)) {
19
+ seen.add(i);
20
+ const line = state.doc.line(i);
21
+ builder.add(line.from, line.from, blockquoteDecoration);
22
+ }
23
+ }
24
+ } });
25
+ return builder.finish();
26
+ }
27
+ const blockquoteLineDecorations = ViewPlugin.fromClass(class {
28
+ decorations;
29
+ constructor(view) {
30
+ this.decorations = buildBlockquoteDecorations(view.state);
31
+ }
32
+ update(update) {
33
+ if (update.docChanged || update.viewportChanged || syntaxTree(update.state) !== syntaxTree(update.startState)) this.decorations = buildBlockquoteDecorations(update.state);
34
+ }
35
+ }, { decorations: (v) => v.decorations });
36
+ const blockquoteTheme = EditorView.theme({
37
+ ".cm-blockquote-line": { position: "relative" },
38
+ ".cm-blockquote-line::before": {
39
+ content: "\"\"",
40
+ position: "absolute",
41
+ right: "calc(100% + 0.5ch)",
42
+ top: "0",
43
+ bottom: "0",
44
+ width: "3px",
45
+ backgroundColor: "var(--lp-color-border, rgba(0, 0, 0, 0.12))",
46
+ pointerEvents: "none"
47
+ }
48
+ });
49
+ const blockquoteHighlight = HighlightStyle.define([{
50
+ tag: tags.quote,
51
+ color: "var(--lp-color-text-secondary)"
52
+ }]);
53
+ function blockquotePlugin(options) {
54
+ const keys = {
55
+ ...defaultShortcuts,
56
+ ...options?.shortcuts
57
+ };
58
+ return [
59
+ syntaxHighlighting(blockquoteHighlight),
60
+ shortcutRegistry.of([{
61
+ key: keys.blockquote,
62
+ action: "blockquote",
63
+ plugin: "blockquote"
64
+ }]),
65
+ markRegistry.of([{
66
+ mark: "blockquote",
67
+ detect: (nodeName) => nodeName === "Blockquote"
68
+ }]),
69
+ keymap.of([{
70
+ key: keys.blockquote,
71
+ run: toggleBlockquote
72
+ }]),
73
+ blockquoteLineDecorations,
74
+ blockquoteTheme
75
+ ];
76
+ }
77
+ //#endregion
78
+ export { blockquotePlugin };
@@ -0,0 +1,6 @@
1
+ import { Extension } from "@codemirror/state";
2
+
3
+ //#region src/core/plugins/bracket.d.ts
4
+ declare function bracketPlugin(): Extension;
5
+ //#endregion
6
+ export { bracketPlugin };
@@ -0,0 +1,38 @@
1
+ import { EditorView } from "@codemirror/view";
2
+ import { EditorSelection } from "@codemirror/state";
3
+ //#region src/core/plugins/bracket.ts
4
+ const BRACKETS = {
5
+ "(": ")",
6
+ "[": "]",
7
+ "{": "}"
8
+ };
9
+ function bracketPlugin() {
10
+ return EditorView.inputHandler.of((view, from, to, insert) => {
11
+ const close = BRACKETS[insert];
12
+ if (!close) return false;
13
+ const range = view.state.selection.main;
14
+ if (range.empty) {
15
+ view.dispatch({
16
+ changes: {
17
+ from,
18
+ to,
19
+ insert: insert + close
20
+ },
21
+ selection: EditorSelection.cursor(from + 1)
22
+ });
23
+ return true;
24
+ }
25
+ const selected = view.state.sliceDoc(range.from, range.to);
26
+ view.dispatch({
27
+ changes: {
28
+ from: range.from,
29
+ to: range.to,
30
+ insert: insert + selected + close
31
+ },
32
+ selection: EditorSelection.range(range.from + 1, range.from + 1 + selected.length)
33
+ });
34
+ return true;
35
+ });
36
+ }
37
+ //#endregion
38
+ export { bracketPlugin };
@@ -0,0 +1,27 @@
1
+ import { PopoverRequest } from "../types.js";
2
+ import { applyCodeBlock, findCodeFenceAtCursor } from "../commands.js";
3
+ import { Extension } from "@codemirror/state";
4
+
5
+ //#region src/core/plugins/code-block.d.ts
6
+ interface CodeBlockData {
7
+ /** Pre-filled language */
8
+ lang: string;
9
+ /** Pre-filled filename */
10
+ filename: string;
11
+ /** Range of the opening fence line to replace */
12
+ fenceFrom: number;
13
+ fenceTo: number;
14
+ /** Whether this is editing an existing block or inserting a new one */
15
+ isNew: boolean;
16
+ /** For new blocks: the cursor position where the block should be inserted */
17
+ insertPos?: number;
18
+ }
19
+ type CodeBlockRequest = PopoverRequest<"codeblock", CodeBlockData>;
20
+ interface CodeBlockPluginOptions {
21
+ shortcuts?: {
22
+ codeBlock?: string;
23
+ };
24
+ }
25
+ declare function codeBlockPlugin(options?: CodeBlockPluginOptions): Extension;
26
+ //#endregion
27
+ export { CodeBlockData, CodeBlockPluginOptions, CodeBlockRequest, codeBlockPlugin };
@@ -0,0 +1,207 @@
1
+ import { markRegistry, shortcutRegistry } from "../registry.js";
2
+ import { findCodeFenceAtCursor } from "../commands.js";
3
+ import { openPopover } from "../popover.js";
4
+ import { Decoration, EditorView, ViewPlugin, keymap } from "@codemirror/view";
5
+ import { HighlightStyle, syntaxHighlighting, syntaxTree } from "@codemirror/language";
6
+ import { RangeSetBuilder } from "@codemirror/state";
7
+ import { tags } from "@lezer/highlight";
8
+ //#region src/core/plugins/code-block.ts
9
+ function buildCodeLineNumbers(state) {
10
+ const builder = new RangeSetBuilder();
11
+ const tree = syntaxTree(state);
12
+ const doc = state.doc;
13
+ tree.iterate({ enter(node) {
14
+ if (node.name !== "FencedCode") return;
15
+ const startLine = doc.lineAt(node.from);
16
+ const endLine = doc.lineAt(node.to);
17
+ const totalLines = endLine.number - startLine.number - 1;
18
+ const digits = String(totalLines).length;
19
+ let num = 1;
20
+ for (let l = startLine.number + 1; l < endLine.number; l++) {
21
+ const line = doc.line(l);
22
+ const attributes = { "data-line-num": String(num++) };
23
+ if (digits > 3) attributes.style = `--line-digits:${digits}`;
24
+ builder.add(line.from, line.from, Decoration.line({
25
+ class: "cm-has-deco",
26
+ attributes
27
+ }));
28
+ }
29
+ } });
30
+ return builder.finish();
31
+ }
32
+ const codeBlockLineNumbers = ViewPlugin.fromClass(class {
33
+ decorations;
34
+ constructor(view) {
35
+ this.decorations = buildCodeLineNumbers(view.state);
36
+ }
37
+ update(update) {
38
+ if (update.docChanged || update.viewportChanged || syntaxTree(update.state) !== syntaxTree(update.startState)) this.decorations = buildCodeLineNumbers(update.state);
39
+ }
40
+ }, { decorations: (v) => v.decorations });
41
+ const codeBlockTheme = EditorView.theme({
42
+ ".cm-has-deco": {
43
+ position: "relative",
44
+ fontSize: "0.875em",
45
+ fontFamily: "var(--lp-font-mono, ui-monospace, monospace)"
46
+ },
47
+ ".cm-has-deco::before": {
48
+ content: "attr(data-line-num)",
49
+ position: "absolute",
50
+ right: "calc(100% + 0.5ch)",
51
+ width: "calc(var(--line-digits, 3) * 1ch)",
52
+ textAlign: "right",
53
+ color: "var(--lp-color-text-faded)",
54
+ opacity: "0.5",
55
+ borderRadius: "3px",
56
+ padding: "0 0.3ch",
57
+ userSelect: "none",
58
+ font: "inherit",
59
+ pointerEvents: "none"
60
+ }
61
+ });
62
+ const codeHighlight = HighlightStyle.define([
63
+ {
64
+ tag: tags.keyword,
65
+ color: "var(--lp-syntax-keyword)"
66
+ },
67
+ {
68
+ tag: tags.operator,
69
+ color: "var(--lp-syntax-operator)"
70
+ },
71
+ {
72
+ tag: tags.variableName,
73
+ color: "var(--lp-syntax-variable)"
74
+ },
75
+ {
76
+ tag: tags.function(tags.variableName),
77
+ color: "var(--lp-syntax-function)"
78
+ },
79
+ {
80
+ tag: tags.definition(tags.variableName),
81
+ color: "var(--lp-syntax-type)"
82
+ },
83
+ {
84
+ tag: tags.typeName,
85
+ color: "var(--lp-syntax-type)"
86
+ },
87
+ {
88
+ tag: tags.className,
89
+ color: "var(--lp-syntax-type)"
90
+ },
91
+ {
92
+ tag: tags.string,
93
+ color: "var(--lp-syntax-string)"
94
+ },
95
+ {
96
+ tag: tags.number,
97
+ color: "var(--lp-syntax-number)"
98
+ },
99
+ {
100
+ tag: tags.bool,
101
+ color: "var(--lp-syntax-number)"
102
+ },
103
+ {
104
+ tag: tags.null,
105
+ color: "var(--lp-syntax-number)"
106
+ },
107
+ {
108
+ tag: tags.comment,
109
+ color: "var(--lp-syntax-comment)",
110
+ fontStyle: "italic"
111
+ },
112
+ {
113
+ tag: tags.propertyName,
114
+ color: "var(--lp-syntax-property)"
115
+ },
116
+ {
117
+ tag: tags.function(tags.propertyName),
118
+ color: "var(--lp-syntax-function)"
119
+ },
120
+ {
121
+ tag: tags.definition(tags.propertyName),
122
+ color: "var(--lp-syntax-function)"
123
+ },
124
+ {
125
+ tag: tags.tagName,
126
+ color: "var(--lp-syntax-tag)"
127
+ },
128
+ {
129
+ tag: tags.attributeName,
130
+ color: "var(--lp-syntax-attribute)"
131
+ },
132
+ {
133
+ tag: tags.attributeValue,
134
+ color: "var(--lp-syntax-string)"
135
+ },
136
+ {
137
+ tag: tags.regexp,
138
+ color: "var(--lp-syntax-string)"
139
+ },
140
+ {
141
+ tag: tags.escape,
142
+ color: "var(--lp-syntax-escape)"
143
+ },
144
+ {
145
+ tag: tags.punctuation,
146
+ color: "var(--lp-syntax-punctuation)"
147
+ }
148
+ ]);
149
+ const defaultShortcuts = { codeBlock: "Mod-Shift-e" };
150
+ function codeBlockPlugin(options) {
151
+ const keys = {
152
+ ...defaultShortcuts,
153
+ ...options?.shortcuts
154
+ };
155
+ return [
156
+ syntaxHighlighting(codeHighlight),
157
+ shortcutRegistry.of([{
158
+ key: keys.codeBlock,
159
+ action: "codeblock",
160
+ plugin: "code-block"
161
+ }]),
162
+ markRegistry.of([{
163
+ mark: "codeblock",
164
+ detect: (nodeName) => nodeName === "FencedCode"
165
+ }]),
166
+ keymap.of([{
167
+ key: keys.codeBlock,
168
+ run(view) {
169
+ const { state } = view;
170
+ const range = state.selection.main;
171
+ const coords = view.coordsAtPos(range.from);
172
+ if (!coords) return false;
173
+ const existing = findCodeFenceAtCursor(view);
174
+ const req = existing ? {
175
+ type: "codeblock",
176
+ x: coords.left,
177
+ y: coords.bottom,
178
+ data: {
179
+ lang: existing.lang,
180
+ filename: existing.filename,
181
+ fenceFrom: existing.fenceLine.from,
182
+ fenceTo: existing.fenceLine.to,
183
+ isNew: false
184
+ }
185
+ } : {
186
+ type: "codeblock",
187
+ x: coords.left,
188
+ y: coords.bottom,
189
+ data: {
190
+ lang: "",
191
+ filename: "",
192
+ fenceFrom: 0,
193
+ fenceTo: 0,
194
+ isNew: true,
195
+ insertPos: range.from
196
+ }
197
+ };
198
+ view.dispatch({ effects: openPopover.of(req) });
199
+ return true;
200
+ }
201
+ }]),
202
+ codeBlockLineNumbers,
203
+ codeBlockTheme
204
+ ];
205
+ }
206
+ //#endregion
207
+ export { codeBlockPlugin };
@@ -0,0 +1,13 @@
1
+ import { Extension } from "@codemirror/state";
2
+
3
+ //#region src/core/plugins/heading.d.ts
4
+ interface HeadingPluginOptions {
5
+ shortcuts?: {
6
+ heading1?: string;
7
+ heading2?: string;
8
+ heading3?: string;
9
+ };
10
+ }
11
+ declare function headingPlugin(options?: HeadingPluginOptions): Extension;
12
+ //#endregion
13
+ export { HeadingPluginOptions, headingPlugin };
@@ -0,0 +1,111 @@
1
+ import { markRegistry, shortcutRegistry } from "../registry.js";
2
+ import { toggleHeading } from "../commands.js";
3
+ import { keymap } from "@codemirror/view";
4
+ import { HighlightStyle, syntaxHighlighting } from "@codemirror/language";
5
+ import { tags } from "@lezer/highlight";
6
+ //#region src/core/plugins/heading.ts
7
+ const defaultShortcuts = {
8
+ heading1: "Mod-Alt-1",
9
+ heading2: "Mod-Alt-2",
10
+ heading3: "Mod-Alt-3"
11
+ };
12
+ const headingHighlight = HighlightStyle.define([
13
+ {
14
+ tag: tags.heading1,
15
+ fontSize: "2em",
16
+ fontWeight: "var(--lp-font-weight-bold, 700)",
17
+ fontFamily: "var(--lp-font-display)"
18
+ },
19
+ {
20
+ tag: tags.heading2,
21
+ fontSize: "1.6em",
22
+ fontWeight: "var(--lp-font-weight-bold, 700)",
23
+ fontFamily: "var(--lp-font-display)"
24
+ },
25
+ {
26
+ tag: tags.heading3,
27
+ fontSize: "1.3em",
28
+ fontWeight: "var(--lp-font-weight-semibold, 600)",
29
+ fontFamily: "var(--lp-font-display)"
30
+ },
31
+ {
32
+ tag: tags.heading4,
33
+ fontSize: "1.1em",
34
+ fontWeight: "var(--lp-font-weight-semibold, 600)",
35
+ fontFamily: "var(--lp-font-display)"
36
+ },
37
+ {
38
+ tag: tags.heading5,
39
+ fontSize: "1.05em",
40
+ fontWeight: "var(--lp-font-weight-semibold, 600)",
41
+ fontFamily: "var(--lp-font-display)"
42
+ },
43
+ {
44
+ tag: tags.heading6,
45
+ fontSize: "1em",
46
+ fontWeight: "var(--lp-font-weight-semibold, 600)",
47
+ fontFamily: "var(--lp-font-display)"
48
+ }
49
+ ]);
50
+ function headingPlugin(options) {
51
+ const keys = {
52
+ ...defaultShortcuts,
53
+ ...options?.shortcuts
54
+ };
55
+ const extensions = [syntaxHighlighting(headingHighlight), markRegistry.of([
56
+ {
57
+ mark: "heading1",
58
+ detect: (nodeName) => nodeName === "ATXHeading1"
59
+ },
60
+ {
61
+ mark: "heading2",
62
+ detect: (nodeName) => nodeName === "ATXHeading2"
63
+ },
64
+ {
65
+ mark: "heading3",
66
+ detect: (nodeName) => nodeName === "ATXHeading3"
67
+ }
68
+ ])];
69
+ const keybindings = [];
70
+ const shortcuts = [];
71
+ if (keys.heading1) {
72
+ keybindings.push({
73
+ key: keys.heading1,
74
+ run: toggleHeading(1)
75
+ });
76
+ shortcuts.push({
77
+ key: keys.heading1,
78
+ action: "heading1",
79
+ plugin: "heading"
80
+ });
81
+ }
82
+ if (keys.heading2) {
83
+ keybindings.push({
84
+ key: keys.heading2,
85
+ run: toggleHeading(2)
86
+ });
87
+ shortcuts.push({
88
+ key: keys.heading2,
89
+ action: "heading2",
90
+ plugin: "heading"
91
+ });
92
+ }
93
+ if (keys.heading3) {
94
+ keybindings.push({
95
+ key: keys.heading3,
96
+ run: toggleHeading(3)
97
+ });
98
+ shortcuts.push({
99
+ key: keys.heading3,
100
+ action: "heading3",
101
+ plugin: "heading"
102
+ });
103
+ }
104
+ if (keybindings.length > 0) {
105
+ extensions.push(keymap.of(keybindings));
106
+ extensions.push(shortcutRegistry.of(shortcuts));
107
+ }
108
+ return extensions;
109
+ }
110
+ //#endregion
111
+ export { headingPlugin };
@@ -0,0 +1,14 @@
1
+ import { Extension } from "@codemirror/state";
2
+
3
+ //#region src/core/plugins/inline.d.ts
4
+ interface InlinePluginOptions {
5
+ shortcuts?: {
6
+ bold?: string;
7
+ italic?: string;
8
+ strikethrough?: string;
9
+ code?: string;
10
+ };
11
+ }
12
+ declare function inlinePlugin(options?: InlinePluginOptions): Extension;
13
+ //#endregion
14
+ export { InlinePluginOptions, inlinePlugin };