@gjermundgaraba/pixel-paper 0.1.0 → 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.
@@ -0,0 +1,88 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ import { liveMarkdown } from "./live/live.js";
3
+ import { withLfLineEndings } from "./reconcile.js";
4
+ import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
5
+ import { commonmarkLanguage, markdownKeymap } from "@codemirror/lang-markdown";
6
+ import { Language } from "@codemirror/language";
7
+ import { diff } from "@codemirror/merge";
8
+ import { Compartment, EditorState, Prec, Transaction } from "@codemirror/state";
9
+ import { EditorView, keymap } from "@codemirror/view";
10
+ import { GFM, MarkdownParser } from "@lezer/markdown";
11
+ // src/markdown-editor/engine.ts
12
+ const DIFF_TIMEOUT_MS = 50;
13
+ const language = new Language(commonmarkLanguage.data, commonmarkLanguage.parser instanceof MarkdownParser ? commonmarkLanguage.parser.configure(GFM) : commonmarkLanguage.parser, [], "markdown");
14
+ /** Who is named by what, and whether the document may change. `readOnly` alone lets Enter and
15
+ * the Markdown keymap edit, so the filter refuses every change but an outside one. */
16
+ const accessExtension = (attributes, isReadOnly) => __foldkitBrandViewResult(([
17
+ EditorState.readOnly.of(isReadOnly),
18
+ ...isReadOnly ? [EditorState.changeFilter.of((transaction) => __foldkitBrandViewResult((transaction.annotation(Transaction.remote) === true), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#anonymous"))] : [],
19
+ EditorView.contentAttributes.of({
20
+ ...attributes,
21
+ ...isReadOnly ? { "aria-disabled": "true" } : {}
22
+ })
23
+ ]), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#accessExtension");
24
+ /** The editor's state. No line separator is set, so CRLF text parses like LF text. Tab stays
25
+ * unbound, so it leaves the field. */
26
+ const editorState = (doc, extensions = []) => __foldkitBrandViewResult((EditorState.create({
27
+ doc,
28
+ extensions: [
29
+ history(),
30
+ language,
31
+ liveMarkdown(),
32
+ Prec.high(keymap.of(markdownKeymap)),
33
+ keymap.of([...defaultKeymap, ...historyKeymap]),
34
+ EditorView.lineWrapping,
35
+ EditorView.contentAttributes.of({
36
+ spellcheck: "true",
37
+ autocorrect: "on",
38
+ autocapitalize: "sentences"
39
+ }),
40
+ extensions
41
+ ]
42
+ })), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#editorState");
43
+ /** The whole document to send up after these transactions, if one of them was a local edit. */
44
+ const emission = (transactions, state) => __foldkitBrandViewResult((transactions.some((transaction) => __foldkitBrandViewResult((transaction.docChanged && transaction.annotation(Transaction.remote) !== true), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#anonymous~2")) ? state.doc.toString() : void 0), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#emission");
45
+ /** A minimal edit from the document to an outside value: the caret survives it, and undo keeps
46
+ * to what was typed. */
47
+ const externalChange = (state, source) => {
48
+ const current = state.doc.toString();
49
+ const next = withLfLineEndings(source);
50
+ return __foldkitBrandViewResult(({
51
+ changes: diff(current, next, { timeout: DIFF_TIMEOUT_MS }).map(({ fromA, toA, fromB, toB }) => (__foldkitBrandViewResult(({
52
+ from: fromA,
53
+ to: toA,
54
+ insert: next.slice(fromB, toB)
55
+ }), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#anonymous~3"))),
56
+ annotations: [Transaction.remote.of(true), Transaction.addToHistory.of(false)]
57
+ }), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#externalChange");
58
+ };
59
+ /** Mounts CodeMirror in `parent`, and returns what the element drives it with. */
60
+ const createEngine = (config) => {
61
+ const access = new Compartment();
62
+ const view = new EditorView({
63
+ parent: config.parent,
64
+ state: editorState(config.doc, [access.of(accessExtension(config.attributes, config.isReadOnly)), EditorView.updateListener.of((update) => {
65
+ const doc = emission(update.transactions, update.state);
66
+ if (doc !== void 0) config.onLocalChange(doc);
67
+ })])
68
+ });
69
+ return __foldkitBrandViewResult(({
70
+ doc: () => __foldkitBrandViewResult((view.state.doc.toString()), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#doc"),
71
+ focus: () => {
72
+ view.focus();
73
+ },
74
+ requestMeasure: () => {
75
+ view.requestMeasure();
76
+ },
77
+ applyExternal: (source) => {
78
+ view.dispatch(externalChange(view.state, source));
79
+ },
80
+ configureAccess: (attributes, isReadOnly) => {
81
+ view.dispatch({ effects: access.reconfigure(accessExtension(attributes, isReadOnly)) });
82
+ },
83
+ destroy: () => {
84
+ view.destroy();
85
+ }
86
+ }), "@gjermundgaraba/pixel-paper/markdown-editor/engine.js#createEngine");
87
+ };
88
+ export { accessExtension, createEngine, editorState, emission, externalChange };
@@ -0,0 +1,5 @@
1
+ import { ViewConfig, view } from "./markdown-editor.js";
2
+ declare namespace index_d_exports {
3
+ export { ViewConfig, view };
4
+ }
5
+ export { type ViewConfig, index_d_exports, view };
@@ -0,0 +1,6 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
3
+ import { view } from "./markdown-editor.js";
4
+ // src/markdown-editor/index.ts
5
+ var markdown_editor_exports = /* @__PURE__ */ __exportAll({ view: () => __foldkitBrandViewResult((view), "@gjermundgaraba/pixel-paper/markdown-editor/index.js#view") });
6
+ export { markdown_editor_exports, view };
@@ -0,0 +1,18 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ // src/markdown-editor/link-policy.ts
3
+ const LINK_PROTOCOLS = /* @__PURE__ */ new Set([
4
+ "http:",
5
+ "https:",
6
+ "mailto:"
7
+ ]);
8
+ const IMAGE_PROTOCOLS = /* @__PURE__ */ new Set(["http:", "https:"]);
9
+ const allowedUrl = (protocols, url, base) => {
10
+ const parsed = URL.parse(url, base);
11
+ return __foldkitBrandViewResult((parsed !== null && protocols.has(parsed.protocol) ? parsed.href : void 0), "@gjermundgaraba/pixel-paper/markdown-editor/link-policy.js#allowedUrl");
12
+ };
13
+ /** A link's target as an absolute URL, when it is one a click may open. The browser's own
14
+ * URL parser decides, so a tab, a newline or mixed case cannot hide a scheme from it. */
15
+ const safeHref = (url, base) => __foldkitBrandViewResult((allowedUrl(LINK_PROTOCOLS, url, base)), "@gjermundgaraba/pixel-paper/markdown-editor/link-policy.js#safeHref");
16
+ /** An image's source as an absolute URL, when the page may fetch it on render. */
17
+ const safeImageSource = (url, base) => __foldkitBrandViewResult((allowedUrl(IMAGE_PROTOCOLS, url, base)), "@gjermundgaraba/pixel-paper/markdown-editor/link-policy.js#safeImageSource");
18
+ export { safeHref, safeImageSource };
@@ -0,0 +1,507 @@
1
+ import { brandViewResult as __foldkitBrandViewResult } from 'foldkit/brand'
2
+ import { safeHref, safeImageSource } from "../link-policy.js";
3
+ import { liveMarkdownTheme } from "./theme.js";
4
+ import { syntaxTree } from "@codemirror/language";
5
+ import { Prec, RangeSetBuilder, StateEffect, StateField } from "@codemirror/state";
6
+ import { Decoration, EditorView, ViewPlugin, WidgetType, keymap } from "@codemirror/view";
7
+ // src/markdown-editor/live/live.ts
8
+ const UNKNOWN_HEIGHT = -1;
9
+ const TABLE_ROW_HEIGHT = 32;
10
+ const IMAGE_ESTIMATED_HEIGHT = 240;
11
+ const TABLE_HINT = "Click to edit the table";
12
+ var DrawnWidget = class extends WidgetType {
13
+ drawing;
14
+ constructor(drawing) {
15
+ super();
16
+ this.drawing = drawing;
17
+ }
18
+ eq(other) {
19
+ return __foldkitBrandViewResult((other.drawing.key === this.drawing.key), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#eq");
20
+ }
21
+ toDOM(view) {
22
+ return __foldkitBrandViewResult((this.drawing.draw(view)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#toDOM");
23
+ }
24
+ get estimatedHeight() {
25
+ return __foldkitBrandViewResult((this.drawing.estimatedHeight), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#estimatedHeight");
26
+ }
27
+ ignoreEvent() {
28
+ return __foldkitBrandViewResult((this.drawing.takesOwnEvents), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#ignoreEvent");
29
+ }
30
+ };
31
+ const spanOf = (className, text) => {
32
+ const span = document.createElement("span");
33
+ span.className = className;
34
+ span.textContent = text;
35
+ return __foldkitBrandViewResult((span), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#spanOf");
36
+ };
37
+ const typographyWidget = (text, isDivider) => __foldkitBrandViewResult((new DrawnWidget({
38
+ key: `typography:${isDivider}:${text}`,
39
+ draw: () => __foldkitBrandViewResult((spanOf(isDivider ? "lmd-labeled-rule" : "", text)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#draw"),
40
+ estimatedHeight: UNKNOWN_HEIGHT,
41
+ takesOwnEvents: false
42
+ })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#typographyWidget");
43
+ const checkboxWidget = (isChecked) => __foldkitBrandViewResult((new DrawnWidget({
44
+ key: `checkbox:${isChecked}`,
45
+ draw: () => {
46
+ const box = document.createElement("input");
47
+ box.type = "checkbox";
48
+ box.checked = isChecked;
49
+ box.className = "lmd-check";
50
+ return __foldkitBrandViewResult((box), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#draw~2");
51
+ },
52
+ estimatedHeight: UNKNOWN_HEIGHT,
53
+ takesOwnEvents: false
54
+ })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#checkboxWidget");
55
+ const listMarkWidget = (text) => __foldkitBrandViewResult((new DrawnWidget({
56
+ key: `list-mark:${text}`,
57
+ draw: () => __foldkitBrandViewResult((spanOf("lmd-bullet", text)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#draw~3"),
58
+ estimatedHeight: UNKNOWN_HEIGHT,
59
+ takesOwnEvents: true
60
+ })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#listMarkWidget");
61
+ const imageWidget = (source, alt) => __foldkitBrandViewResult((new DrawnWidget({
62
+ key: `image:${source}\n${alt}`,
63
+ draw: () => {
64
+ const box = spanOf("lmd-img-box", "");
65
+ const safeSource = safeImageSource(source, document.baseURI);
66
+ if (safeSource === void 0) {
67
+ box.append(spanOf("lmd-img-note", alt === "" ? "Image not shown" : alt));
68
+ return __foldkitBrandViewResult((box), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#draw~4");
69
+ }
70
+ const image = document.createElement("img");
71
+ image.className = "lmd-img";
72
+ image.alt = alt;
73
+ image.addEventListener("error", () => {
74
+ image.replaceWith(spanOf("lmd-img-note", alt === "" ? "Image not found" : `Image not found: ${alt}`));
75
+ }, { once: true });
76
+ image.src = safeSource;
77
+ box.append(image);
78
+ return __foldkitBrandViewResult((box), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#draw~4");
79
+ },
80
+ estimatedHeight: IMAGE_ESTIMATED_HEIGHT,
81
+ takesOwnEvents: false
82
+ })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#imageWidget");
83
+ const isList = (node) => __foldkitBrandViewResult((node?.name === "BulletList" || node?.name === "OrderedList"), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#isList");
84
+ const listDepth = (item) => {
85
+ let depth = 0;
86
+ for (let node = item.parent; node !== null; node = node.parent) if (isList(node)) depth += 1;
87
+ return __foldkitBrandViewResult((depth), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#listDepth");
88
+ };
89
+ const firstMarkOf = (state, item) => {
90
+ const mark = item.parent?.firstChild?.getChild("ListMark");
91
+ return __foldkitBrandViewResult((mark === void 0 || mark === null ? void 0 : state.sliceDoc(mark.from, mark.to)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#firstMarkOf");
92
+ };
93
+ const itemNumber = (state, item) => {
94
+ const start = Number(/^\d+/u.exec(firstMarkOf(state, item) ?? "")?.[0] ?? 1);
95
+ let index = 0;
96
+ for (let node = item.prevSibling; node !== null; node = node.prevSibling) if (node.name === "ListItem") index += 1;
97
+ return __foldkitBrandViewResult((start + index), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#itemNumber");
98
+ };
99
+ const listDelimiter = (state, item) => __foldkitBrandViewResult((/[.)]$/u.exec(firstMarkOf(state, item) ?? "")?.[0] ?? "."), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#listDelimiter");
100
+ const outlineNumber = (state, item) => {
101
+ const parts = [];
102
+ for (let node = item; node !== null; node = node.parent) if (node.name === "ListItem" && node.parent?.name === "OrderedList") parts.unshift(itemNumber(state, node));
103
+ return __foldkitBrandViewResult((`${parts.join(".")}${listDelimiter(state, item)}`), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#outlineNumber");
104
+ };
105
+ const listMarker = (state, item) => {
106
+ const list = item.parent;
107
+ if (list?.name === "BulletList") return __foldkitBrandViewResult((Array.from({ length: listDepth(item) }, () => __foldkitBrandViewResult(("•"), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~2")).join(" ")), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#listMarker");
108
+ return __foldkitBrandViewResult((list?.name === "OrderedList" ? outlineNumber(state, item) : ""), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#listMarker");
109
+ };
110
+ const hide = Decoration.replace({});
111
+ const mark = (className) => __foldkitBrandViewResult((Decoration.mark({ class: className })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#mark");
112
+ const line = (className) => __foldkitBrandViewResult((Decoration.line({ class: className })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#line");
113
+ const INLINE = /* @__PURE__ */ new Map([
114
+ ["Emphasis", "lmd-em"],
115
+ ["StrongEmphasis", "lmd-strong"],
116
+ ["Strikethrough", "lmd-strike"],
117
+ ["InlineCode", "lmd-code"],
118
+ ["Link", "lmd-link"]
119
+ ]);
120
+ const HIDDEN_MARKS = /* @__PURE__ */ new Set([
121
+ "EmphasisMark",
122
+ "StrikethroughMark",
123
+ "LinkMark",
124
+ "URL"
125
+ ]);
126
+ const LABELED_RULE = /^ {0,3}---[ \t]+(?<title>\S(?:[^\n]*?\S)?)[ \t]+---[ \t]*$/gmu;
127
+ const ATX_HEADING = /^ATXHeading(?<level>\d)$/u;
128
+ const STANDALONE_DASHES = /(?<![\S\\])--(?!\S)/gu;
129
+ const NOT_PLAIN_TEXT = /Code|Link|URL|Image|HTML|HorizontalRule|Table|Escape/u;
130
+ const isLinkLike = (node) => __foldkitBrandViewResult((node?.name === "Link" || node?.name === "Image"), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#isLinkLike");
131
+ const normalizedLabel = (label) => __foldkitBrandViewResult((label.trim().replaceAll(/\s+/gu, " ").toLowerCase()), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#normalizedLabel");
132
+ const linkDefinitions = (state) => {
133
+ const labels = /* @__PURE__ */ new Set();
134
+ for (let node = syntaxTree(state).topNode.firstChild; node !== null; node = node.nextSibling) {
135
+ const label = node.name === "LinkReference" ? node.getChild("LinkLabel") : null;
136
+ if (label !== null) labels.add(normalizedLabel(state.sliceDoc(label.from + 1, label.to - 1)));
137
+ }
138
+ return __foldkitBrandViewResult((labels), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#linkDefinitions");
139
+ };
140
+ const bracketedText = (state, node) => {
141
+ const label = node.getChild("LinkLabel");
142
+ const text = label === null ? "" : state.sliceDoc(label.from + 1, label.to - 1);
143
+ const [opening, closing] = node.getChildren("LinkMark");
144
+ return __foldkitBrandViewResult((normalizedLabel(text) === "" && opening !== void 0 && closing !== void 0 ? state.sliceDoc(opening.to, closing.from) : text), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#bracketedText");
145
+ };
146
+ const isPlainBrackets = (state, node, definitions = linkDefinitions(state)) => __foldkitBrandViewResult((isLinkLike(node) && node.getChild("URL") === null && !definitions.has(normalizedLabel(bracketedText(state, node)))), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#isPlainBrackets");
147
+ const build = (view) => {
148
+ const { state } = view;
149
+ const { ranges } = state.selection;
150
+ const isFocused = view.hasFocus;
151
+ const touched = (from, to) => __foldkitBrandViewResult((isFocused && ranges.some((range) => __foldkitBrandViewResult((range.from <= to && range.to >= from), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~3"))), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#touched");
152
+ const activeLine = (position) => {
153
+ const { from, to } = state.doc.lineAt(position);
154
+ return __foldkitBrandViewResult((touched(from, to)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#activeLine");
155
+ };
156
+ const placed = [];
157
+ const add = (from, to, decoration) => {
158
+ placed.push({
159
+ from,
160
+ to,
161
+ decoration,
162
+ isReplace: decoration === hide
163
+ });
164
+ };
165
+ const replace = (from, to, widget) => {
166
+ placed.push({
167
+ from,
168
+ to,
169
+ decoration: Decoration.replace({ widget }),
170
+ isReplace: true
171
+ });
172
+ };
173
+ const addLine = (position, decoration) => {
174
+ placed.push({
175
+ from: position,
176
+ to: position,
177
+ decoration,
178
+ isReplace: false
179
+ });
180
+ };
181
+ const addLines = (from, to, className) => {
182
+ for (let position = from; position <= to;) {
183
+ const { from: start, to: end } = state.doc.lineAt(position);
184
+ addLine(start, line(className));
185
+ position = end + 1;
186
+ }
187
+ };
188
+ const hideWithFollowingSpace = (from, to) => {
189
+ add(from, Math.min(to + 1, state.doc.lineAt(from).to), hide);
190
+ };
191
+ const labeledRanges = [];
192
+ const definitions = linkDefinitions(state);
193
+ for (const { from, to } of view.visibleRanges) {
194
+ const text = state.sliceDoc(from, to);
195
+ syntaxTree(state).iterate({
196
+ from,
197
+ to,
198
+ enter: (node) => {
199
+ if (labeledRanges.some(([start, end]) => __foldkitBrandViewResult((node.from >= start && node.to <= end), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~4"))) return __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
200
+ const { name } = node;
201
+ const { parent } = node.node;
202
+ if (name === "Paragraph" && parent?.name === "Document") {
203
+ const paragraph = state.sliceDoc(node.from, node.to);
204
+ for (const match of paragraph.matchAll(LABELED_RULE)) {
205
+ const start = node.from + match.index;
206
+ const end = start + match[0].length;
207
+ const title = match.groups?.["title"];
208
+ if (title !== void 0 && !activeLine(start)) {
209
+ labeledRanges.push([start, end]);
210
+ replace(start, end, typographyWidget(title, true));
211
+ }
212
+ }
213
+ }
214
+ const level = ATX_HEADING.exec(name)?.groups?.["level"];
215
+ if (level !== void 0) {
216
+ addLine(state.doc.lineAt(node.from).from, line(`lmd-h lmd-h${level}`));
217
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
218
+ }
219
+ if (name === "HeaderMark" && parent?.name.startsWith("ATXHeading") === true) {
220
+ if (!activeLine(node.from)) hideWithFollowingSpace(node.from, node.to);
221
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
222
+ }
223
+ if (isLinkLike(node.node) && isPlainBrackets(state, node.node, definitions)) return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
224
+ if (name === "LinkMark" && parent !== null && isPlainBrackets(state, parent, definitions)) return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
225
+ if (name === "Escape") {
226
+ if (!touched(node.from, node.to)) add(node.from, node.from + 1, hide);
227
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
228
+ }
229
+ if (name === "Image") {
230
+ const url = node.node.getChild("URL");
231
+ if (url !== null && !touched(node.from, node.to)) {
232
+ const alt = state.sliceDoc(node.from + 2, Math.max(node.from + 2, url.from - 2));
233
+ replace(node.from, node.to, imageWidget(state.sliceDoc(url.from, url.to), alt));
234
+ }
235
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
236
+ }
237
+ const inlineClass = INLINE.get(name);
238
+ if (inlineClass !== void 0) {
239
+ add(node.from, node.to, mark(inlineClass));
240
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
241
+ }
242
+ if (name === "URL" && !isLinkLike(parent)) {
243
+ add(node.from, node.to, mark("lmd-link"));
244
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
245
+ }
246
+ if (parent !== null && (HIDDEN_MARKS.has(name) || name === "CodeMark" && parent.name === "InlineCode")) {
247
+ if (!touched(parent.from, parent.to)) add(node.from, node.to, hide);
248
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
249
+ }
250
+ if (name === "FencedCode" || name === "CodeBlock") {
251
+ addLines(node.from, node.to, "lmd-codeblock");
252
+ return __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
253
+ }
254
+ if (name === "Blockquote") {
255
+ addLines(node.from, node.to, "lmd-quote");
256
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
257
+ }
258
+ if (name === "QuoteMark") {
259
+ if (!activeLine(node.from)) hideWithFollowingSpace(node.from, node.to);
260
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
261
+ }
262
+ if (name === "HorizontalRule") {
263
+ if (!activeLine(node.from)) {
264
+ addLine(state.doc.lineAt(node.from).from, line("lmd-hr"));
265
+ add(node.from, node.to, hide);
266
+ }
267
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
268
+ }
269
+ if (name === "Table") {
270
+ addLines(node.from, node.to, "lmd-table");
271
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
272
+ }
273
+ if (name === "ListMark" && parent !== null && isList(parent.parent)) {
274
+ if (activeLine(node.from)) return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
275
+ if (parent.getChild("Task") === null) replace(node.from, node.to, listMarkWidget(listMarker(state, parent)));
276
+ else hideWithFollowingSpace(node.from, node.to);
277
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
278
+ }
279
+ if (name === "TaskMarker" && !touched(node.from, node.to)) {
280
+ const isChecked = /x/iu.test(state.sliceDoc(node.from, node.to));
281
+ replace(node.from, node.to, checkboxWidget(isChecked));
282
+ if (isChecked && parent !== null) add(node.to, parent.to, mark("lmd-done"));
283
+ }
284
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter");
285
+ }
286
+ });
287
+ for (const match of text.matchAll(STANDALONE_DASHES)) {
288
+ const start = from + match.index;
289
+ const end = start + 2;
290
+ if (!touched(start, end)) {
291
+ let node = syntaxTree(state).resolveInner(start, 1);
292
+ let isPlain = true;
293
+ while (node !== null && isPlain) {
294
+ isPlain = !NOT_PLAIN_TEXT.test(node.name);
295
+ node = node.parent;
296
+ }
297
+ if (isPlain) replace(start, end, typographyWidget("—", false));
298
+ }
299
+ }
300
+ }
301
+ placed.sort((left, right) => __foldkitBrandViewResult((left.from - right.from || left.decoration.startSide - right.decoration.startSide), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~5"));
302
+ const builder = new RangeSetBuilder();
303
+ let lastReplaceEnd = -1;
304
+ for (const { from, to, decoration, isReplace } of placed) {
305
+ const isRangeReplace = from !== to && isReplace;
306
+ if (!isRangeReplace || from >= lastReplaceEnd) {
307
+ builder.add(from, to, decoration);
308
+ if (isRangeReplace) lastReplaceEnd = to;
309
+ }
310
+ }
311
+ return __foldkitBrandViewResult((builder.finish()), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#build");
312
+ };
313
+ const DELIMITER_ROW = /^\s*\|?[\s:|-]+\|?\s*$/u;
314
+ const tableCells = (row) => __foldkitBrandViewResult((row.trim().replaceAll(/^\||\|$/gu, "").split(/(?<!\\)\|/u).map((cell) => __foldkitBrandViewResult((cell.trim().replaceAll(String.raw`\|`, "|")), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~6"))), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#tableCells");
315
+ const tableOf = (source) => {
316
+ const table = document.createElement("table");
317
+ const head = table.createTHead();
318
+ const body = table.createTBody();
319
+ const rows = source.split("\n").filter((row) => __foldkitBrandViewResult((row.trim() !== ""), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~7"));
320
+ table.className = "lmd-table-view";
321
+ for (const [index, row] of rows.entries()) if (index !== 1 || !DELIMITER_ROW.test(row)) {
322
+ const tableRow = document.createElement("tr");
323
+ for (const text of tableCells(row)) {
324
+ const cell = document.createElement(index === 0 ? "th" : "td");
325
+ cell.textContent = text;
326
+ tableRow.append(cell);
327
+ }
328
+ (index === 0 ? head : body).append(tableRow);
329
+ }
330
+ return __foldkitBrandViewResult((table), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#tableOf");
331
+ };
332
+ const tableWidget = (text) => __foldkitBrandViewResult((new DrawnWidget({
333
+ key: `table:${text}`,
334
+ draw: (view) => {
335
+ const dom = document.createElement("div");
336
+ dom.className = "lmd-table-widget";
337
+ dom.title = TABLE_HINT;
338
+ dom.append(tableOf(text));
339
+ dom.addEventListener("mousedown", (event) => {
340
+ event.preventDefault();
341
+ const row = event.target instanceof Element ? event.target.closest("tr") : null;
342
+ const rows = [...dom.querySelectorAll("tr")];
343
+ const rowIndex = row === null ? -1 : rows.indexOf(row);
344
+ const sourceOffset = rowIndex <= 0 ? 0 : rowIndex + 1;
345
+ const first = view.state.doc.lineAt(view.posAtDOM(dom));
346
+ const target = view.state.doc.line(Math.min(first.number + sourceOffset, view.state.doc.lines));
347
+ view.dispatch({ selection: { anchor: Math.min(target.from + 2, target.to) } });
348
+ view.focus();
349
+ });
350
+ return __foldkitBrandViewResult((dom), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#draw~5");
351
+ },
352
+ estimatedHeight: TABLE_ROW_HEIGHT * text.split("\n").length,
353
+ takesOwnEvents: true
354
+ })), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#tableWidget");
355
+ const lastValueOf = (transaction, type, held) => {
356
+ const last = transaction.effects.findLast((effect) => __foldkitBrandViewResult((effect.is(type)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~9"));
357
+ return __foldkitBrandViewResult((last === void 0 ? held : last.value), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#lastValueOf");
358
+ };
359
+ const setFocus = StateEffect.define();
360
+ const setPointerDown = StateEffect.define();
361
+ const pointerDownField = StateField.define({
362
+ create: () => __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#create"),
363
+ update: (isDown, transaction) => __foldkitBrandViewResult((lastValueOf(transaction, setPointerDown, isDown)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#update")
364
+ });
365
+ const POINTER_RELEASE_EVENTS = [
366
+ "mouseup",
367
+ "dragend",
368
+ "contextmenu"
369
+ ];
370
+ const holdRevealUntilPointerRelease = (view) => {
371
+ const { ownerDocument } = view.dom;
372
+ const release = () => {
373
+ for (const name of POINTER_RELEASE_EVENTS) ownerDocument.removeEventListener(name, release);
374
+ setTimeout(() => {
375
+ view.dispatch({ effects: setPointerDown.of(false) });
376
+ }, 0);
377
+ };
378
+ view.dispatch({ effects: setPointerDown.of(true) });
379
+ for (const name of POINTER_RELEASE_EVENTS) ownerDocument.addEventListener(name, release);
380
+ };
381
+ const buildTables = (state, isFocused) => {
382
+ const builder = new RangeSetBuilder();
383
+ syntaxTree(state).iterate({ enter: (node) => {
384
+ if (node.name !== "Table") return __foldkitBrandViewResult((node.name === "Document" || node.name.endsWith("List") || node.name === "ListItem" || node.name === "Blockquote"), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter~2");
385
+ const { from } = state.doc.lineAt(node.from);
386
+ const { to } = state.doc.lineAt(node.to);
387
+ const isInside = state.selection.ranges.some((range) => __foldkitBrandViewResult((range.from <= to && range.to >= from), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~11"));
388
+ if (from === node.from && !(isFocused && isInside)) builder.add(from, to, Decoration.replace({
389
+ widget: tableWidget(state.sliceDoc(from, to)),
390
+ block: true
391
+ }));
392
+ return __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#enter~2");
393
+ } });
394
+ return __foldkitBrandViewResult((builder.finish()), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#buildTables");
395
+ };
396
+ const tablesField = StateField.define({
397
+ create: (state) => (__foldkitBrandViewResult(({
398
+ isFocused: false,
399
+ decorations: buildTables(state, false)
400
+ }), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#create~2")),
401
+ update: (value, transaction) => {
402
+ const isFocused = lastValueOf(transaction, setFocus, value.isFocused);
403
+ const wasDown = transaction.startState.field(pointerDownField);
404
+ const isDown = transaction.state.field(pointerDownField);
405
+ if (isDown && !transaction.docChanged) return __foldkitBrandViewResult(({
406
+ isFocused,
407
+ decorations: value.decorations
408
+ }), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#update~2");
409
+ return __foldkitBrandViewResult((isFocused === value.isFocused && wasDown === isDown && !transaction.docChanged && transaction.selection === void 0 && syntaxTree(transaction.startState) === syntaxTree(transaction.state) ? value : {
410
+ isFocused,
411
+ decorations: buildTables(transaction.state, isFocused)
412
+ }), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#update~2");
413
+ },
414
+ provide: (field) => __foldkitBrandViewResult((EditorView.decorations.from(field, (value) => __foldkitBrandViewResult((value.decorations), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~12"))), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#provide")
415
+ });
416
+ const linkHref = (state, node) => {
417
+ const url = node.name === "Link" ? node.getChild("URL") : node;
418
+ if (url === null) return;
419
+ const href = state.sliceDoc(url.from, url.to);
420
+ return __foldkitBrandViewResult((/^www\./iu.test(href) ? `https://${href}` : href), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#linkHref");
421
+ };
422
+ const isLinkNode = (state, node) => __foldkitBrandViewResult((!isPlainBrackets(state, node) && (node.name === "Link" || node.name === "URL" && !isLinkLike(node.parent))), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#isLinkNode");
423
+ const toggleCheckbox = (view, box) => {
424
+ const position = view.posAtDOM(box);
425
+ const text = view.state.sliceDoc(position, position + 3);
426
+ if (!/^\[[ xX]\]$/u.test(text)) return __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#toggleCheckbox");
427
+ view.dispatch({ changes: {
428
+ from: position + 1,
429
+ to: position + 2,
430
+ insert: text.charAt(1) === " " ? "x" : " "
431
+ } });
432
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#toggleCheckbox");
433
+ };
434
+ const linkAt = (state, position, side) => {
435
+ for (let node = syntaxTree(state).resolveInner(position, side); node !== null; node = node.parent) if (isLinkNode(state, node)) return __foldkitBrandViewResult((linkHref(state, node)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#linkAt");
436
+ };
437
+ const openLink = (url) => {
438
+ const href = safeHref(url, document.baseURI);
439
+ if (href !== void 0) window.open(href, "_blank", "noopener,noreferrer");
440
+ };
441
+ const openLinkAtCaret = (view) => {
442
+ const { head } = view.state.selection.main;
443
+ const url = linkAt(view.state, head, 1) ?? linkAt(view.state, head, -1);
444
+ if (url === void 0) return __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#openLinkAtCaret");
445
+ openLink(url);
446
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#openLinkAtCaret");
447
+ };
448
+ /** Markdown drawn over its own text, as in Obsidian's Live Preview: the document stays
449
+ * Markdown, and its marks show only around the selection. Redrawing a reveal moves text, so
450
+ * nothing redraws under an IME's composition or a pressed mouse button. */
451
+ const liveMarkdown = () => {
452
+ const preview = ViewPlugin.fromClass(class {
453
+ decorations;
454
+ isStale = false;
455
+ constructor(view) {
456
+ this.decorations = build(view);
457
+ }
458
+ update(update) {
459
+ if (update.view.composing || update.state.field(pointerDownField) && !update.docChanged) {
460
+ this.decorations = this.decorations.map(update.changes);
461
+ this.isStale = true;
462
+ } else if (this.isStale || update.docChanged || update.selectionSet || update.focusChanged || update.viewportChanged || syntaxTree(update.startState) !== syntaxTree(update.state)) {
463
+ this.decorations = build(update.view);
464
+ this.isStale = false;
465
+ }
466
+ }
467
+ }, {
468
+ decorations: (plugin) => __foldkitBrandViewResult((plugin.decorations), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#decorations"),
469
+ eventObservers: { compositionend: (_, view) => {
470
+ setTimeout(() => {
471
+ view.dispatch({});
472
+ }, 0);
473
+ } },
474
+ eventHandlers: { mousedown: (event, view) => {
475
+ if (event.target instanceof HTMLInputElement && event.target.classList.contains("lmd-check") && toggleCheckbox(view, event.target)) {
476
+ event.preventDefault();
477
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#mousedown");
478
+ }
479
+ if (event.metaKey || event.ctrlKey) {
480
+ const position = view.posAtCoords({
481
+ x: event.clientX,
482
+ y: event.clientY
483
+ });
484
+ const url = position === null ? void 0 : linkAt(view.state, position, 1);
485
+ if (url !== void 0) {
486
+ openLink(url);
487
+ event.preventDefault();
488
+ return __foldkitBrandViewResult((true), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#mousedown");
489
+ }
490
+ }
491
+ if (event.button === 0) holdRevealUntilPointerRelease(view);
492
+ return __foldkitBrandViewResult((false), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#mousedown");
493
+ } }
494
+ });
495
+ return __foldkitBrandViewResult(([
496
+ pointerDownField,
497
+ preview,
498
+ tablesField,
499
+ Prec.high(keymap.of([{
500
+ key: "Mod-Enter",
501
+ run: openLinkAtCaret
502
+ }])),
503
+ EditorView.focusChangeEffect.of((_, isFocusing) => __foldkitBrandViewResult((setFocus.of(isFocusing)), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#anonymous~14")),
504
+ liveMarkdownTheme
505
+ ]), "@gjermundgaraba/pixel-paper/markdown-editor/live/live.js#liveMarkdown");
506
+ };
507
+ export { liveMarkdown };