# Mentions

The mentions feature allows users to reference people, tags, or entities within cells using the `@` symbol, similar to social media platforms. This is useful for collaborative spreadsheets, task management, and commenting systems.

## Overview

Mentions enable:

* **User tagging**: Reference team members in cells
* **Entity references**: Link to external resources or data
* **Autocomplete**: Dropdown suggestions as users type
* **Custom rendering**: Display mentions with custom styling
* **Data binding**: Connect mentions to your application's data model

## Basic Usage

```tsx
import { SpreadsheetProvider, CanvasGrid } from "@rowsncolumns/spreadsheet";
import { useCallback } from "react";

function SpreadsheetWithMentions() {
  const getMentions = useCallback(async (query?: string) => {
    // Fetch mentions from your API or database
    return [
      { label: "John Doe", value: "user-123" },
      { label: "Jane Smith", value: "user-456" },
      { label: "Marketing Team", value: "team-789" },
    ];
  }, []);

  return (
    <SpreadsheetProvider>
      <CanvasGrid
        sheetId={1}
        getMentions={getMentions}
        // ... other props
      />
    </SpreadsheetProvider>
  );
}
```

## getMentions Function

The `getMentions` callback is called when users type `@` in a cell. It should return a Promise that resolves to an array of mention objects.

### Function Signature

```typescript
type MentionItem = {
  label: string;      // Display text in dropdown
  value: string;      // Unique identifier
  [key: string]: any; // Additional custom properties
};

type GetMentions = (query?: string) => Promise<MentionItem[]>;
```

### Parameters

* **query** (optional): The search text entered by the user after `@`

### Example with Search

```tsx
const getMentions = useCallback(async (query?: string) => {
  // Filter mentions based on query
  const allMentions = [
    { label: "Alice Johnson", value: "user-1", email: "alice@example.com" },
    { label: "Bob Wilson", value: "user-2", email: "bob@example.com" },
    { label: "Charlie Brown", value: "user-3", email: "charlie@example.com" },
  ];

  if (!query) {
    return allMentions;
  }

  // Filter by query
  const filtered = allMentions.filter((mention) =>
    mention.label.toLowerCase().includes(query.toLowerCase())
  );

  return filtered;
}, []);
```

## Custom Dropdown Rendering

Customize how mentions appear in the autocomplete dropdown using `MentionDropdownItemComponent`:

```tsx
import { SpreadsheetProvider, CanvasGrid } from "@rowsncolumns/spreadsheet";

function SpreadsheetWithCustomMentions() {
  const MentionItem = ({ mention }) => {
    return (
      <div className="flex items-center gap-2 p-2">
        <img
          src={mention.avatar}
          alt={mention.label}
          className="w-8 h-8 rounded-full"
        />
        <div>
          <div className="font-semibold">{mention.label}</div>
          <div className="text-xs text-gray-500">{mention.email}</div>
        </div>
      </div>
    );
  };

  return (
    <SpreadsheetProvider>
      <CanvasGrid
        sheetId={1}
        getMentions={getMentions}
        MentionDropdownItemComponent={MentionItem}
        // ... other props
      />
    </SpreadsheetProvider>
  );
}
```

### MentionDropdownItemComponent Props

```typescript
type MentionDropdownItemProps = {
  mention: MentionItem;
  isSelected?: boolean;
  onClick?: () => void;
};
```

## Async Data Loading

Fetch mentions from an API:

```tsx
const getMentions = useCallback(async (query?: string) => {
  try {
    const response = await fetch(
      `/api/mentions?query=${encodeURIComponent(query || '')}`
    );
    const data = await response.json();
    return data.mentions;
  } catch (error) {
    console.error("Failed to fetch mentions:", error);
    return [];
  }
}, []);
```

## Complete Example

