Utility
TypePaste
Paste formatted text as plain keystrokes. Strips rich formatting from Claude, ChatGPT, Notion, and pastes clean text into Slack, Teams, Discord — or converts Markdown to each app's native format.
Implementation
// TypePaste - Clipboard → Keystrokes
// Solves: pasting bold/italic/bullets from AI tools into Slack breaks formatting
interface TypePasteConfig {
mode: 'plain' | 'slack' | 'discord' | 'teams' | 'markdown';
delay: number; // ms between keystrokes (default: 5)
preserveNewlines: boolean;
}
interface FormatRule {
pattern: RegExp;
replace: string;
}
// Format conversion rules per platform
const formatRules: Record<string, FormatRule[]> = {
plain: [
{ pattern: /\*\*(.+?)\*\*/g, replace: '$1' },
{ pattern: /\*(.+?)\*/g, replace: '$1' },
{ pattern: /_(.+?)_/g, replace: '$1' },
{ pattern: /~~(.+?)~~/g, replace: '$1' },
{ pattern: /`(.+?)`/g, replace: '$1' },
{ pattern: /^#{1,6}\s+/gm, replace: '' },
{ pattern: /^[\-\*]\s+/gm, replace: '• ' },
{ pattern: /^\d+\.\s+/gm, replace: '' },
{ pattern: /\[(.+?)\]\((.+?)\)/g, replace: '$1 ($2)' },
],
slack: [
{ pattern: /\*\*(.+?)\*\*/g, replace: '*$1*' }, // bold
{ pattern: /(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, replace: '_$1_' }, // italic
{ pattern: /~~(.+?)~~/g, replace: '~$1~' }, // strike
{ pattern: /```(\w+)?\n([\s\S]+?)```/g, replace: '```$2```' },
{ pattern: /^#{1,6}\s+(.+)/gm, replace: '*$1*' }, // headings → bold
{ pattern: /^[\-\*]\s+/gm, replace: '• ' },
{ pattern: /\[(.+?)\]\((.+?)\)/g, replace: '<$2|$1>' }, // links
],
discord: [
// Discord uses same markdown, mostly passthrough
{ pattern: /^[\-\*]\s+/gm, replace: '• ' },
{ pattern: /\[(.+?)\]\((.+?)\)/g, replace: '$1 (<$2>)' },
],
};
function convertClipboard(text: string, mode: string): string {
const rules = formatRules[mode] || formatRules.plain;
let result = text;
for (const rule of rules) {
result = result.replace(rule.pattern, rule.replace);
}
// Strip any remaining HTML tags
result = result.replace(/<[^>]+>/g, '');
// Normalize whitespace
result = result.replace(/\r\n/g, '\n').replace(/[ \t]+$/gm, '');
return result;
}
// Simulate typing via keyboard events (Electron/native context)
async function typeText(text: string, delayMs = 5): Promise<void> {
for (const char of text) {
// In Electron: use robotjs or @nut-tree/nut-js
// In browser extension: use document.execCommand or Input Events
await simulateKeystroke(char);
await sleep(delayMs);
}
}
// System tray hotkey handler
function registerHotkey(combo: string, mode: string): void {
// Ctrl+Shift+V → paste as plain
// Ctrl+Shift+S → paste as Slack format
// Ctrl+Shift+D → paste as Discord format
globalShortcut.register(combo, async () => {
const clipboard = await readClipboard();
const converted = convertClipboard(clipboard, mode);
await typeText(converted);
});
}
// Usage
const slackReady = convertClipboard(
'**Bold title**\n- Item one\n- Item two\n[Link](https://example.com)',
'slack'
);
// => "*Bold title*\n• Item one\n• Item two\n<https://example.com|Link>"Usage
Use convertClipboard(text, mode) to transform formatted text. Modes: "plain", "slack", "discord", "teams". As a desktop app, register Ctrl+Shift+V for instant type-paste.
Examples
Input:
Output:
convertClipboard("**hello** _world_", "plain")Output:
"hello world"Input:
Output:
convertClipboard("**bold** and *italic*", "slack")Output:
"*bold* and _italic_"Input:
Output:
convertClipboard("[Link](https://x.com)", "slack")Output:
"<https://x.com|Link>"