# Response

Import: `import { Response } from '@neo4j-ndl/react/ai'`

## Props

### Response

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `children` | `string` | ✅ |  | The response from the AI |
| `isAnimating` | `boolean` |  |  | Whether the response is animating |
| `ref` | `Ref<HTMLDivElement>` |  |  | A ref to apply to the root element. |

## Examples

### Default

```tsx
import { Response } from '@neo4j-ndl/react/ai';

const markdownContent = `
# Hello World

This is a **bold** text and this is an *italic* text.

Here is a list:
- Item 1
- Item 2
- Item 3

And a code block:

\`\`\`typescript
const greeting = "Hello World";
console.log(greeting);
\`\`\`

[Link to Neo4j](https://neo4j.com)
`;

export const Component = () => {
  return <Response>{markdownContent}</Response>;
};

export default Component;
```

### All Components

```tsx
import { Response } from '@neo4j-ndl/react/ai';

const comprehensiveMarkdown = `
# All Markdown Components Demo

This story demonstrates all the markdown components that the Response component can render.

## Headings

# Heading 1
## Heading 2
### Heading 3
#### Heading 4
##### Heading 5
###### Heading 6

## Text Formatting

This is **bold text** and this is *italic text*.

You can also use __bold__ and _italic_ with underscores.

Combine them: **bold and *italic* together**.

## Lists

### Unordered Lists

- Item 1
- Item 2
- Item 3
  - Nested item 1
  - Nested item 2
    - Deeply nested item
    - <h1>Nested nested heading</h1>

### Ordered Lists

1. First item
2. Second item
3. Third item
   1. Nested numbered item
   2. Another nested item
   3. <h2>Nested nested heading</h2>

## Code

### Inline Code

Use \`const x = 5\` for inline code.

### Code Blocks

#### JavaScript

\`\`\`javascript
const greeting = "Hello World";
console.log(greeting);

function sayHello(name) {
  return \`Hello, \${name}!\`;
}
\`\`\`

#### Python

\`\`\`python
def greet(name):
    return f"Hello, {name}!"

print(greet("World"))
\`\`\`

#### Cypher

\`\`\`cypher
MATCH (n:Person)-[:KNOWS]->(m:Person)
WHERE n.name = "Alice"
RETURN m.name
\`\`\`

#### TypeScript

\`\`\`typescript
interface User {
  name: string;
  age: number;
}

const user: User = {
  name: "John",
  age: 30
};
\`\`\`

#### Without Language Specification

\`\`\`
Plain code block
without syntax highlighting
\`\`\`

## Links

Visit [Neo4j](https://neo4j.com) for more information.

Multiple links: [Documentation](https://neo4j.com/docs) and [Community](https://community.neo4j.com)

## Blockquotes

> This is a blockquote.
> It can span multiple lines.

> ### Blockquote with heading
> 
> You can also include other markdown inside blockquotes.
> 
> - Like lists
> - And other elements

### Nested Blockquotes

> Outer quote
>> Nested quote
>>> Deeply nested quote

## Horizontal Rules

Content above the rule

---

Content below the rule

## Images

![A smiling man](https://media.istockphoto.com/id/1334716681/photo/a-smiling-man.jpg?s=612x612&w=0&k=20&c=U6rkSDpQMzkcJEqx2hAa63fNLIhqnZb31Xuc_QSi648=)

## Paragraphs

This is a paragraph with multiple sentences. It demonstrates how regular text is rendered. You can write long-form content that spans multiple lines.

Another paragraph here. Paragraphs are separated by blank lines in markdown.

## Mixed Content Example

Here's a practical example combining multiple elements:

### Database Query Tutorial

To query your Neo4j database, follow these steps:

1. **Connect to your database**
   
   Use the following code:
   
   \`\`\`javascript
   const driver = neo4j.driver(
     'bolt://localhost:7687',
     neo4j.auth.basic('neo4j', 'password')
   );
   \`\`\`

2. **Write your Cypher query**
   
   \`\`\`cypher
   MATCH (n:Movie)
   WHERE n.released > 2000
   RETURN n.title, n.released
   ORDER BY n.released DESC
   LIMIT 10
   \`\`\`

3. **Execute and process results**
   
   > **Note**: Always close your session after use!

For more information, visit the [Neo4j Documentation](https://neo4j.com/docs).

---

## Special Characters and Escaping

You can escape special characters: \\* \\_ \\[ \\]

## Preformatted Text

Use code blocks for preformatted text with preserved spacing:

\`\`\`
    This text
      has preserved
        indentation
\`\`\`

| Item              | In Stock | Price |
| :---------------- | :------: | ----: |
| Python Hat        |   True   | 222222223.99 |
| SQL Hat           |   True   | 23.99 |
| Codecademy Tee    |  False   | 19.99 |
| Codecademy Hoodie |  False   | 42.99 |
`;

