@pixerate/editor 0.4.4 → 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.
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/serializers/index.ts
@@ -22,8 +32,10 @@ var serializers_exports = {};
22
32
  __export(serializers_exports, {
23
33
  escapeHtml: () => escapeHtml,
24
34
  extractMentionsFromDoc: () => extractMentionsFromDoc,
35
+ getEditorMarkdown: () => getEditorMarkdown,
25
36
  getEditorText: () => getEditorText,
26
37
  htmlToPlainText: () => htmlToPlainText,
38
+ markdownToTipTapHtml: () => markdownToTipTapHtml,
27
39
  plainTextToTipTapHtml: () => plainTextToTipTapHtml
28
40
  });
29
41
  module.exports = __toCommonJS(serializers_exports);
@@ -155,12 +167,34 @@ function extractMentionsFromDoc(docOrEditor) {
155
167
  }
156
168
  return mentions;
157
169
  }
170
+
171
+ // src/serializers/markdown.ts
172
+ var import_markdown_it = __toESM(require("markdown-it"), 1);
173
+ var import_markdown_it_task_lists = __toESM(require("markdown-it-task-lists"), 1);
174
+ var md = new import_markdown_it.default({
175
+ html: true,
176
+ linkify: true,
177
+ breaks: true
178
+ }).use(import_markdown_it_task_lists.default);
179
+ function markdownToTipTapHtml(markdown) {
180
+ if (!markdown) return "<p></p>";
181
+ return md.render(markdown);
182
+ }
183
+ function getEditorMarkdown(editor) {
184
+ if (!editor) return "";
185
+ if (typeof editor.storage?.markdown?.getMarkdown === "function") {
186
+ return editor.storage.markdown.getMarkdown();
187
+ }
188
+ return getEditorText(editor);
189
+ }
158
190
  // Annotate the CommonJS export names for ESM import in node:
159
191
  0 && (module.exports = {
160
192
  escapeHtml,
161
193
  extractMentionsFromDoc,
194
+ getEditorMarkdown,
162
195
  getEditorText,
163
196
  htmlToPlainText,
197
+ markdownToTipTapHtml,
164
198
  plainTextToTipTapHtml
165
199
  });
