No framework
The viewer is a plain class. The framework wrappers are a hundred lines each over exactly this.
Nothing about the viewer needs a framework: it takes an element, opens a file into it, and reports what happens on a typed event bus. If your application is not a React one — or is a Web Component, a Svelte island, or a page with a script tag — this is the whole API.
viewer.ts
import { createViewer } from '@genomdev/core/viewer';
import { docx, xlsx, pdf } from '@genomdev/genom/lazy';
const viewer = createViewer(document.querySelector('#pane')!, {
formats: [docx, xlsx, pdf],
fit: 'width',
options: { xlsx: { sheetTabs: true } },
});
const off = viewer.on('page:change', ({ index, total }) => {
label.textContent = `${index + 1} / ${total ?? '?'}`;
});
await viewer.open(file);
// later
off();
viewer.destroy();Every format in one line
When an application does not know what it will be handed, @genomdev/genom/viewer is the same class with all four formats already registered lazily.
umbrella
import { createViewer } from '@genomdev/genom/viewer';
const viewer = createViewer(element);
await viewer.open(file); // whatever it turns out to beState and events
subscribe gives you the whole state as a store — status, progress, error, document — which is what a UI framework wants. on gives you individual named events, which is what a toolbar wants.
| Event | Payload |
|---|---|
status | { status, progress, error } |
document:open | { document, detection } |
document:close | {} |
page:change | { index, total } |
selection:change | { text } |
link:activate | { href, event } — cancel the event to stop the navigation |
error | { error } |
sheet:*, slide:* | format-specific, named after the format that emits them |