npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@danjari/blocknote-ai-extension

v1.0.0

Published

AI-powered slash commands extension for BlockNote editor. Add ChatGPT, Claude, and Gemini AI capabilities to your BlockNote editor with custom slash commands like /explain, /summarize, /quiz-me, and /diagram.

Readme

BlockNote AI Slash Extension

AI-powered slash commands extension for BlockNote editor (use case for Synapsed ). This extension adds AI functionality to BlockNote while maintaining full compatibility with all existing features.

✨ Features

  • AI Slash Commands: /explain, /quiz-me, /summarize, /diagram
  • Full BlockNote Compatibility: All existing commands work alongside AI commands
  • Event-Driven Architecture: Clean separation between UI and AI logic
  • Streaming Support: Real-time AI response streaming
  • Synapsed Theme: Custom styling with indigo accent colors
  • TypeScript Support: Full type safety

🚀 Quick Start

Installation

npm install @danjari/blocknote-ai-extension

When to Add AI APIs

Phase 1: Development & Testing (Current)

  • ✅ Use simulated responses for testing
  • ✅ Focus on UI/UX and command structure
  • ✅ Test with the BlockNote playground
  • ✅ Verify all commands work correctly

Phase 2: AI Integration (Next Step)

  • 🔄 Replace simulated responses with real AI APIs
  • 🔄 Add error handling and fallbacks
  • 🔄 Implement streaming for real-time responses
  • 🔄 Add user authentication and rate limiting

Phase 3: Production (Final)

  • 🎯 Deploy with production AI services
  • 🎯 Add monitoring and analytics
  • 🎯 Implement caching and optimization
  • 🎯 Add advanced features like conversation history

Basic Usage

import { BlockNoteEditor, getDefaultSlashMenuItems } from "@blocknote/core";
import { BlockNoteView } from "@blocknote/react";
import {
  getAISlashMenuItems,
  createAIStreamingUtils,
} from "@danjari/blocknote-ai-extension";

// Create AI command handler
function handleAICommand(action, payload) {
  console.log("AI Command:", action, payload);

  // Connect to your AI API here
  switch (action) {
    case "explain":
      // Call your AI API for explanation
      break;
    case "quiz-me":
      // Generate quiz
      break;
    case "summarize":
      // Summarize content
      break;
    case "diagram":
      // Create diagram
      break;
  }
}

// Create editor with AI commands
const editor = new BlockNoteEditor({
  slashMenuItems: [
    ...getDefaultSlashMenuItems(editor), // All original BlockNote commands
    ...getAISlashMenuItems(editor, handleAICommand), // AI commands
  ],
});

// Set up streaming utilities
const streamingUtils = createAIStreamingUtils(editor);

// Render the editor
function MyEditor() {
  return <BlockNoteView editor={editor} />;
}

🎯 Available Commands

Original BlockNote Commands (All Work!)

  • /paragraph - Regular text block
  • /heading - Heading (H1, H2, H3)
  • /bulletListItem - Bullet list item
  • /numberedListItem - Numbered list item
  • /quote - Quote block
  • /code - Code block
  • /image - Image block
  • /table - Table
  • /divider - Horizontal divider
  • And many more...

AI Commands (New!)

  • /explain 🤖 - Explain selected text
  • /quiz-me 🤖 - Generate quiz based on content
  • /summarize 🤖 - Summarize selected text
  • /diagram 🤖 - Create diagram from content

🔧 API Reference

getAISlashMenuItems(editor, emitAICommand)

Returns AI slash menu items for the BlockNote editor.

Parameters:

  • editor - BlockNote editor instance
  • emitAICommand - Function to handle AI commands

Returns: Array of slash menu items

Example:

const menuItems = getAISlashMenuItems(editor, (action, payload) => {
  console.log("AI Command:", action, payload);
});

createAIStreamingUtils(editor)

Creates streaming utilities for real-time AI responses.

Parameters:

  • editor - BlockNote editor instance

Returns: AIStreamingUtils instance

Example:

const streamingUtils = createAIStreamingUtils(editor);

// Start streaming AI response
streamingUtils.startStreaming("quote", "AI is thinking...");

// Update streaming content
streamingUtils.updateStreaming("This is the AI response...");

// Finish streaming
streamingUtils.finishStreaming();

useAISlash(config)

React hook for AI functionality.

Parameters:

  • config - Configuration object (optional)

Returns: AI hook with event emitter

Example:

const aiSlash = useAISlash({
  callbacks: {
    onAICommand: (event) => {
      console.log("AI Command:", event.action, event.payload);
    },
    onStream: (chunk) => {
      console.log("Stream chunk:", chunk);
    },
  },
});

🔗 Complete Integration Example

import { BlockNoteEditor, getDefaultSlashMenuItems } from "@blocknote/core";
import { BlockNoteView } from "@blocknote/react";
import {
  getAISlashMenuItems,
  createAIStreamingUtils,
  useAISlash,
} from "@danjari/blocknote-ai-extension";

function MyAIEditor() {
  // Set up streaming utilities
  const [streamingUtils, setStreamingUtils] = useState(null);

  // AI command handler
  const handleAICommand = async (action, payload) => {
    console.log("AI Command:", action, payload);

    // Start streaming indicator
    if (streamingUtils) {
      streamingUtils.startStreaming("quote", "AI is thinking...");
    }

    try {
      // Call your AI API
      const response = await fetch("/api/ai/" + action, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          text: payload.selectedText,
          action: action,
        }),
      });

      const data = await response.json();

      // Update streaming content
      if (streamingUtils) {
        streamingUtils.updateStreaming(data.content);
        streamingUtils.finishStreaming();
      }
    } catch (error) {
      console.error("AI API error:", error);
      if (streamingUtils) {
        streamingUtils.finishStreaming();
      }
    }
  };

  // Create editor
  const editor = useMemo(() => {
    const editorInstance = new BlockNoteEditor({
      slashMenuItems: [
        ...getDefaultSlashMenuItems(editorInstance), // All original commands
        ...getAISlashMenuItems(editorInstance, handleAICommand), // AI commands
      ],
    });

    // Set up streaming utilities
    setStreamingUtils(createAIStreamingUtils(editorInstance));

    return editorInstance;
  }, []);

  return <BlockNoteView editor={editor} />;
}

🎨 Theming

The extension includes Synapsed theme with indigo accent colors:

:root {
  --bn-synapsed-accent-color: #6366f1;
  --bn-synapsed-font-family: "Inter", sans-serif;
}

Import the theme CSS:

import "@danjari/blocknote-ai-extension/theme.css";

📦 Exports

import {
  // Main functions
  useAISlash,
  getAISlashMenuItems,
  createAIStreamingUtils,
  AIStreamingUtils,

  // Theme
  defaultSynapsedTheme,
  generateSynapsedThemeCSS,
  getDefaultSynapsedThemeCSS,

  // Types
  AICommandAction,
  AICommandPayload,
  AISlashConfig,
  AISlashHook,
  AISlashMenuItem,
  SynapsedTheme,
} from "@danjari/blocknote-ai-extension";

🧪 Testing

Run the test suite:

npm test

Test manually:

# Test extension functionality
node test-extension.js

# Test compatibility with BlockNote
node test-compatibility.js

# Test all commands
node test-all-commands.js

# View integration example
node integration-example.js

Browser Testing:

Open simple-test.html in your browser to test the extension in a web environment.

Interactive Testing in BlockNote Playground:

  1. Start the BlockNote playground:

    cd /path/to/blocknote
    pnpm run dev
  2. Navigate to your example:

    • Open http://localhost:5177/
    • Look for "Custom AI Slash Extension" in the AI section
    • Click to load your extension
  3. Test your commands:

    • Type / to see the slash menu
    • Try /explain, /quiz-me, /summarize, /diagram
    • Verify responses appear in the editor

🚀 Deployment

Pre-deployment Checklist:

  1. Build the extension:

    npm run build
  2. Test in production environment:

    npm run preview
  3. Verify all commands work:

    • Test all AI commands (/explain, /quiz-me, /summarize, /diagram)
    • Ensure BlockNote commands still work
    • Check TypeScript compilation
  4. Test with your AI integration:

    • Connect to your AI APIs
    • Test response handling
    • Verify streaming works

Production Integration:

// Production-ready AI command handler
const handleAICommand = async (action, payload) => {
  try {
    // Call your production AI API
    const response = await fetch("/api/ai/" + action, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${process.env.AI_API_KEY}`,
      },
      body: JSON.stringify({
        text: payload.selectedText,
        action: action,
        userId: getCurrentUserId(), // Add user context
        sessionId: getSessionId(), // Add session tracking
      }),
    });

    if (!response.ok) {
      throw new Error(`AI API error: ${response.status}`);
    }

    const data = await response.json();
    return data.content;
  } catch (error) {
    console.error("AI command failed:", error);
    return `Sorry, I couldn't process that request. Please try again.`;
  }
};

Environment Variables:

# Required for production
AI_API_KEY=your_ai_api_key_here
AI_API_ENDPOINT=https://api.your-ai-service.com
AI_MODEL=gpt-4 # or your preferred model

# Optional
AI_MAX_TOKENS=1000
AI_TEMPERATURE=0.7
AI_TIMEOUT=30000

🤖 AI Integration Guide

Step 1: Choose Your AI Provider

OpenAI (Recommended for beginners):

// OpenAI integration
const openaiResponse = await fetch(
  "https://api.openai.com/v1/chat/completions",
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      model: "gpt-4",
      messages: [
        { role: "system", content: "You are a helpful AI assistant." },
        { role: "user", content: `Explain this: ${payload.selectedText}` },
      ],
      max_tokens: 1000,
    }),
  },
);

Anthropic Claude:

// Claude integration
const claudeResponse = await fetch("https://api.anthropic.com/v1/messages", {
  method: "POST",
  headers: {
    "x-api-key": process.env.ANTHROPIC_API_KEY,
    "Content-Type": "application/json",
    "anthropic-version": "2023-06-01",
  },
  body: JSON.stringify({
    model: "claude-3-sonnet-20240229",
    max_tokens: 1000,
    messages: [
      { role: "user", content: `Explain this: ${payload.selectedText}` },
    ],
  }),
});

Google Gemini:

// Gemini integration
const geminiResponse = await fetch(
  `https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${process.env.GEMINI_API_KEY}`,
  {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      contents: [
        {
          parts: [{ text: `Explain this: ${payload.selectedText}` }],
        },
      ],
    }),
  },
);

Step 2: Implement Command-Specific Logic

const handleAICommand = async (action, payload) => {
  const selectedText = payload.selectedText || "current content";

  switch (action) {
    case "explain":
      return await callAI(`Explain this text in simple terms: ${selectedText}`);

    case "summarize":
      return await callAI(
        `Summarize this text in 2-3 sentences: ${selectedText}`,
      );

    case "quiz-me":
      return await callAI(
        `Create 3 multiple choice questions based on this text: ${selectedText}`,
      );

    case "diagram":
      return await callAI(
        `Create a mermaid diagram based on this text: ${selectedText}`,
      );

    default:
      return "Unknown AI command";
  }
};

async function callAI(prompt) {
  // Your AI API call here
  const response = await fetch("/api/ai", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ prompt }),
  });

  const data = await response.json();
  return data.content;
}

Step 3: Add Streaming Support

// For real-time streaming responses
const handleAICommandWithStreaming = async (action, payload) => {
  const streamingUtils = createAIStreamingUtils(editor);

  // Start streaming indicator
  streamingUtils.startStreaming("quote", "AI is thinking...");

  try {
    // Call your streaming AI API
    const response = await fetch("/api/ai/stream", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ action, payload }),
    });

    const reader = response.body.getReader();
    let accumulatedContent = "";

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = new TextDecoder().decode(value);
      accumulatedContent += chunk;

      // Update streaming content
      streamingUtils.updateStreaming(accumulatedContent);
    }

    // Finish streaming
    streamingUtils.finishStreaming();
  } catch (error) {
    console.error("Streaming error:", error);
    streamingUtils.finishStreaming();
  }
};

Step 4: Error Handling & Fallbacks

const handleAICommandWithFallback = async (action, payload) => {
  try {
    // Primary AI service
    return await callPrimaryAI(action, payload);
  } catch (error) {
    console.warn("Primary AI failed, trying fallback:", error);

    try {
      // Fallback AI service
      return await callFallbackAI(action, payload);
    } catch (fallbackError) {
      console.error("All AI services failed:", fallbackError);

      // Return helpful error message
      return `Sorry, I'm having trouble processing your request right now. Please try again in a moment.`;
    }
  }
};

✅ Compatibility

✅ Full BlockNote Compatibility

  • All original slash commands work
  • All block types supported
  • All formatting options available
  • No breaking changes

✅ AI Commands

  • Properly grouped under "AI" category
  • No conflicts with existing commands
  • Follow BlockNote command structure
  • Type-safe implementation

🔧 Development

Building the extension:

npm run build

Development mode:

npm run dev

Preview:

npm run preview

📄 License

MIT License - see LICENSE file for details.

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests
  5. Submit a pull request

🚀 Roadmap

  • [ ] Interactive quiz blocks
  • [ ] More AI commands
  • [ ] Custom AI model support
  • [ ] Advanced streaming features
  • [ ] Collaborative AI features