166
200
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/serializers/index.ts","../../src/serializers/plain-text.ts"],"sourcesContent":["export * from \"./plain-text\";\n","/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (/<p[\\s>]/i.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-label=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n )\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-id=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n );\n\n if (typeof document !== \"undefined\") {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = mentionNormalized;\n tempDiv\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n tempDiv.querySelectorAll(\"br\").forEach((br) => br.replaceWith(\"\\n\"));\n const paragraphs = tempDiv.querySelectorAll(\"p, div, li, h1, h2, h3, h4, h5, h6\");\n if (paragraphs.length > 0) {\n const textParts: string[] = [];\n paragraphs.forEach((p) => {\n textParts.push(p.textContent || \"\");\n });\n return textParts.join(\"\\n\");\n }\n return tempDiv.textContent || \"\";\n }\n\n // Node.js fallback regex\n return mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#039;/g, \"'\")\n .trim();\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n const div = document.createElement(\"div\");\n div.innerHTML = docOrEditor;\n div.querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n }\n\n return mentions;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/serializers/index.ts","../../src/serializers/plain-text.ts","../../src/serializers/markdown.ts"],"sourcesContent":["export * from \"./plain-text\";\nexport * from \"./markdown\";\n","/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (/<p[\\s>]/i.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-label=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n )\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-id=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n );\n\n if (typeof document !== \"undefined\") {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = mentionNormalized;\n tempDiv\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n tempDiv.querySelectorAll(\"br\").forEach((br) => br.replaceWith(\"\\n\"));\n const paragraphs = tempDiv.querySelectorAll(\"p, div, li, h1, h2, h3, h4, h5, h6\");\n if (paragraphs.length > 0) {\n const textParts: string[] = [];\n paragraphs.forEach((p) => {\n textParts.push(p.textContent || \"\");\n });\n return textParts.join(\"\\n\");\n }\n return tempDiv.textContent || \"\";\n }\n\n // Node.js fallback regex\n return mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#039;/g, \"'\")\n .trim();\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n const div = document.createElement(\"div\");\n div.innerHTML = docOrEditor;\n div.querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n }\n\n return mentions;\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n */\nexport function markdownToTipTapHtml(markdown: string): string {\n if (!markdown) return \"<p></p>\";\n return md.render(markdown);\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"],"mappings":"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","names":["MarkdownIt","taskLists"]}
@@ -30,4 +30,15 @@ interface ExtractedMention {
30
30
  */
31
31
  declare function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[];
32
32
 
33
- export { type ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorText, htmlToPlainText, plainTextToTipTapHtml };
33
+ /**
34
+ * Converts a markdown string into HTML suitable for TipTap initial content or setContent.
35
+ */
36
+ declare function markdownToTipTapHtml(markdown: string): string;
37
+ /**
38
+ * Extracts clean markdown from a TipTap editor instance.
39
+ * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().
40
+ * Otherwise, it falls back to getEditorText(editor).
41
+ */
42
+ declare function getEditorMarkdown(editor: any): string;
43
+
44
+ export { type ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, plainTextToTipTapHtml };
@@ -30,4 +30,15 @@ interface ExtractedMention {
30
30
  */
31
31
  declare function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[];
32
32
 
33
- export { type ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorText, htmlToPlainText, plainTextToTipTapHtml };
33
+ /**
34
+ * Converts a markdown string into HTML suitable for TipTap initial content or setContent.
35
+ */
36
+ declare function markdownToTipTapHtml(markdown: string): string;
37
+ /**
38
+ * Extracts clean markdown from a TipTap editor instance.
39
+ * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().
40
+ * Otherwise, it falls back to getEditorText(editor).
41
+ */
42
+ declare function getEditorMarkdown(editor: any): string;
43
+
44
+ export { type ExtractedMention, escapeHtml, extractMentionsFromDoc, getEditorMarkdown, getEditorText, htmlToPlainText, markdownToTipTapHtml, plainTextToTipTapHtml };
@@ -125,11 +125,33 @@ function extractMentionsFromDoc(docOrEditor) {
125
125
  }
126
126
  return mentions;
127
127
  }
128
+
129
+ // src/serializers/markdown.ts
130
+ import MarkdownIt from "markdown-it";
131
+ import taskLists from "markdown-it-task-lists";
132
+ var md = new MarkdownIt({
133
+ html: true,
134
+ linkify: true,
135
+ breaks: true
136
+ }).use(taskLists);
137
+ function markdownToTipTapHtml(markdown) {
138
+ if (!markdown) return "<p></p>";
139
+ return md.render(markdown);
140
+ }
141
+ function getEditorMarkdown(editor) {
142
+ if (!editor) return "";
143
+ if (typeof editor.storage?.markdown?.getMarkdown === "function") {
144
+ return editor.storage.markdown.getMarkdown();
145
+ }
146
+ return getEditorText(editor);
147
+ }
128
148
  export {
129
149
  escapeHtml,
130
150
  extractMentionsFromDoc,
151
+ getEditorMarkdown,
131
152
  getEditorText,
132
153
  htmlToPlainText,
154
+ markdownToTipTapHtml,
133
155
  plainTextToTipTapHtml
134
156
  };
135
157
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/serializers/plain-text.ts"],"sourcesContent":["/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (/<p[\\s>]/i.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-label=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n )\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-id=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n );\n\n if (typeof document !== \"undefined\") {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = mentionNormalized;\n tempDiv\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n tempDiv.querySelectorAll(\"br\").forEach((br) => br.replaceWith(\"\\n\"));\n const paragraphs = tempDiv.querySelectorAll(\"p, div, li, h1, h2, h3, h4, h5, h6\");\n if (paragraphs.length > 0) {\n const textParts: string[] = [];\n paragraphs.forEach((p) => {\n textParts.push(p.textContent || \"\");\n });\n return textParts.join(\"\\n\");\n }\n return tempDiv.textContent || \"\";\n }\n\n // Node.js fallback regex\n return mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#039;/g, \"'\")\n .trim();\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n const div = document.createElement(\"div\");\n div.innerHTML = docOrEditor;\n div.querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n }\n\n return mentions;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/serializers/plain-text.ts","../../src/serializers/markdown.ts"],"sourcesContent":["/**\n * Escapes characters that have syntactic meaning in HTML text.\n */\nexport function escapeHtml(text: string): string {\n if (!text) return \"\";\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#039;\");\n}\n\n/**\n * Converts a plain-text string with newlines into HTML paragraphs suitable\n * for TipTap initial content or setContent, preserving line breaks.\n */\nexport function plainTextToTipTapHtml(text: string): string {\n if (!text) return \"<p></p>\";\n if (/<p[\\s>]/i.test(text)) {\n return text;\n }\n return text\n .replace(/\\r\\n/g, \"\\n\")\n .replace(/\\r/g, \"\\n\")\n .split(\"\\n\")\n .map((line) => `<p>${escapeHtml(line)}</p>`)\n .join(\"\");\n}\n\n/**\n * Extracts plain text from an HTML string or TipTap HTML, preserving newlines between block tags.\n */\nexport function htmlToPlainText(html: string): string {\n if (!html) return \"\";\n\n // Normalize mentions so data-label is preserved as @label even if textContent is empty\n const mentionNormalized = html\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-label=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n )\n .replace(\n /<span[^>]*data-type=[\"']mention[\"'][^>]*data-id=[\"']([^\"']+)[\"'][^>]*>.*?<\\/span>/gi,\n \"@$1\",\n );\n\n if (typeof document !== \"undefined\") {\n const tempDiv = document.createElement(\"div\");\n tempDiv.innerHTML = mentionNormalized;\n tempDiv\n .querySelectorAll(\"br.ProseMirror-trailingBreak\")\n .forEach((br) => br.remove());\n tempDiv.querySelectorAll(\"br\").forEach((br) => br.replaceWith(\"\\n\"));\n const paragraphs = tempDiv.querySelectorAll(\"p, div, li, h1, h2, h3, h4, h5, h6\");\n if (paragraphs.length > 0) {\n const textParts: string[] = [];\n paragraphs.forEach((p) => {\n textParts.push(p.textContent || \"\");\n });\n return textParts.join(\"\\n\");\n }\n return tempDiv.textContent || \"\";\n }\n\n // Node.js fallback regex\n return mentionNormalized\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/&amp;/g, \"&\")\n .replace(/&lt;/g, \"<\")\n .replace(/&gt;/g, \">\")\n .replace(/&quot;/g, '\"')\n .replace(/&#039;/g, \"'\")\n .trim();\n}\n\n/**\n * Extracts plain text from a TipTap editor instance, preserving newline separators\n * between block nodes and converting mention nodes to @label.\n */\nexport function getEditorText(editor: any): string {\n if (!editor) return \"\";\n const html = typeof editor.getHTML === \"function\" ? editor.getHTML() : \"\";\n if (html) {\n return htmlToPlainText(html);\n }\n if (typeof editor.getText === \"function\") {\n try {\n return editor.getText({ blockSeparator: \"\\n\" });\n } catch {\n return editor.getText();\n }\n }\n return \"\";\n}\n\nexport interface ExtractedMention {\n id: string;\n label: string;\n type?: string;\n avatarUrl?: string;\n color?: string;\n [key: string]: any;\n}\n\n/**\n * Traverses an editor instance, ProseMirror document, JSONContent, or HTML string\n * and extracts all mention attributes without needing regex.\n */\nexport function extractMentionsFromDoc(docOrEditor: any): ExtractedMention[] {\n if (!docOrEditor) return [];\n const mentions: ExtractedMention[] = [];\n\n // TipTap editor or ProseMirror Node with .descendants()\n const doc =\n docOrEditor?.state?.doc ||\n (typeof docOrEditor?.descendants === \"function\" ? docOrEditor : null);\n\n if (doc && typeof doc.descendants === \"function\") {\n doc.descendants((node: any) => {\n if (node.type?.name === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n });\n return mentions;\n }\n\n // JSONContent tree\n if (typeof docOrEditor === \"object\" && docOrEditor.content) {\n const walk = (nodes: any[]) => {\n for (const node of nodes) {\n if (node.type === \"mention\" && node.attrs) {\n mentions.push({\n id: node.attrs.id || \"\",\n label: node.attrs.label || \"\",\n type: node.attrs.type,\n avatarUrl: node.attrs.avatarUrl,\n color: node.attrs.color,\n ...node.attrs,\n });\n }\n if (Array.isArray(node.content)) {\n walk(node.content);\n }\n }\n };\n walk(docOrEditor.content);\n return mentions;\n }\n\n // HTML String\n if (typeof docOrEditor === \"string\") {\n if (typeof document !== \"undefined\") {\n const div = document.createElement(\"div\");\n div.innerHTML = docOrEditor;\n div.querySelectorAll('span[data-type=\"mention\"]').forEach((el) => {\n mentions.push({\n id: el.getAttribute(\"data-id\") || \"\",\n label: el.getAttribute(\"data-label\") || \"\",\n type: el.getAttribute(\"data-type-name\") || undefined,\n avatarUrl: el.getAttribute(\"data-avatar-url\") || undefined,\n color: el.getAttribute(\"data-color\") || undefined,\n });\n });\n } else {\n const spanRegex = /<span([^>]*data-type=[\"']mention[\"'][^>]*)>/gi;\n let match;\n while ((match = spanRegex.exec(docOrEditor)) !== null) {\n const attrStr = match[1];\n const getAttr = (name: string) => {\n const m = new RegExp(`${name}=[\"']([^\"']*)[\"']`, \"i\").exec(attrStr);\n return m ? m[1] : undefined;\n };\n mentions.push({\n id: getAttr(\"data-id\") || \"\",\n label: getAttr(\"data-label\") || \"\",\n type: getAttr(\"data-type-name\") || getAttr(\"data-entity-type\"),\n avatarUrl: getAttr(\"data-avatar-url\"),\n color: getAttr(\"data-color\"),\n });\n }\n }\n }\n\n return mentions;\n}\n","import MarkdownIt from \"markdown-it\";\nimport taskLists from \"markdown-it-task-lists\";\nimport { getEditorText } from \"./plain-text\";\n\nconst md = new MarkdownIt({\n html: true,\n linkify: true,\n breaks: true,\n}).use(taskLists);\n\n/**\n * Converts a markdown string into HTML suitable for TipTap initial content or setContent.\n */\nexport function markdownToTipTapHtml(markdown: string): string {\n if (!markdown) return \"<p></p>\";\n return md.render(markdown);\n}\n\n/**\n * Extracts clean markdown from a TipTap editor instance.\n * If the editor has the Markdown extension configured, it uses editor.storage.markdown.getMarkdown().\n * Otherwise, it falls back to getEditorText(editor).\n */\nexport function getEditorMarkdown(editor: any): string {\n if (!editor) return \"\";\n if (typeof editor.storage?.markdown?.getMarkdown === \"function\") {\n return editor.storage.markdown.getMarkdown();\n }\n return getEditorText(editor);\n}\n"],"mappings":";AAGO,SAAS,WAAW,MAAsB;AAC/C,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AAMO,SAAS,sBAAsB,MAAsB;AAC1D,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,WAAW,KAAK,IAAI,GAAG;AACzB,WAAO;AAAA,EACT;AACA,SAAO,KACJ,QAAQ,SAAS,IAAI,EACrB,QAAQ,OAAO,IAAI,EACnB,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,MAAM,WAAW,IAAI,CAAC,MAAM,EAC1C,KAAK,EAAE;AACZ;AAKO,SAAS,gBAAgB,MAAsB;AACpD,MAAI,CAAC,KAAM,QAAO;AAGlB,QAAM,oBAAoB,KACvB;AAAA,IACC;AAAA,IACA;AAAA,EACF,EACC;AAAA,IACC;AAAA,IACA;AAAA,EACF;AAEF,MAAI,OAAO,aAAa,aAAa;AACnC,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AACpB,YACG,iBAAiB,8BAA8B,EAC/C,QAAQ,CAAC,OAAO,GAAG,OAAO,CAAC;AAC9B,YAAQ,iBAAiB,IAAI,EAAE,QAAQ,CAAC,OAAO,GAAG,YAAY,IAAI,CAAC;AACnE,UAAM,aAAa,QAAQ,iBAAiB,oCAAoC;AAChF,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,YAAsB,CAAC;AAC7B,iBAAW,QAAQ,CAAC,MAAM;AACxB,kBAAU,KAAK,EAAE,eAAe,EAAE;AAAA,MACpC,CAAC;AACD,aAAO,UAAU,KAAK,IAAI;AAAA,IAC5B;AACA,WAAO,QAAQ,eAAe;AAAA,EAChC;AAGA,SAAO,kBACJ,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,WAAW,IAAI,EACvB,QAAQ,aAAa,IAAI,EACzB,QAAQ,YAAY,IAAI,EACxB,QAAQ,YAAY,EAAE,EACtB,QAAQ,UAAU,GAAG,EACrB,QAAQ,SAAS,GAAG,EACpB,QAAQ,SAAS,GAAG,EACpB,QAAQ,WAAW,GAAG,EACtB,QAAQ,WAAW,GAAG,EACtB,KAAK;AACV;AAMO,SAAS,cAAc,QAAqB;AACjD,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,OAAO,YAAY,aAAa,OAAO,QAAQ,IAAI;AACvE,MAAI,MAAM;AACR,WAAO,gBAAgB,IAAI;AAAA,EAC7B;AACA,MAAI,OAAO,OAAO,YAAY,YAAY;AACxC,QAAI;AACF,aAAO,OAAO,QAAQ,EAAE,gBAAgB,KAAK,CAAC;AAAA,IAChD,QAAQ;AACN,aAAO,OAAO,QAAQ;AAAA,IACxB;AAAA,EACF;AACA,SAAO;AACT;AAeO,SAAS,uBAAuB,aAAsC;AAC3E,MAAI,CAAC,YAAa,QAAO,CAAC;AAC1B,QAAM,WAA+B,CAAC;AAGtC,QAAM,MACJ,aAAa,OAAO,QACnB,OAAO,aAAa,gBAAgB,aAAa,cAAc;AAElE,MAAI,OAAO,OAAO,IAAI,gBAAgB,YAAY;AAChD,QAAI,YAAY,CAAC,SAAc;AAC7B,UAAI,KAAK,MAAM,SAAS,aAAa,KAAK,OAAO;AAC/C,iBAAS,KAAK;AAAA,UACZ,IAAI,KAAK,MAAM,MAAM;AAAA,UACrB,OAAO,KAAK,MAAM,SAAS;AAAA,UAC3B,MAAM,KAAK,MAAM;AAAA,UACjB,WAAW,KAAK,MAAM;AAAA,UACtB,OAAO,KAAK,MAAM;AAAA,UAClB,GAAG,KAAK;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,gBAAgB,YAAY,YAAY,SAAS;AAC1D,UAAM,OAAO,CAAC,UAAiB;AAC7B,iBAAW,QAAQ,OAAO;AACxB,YAAI,KAAK,SAAS,aAAa,KAAK,OAAO;AACzC,mBAAS,KAAK;AAAA,YACZ,IAAI,KAAK,MAAM,MAAM;AAAA,YACrB,OAAO,KAAK,MAAM,SAAS;AAAA,YAC3B,MAAM,KAAK,MAAM;AAAA,YACjB,WAAW,KAAK,MAAM;AAAA,YACtB,OAAO,KAAK,MAAM;AAAA,YAClB,GAAG,KAAK;AAAA,UACV,CAAC;AAAA,QACH;AACA,YAAI,MAAM,QAAQ,KAAK,OAAO,GAAG;AAC/B,eAAK,KAAK,OAAO;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AACA,SAAK,YAAY,OAAO;AACxB,WAAO;AAAA,EACT;AAGA,MAAI,OAAO,gBAAgB,UAAU;AACnC,QAAI,OAAO,aAAa,aAAa;AACnC,YAAM,MAAM,SAAS,cAAc,KAAK;AACxC,UAAI,YAAY;AAChB,UAAI,iBAAiB,2BAA2B,EAAE,QAAQ,CAAC,OAAO;AAChE,iBAAS,KAAK;AAAA,UACZ,IAAI,GAAG,aAAa,SAAS,KAAK;AAAA,UAClC,OAAO,GAAG,aAAa,YAAY,KAAK;AAAA,UACxC,MAAM,GAAG,aAAa,gBAAgB,KAAK;AAAA,UAC3C,WAAW,GAAG,aAAa,iBAAiB,KAAK;AAAA,UACjD,OAAO,GAAG,aAAa,YAAY,KAAK;AAAA,QAC1C,CAAC;AAAA,MACH,CAAC;AAAA,IACH,OAAO;AACL,YAAM,YAAY;AAClB,UAAI;AACJ,cAAQ,QAAQ,UAAU,KAAK,WAAW,OAAO,MAAM;AACrD,cAAM,UAAU,MAAM,CAAC;AACvB,cAAM,UAAU,CAAC,SAAiB;AAChC,gBAAM,IAAI,IAAI,OAAO,GAAG,IAAI,qBAAqB,GAAG,EAAE,KAAK,OAAO;AAClE,iBAAO,IAAI,EAAE,CAAC,IAAI;AAAA,QACpB;AACA,iBAAS,KAAK;AAAA,UACZ,IAAI,QAAQ,SAAS,KAAK;AAAA,UAC1B,OAAO,QAAQ,YAAY,KAAK;AAAA,UAChC,MAAM,QAAQ,gBAAgB,KAAK,QAAQ,kBAAkB;AAAA,UAC7D,WAAW,QAAQ,iBAAiB;AAAA,UACpC,OAAO,QAAQ,YAAY;AAAA,QAC7B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACpMA,OAAO,gBAAgB;AACvB,OAAO,eAAe;AAGtB,IAAM,KAAK,IAAI,WAAW;AAAA,EACxB,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AACV,CAAC,EAAE,IAAI,SAAS;AAKT,SAAS,qBAAqB,UAA0B;AAC7D,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,GAAG,OAAO,QAAQ;AAC3B;AAOO,SAAS,kBAAkB,QAAqB;AACrD,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,OAAO,OAAO,SAAS,UAAU,gBAAgB,YAAY;AAC/D,WAAO,OAAO,QAAQ,SAAS,YAAY;AAAA,EAC7C;AACA,SAAO,cAAc,MAAM;AAC7B;","names":[]}
@@ -1229,6 +1229,24 @@ var SpreadsheetController = class {
1229
1229
  this.notifyChange();
1230
1230
  }
1231
1231
  }
1232
+ autoFitColumnWidth(colId, customWidth) {
1233
+ if (customWidth !== void 0) {
1234
+ this.setColumnWidth(colId, customWidth);
1235
+ return;
1236
+ }
1237
+ const col = this.document.columns.find((c) => c.id === colId);
1238
+ if (!col) return;
1239
+ let maxLen = (col.title || "").length + (col.key ? col.key.length + 3 : 0);
1240
+ for (const row of this.document.rows) {
1241
+ const cell = this.getCell(row.id, col.id);
1242
+ const valStr = cell.value != null ? String(cell.value) : "";
1243
+ if (valStr.length > maxLen) {
1244
+ maxLen = valStr.length;
1245
+ }
1246
+ }
1247
+ const estimatedWidth = Math.min(600, Math.max(50, Math.ceil(maxLen * 8.5 + 32)));
1248
+ this.setColumnWidth(colId, estimatedWidth);
1249
+ }
1232
1250
  // --- Clipboard TSV/CSV ---
1233
1251
  exportToTsv() {
1234
1252
  return this.document.rows.map(