Rasterex API/docs/components/files/page-list

Page List

Listen for `pageList` and render a host-side page panel from the latest canvas snapshot.

Overview

The canvas emits pageList as an outbound event. The host should treat the payload as the latest page snapshot and re-render its page list UI whenever a new event arrives.

Each page record includes label and selection metadata, plus optional thumbnail data for preview rendering.

Quick Start

Listen for pageList and pass the returned page items directly into your own rendering function.

Listen for pageList

window.addEventListener('message', (event) => {
  const data = event.data;
  if (!data || data.type !== 'pageList') return;

  renderPages(data.payload.pages);
});

Render page previews

function renderPages(pages) {
  const container = document.getElementById('pages');
  container.innerHTML = '';

  pages.forEach((page) => {
    const item = document.createElement('button');
    item.className = page.isSelected ? 'page active' : 'page';

    const img = document.createElement('img');
    img.src = page.thumbnailDataUrl || '';
    img.width = page.thumbnailWidth || 120;
    img.height = page.thumbnailHeight || 160;

    const label = document.createElement('div');
    label.textContent = page.label;

    item.appendChild(img);
    item.appendChild(label);
    container.appendChild(item);
  });
}

Payload Shape

This is the shape your host UI should expect from the latest page snapshot.

type PageListPayload = {
  activeId: string;
  activeIndex: number;
  currentPage: number;
  pageCount: number;
  pages: Array<{
    index: number;
    pageNumber: number;
    title: string;
    label: string;
    isSelected: boolean;
    thumbnailDataUrl?: string;
    thumbnailWidth?: number;
    thumbnailHeight?: number;
  }>;
};
Payload Shape

Host Guidance

Keep the page list code simple and event-driven.

  • Do not call a separate thumbnail API.
  • Do not maintain a second page-selection source of truth outside the canvas events.
  • Use the latest pageList payload to refresh labels, thumbnails, and active state.

Complete HTML Example

Use this full standalone HTML document when you want a minimal host page for the pageList workflow.

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>PDF Page List Demo</title>
  <style>
    body {
      margin: 0;
      font-family: Arial, sans-serif;
      background: #0b1220;
      color: #e5e7eb;
    }
    .app {
      display: grid;
      grid-template-columns: 320px 1fr;
      gap: 12px;
      min-height: 100vh;
      padding: 12px;
    }
    .panel {
      border: 1px solid #2f3b4f;
      border-radius: 12px;
      background: #111827;
      padding: 12px;
      display: grid;
      gap: 10px;
      align-content: start;
    }
    .stack {
      display: grid;
      gap: 8px;
    }
    .row {
      display: flex;
      gap: 8px;
      flex-wrap: wrap;
    }
    input, button, select {
      width: 100%;
      border: 1px solid #2f3b4f;
      border-radius: 8px;
      background: #0f172a;
      color: #e5e7eb;
      padding: 8px 10px;
      font: inherit;
      box-sizing: border-box;
    }
    button {
      width: auto;
      cursor: pointer;
    }
    .pages {
      display: grid;
      gap: 8px;
      max-height: 60vh;
      overflow: auto;
    }
    .page {
      border: 1px solid #2f3b4f;
      border-radius: 10px;
      background: #0d1728;
      padding: 8px;
      display: grid;
      gap: 8px;
    }
    .page.active {
      border-color: #22d3ee;
    }
    iframe {
      width: 100%;
      height: calc(100vh - 24px);
      border: 1px solid #2f3b4f;
      border-radius: 12px;
      background: #04101c;
    }
    img {
      max-width: 100%;
      height: auto;
      display: block;
      background: #fff;
      border-radius: 8px;
    }
    .meta {
      font-size: 12px;
      color: #9ca3af;
    }
  </style>
</head>
<body>
  <div class="app">
    <div class="panel">
      <div class="stack">
      <input id="viewerUrl" value="http://localhost:5173" />
      <input id="fileUrl" placeholder="Public PDF URL" />
      <div class="row">
        <button id="loadViewerBtn">Load Canvas</button>
        <button id="loadPdfBtn">Load PDF</button>
      </div>
      <div id="pages" class="pages"></div>
    </div>
    </div>
    <iframe id="viewerFrame" title="PDF Page List Demo Canvas"></iframe>
  </div>
  <script>
const viewerFrame = document.getElementById('viewerFrame');
const viewerUrlInput = document.getElementById('viewerUrl');
const fileUrlInput = document.getElementById('fileUrl');
const pagesEl = document.getElementById('pages');
let latestPageList = null;

function post(type, payload) {
  viewerFrame.contentWindow.postMessage({ type, payload }, '*');
}

function loadViewer() {
  viewerFrame.src = viewerUrlInput.value.trim();
}

function loadPdf() {
  post('view', {
    fileUrl: fileUrlInput.value.trim(),
    displayName: 'Demo User',
    username: 'demo.user',
    email: 'demo@example.com'
  });
}

window.addEventListener('message', (event) => {
  if (event.source !== viewerFrame.contentWindow) return;
  const data = event.data;
  if (!data || typeof data !== 'object') return;
  if (data.type === 'pageList') {
    latestPageList = data.payload;
    renderPages(data.payload.pages);
  }
  onViewerMessage(data);
});

function renderPages(pages) {
  if (!pagesEl) return;
  pagesEl.innerHTML = '';
  pages.forEach((page) => {
    const item = document.createElement('div');
    item.className = page.isSelected ? 'page active' : 'page';
    const actions = pageActions(page);
    item.innerHTML = [
      page.thumbnailDataUrl
        ? '<img src="' + page.thumbnailDataUrl + '" width="' + (page.thumbnailWidth || 120) + '" height="' + (page.thumbnailHeight || 160) + '" />'
        : '<div class="meta">No thumbnail data</div>',
      '<div><strong>' + (page.label || ('Page ' + (page.index + 1))) + '</strong></div>',
      '<div class="meta">' + (page.title || 'Default') + '</div>',
      actions
    ].join('');
    wirePageActions(item, page);
    pagesEl.appendChild(item);
  });
}

document.getElementById('loadViewerBtn').addEventListener('click', loadViewer);
document.getElementById('loadPdfBtn').addEventListener('click', loadPdf);

function pageActions() { return ''; }
function wirePageActions() {}
function onViewerMessage() {}
  </script>
</body>
</html>
Complete HTML Example

Live Preview

Open the focused demo to watch the page rail update live from pageList events.

File Page List Demo

Focused live demo for the pageList workflow.

Preview opens in a large modal for zoom-friendly review.