export const Component = () => {
  return (
    <div className="max-w-4xl">
      <Response>{comprehensiveMarkdown}</Response>
    </div>
  );
};

export default Component;
```

### Code Examples

```tsx
import { Response } from '@neo4j-ndl/react/ai';

const codeExamplesMarkdown = `
# Code Examples

This story focuses on different code rendering capabilities.

## Multiple Programming Languages

### JavaScript

\`\`\`javascript
// Array methods
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const sum = numbers.reduce((acc, n) => acc + n, 0);

console.log('Doubled:', doubled);
console.log('Sum:', sum);
\`\`\`

### TypeScript

\`\`\`typescript
// Generics
function identity<T>(arg: T): T {
  return arg;
}

const result = identity<string>("Hello");
const num = identity(42);
\`\`\`

### Python

\`\`\`python
# List comprehension
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]

# Dictionary comprehension
square_dict = {x: x**2 for x in range(5)}

print(f"Squares: {squares}")
print(f"Evens: {evens}")
\`\`\`

### Cypher

\`\`\`cypher
// Create nodes and relationships
CREATE (alice:Person {name: 'Alice', age: 30})
CREATE (bob:Person {name: 'Bob', age: 25})
CREATE (alice)-[:KNOWS {since: 2020}]->(bob)
RETURN alice, bob
\`\`\`

### SQL

\`\`\`sql
-- Complex query
SELECT 
  u.name,
  COUNT(o.id) as order_count,
  SUM(o.total) as total_spent
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE u.active = true
GROUP BY u.id, u.name
HAVING COUNT(o.id) > 5
ORDER BY total_spent DESC
LIMIT 10;
\`\`\`

### Rust

\`\`\`rust
// Pattern matching
fn describe_number(n: i32) -> String {
    match n {
        0 => "zero".to_string(),
        1..=10 => "small".to_string(),
        11..=100 => "medium".to_string(),
        _ => "large".to_string(),
    }
}
\`\`\`

### Go

\`\`\`go
// Goroutines and channels
func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {
        fmt.Printf("worker %d processing job %d\\n", id, j)
        results <- j * 2
    }
}
\`\`\`

### JSON

\`\`\`json
{
  "name": "Response Component",
  "version": "1.0.0",
  "features": [
    "markdown rendering",
    "syntax highlighting",
    "streaming support"
  ],
  "config": {
    "theme": "dark",
    "lineNumbers": true
  }
}
\`\`\`

### YAML

\`\`\`yaml
# Configuration file
app:
  name: MyApp
  version: 1.0.0
  port: 3000

database:
  host: localhost
  port: 5432
  credentials:
    username: admin
    password: secret

features:
  - authentication
  - logging
  - caching
\`\`\`

### Shell/Bash

\`\`\`bash
#!/bin/bash

# Deploy script
echo "Starting deployment..."

npm install
npm run build
npm test

if [ $? -eq 0 ]; then
    echo "Deployment successful!"
else
    echo "Deployment failed!"
    exit 1
fi
\`\`\`

## Inline Code

You can use inline code like \`const x = 5\`, \`npm install\`, or \`SELECT * FROM users\` within sentences.

Mixed with text: The \`Array.map()\` method creates a new array and the \`filter()\` method filters elements.

## Code Without Language

\`\`\`
Plain text code block
No syntax highlighting
Just monospace font
\`\`\`

## Long Code Blocks

\`\`\`javascript
// Complex React component
import React, { useState, useEffect, useCallback } from 'react';

const UserDashboard = ({ userId }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  const fetchUser = useCallback(async () => {
    try {
      setLoading(true);
      const response = await fetch(\`/api/users/\${userId}\`);
      if (!response.ok) throw new Error('Failed to fetch user');
      const data = await response.json();
      setUser(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }, [userId]);

  useEffect(() => {
    fetchUser();
  }, [fetchUser]);

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!user) return <div>No user found</div>;

  return (
    <div className="dashboard">
      <h1>{user.name}</h1>
      <p>Email: {user.email}</p>
      <button onClick={fetchUser}>Refresh</button>
    </div>
  );
};

export default UserDashboard;
\`\`\`
`;

export const Component = () => {
  return (
    <div className="max-w-4xl">
      <Response>{codeExamplesMarkdown}</Response>
    </div>
  );
};

