Files
WRNexusJS/packages/viewer/src/actions.ts
T

61 lines
1.9 KiB
TypeScript

import type { Renderer, ViewerSource } from "./types.ts";
/**
* What an action can see when it is offered and when it runs. `content` is the
* element the renderer drew into, so an action can read or print what is on
* screen rather than re-fetching the file.
*/
export interface ViewerActionContext {
host: HTMLElement;
content: HTMLElement;
source: ViewerSource;
/** Absent while the preview is still resolving, or when nothing could render. */
renderer?: Renderer;
kind?: string;
}
export interface ViewerAction {
/** Stable identifier; registering the same id again replaces the earlier one. */
id: string;
label: string;
/** Name from the built-in icon set. Falls back to one derived from the label. */
icon?: string;
/** Toolbar side: alongside the renderer's own controls, or with download. */
placement?: "controls" | "actions";
/** Offered only when this returns true. Defaults to always. */
when?: (context: ViewerActionContext) => boolean;
run: (context: ViewerActionContext) => void | Promise<void>;
}
const registered = new Map<string, ViewerAction>();
/**
* Adds a toolbar action to every viewer in the page. Returns an unregister
* function, so a component can add one for as long as it is mounted.
*
* ```ts
* registerViewerAction({
* id: "open-in-tab",
* label: "Open in new tab",
* when: ({ source }) => Boolean(source.src),
* run: ({ source }) => window.open(source.src, "_blank", "noopener"),
* });
* ```
*/
export function registerViewerAction(action: ViewerAction): () => void {
registered.set(action.id, action);
return () => {
if (registered.get(action.id) === action) registered.delete(action.id);
};
}
/** Globally registered actions, in registration order. */
export function viewerActions(): ViewerAction[] {
return [...registered.values()];
}
/** Testing helper: drops every globally registered action. */
export function clearViewerActions(): void {
registered.clear();
}