UNPKG

claritykit-svelte

Version:

A comprehensive Svelte component library focused on accessibility, ADHD-optimized design, developer experience, and full SSR compatibility

248 lines (247 loc) 9.05 kB
import { Extension } from '@tiptap/core'; import { PluginKey } from '@tiptap/pm/state'; import { Plugin } from '@tiptap/pm/state'; import Suggestion from '@tiptap/suggestion'; export const SlashCommandsExtension = Extension.create({ name: 'slashCommands', addOptions() { return { suggestion: { items: ({ query }) => { return this.options.commands .filter(command => { if (!command.enabled) return false; const searchText = query.toLowerCase(); return (command.title.toLowerCase().includes(searchText) || command.description.toLowerCase().includes(searchText) || command.keywords.some(keyword => keyword.toLowerCase().includes(searchText))); }) .slice(0, 10); }, render: () => { let component; let popup; return { onStart: (props) => { // This would render a SlashCommandsList component console.log('Slash commands started', props); }, onUpdate: (props) => { console.log('Slash commands updated', props); }, onKeyDown: (props) => { if (props.event.key === 'Escape') { return true; } if (props.event.key === 'ArrowUp') { // Handle up navigation return true; } if (props.event.key === 'ArrowDown') { // Handle down navigation return true; } if (props.event.key === 'Enter') { const selectedCommand = props.items[0]; // Get selected command if (selectedCommand) { selectedCommand.command({ editor: props.editor, range: props.range, props: props.props, }); } return true; } return false; }, onExit: () => { console.log('Slash commands exited'); }, }; }, char: '/', allowSpaces: false, startOfLine: false, }, commands: [], }; }, addCommands() { return { executeSlashCommand: (commandId, props) => ({ editor, tr, state }) => { const command = this.options.commands.find(cmd => cmd.id === commandId); if (command) { command.command({ editor, range: null, props }); return true; } return false; }, }; }, addProseMirrorPlugins() { return [ Suggestion({ editor: this.editor, ...this.options.suggestion, }), ]; }, }); // Default slash commands for chat export const defaultSlashCommands = [ { id: 'gif', title: 'GIF', description: 'Search and insert a GIF', icon: '🎬', keywords: ['gif', 'animation', 'image', 'funny'], category: 'media', enabled: true, command: ({ editor, range }) => { // This would open a GIF picker console.log('Opening GIF picker'); if (range) { editor.chain().focus().deleteRange(range).run(); } // Insert placeholder or open GIF picker modal editor.chain().focus().insertContent('<div class="gif-placeholder">🎬 GIF picker would open here</div>').run(); }, }, { id: 'poll', title: 'Poll', description: 'Create an interactive poll', icon: '📊', keywords: ['poll', 'vote', 'survey', 'question'], category: 'interaction', enabled: true, command: ({ editor, range }) => { console.log('Creating poll'); if (range) { editor.chain().focus().deleteRange(range).run(); } // Insert poll template const pollTemplate = ` <div class="poll-block" data-type="poll"> <div class="poll-question" contenteditable="true">What's your question?</div> <div class="poll-options"> <div class="poll-option" contenteditable="true">Option 1</div> <div class="poll-option" contenteditable="true">Option 2</div> </div> <button class="poll-add-option">+ Add option</button> </div> `; editor.chain().focus().insertContent(pollTemplate).run(); }, }, { id: 'remind', title: 'Reminder', description: 'Set a reminder for this message', icon: '⏰', keywords: ['remind', 'reminder', 'schedule', 'later'], category: 'utility', enabled: true, command: ({ editor, range }) => { console.log('Setting reminder'); if (range) { editor.chain().focus().deleteRange(range).run(); } // Insert reminder component const reminderTemplate = ` <div class="reminder-block" data-type="reminder"> <span class="reminder-icon">⏰</span> <input type="datetime-local" class="reminder-datetime" /> <span class="reminder-text">Remind me about this message</span> </div> `; editor.chain().focus().insertContent(reminderTemplate).run(); }, }, { id: 'code', title: 'Code Block', description: 'Insert a code block with syntax highlighting', icon: '💻', keywords: ['code', 'programming', 'syntax', 'block'], category: 'formatting', enabled: true, command: ({ editor, range }) => { console.log('Inserting code block'); if (range) { editor.chain().focus().deleteRange(range).run(); } // Insert code block editor.chain().focus().toggleCodeBlock().run(); }, }, { id: 'table', title: 'Table', description: 'Insert a table', icon: '📋', keywords: ['table', 'grid', 'data', 'rows', 'columns'], category: 'formatting', enabled: true, command: ({ editor, range }) => { console.log('Inserting table'); if (range) { editor.chain().focus().deleteRange(range).run(); } // Insert 3x3 table editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(); }, }, { id: 'divider', title: 'Divider', description: 'Insert a horizontal divider', icon: '➖', keywords: ['divider', 'separator', 'line', 'break'], category: 'formatting', enabled: true, command: ({ editor, range }) => { console.log('Inserting divider'); if (range) { editor.chain().focus().deleteRange(range).run(); } editor.chain().focus().setHorizontalRule().run(); }, }, { id: 'emoji', title: 'Emoji', description: 'Insert an emoji', icon: '😀', keywords: ['emoji', 'emoticon', 'smiley', 'reaction'], category: 'media', enabled: true, command: ({ editor, range }) => { console.log('Opening emoji picker'); if (range) { editor.chain().focus().deleteRange(range).run(); } // This would open an emoji picker editor.chain().focus().insertContent('😀').run(); }, }, { id: 'mention', title: 'Mention', description: 'Mention someone in the chat', icon: '@', keywords: ['mention', 'user', 'notify', 'at'], category: 'interaction', enabled: true, command: ({ editor, range }) => { console.log('Triggering mention'); if (range) { editor.chain().focus().deleteRange(range).run(); } // Insert @ to trigger mention suggestion editor.chain().focus().insertContent('@').run(); }, }, ]; export default SlashCommandsExtension;