export default Component;
```

### Full Example

```tsx
import { CleanIconButton, TextLink, Typography } from '@neo4j-ndl/react';
import {
  Prompt,
  Response,
  Suggestion,
  Thinking,
  UserBubble,
} from '@neo4j-ndl/react/ai';
import {
  ArrowPathIconOutline,
  Cog6ToothIconOutline,
  HandThumbDownIconOutline,
  PlusIconOutline,
  Square2StackIconOutline,
  XMarkIconOutline,
} from '@neo4j-ndl/react/icons';
import { useEffect, useRef, useState } from 'react';

const FAKE_RESPONSES = [
  `Here is a simple response with some **bold text** and *italics*.`,
  `Here is a list of items:
- Item 1
- Item 2
- Item 3`,
  `Here is a code block example:

\`\`\`typescript
const greeting = "Hello World";
console.log(greeting);
\`\`\`
`,
  `# Heading 1
## Heading 2
### Heading 3

Some text under headings.`,
  `You can also use tables:

| Header 1 | Header 2 |
|Data 1|Data 2|
|Data 3|Data 4|
`,
];

export const Component = () => {
  const [messages, setMessages] = useState<
    {
      role: 'user' | 'assistant';
      content: string;
      thinkingTime?: number;
      done?: boolean;
    }[]
  >([]);
  const [prompt, setPrompt] = useState('');
  const [isThinking, setIsThinking] = useState(false);
  const [isStreaming, setIsStreaming] = useState(false);
  const [responseIndex, setResponseIndex] = useState(0);
  const messagesEndRef = useRef<HTMLDivElement>(null);
  const timeoutRef = useRef<NodeJS.Timeout | null>(null);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);

  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  };

  useEffect(() => {
    scrollToBottom();
  }, [messages, isThinking]);

  const handleCancel = () => {
    if (timeoutRef.current) {
      clearTimeout(timeoutRef.current);
    }
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
    }
    setIsThinking(false);
    setIsStreaming(false);

    // Mark the last message as done if stopped
    setMessages((prev) => {
      const newMessages = [...prev];
      const lastMessage = newMessages[newMessages.length - 1];
      if (lastMessage?.role === 'assistant') {
        lastMessage.done = true;
      }
      return newMessages;
    });
  };

  const handleSend = (overridePrompt?: string) => {
    const textToSend = overridePrompt || prompt;

    if (!textToSend.trim()) {
      return;
    }

    setMessages((prev) => [...prev, { content: textToSend, role: 'user' }]);
    setPrompt('');
    setIsThinking(true);
    const startTime = Date.now();

    // Simulate network delay (thinking time)
    timeoutRef.current = setTimeout(() => {
      const endTime = Date.now();
      const thinkingTime = endTime - startTime;
      setIsThinking(false);
      setIsStreaming(true);

      const responseText = FAKE_RESPONSES[responseIndex];
      setResponseIndex((prev) => (prev + 1) % FAKE_RESPONSES.length);

      let currentText = '';
      setMessages((prev) => [
        ...prev,
        { content: '', done: false, role: 'assistant', thinkingTime },
      ]);

      // Simulate streaming
      intervalRef.current = setInterval(() => {
        if (currentText.length < responseText.length) {
          // Add a few characters at a time to simulate chunks
          // Ensure we don't split newlines incorrectly if that's an issue,
          // but simple slicing should be fine as long as the source has \n.
          const chunk = responseText.slice(
            currentText.length,
            currentText.length + 2,
          );
          currentText += chunk;

          setMessages((prev) => {
            const newMessages = [...prev];
            const lastMessage = newMessages[newMessages.length - 1];
            if (lastMessage.role === 'assistant') {
              lastMessage.content = currentText;
            }
            return newMessages;
          });
        } else {
          if (intervalRef.current) {
            clearInterval(intervalRef.current);
          }
          setIsStreaming(false);
          setMessages((prev) => {
            const newMessages = [...prev];
            const lastMessage = newMessages[newMessages.length - 1];
            if (lastMessage.role === 'assistant') {
              lastMessage.done = true;
            }
            return newMessages;
          });
        }
      }, 50);
    }, 2000);
  };

  return (
    <section className="n-h-screen">
      <div className="n-w-[440px] n-h-full n-flex n-flex-col n-bg-neutral-bg-weak">
        <div className="n-flex n-flex-row n-border-b n-border-neutral-border-weak n-p-3">
          <div className="n-ml-auto">
            <CleanIconButton description="settings" tooltipProps={{}}>
              <Cog6ToothIconOutline />
            </CleanIconButton>
            <CleanIconButton description="close">
              <XMarkIconOutline />
            </CleanIconButton>
          </div>
        </div>
        <div className="n-p-4 n-flex n-flex-col n-grow n-overflow-y-auto">
          {messages.length === 0 ? (
            <div className="n-flex n-flex-col ">
              <div className="n-flex n-flex-col n-gap-12">
                <Typography variant="display">
                  Hi [User], how can I help you today?
                </Typography>
                <div className="n-flex n-flex-col n-gap-4">
                  <Typography variant="body-medium">Suggestions</Typography>
                  <Suggestion
                    isPrimary
                    onClick={() => {
                      handleSend('I want to import data');
                    }}
                  >
                    I want to import data
                  </Suggestion>
                  <Suggestion
                    onClick={() => {
                      handleSend('Create an AI agent');
                    }}
                  >
                    Create an AI agent
                  </Suggestion>
                  <Suggestion
                    onClick={() => {
                      handleSend('Invite project members');
                    }}
                  >
                    Invite project members
                  </Suggestion>
                  <Suggestion
                    onClick={() => {
                      handleSend('Generate a report');
                    }}
                  >
                    Generate a report
                  </Suggestion>
                </div>
                <Typography variant="body-medium">
                  You can also drag and drop files here, or{' '}
                  <TextLink as="button" type="internal-underline">
                    browse
                  </TextLink>
                  . Supports CVG, MOV, PDF
                </Typography>
              </div>
            </div>
          ) : (
            <div className="n-flex n-flex-col n-gap-4 n-pb-4">
              {messages.map((msg, idx) => (
                <div
                  key={idx}
                  className={`n-flex ${
                    msg.role === 'user' ? 'n-justify-end' : 'n-justify-start'
                  }`}
                >
                  {msg.role === 'user' ? (
                    <div className="n-max-w-[85%]">
                      <UserBubble
                        avatarProps={{
                          name: 'NM',
                          type: 'letters',
                        }}
                      >
                        {msg.content}
                      </UserBubble>
                    </div>
                  ) : (
                    <div className="n-w-full n-flex n-flex-col n-gap-2">
                      {msg.thinkingTime !== undefined && (
                        <Thinking
                          isThinking={false}
                          thinkingMs={msg.thinkingTime}
                        />
                      )}
                      <div className="n-flex n-flex-col n-gap-2">
                        <Response>{msg.content}</Response>

                        {msg.done === true && (
                          <div className="n-flex n-flex-row n-gap-1.5">
                            <CleanIconButton size="small" description="Dislike">
                              <HandThumbDownIconOutline />
                            </CleanIconButton>
                            <CleanIconButton size="small" description="Re-run">
                              <ArrowPathIconOutline />
                            </CleanIconButton>
                            <CleanIconButton size="small" description="Copy">
                              <Square2StackIconOutline />
                            </CleanIconButton>
                          </div>
                        )}
                      </div>
                    </div>
                  )}
                </div>
              ))}
              {isThinking && <Thinking isThinking={true} />}
              <div ref={messagesEndRef} />
            </div>
          )}
        </div>
        <div className="n-px-4 n-pt-4 n-pb-1 n-mt-auto">
          <Prompt
            value={prompt}
            onChange={(e) => setPrompt(e.target.value)}
            onSubmitPrompt={() => handleSend()}
            onCancelPrompt={handleCancel}
            isRunningPrompt={isThinking || isStreaming}
            isSubmitDisabled={
              prompt.length === 0 && !(isThinking || isStreaming)
            }
            bottomContent={
              <CleanIconButton description="Add files" size="small">
                <PlusIconOutline />
              </CleanIconButton>
            }
          />
        </div>
      </div>
    </section>
  );
};

