# Multi-Instance Spreadsheets

The `SpreadsheetMultiInstanceProvider` component allows you to render multiple spreadsheet instances within the same application while maintaining isolated state and preventing conflicts between instances.

## Overview

By default, each spreadsheet instance shares global context through `SpreadsheetProvider`. When you need to render multiple spreadsheets simultaneously (e.g., side-by-side comparison, multi-document interface), you need to wrap them in `SpreadsheetMultiInstanceProvider` to ensure proper isolation.

## Basic Usage

```tsx
import {
  SpreadsheetProvider,
  SpreadsheetMultiInstanceProvider,
  CanvasGrid,
} from "@rowsncolumns/spreadsheet";
import { useSpreadsheetState } from "@rowsncolumns/spreadsheet-state";

function MultiSpreadsheetApp() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <SpreadsheetProvider>
        <SpreadsheetInstance instanceId="spreadsheet-1" />
      </SpreadsheetProvider>

      <SpreadsheetProvider>
        <SpreadsheetInstance instanceId="spreadsheet-2" />
      </SpreadsheetProvider>
    </SpreadsheetMultiInstanceProvider>
  );
}

function SpreadsheetInstance({ instanceId }: { instanceId: string }) {
  const {
    activeCell,
    activeSheetId,
    selections,
    // ... other state
  } = useSpreadsheetState({
    // configuration
  });

  return (
    <CanvasGrid
      instanceId={instanceId}
      sheetId={activeSheetId}
      activeCell={activeCell}
      selections={selections}
      // ... other props
    />
  );
}
```

## Instance ID

Each `CanvasGrid` instance should have a unique `instanceId` prop when rendered within `SpreadsheetMultiInstanceProvider`:

```tsx
<CanvasGrid
  instanceId="spreadsheet-a"  // Unique identifier
  sheetId={activeSheetId}
  // ... other props
/>
```

### Why Instance IDs Matter

Instance IDs ensure that:

* Keyboard events are routed to the correct spreadsheet
* Editor state is isolated between instances
* Context menus and dialogs appear in the correct location
* Formula evaluation doesn't cross instance boundaries

## Use Cases

### Side-by-Side Comparison

Compare two spreadsheets side by side:

```tsx
function SpreadsheetComparison() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <div className="flex gap-4">
        <div className="flex-1">
          <h2>Version 1</h2>
          <SpreadsheetProvider>
            <SpreadsheetView instanceId="version-1" />
          </SpreadsheetProvider>
        </div>

        <div className="flex-1">
          <h2>Version 2</h2>
          <SpreadsheetProvider>
            <SpreadsheetView instanceId="version-2" />
          </SpreadsheetProvider>
        </div>
      </div>
    </SpreadsheetMultiInstanceProvider>
  );
}
```

### Multi-Document Interface

Create a tabbed or windowed interface with multiple spreadsheet documents:

```tsx
function MultiDocumentInterface() {
  const [documents] = useState([
    { id: "doc-1", name: "Budget 2024" },
    { id: "doc-2", name: "Sales Report" },
    { id: "doc-3", name: "Inventory" },
  ]);

  return (
    <SpreadsheetMultiInstanceProvider>
      {documents.map((doc) => (
        <SpreadsheetProvider key={doc.id}>
          <div className="document-window">
            <h3>{doc.name}</h3>
            <SpreadsheetView instanceId={doc.id} />
          </div>
        </SpreadsheetProvider>
      ))}
    </SpreadsheetMultiInstanceProvider>
  );
}
```

### Master-Detail View

Display a master spreadsheet with a detail view:

```tsx
function MasterDetailView() {
  const [selectedRow, setSelectedRow] = useState<number | null>(null);

  return (
    <SpreadsheetMultiInstanceProvider>
      <div className="grid grid-cols-2 gap-4">
        {/* Master spreadsheet */}
        <SpreadsheetProvider>
          <h2>Sales Overview</h2>
          <SpreadsheetView
            instanceId="master"
            onRowSelect={setSelectedRow}
          />
        </SpreadsheetProvider>

        {/* Detail spreadsheet */}
        {selectedRow && (
          <SpreadsheetProvider>
            <h2>Row Details</h2>
            <SpreadsheetView
              instanceId="detail"
              rowData={selectedRow}
            />
          </SpreadsheetProvider>
        )}
      </div>
    </SpreadsheetMultiInstanceProvider>
  );
}
```

## Complete Example

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

function App() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <div className="flex gap-5 h-screen p-5">
        <div className="flex-1">
          <SpreadsheetProvider>
            <SpreadsheetA />
          </SpreadsheetProvider>
        </div>

        <div className="flex-1">
          <SpreadsheetProvider>
            <SpreadsheetB />
          </SpreadsheetProvider>
        </div>
      </div>
    </SpreadsheetMultiInstanceProvider>
  );
}

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

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

  return (
    <CanvasGrid
      instanceId="spreadsheet-a"
      sheetId={activeSheetId}
      activeCell={activeCell}
      selections={selections}
      getCellData={getCellData}
      onChangeActiveCell={onChangeActiveCell}
      onChangeSelections={onChangeSelections}
      onChange={onChange}
    />
  );
}

function SpreadsheetB() {
  // Similar implementation with different instance ID
  // ...

  return (
    <CanvasGrid
      instanceId="spreadsheet-b"
      // ... props
    />
  );
}
```

## Best Practices

1. **Always Use Unique Instance IDs**: Ensure each spreadsheet has a unique `instanceId` to prevent conflicts
2. **Wrap Each Instance**: Each spreadsheet should have its own `SpreadsheetProvider` wrapper
3. **Isolate State**: Use separate state management for each spreadsheet instance
4. **Performance Considerations**: Be mindful of rendering multiple large spreadsheets simultaneously - consider lazy loading or virtualization
5. **Memory Management**: Clean up instances when they're no longer needed to free up resources

## Limitations

* Each instance maintains its own calculation engine and state
* Cross-instance formulas are not supported (formulas cannot reference cells from other instances)
* Each instance requires separate data management

## Performance Tips

When rendering multiple instances:

```tsx
// Use React.memo to prevent unnecessary re-renders
const SpreadsheetInstance = React.memo(({ instanceId, data }) => {
  // ... implementation
});

// Lazy load instances that aren't immediately visible
const LazySpreadsheet = lazy(() => import('./SpreadsheetInstance'));

function MultiInstance() {
  return (
    <SpreadsheetMultiInstanceProvider>
      <Suspense fallback={<div>Loading...</div>}>
        <LazySpreadsheet instanceId="lazy-1" />
      </Suspense>
    </SpreadsheetMultiInstanceProvider>
  );
}
```

## Troubleshooting

### Keyboard Events Not Working

If keyboard events aren't working properly, ensure:

* Each `CanvasGrid` has a unique `instanceId`
* The `SpreadsheetMultiInstanceProvider` wraps all instances
* Only one spreadsheet has focus at a time

### State Conflicts

If you experience state conflicts between instances:

* Verify each instance has its own `SpreadsheetProvider`
* Check that state management is properly isolated
* Ensure instance IDs are unique and don't change during component lifecycle
