@pixerate/editor 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -43,6 +43,8 @@ __export(src_exports, {
43
43
  INSTRUCTION_REGEX: () => INSTRUCTION_REGEX,
44
44
  Image: () => Image2,
45
45
  LoadingNode: () => LoadingNode,
46
+ MARKDOWN_MENTION_SPLIT_REGEX: () => MARKDOWN_MENTION_SPLIT_REGEX,
47
+ MENTION_REGEX: () => MENTION_REGEX,
46
48
  Markdown: () => Markdown2,
47
49
  Mention: () => Mention,
48
50
  SlashCommands: () => SlashCommands,
@@ -61,6 +63,7 @@ __export(src_exports, {
61
63
  escapeHtml: () => escapeHtml,
62
64
  extractCellDependencies: () => extractCellDependencies,
63
65
  extractInstructionNames: () => extractInstructionNames,
66
+ extractMentions: () => extractMentions,
64
67
  extractMentionsFromDoc: () => extractMentionsFromDoc,
65
68
  extractTemplateNames: () => extractTemplateNames,
66
69
  extractVariableNames: () => extractVariableNames,
@@ -79,12 +82,16 @@ __export(src_exports, {
79
82
  markdownToTipTapHtml: () => markdownToTipTapHtml,
80
83
  parseCellReference: () => parseCellReference,
81
84
  parseFormula: () => parseFormula,
85
+ parseMentionSegments: () => parseMentionSegments,
82
86
  parseRange: () => parseRange,
83
87
  plainTextToTipTapHtml: () => plainTextToTipTapHtml,
88
+ preprocessMarkdownFileLinks: () => preprocessMarkdownFileLinks,
89
+ preprocessMarkdownMentions: () => preprocessMarkdownMentions,
84
90
  removeImageNode: () => removeImageNode,
85
91
  resolveTemplates: () => resolveTemplates,
86
92
  resolveTemplatesWithMapping: () => resolveTemplatesWithMapping,
87
93
  resolveVariables: () => resolveVariables,
94
+ stripMarkdownCode: () => stripMarkdownCode,
88
95
  templateRegex: () => templateRegex,
89
96
  tokenizeFormula: () => tokenizeFormula,
90
97
  tokenizePrompt: () => tokenizePrompt,
@@ -2205,6 +2212,7 @@ function createRichTextPreset(options = {}) {
2205
2212
  openOnClick: openLinksOnClick,
2206
2213
  autolink: true,
2207
2214
  defaultProtocol: "https",
2215
+ protocols: ["file", "vscode", "cursor"],
2208
2216
  HTMLAttributes: {
2209
2217
  target: "_blank",
2210
2218
  rel: "noopener noreferrer",
@@ -2289,6 +2297,150 @@ function createRichTextPreset(options = {}) {
2289
2297
  return extensions2;
2290
2298
  }
2291
2299
 
2300
+ // src/serializers/mentions.ts
2301
+ var MENTION_REGEX = /(?:^|[\s>(*_"';\\/[\]{}~`:]|"|>|<|&)@(?:"([^"]+)"|"([^&]+)"|([a-zA-Z0-9_-]+(?:\.[a-zA-Z0-9_-]+)*))/g;
2302
+ var MARKDOWN_MENTION_SPLIT_REGEX = /(```[\s\S]*?```|~~~[\s\S]*?~~~|<pre[\s\S]*?<\/pre>|<code[\s\S]*?<\/code>|`[^`\n]+`|<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])[^>]*>[\s\S]*?<\/span>|<[^>]+>|\]\([^)]+\)|(?:https?|file|vscode|cursor|mailto):\/\/[^\s<)]+)/gi;
2303
+ function stripMarkdownCode(content) {
2304
+ if (!content || typeof content !== "string") return "";
2305
+ return content.replace(/```[\s\S]*?```/g, "").replace(/~~~[\s\S]*?~~~/g, "").replace(/<pre[\s\S]*?<\/pre>/gi, "").replace(/<code[\s\S]*?<\/code>/gi, "").replace(/`[^`\n]*`/g, "");
2306
+ }
2307
+ function extractMentions(content) {
2308
+ if (!content || typeof content !== "string") return [];
2309
+ const normalizedMentionNodes = content.replace(
2310
+ /<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["'])[^>]*>([\s\S]*?)<\/span>/gi,
2311
+ (match2, inner) => {
2312
+ const labelMatch = match2.match(/\bdata-label=["']([^"']+)["']/i);
2313
+ if (labelMatch) return ` @${labelMatch[1]} `;
2314
+ const idMatch = match2.match(/\bdata-id=["']([^"']+)["']/i);
2315
+ if (idMatch) return ` @${idMatch[1]} `;
2316
+ return ` ${inner} `;
2317
+ }
2318
+ );
2319
+ const cleanContent = stripMarkdownCode(normalizedMentionNodes);
2320
+ const withoutUrls = cleanContent.replace(/(?:https?|ftp|file|vscode|cursor|mailto):\/\/[^\s<>()]+/gi, "").replace(/\]\([^)]*\)/g, "]");
2321
+ const textOnly = withoutUrls.replace(/<[^>]+>/g, " ");
2322
+ const mentions = [];
2323
+ const seen = /* @__PURE__ */ new Set();
2324
+ const regex = new RegExp(MENTION_REGEX.source, "g");
2325
+ let match;
2326
+ while ((match = regex.exec(textOnly)) !== null) {
2327
+ const handle = (match[1] ?? match[2] ?? match[3] ?? "").trim();
2328
+ if (handle && !seen.has(handle)) {
2329
+ seen.add(handle);
2330
+ mentions.push(handle);
2331
+ }
2332
+ }
2333
+ return mentions;
2334
+ }
2335
+ function parseMentionSegments(content) {
2336
+ if (!content) return [];
2337
+ const segments = [];
2338
+ const regex = new RegExp(MENTION_REGEX.source, "g");
2339
+ let lastIndex = 0;
2340
+ let match;
2341
+ while ((match = regex.exec(content)) !== null) {
2342
+ const fullMatch = match[0];
2343
+ const atIndex = fullMatch.indexOf("@");
2344
+ const prefix = atIndex > 0 ? fullMatch.slice(0, atIndex) : "";
2345
+ const mentionToken = fullMatch.slice(atIndex);
2346
+ const handle = match[1] ?? match[2] ?? match[3];
2347
+ const matchStart = match.index + prefix.length;
2348
+ if (matchStart > lastIndex) {
2349
+ segments.push({
2350
+ type: "text",
2351
+ value: content.slice(lastIndex, matchStart)
2352
+ });
2353
+ }
2354
+ segments.push({
2355
+ type: "mention",
2356
+ value: mentionToken,
2357
+ handle
2358
+ });
2359
+ lastIndex = matchStart + mentionToken.length;
2360
+ }
2361
+ if (lastIndex < content.length) {
2362
+ segments.push({
2363
+ type: "text",
2364
+ value: content.slice(lastIndex)
2365
+ });
2366
+ }
2367
+ return segments;
2368
+ }
2369
+ function preprocessMarkdownMentions(content, optionsOrMentionables = []) {
2370
+ if (!content || typeof content !== "string") return "";
2371
+ const options = Array.isArray(optionsOrMentionables) ? { mentionables: optionsOrMentionables } : optionsOrMentionables;
2372
+ const allMentionables = options.mentionables || [];
2373
+ const defaultType = options.defaultType || "user";
2374
+ const resolveMention = options.resolveMention;
2375
+ const parts = content.split(MARKDOWN_MENTION_SPLIT_REGEX);
2376
+ return parts.map((part) => {
2377
+ if (!part) return "";
2378
+ if (part.startsWith("```") || part.startsWith("~~~") || part.startsWith("`") || part.startsWith("](") || /^(?:https?|file|vscode|cursor|mailto):\/\//i.test(part) || /^<pre[\s>]/i.test(part) || /^<code[\s>]/i.test(part) || /^<[^>]+>$/i.test(part) || /^<span\b[^>]*\b(?:data-type=["']mention["']|class=["'][^"']*pixerate-mention-node[^"']*["']|data-mention=["'][^"']*["'])/i.test(
2379
+ part
2380
+ )) {
2381
+ return part;
2382
+ }
2383
+ const regex = new RegExp(MENTION_REGEX.source, "g");
2384
+ return part.replace(regex, (match, quotedHandle, escapedQuotedHandle, standardHandle) => {
2385
+ const atIndex = match.indexOf("@");
2386
+ const prefix = atIndex > 0 ? match.slice(0, atIndex) : "";
2387
+ const rawHandle = (quotedHandle || escapedQuotedHandle || standardHandle || "").trim();
2388
+ if (!rawHandle) return match;
2389
+ const lowerHandle = rawHandle.toLowerCase();
2390
+ const entity = allMentionables.find((e) => {
2391
+ if (e.label?.toLowerCase() === lowerHandle) return true;
2392
+ if (e.handle?.toLowerCase() === lowerHandle) return true;
2393
+ if (e.name?.toLowerCase() === lowerHandle) return true;
2394
+ if (e.id?.toLowerCase() === lowerHandle) return true;
2395
+ if (e.type === "agent" && `agent${(e.handle || e.label || "").toLowerCase()}` === lowerHandle) return true;
2396
+ if (e.aliases?.some(
2397
+ (a) => a.toLowerCase() === lowerHandle || e.type === "agent" && `agent${a.toLowerCase()}` === lowerHandle
2398
+ )) {
2399
+ return true;
2400
+ }
2401
+ return false;
2402
+ });
2403
+ let id = entity?.id;
2404
+ let label = entity?.label || entity?.handle || rawHandle;
2405
+ let type = entity?.type;
2406
+ let avatarUrl = entity?.avatarUrl;
2407
+ let color = entity?.color || entity?.hexColor;
2408
+ if (!entity) {
2409
+ const customResolved = resolveMention?.(rawHandle);
2410
+ if (customResolved) {
2411
+ id = customResolved.id ?? id;
2412
+ label = customResolved.label ?? customResolved.handle ?? label;
2413
+ type = customResolved.type ?? type;
2414
+ avatarUrl = customResolved.avatarUrl ?? avatarUrl;
2415
+ color = customResolved.color ?? customResolved.hexColor ?? color;
2416
+ } else {
2417
+ const stripped = lowerHandle.replace(/^agent[\s\-_]*/i, "");
2418
+ if (["supervisor", "coordinator", "planner", "validator", "executor"].includes(stripped)) {
2419
+ type = "agent";
2420
+ id = stripped;
2421
+ label = stripped;
2422
+ } else if (lowerHandle === "agents") {
2423
+ type = "team";
2424
+ id = "agents";
2425
+ label = "agents";
2426
+ } else {
2427
+ type = defaultType;
2428
+ id = rawHandle;
2429
+ label = rawHandle;
2430
+ }
2431
+ }
2432
+ }
2433
+ const avatarAttr = avatarUrl ? ` data-avatar-url="${escapeHtml(avatarUrl)}"` : "";
2434
+ const colorAttr = color ? ` data-color="${escapeHtml(color)}"` : "";
2435
+ return `${prefix}<span class="pixerate-mention-node" data-type="mention" data-id="${escapeHtml(
2436
+ id || label
2437
+ )}" data-label="${escapeHtml(label)}" data-mention-suggestion-char="@" data-type-name="${escapeHtml(
2438
+ type || defaultType
2439
+ )}"${avatarAttr}${colorAttr}>@${escapeHtml(label)}</span>`;
2440
+ });
2441
+ }).join("");
2442
+ }
2443
+
2292
2444
  // src/serializers/plain-text.ts
2293
2445
  function escapeHtml(text) {
2294
2446
  if (!text) return "";
@@ -2413,6 +2565,16 @@ function extractMentionsFromDoc(docOrEditor) {
2413
2565
  });
2414
2566
  }
2415
2567
  }
2568
+ if (mentions.length === 0) {
2569
+ const rawHandles = extractMentions(docOrEditor);
2570
+ for (const handle of rawHandles) {
2571
+ mentions.push({
2572
+ id: handle,
2573
+ label: handle,
2574
+ type: "user"
2575
+ });
2576
+ }
2577
+ }
2416
2578
  }
2417
2579
  return mentions;
2418
2580
  }
@@ -2425,9 +2587,38 @@ var md2 = new import_markdown_it2.default({
2425
2587
  linkify: true,
2426
2588
  breaks: true
2427
2589
  }).use(import_markdown_it_task_lists2.default);
2428
- function markdownToTipTapHtml(markdown) {
2590
+ var defaultValidateLink = md2.validateLink;
2591
+ md2.validateLink = (url) => {
2592
+ if (url.startsWith("file://") || url.startsWith("vscode://") || url.startsWith("cursor://")) {
2593
+ return true;
2594
+ }
2595
+ return defaultValidateLink.call(md2, url);
2596
+ };
2597
+ function preprocessMarkdownFileLinks(content) {
2598
+ if (!content) return "";
2599
+ return content.replace(
2600
+ /\[([^\]]+)\]\(((?:file|vscode|cursor):\/\/[^)]+)\)/g,
2601
+ (_match, rawLabel, href) => {
2602
+ const trimmed = rawLabel.trim();
2603
+ const codeMatch = trimmed.match(/^`([^`]+)`$/);
2604
+ const labelContent = codeMatch ? `<code>${codeMatch[1]}</code>` : trimmed;
2605
+ return `<a href="${href}" data-file-link="true" title="Click to copy file path">${labelContent}</a>`;
2606
+ }
2607
+ );
2608
+ }
2609
+ function markdownToTipTapHtml(markdown, options) {
2429
2610
  if (!markdown) return "<p></p>";
2430
- return md2.render(markdown);
2611
+ let content = markdown;
2612
+ if (options?.preprocessFileLinks) {
2613
+ content = preprocessMarkdownFileLinks(content);
2614
+ }
2615
+ if (options?.preprocessMentions || options?.mentionables || options?.preprocessOptions) {
2616
+ const mentionOpts = options.preprocessOptions || {
2617
+ mentionables: options.mentionables
2618
+ };
2619
+ content = preprocessMarkdownMentions(content, mentionOpts);
2620
+ }
2621
+ return md2.render(content);
2431
2622
  }
2432
2623
  function getEditorMarkdown(editor) {
2433
2624
  if (!editor) return "";
@@ -4167,6 +4358,8 @@ function createHistoryManager(options = {}) {
4167
4358
  INSTRUCTION_REGEX,
4168
4359
  Image,
4169
4360
  LoadingNode,
4361
+ MARKDOWN_MENTION_SPLIT_REGEX,
4362
+ MENTION_REGEX,
4170
4363
  Markdown,
4171
4364
  Mention,
4172
4365
  SlashCommands,
@@ -4185,6 +4378,7 @@ function createHistoryManager(options = {}) {
4185
4378
  escapeHtml,
4186
4379
  extractCellDependencies,
4187
4380
  extractInstructionNames,
4381
+ extractMentions,
4188
4382
  extractMentionsFromDoc,
4189
4383
  extractTemplateNames,
4190
4384
  extractVariableNames,
@@ -4203,12 +4397,16 @@ function createHistoryManager(options = {}) {
4203
4397
  markdownToTipTapHtml,
4204
4398
  parseCellReference,
4205
4399
  parseFormula,
4400
+ parseMentionSegments,
4206
4401
  parseRange,
4207
4402
  plainTextToTipTapHtml,
4403
+ preprocessMarkdownFileLinks,
4404
+ preprocessMarkdownMentions,
4208
4405
  removeImageNode,
4209
4406
  resolveTemplates,
4210
4407
  resolveTemplatesWithMapping,
4211
4408
  resolveVariables,
4409
+ stripMarkdownCode,
4212
4410
  templateRegex,
4213
4411
  tokenizeFormula,
4214
4412
  tokenizePrompt,