export default Component;
```

### Headings

```tsx
import { Response } from '@neo4j-ndl/react/ai';

const headingsMarkdown = `
# Heading Level 1
This is content under heading 1.

## Heading Level 2
This is content under heading 2.

### Heading Level 3
This is content under heading 3.

#### Heading Level 4
This is content under heading 4.

##### Heading Level 5
This is content under heading 5.

###### Heading Level 6
This is content under heading 6.

---

## Document Structure Example

# Main Document Title

Brief introduction to the document.

## Introduction

This section provides an overview of what we'll cover.

### Background

Some background information about the topic.

#### Historical Context

Details about the history.

##### Key Events

- Event 1
- Event 2
- Event 3

###### Notes

Additional notes and references.

## Content Section

Main content goes here.

### Subsection A

Details for subsection A.

### Subsection B

Details for subsection B.

## Conclusion

Final thoughts and summary.

---

## Headings with Other Elements

### Code Example

\`\`\`javascript
console.log("Hello from heading section");
\`\`\`

### List Example

- Item 1
- Item 2
- Item 3

### Quote Example

> "This is a quote under a heading."

### Mixed Content

Regular paragraph with **bold** and *italic* text.
`;

export const Component = () => {
  return (
    <div className="max-w-4xl">
      <Response>{headingsMarkdown}</Response>
    </div>
  );
};