```tsx
import React, { useCallback, useState } from "react";
import {
  SpreadsheetProvider,
  CanvasGrid,
  Sheet,
} from "@rowsncolumns/spreadsheet";
import {
  useSpreadsheetState,
  SheetData,
  CellData,
} from "@rowsncolumns/spreadsheet-state";

// Mock user database
const users = [
  {
    label: "Alice Johnson",
    value: "user-1",
    email: "alice@company.com",
    department: "Engineering",
    avatar: "/avatars/alice.jpg",
  },
  {
    label: "Bob Smith",
    value: "user-2",
    email: "bob@company.com",
    department: "Marketing",
    avatar: "/avatars/bob.jpg",
  },
  {
    label: "Charlie Davis",
    value: "user-3",
    email: "charlie@company.com",
    department: "Sales",
    avatar: "/avatars/charlie.jpg",
  },
];

function TaskSpreadsheet() {
  const [sheets, setSheets] = useState<Sheet[]>([
    { sheetId: 1, rowCount: 100, columnCount: 10, title: "Tasks" }
  ]);
  const [sheetData, setSheetData] = useState<SheetData<CellData>>({});

  const {
    activeCell,
    activeSheetId,
    selections,
    getCellData,
    onChangeActiveCell,
    onChangeSelections,
    onChange,
  } = useSpreadsheetState({
    sheets,
    sheetData,
    onChangeSheets: setSheets,
    onChangeSheetData: setSheetData,
  });

  // Fetch mentions with search
  const getMentions = useCallback(async (query?: string) => {
    // Simulate API delay
    await new Promise((resolve) => setTimeout(resolve, 100));

    if (!query) {
      return users;
    }

    // Filter by name or email
    return users.filter((user) =>
      user.label.toLowerCase().includes(query.toLowerCase()) ||
      user.email.toLowerCase().includes(query.toLowerCase()) ||
      user.department.toLowerCase().includes(query.toLowerCase())
    );
  }, []);

  // Custom mention dropdown item
  const MentionDropdownItem = ({ mention }) => {
    return (
      <div className="flex items-center gap-3 px-3 py-2 hover:bg-gray-100">
        <img
          src={mention.avatar}
          alt={mention.label}
          className="w-10 h-10 rounded-full"
        />
        <div className="flex-1">
          <div className="font-medium text-sm">{mention.label}</div>
          <div className="text-xs text-gray-600">{mention.email}</div>
        </div>
        <span className="text-xs text-gray-500 bg-gray-200 px-2 py-1 rounded">
          {mention.department}
        </span>
      </div>
    );
  };

  return (
    <SpreadsheetProvider>
      <CanvasGrid
        sheetId={activeSheetId}
        activeCell={activeCell}
        selections={selections}
        getCellData={getCellData}
        onChangeActiveCell={onChangeActiveCell}
        onChangeSelections={onChangeSelections}
        onChange={onChange}
        getMentions={getMentions}
        MentionDropdownItemComponent={MentionDropdownItem}
      />
    </SpreadsheetProvider>
  );
}

export default TaskSpreadsheet;
```

## Accessing Mention Data

When a mention is selected, it's stored in the cell data. You can access it through the cell's data structure:

```tsx
const cellData = getCellData(sheetId, rowIndex, columnIndex);

// Check if cell contains mentions
if (cellData?.mentions) {
  cellData.mentions.forEach((mention) => {
    console.log("Mentioned user:", mention.label, mention.value);
  });
}
```

## Use Cases

### Team Collaboration

```tsx
// Track task assignments
const getMentions = async () => [
  { label: "@alice", value: "user-1", role: "Developer" },
  { label: "@bob", value: "user-2", role: "Designer" },
];
```

### Project Management

```tsx
// Reference project resources
const getMentions = async (query) => {
  return [
    { label: "@project-alpha", value: "proj-1", type: "project" },
    { label: "@milestone-q1", value: "mile-1", type: "milestone" },
    { label: "@alice", value: "user-1", type: "user" },
  ];
};
```

### Comments and Notes

```tsx
// Add comments with user mentions
const getMentions = async () => {
  const teamMembers = await fetchTeamMembers();
  return teamMembers.map((member) => ({
    label: `@${member.username}`,
    value: member.id,
    name: member.fullName,
  }));
};
```

## Styling

Mentions in cells can be styled using custom text format runs. The spreadsheet automatically formats mentioned text when rendered.

## Performance Optimization

### Debounced Search

```tsx
import { useMemo } from "react";
import debounce from "lodash/debounce";

function SpreadsheetWithMentions() {
  const fetchMentions = async (query?: string) => {
    const response = await fetch(`/api/mentions?q=${query}`);
    return response.json();
  };

  const getMentions = useMemo(
    () => debounce(fetchMentions, 300),
    []
  );

  return (
    <CanvasGrid
      getMentions={getMentions}
      // ... other props
    />
  );
}
```

### Caching

```tsx
const mentionCache = new Map();

const getMentions = useCallback(async (query?: string) => {
  const cacheKey = query || "all";

  if (mentionCache.has(cacheKey)) {
    return mentionCache.get(cacheKey);
  }

  const mentions = await fetchMentions(query);
  mentionCache.set(cacheKey, mentions);

  return mentions;
}, []);
```

## Best Practices

1. **Limit Results**: Return a maximum of 10-20 mentions to keep the dropdown manageable
2. **Fast Response**: Keep the `getMentions` function fast (< 300ms) for good UX
3. **Error Handling**: Handle API failures gracefully and return an empty array
4. **Unique Values**: Ensure each mention has a unique `value` property
5. **Clear Labels**: Use descriptive labels that help users identify the right mention
6. **Type Safety**: Use TypeScript to define your mention structure

## Troubleshooting

### Mentions Not Appearing

* Verify `getMentions` returns an array of objects with `label` and `value` properties
* Check that the function returns a Promise
* Ensure there are no JavaScript errors in the console

### Search Not Working

* Confirm the `query` parameter is being used in your filter logic
* Test the search function independently
* Check for case sensitivity issues

### Slow Performance

* Implement debouncing for API calls
* Add caching for frequently accessed results
* Limit the number of returned results
* Use pagination for large datasets


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.rowsncolumns.app/configuration/features/mentions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
