# How AionUi's Preview Panel Supports 10+ File Formats with Version History and Real-Time Editing

> Explore AionUi's versatile preview panel supporting 10+ file formats. Discover real-time editing, version history, and instant updates for seamless collaboration.

- Repository: [OfficeAI/AionUi](https://github.com/iofficeai/aionui)
- Tags: how-to-guide
- Published: 2026-02-19

---

**AionUi's preview panel combines file-type-specific renderers with a debounced snapshot system and split-screen editing to support Markdown, HTML, PDF, Office documents, and images with full version history and instant updates.**

The **AionUi** repository implements a sophisticated preview architecture that transforms a simple file viewer into a comprehensive editing environment. The preview panel automatically selects appropriate renderers for over ten file formats while maintaining a complete version history through the **IO⁺** service. This article examines the component structure, real-time editing mechanisms, and snapshot persistence that power this feature.

## Architecture of the AionUi Preview Panel

The preview panel operates as a dynamic container that instantiates format-specific components based on content type detection.

### File Type Detection and Component Selection

The `PreviewPanel` component in [`src/renderer/pages/conversation/preview/components/PreviewPanel/PreviewPanel.tsx`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/components/PreviewPanel/PreviewPanel.tsx) acts as the central router for file rendering. It inspects the `contentType` property to determine which specialized viewer to mount:

- **MarkdownPreview** for `.md` files
- **HTMLRenderer** for `.html` content
- **PDFPreview** for PDF documents
- **WordPreview**, **ExcelPreview**, **PowerPointPreview** for Office formats
- **ImagePreview** for visual assets
- **URLViewer** for web links

This modular approach allows the AionUi preview panel to extend support for new formats without refactoring the core container logic.

### Split-Screen Layout for Real-Time Editing

Real-time editing relies on the `useResizableSplit` hook to create a draggable divider between editor and preview panes. When `isSplitScreenEnabled` is active, the panel renders side-by-side components:

```typescript
// Inside PreviewPanel.tsx
if (isSplitScreenEnabled) {
  return (
    <div className="flex flex-1 relative overflow-hidden">
      {/* Editor side */}
      <div className="flex flex-col" style={{ width: `${splitRatio}%` }}>
        <MarkdownEditor
          value={content}
          onChange={updateContent}
          containerRef={editorContainerRef}
          onScroll={handleEditorScroll}
        />
      </div>

      {/* Preview side */}
      <div className="flex flex-col" style={{ width: `${100 - splitRatio}%` }}>
        <MarkdownPreview
          content={content}
          filePath={metadata?.filePath}
        />
      </div>
    </div>
  );
}

```

The `updateContent` function propagates changes immediately to the preview component, creating the real-time feedback loop that characterizes the AionUi editing experience.

## Implementing Version History in AionUi

The **IO⁺** version history system persists content snapshots through a combination of React hooks and IPC communication with the main process.

### The usePreviewHistory Hook

Located in [`src/renderer/pages/conversation/preview/hooks/usePreviewHistory.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/hooks/usePreviewHistory.ts), this hook encapsulates all history operations. It constructs a `historyTarget` object from the active tab's metadata to identify the resource being versioned:

```typescript
const historyTarget = useMemo(() => {
  if (!activeTab?.metadata) return null;
  
  return {
    id: activeTab.id,
    type: activeTab.contentType,
    path: activeTab.metadata.filePath,
  };
}, [activeTab]);

```

The hook exposes three primary operations through the `ipcBridge.previewHistory` namespace:
- `list.invoke()` retrieves all snapshots for the target
- `save.invoke()` persists current content as a new version
- `getContent.invoke()` retrieves specific snapshot data for restoration

### Debounced Snapshot Mechanism

To prevent storage flooding during rapid editing, AionUi implements a debounce guard using `lastSnapshotTimeRef` and the `SNAPSHOT_DEBOUNCE_TIME` constant (default 1000ms):

```typescript
const handleSaveSnapshot = useCallback(async () => {
  if (!historyTarget || !activeTab) return;
  if (snapshotSaving) return;

  const now = Date.now();
  if (now - lastSnapshotTimeRef.current < SNAPSHOT_DEBOUNCE_TIME) {
    messageApi.info(t('preview.tooFrequent'));
    return;
  }

  try {
    setSnapshotSaving(true);
    lastSnapshotTimeRef.current = now;
    await ipcBridge.previewHistory.save.invoke({
      target: historyTarget,
      content: activeTab.content,
    });
    messageApi.success(t('preview.snapshotSaved'));
    await refreshHistory();
  } finally {
    setSnapshotSaving(false);
  }
}, [historyTarget, activeTab, snapshotSaving, messageApi, refreshHistory, t]);

```

The `PreviewToolbar` component surfaces this functionality through a "Save Snapshot" button, while the history list renders available versions for selection and restoration.

## Real-Time Editing Workflow

The complete editing cycle demonstrates how AionUi synchronizes user input, preview updates, and version persistence:

1. **Activation**: User toggles edit mode via `setIsEditMode(true)` in [`PreviewPanel.tsx`](https://github.com/iOfficeAI/AionUi/blob/main/PreviewPanel.tsx) (line 73)
2. **Layout**: For code-type files, split-screen auto-enables via `setIsSplitScreenEnabled(true)`
3. **Input**: Editor components (`MarkdownEditor`, `HTMLEditor`, etc.) bind `onChange={updateContent}`
4. **Propagation**: `updateContent` modifies the active tab's content in the preview context, triggering immediate re-render of the preview pane (lines 69-73)
5. **Persistence**: The debounced snapshot mechanism ensures version history updates without blocking the UI thread

This architecture allows users to edit Markdown, HTML, and text files while viewing formatted output simultaneously, with every significant change eligible for version capture.

## Key Source Files and Components

| File | Role |
|------|------|
| [`src/renderer/pages/conversation/preview/components/PreviewPanel/PreviewPanel.tsx`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/components/PreviewPanel/PreviewPanel.tsx) | Core container managing file-type routing, split-screen layout, and editing state |
| [`src/renderer/pages/conversation/preview/hooks/usePreviewHistory.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/hooks/usePreviewHistory.ts) | Version history logic including debounced saves and snapshot retrieval |
| [`src/renderer/pages/conversation/preview/components/Toolbar/PreviewToolbar.tsx`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/components/Toolbar/PreviewToolbar.tsx) | Action buttons for edit mode, snapshot creation, and history refresh |
| [`src/common/ipcBridge.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/common/ipcBridge.ts) | IPC contract defining `previewHistory.*` channels for main-process communication |
| [`src/renderer/pages/conversation/preview/constants.ts`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/constants.ts) | Configuration values including `SNAPSHOT_DEBOUNCE_TIME` |

These files collectively implement the **IO⁺** standard for the AionUi preview panel, delivering format-agnostic viewing, real-time collaborative editing capabilities, and robust version persistence.

## Summary

- **AionUi's preview panel** dynamically selects specialized renderers for 10+ file formats including Markdown, HTML, PDF, Office documents, and images through a modular component architecture in [`PreviewPanel.tsx`](https://github.com/iOfficeAI/AionUi/blob/main/PreviewPanel.tsx).
- **Real-time editing** utilizes a resizable split-screen layout (`useResizableSplit`) that synchronizes editor input with live preview updates via the `updateContent` callback.
- **Version history (IO⁺)** persists through `usePreviewHistory`, which manages snapshots via IPC bridges to the main process, implementing debounced saves to prevent storage flooding.
- **Snapshot restoration** allows users to retrieve any historical version through `previewHistory.getContent.invoke` and inject it back into the active editor session.

## Frequently Asked Questions

### How does AionUi determine which viewer to use for different file formats?

The `PreviewPanel` component inspects the `contentType` property of the active tab to select the appropriate renderer. It maintains a mapping that instantiates `MarkdownPreview` for Markdown files, `PDFPreview` for PDFs, `WordPreview` for DOCX files, and specialized components for Excel, PowerPoint, images, and URLs. This routing logic lives in [`src/renderer/pages/conversation/preview/components/PreviewPanel/PreviewPanel.tsx`](https://github.com/iOfficeAI/AionUi/blob/main/src/renderer/pages/conversation/preview/components/PreviewPanel/PreviewPanel.tsx).

### What prevents the version history from saving too frequently during rapid editing?

AionUi implements a debounce mechanism in the `usePreviewHistory` hook using a `lastSnapshotTimeRef` and the `SNAPSHOT_DEBOUNCE_TIME` constant (set to 1000ms by default). Before saving a snapshot, the system checks if the elapsed time since the last save exceeds this threshold. If the user attempts to save too frequently, the UI displays a toast notification indicating the action is rate-limited.

### Can users restore previous versions without leaving the preview panel?

Yes, the version history system allows complete restoration within the panel interface. When a user selects a historical snapshot from the history list, the `handleSnapshotSelect` function in [`usePreviewHistory.ts`](https://github.com/iOfficeAI/AionUi/blob/main/usePreviewHistory.ts) calls `ipcBridge.previewHistory.getContent.invoke` to retrieve the snapshot data. It then uses the `updateContent` callback to inject the historical content directly into the active editor, updating both the editor state and live preview simultaneously.