export default Component;
```

### Lists

```tsx
import { Response } from '@neo4j-ndl/react/ai';

const listsMarkdown = `
# Lists Examples

## Simple Unordered List

- Apple
- Banana
- Cherry
- Date
- Elderberry

## Simple Ordered List

1. First step
2. Second step
3. Third step
4. Fourth step
5. Fifth step

## Nested Unordered Lists

- Fruits
  - Apples
    - Granny Smith
    - Honeycrisp
    - Fuji
  - Oranges
    - Navel
    - Blood Orange
  - Berries
    - Strawberry
    - Blueberry
    - Raspberry
- Vegetables
  - Leafy Greens
    - Spinach
    - Kale
  - Root Vegetables
    - Carrot
    - Potato

## Nested Ordered Lists

1. Introduction
   1. Overview
   2. Purpose
   3. Scope
2. Main Content
   1. Chapter 1
      1. Section 1.1
      2. Section 1.2
      3. Section 1.3
   2. Chapter 2
      1. Section 2.1
      2. Section 2.2
3. Conclusion
   1. Summary
   2. Recommendations

## Mixed Lists

1. Install dependencies
   - Node.js
   - npm or yarn
   - Git
2. Clone repository
   - \`git clone <url>\`
   - \`cd project-name\`
3. Configure settings
   1. Copy \`.env.example\` to \`.env\`
   2. Update configuration values:
      - Database URL
      - API keys
      - Port number
4. Start development server
   - Run \`npm install\`
   - Run \`npm start\`

## Lists with Paragraphs

- **First Item**
  
  This is a detailed explanation of the first item. It can contain multiple sentences and provide context.

- **Second Item**
  
  The second item also has a detailed explanation. This helps provide more information to the reader.

- **Third Item**
  
  Each item can have as much detail as needed.

## Lists with Code

- JavaScript example:
  
  \`\`\`javascript
  const items = ['a', 'b', 'c'];
  items.forEach(item => console.log(item));
  \`\`\`

- Python example:
  
  \`\`\`python
  items = ['a', 'b', 'c']
  for item in items:
      print(item)
  \`\`\`

## Task Lists Representation

- [x] Complete feature A
- [x] Write tests
- [ ] Review code
- [ ] Deploy to production
- [ ] Monitor metrics

## Lists with Links

1. Official Resources
   - [Neo4j Documentation](https://neo4j.com/docs)
   - [Neo4j Community](https://community.neo4j.com)
   - [Neo4j GitHub](https://github.com/neo4j)
2. Tutorials
   - [Getting Started Guide](https://neo4j.com/start)
   - [Cypher Query Language](https://neo4j.com/cypher)
3. Tools
   - Neo4j Desktop
   - Neo4j Browser
   - Neo4j Bloom

## Lists with Inline Formatting

- **Bold item** with regular text
- *Italic item* with regular text
- \`Code item\` with regular text
- Regular text with **bold**, *italic*, and \`code\`
- Combination: **bold and *italic* text** together
`;

export const Component = () => {
  return (
    <div className="max-w-4xl">
      <Response>{listsMarkdown}</Response>
    </div>
  );
};

export default Component;
```

### Streaming

```tsx
import { Response } from '@neo4j-ndl/react/ai';
import { useEffect, useState } from 'react';

const StreamingComponent = () => {
  const [content, setContent] = useState('');

  useEffect(() => {
    const fullContent = `
# Streaming Response

This content is being **streamed (and here's a long long long long bold text)** to simulate an AI response.

It handles:
1. Partial updates
2. Incomplete markdown
3. Code blocks

\`\`\`javascript
function stream() {
  return "streaming...";
}
\`\`\`
And here comes more text after the code block.`;

    let currentIndex = 0;
    const interval = setInterval(() => {
      if (currentIndex < fullContent.length) {
        setContent(fullContent.slice(0, currentIndex + 1));
        currentIndex++;
      } else {
        clearInterval(interval);
      }
    }, 30);

    return () => clearInterval(interval);
  }, []);

  return <Response>{content}</Response>;
};

export const Component = () => {
  return <StreamingComponent />;
};

export default Component;
```
