scmJS docs

api.ui

UiApi

Everything a plugin puts on the screen: the status line, toasts, dialogs, floating panels, confirm / alert / prompt / progress, a map tool that owns the pointer, a passive overlay drawn over the map, and picking an area or a tile.

Members

status

status(text: string): void;

Set the status bar line.

statusText

statusText(): string;

The status bar line as it stands.

toast

toast(toast: { kind?: Toast["kind"]; title: string; detail?: string; ttl?: number; }): void;

A short notice over the map that leaves by itself — how Save reports; ttl 0 keeps it until dismissed.

saveFile

saveFile(data: Blob | Uint8Array, fileName: string): Promise<{ route: "picker" | "download"; fileName: string; } | null>;

Write a file to disk the way the editor's own exports do: into the file the browser's save dialog picks, or as a download where there is no dialog. Resolves with where it went, or null when the user dismissed the dialog.

dialog

dialog(spec: DialogSpec): DialogHandle;

panel

panel(spec: PanelSpec): PanelHandle;

Open a floating panel over the map. As many as you like; each closes with the plugin.

mapTool

mapTool(spec: MapToolSpec): MapToolHandle;

Take over the pointer on the map until stop(), Esc, a right-click, a map change or another tool. One tool runs at a time — starting one stops the previous — and a pickArea / pickTile in progress is served first.

overlay

overlay(spec: OverlaySpec): OverlayHandle;

A picture over the map the user can switch on and off (View ▸ Overlays, the Layers panel) and that stays while they work on any layer. It draws at every repaint and hears the pointer, but never takes it. As many as you like; they go with the plugin.

pickFiles

pickFiles(options?: PickFilesOptions): Promise<File[]>;

The browser's file picker; resolves with an empty list on cancel.

pickArea

pickArea(options?: PickOptions): Promise<Rect | null>;

Let the user drag a rectangle on the map. The viewport switches to a crosshair, draws the marquee and takes the gesture ahead of the active layer's tools; resolves with the tile rect (exclusive x1 / y1), or null when the user pressed Esc or right-clicked, no map is open, the map was replaced, or the plugin was disabled. Only one pick runs at a time — a new one cancels the previous. A modal dialog covers the map, so close yours first and reopen it with the result.

pickTile

pickTile(options?: PickOptions): Promise<{ x: number; y: number; } | null>;

As pickArea, for a single click: the tile under it.

loadImage

loadImage(source: Blob | string): Promise<ImageBitmap>;

Decode a picture: a File / Blob, a data: URL, or an http(s) URL (fetched, and when the site refuses cross-origin reads, loaded through an <img> with crossOrigin — a site that allows neither rejects with a message saying so).

readClipboardImage

readClipboardImage(): Promise<Blob | null>;

The image on the system clipboard, if the browser lets the page read it (a permission prompt may appear); null otherwise.

confirm

confirm(message: string, options?: ConfirmOptions): Promise<boolean>;

Ask a yes/no question; resolves false on Cancel, Escape or the ×.

alert

alert(message: string, options?: ConfirmOptions): Promise<void>;

Say something with a single OK.

prompt

prompt(message: string, options?: PromptOptions): Promise<string | null>;

Ask for a line of text; null when the user cancelled.

progress

progress(label: string, options?: ProgressOptions): ProgressHandle;

A progress bar over the map for long work, with an optional Cancel.

el

el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Record<string, unknown>, ...children: WidgetChild[]): HTMLElementTagNameMap[K];

el("div", { className: "row" }, …): the DOM helper the widgets are built from.

widgets

readonly widgets: WidgetsApi;

Buttons, fields, forms and lists in the editor's own styles.

open

open(dialog: DialogId, payload?: Record<string, unknown>): void;

Open a built-in dialog (fire and forget; ask waits for one that answers).

ask

ask(dialog: DialogId, payload?: Record<string, unknown>): Promise<boolean>;

Open a built-in dialog that answers — "saveAs", "confirmClose", "newMap" — and resolve true when it went through, false when it was dismissed.

repaint

repaint(): void;

Ask the viewport to repaint (a transaction does this by itself). Raises no event.

Types

Declarations only this group names.

Toastinterface

interface Toast

A short notice over the map that leaves by itself — what a save says when it is done, since the status bar line is easy to miss and the menubar dot only stops glowing.

id: number
kind: "ok" | "info" | "warn" | "error"
title: string
detail?: string
ttl: number

Milliseconds before it leaves on its own; 0 keeps it until dismissed.

action?: { label: string; run: () => void; }

One button beside the text, for a notice that is really a question — the update check's "Download". Pressing it dismisses the toast as well as running this.

DialogSizetype

type DialogSize = "sm" | "md" | "lg" | "xl" | "full";

DialogButtoninterface

interface DialogButton
label: string
primary?: boolean
run?: (dialog: DialogHandle) => void | boolean | Promise<void | boolean>

Return false (or a promise of it) to keep the dialog open.

closes?: boolean

Close after run; default true.

DialogTransferinterface

interface DialogTransfer

What a paste or a drop brought into a dialog.

files: File[]
text: string

DialogSpecinterface

interface DialogSpec
title: string
size?: DialogSize
tall?: boolean
mount(body: HTMLElement, dialog: DialogHandle): void | (() => void)

Fill body (an empty <div> inside the dialog); return a cleanup if you need one.

buttons?: DialogButton[]

Footer buttons, left to right; a single Close when omitted.

onPaste?: (transfer: DialogTransfer, dialog: DialogHandle) => void

Ctrl+V anywhere in the dialog (while it is the topmost one). Files come from the clipboard's items — a screenshot pastes as one image/png file — and text is the plain-text part, so a copied image URL arrives here too.

onDrop?: (transfer: DialogTransfer, dialog: DialogHandle) => void

Something dropped onto the dialog body.

keepOpenOnEscape?: (target: EventTarget | null) => boolean

Escape normally closes the dialog. Answer true to keep it open for this press — when the key was meant for something inside the dialog that handles Escape itself (a code editor dismissing its own popups), judged by the element it landed on.

DialogHandleinterface

interface DialogHandle
close(): void
isOpen(): boolean

Whether the dialog is still on screen.

setTitle(title: string): void

Change the title strip's text.

PanelSpecinterface

interface PanelSpec

A panel floats over the map and does not block it: the user keeps drawing, scrolling and using hotkeys while it is open (except while typing in one of its fields). It is dragged by its title bar and closed with the × or close().

title: string
width?: number

In CSS pixels; 260 by default. The panel is as tall as its content, up to the map's height.

mount(body: HTMLElement, panel: PanelHandle): void | (() => void)

Fill body (an empty <div> inside the panel); return a cleanup if you need one.

onClose?: () => void

The panel closed, whichever way.

PanelHandleinterface

interface PanelHandle
close(): void
isOpen(): boolean
setTitle(title: string): void

MapPointerinterface

interface MapPointer

The pointer over the map, in the map's own units. A tile is 32 × 32 pixels.

px: number

Map pixels. Kept inside the map while a button is held, as the built-in brushes do.

py: number
tx: number

The tile under the pointer.

ty: number
inMap: boolean

False once the pointer has left the map with no button held.

down: boolean

Whether the primary button is held.

shift: boolean
ctrl: boolean
alt: boolean

MapViewinterface

interface MapView

Map pixels to canvas pixels, for a tool's draw.

zoom: number
tilePx: number

Canvas pixels per tile.

x(px: number): number

A map pixel's x on the canvas.

y(py: number): number
visible: Rect

The tiles on screen.

MapToolStopReasontype

type MapToolStopReason = 
/** `handle.stop()`. */
"stopped"
/** Esc or a right-click, and `onCancel` did not keep the tool. */
 | "cancelled"
/** The map was closed or replaced. */
 | "document"
/** Another tool started. */
 | "replaced"
/** The plugin was disabled. */
 | "disabled";

MapToolSpecinterface

interface MapToolSpec

A tool owns the pointer over the map: the viewport hands it every press, move and release ahead of the active layer's own tools, hides the layer's brush ghost, and lets it draw an overlay. The map stays visible and scrollable, and a panel can stay open beside it — which is how a plugin gets a drawing mode of its own.

name: string

Shown in the viewport's HUD and the status bar while the tool runs.

hint?: string

After the name: "drag to draw a line".

cursor?: string

CSS cursor over the map; "crosshair" by default.

onDown?(p: MapPointer): void
onMove?(p: MapPointer): void

Every pointer move over the map, button held or not, and once with inMap: false when it leaves.

onUp?(p: MapPointer): void
onCancel?(): boolean | void

Esc or a right-click. Return true to keep the tool running (you cancelled a gesture of your own); otherwise it stops.

draw?(ctx: CanvasRenderingContext2D, view: MapView): void

Draw over the map, after everything else, each time the viewport repaints.

onStop?(reason: MapToolStopReason): void

The tool is no longer running, for whatever reason (once).

MapToolHandleinterface

interface MapToolHandle
stop(): void
isActive(): boolean
redraw(): void

Repaint the viewport — and so call draw — now. Cheap; call it from onMove.

OverlayAbovetype

type OverlayAbove = 
/** Over the terrain and grid, under doodad footprints, units, sprites and locations (the default). */
"terrain"
/** Over units, sprites and locations, under fog of war. */
 | "objects"
/** Over everything but a running map tool's own drawing. */
 | "everything";

Where in the viewport's paint pass an overlay draws.

OverlaySpecinterface

interface OverlaySpec

An overlay is a picture drawn over the map that the user can turn on and off: it is listed under View ▸ Overlays and in the Layers panel, stays while the user works on any layer, and never takes the pointer — clicks go to the active layer's tools as usual. It hears the pointer through onHover, which is how a readout follows the mouse while the user places units. Register one at activation and keep the handle; it goes away with the plugin.

name: string

Shown in View ▸ Overlays and the Layers panel. Unique per plugin.

visible?: boolean

Start visible; true by default. What the user last set for this name wins for the session.

above?: OverlayAbove

Where the picture goes in the paint pass; "terrain" by default.

draw(ctx: CanvasRenderingContext2D, view: MapView): void

Draw in canvas pixels through view, each time the viewport repaints while visible.

onHover?(p: MapPointer | null): void

The pointer over the map while the overlay is visible, on every layer and while a map tool runs; null once when it leaves. Call handle.redraw() here to move a hover mark. A press sets down but is never captured for you.

onToggle?(visible: boolean): void

The overlay was shown or hidden, by the user in the chrome or by your handle.

OverlayHandleinterface

interface OverlayHandle
show(): void
hide(): void
toggle(): void
isVisible(): boolean
redraw(): void

Repaint the viewport — and so call draw — now.

remove(): void

Take the overlay out of the chrome for good; isVisible is false from then on.

PickOptionsinterface

interface PickOptions
prompt?: string

Shown in the viewport's HUD while the user picks; also the status line.

PickFilesOptionsinterface

interface PickFilesOptions
accept?: string

accept for the file input, e.g. "image/*" or ".png,.jpg".

multiple?: boolean

ConfirmOptionsinterface

interface ConfirmOptions
title?: string
confirmLabel?: string

The primary button; OK by default.

cancelLabel?: string
danger?: boolean

Paint the primary button as a destructive action.

PromptOptionsinterface

interface PromptOptions
value?: string
placeholder?: string
multiline?: boolean

A multi-line field.

ProgressOptionsinterface

interface ProgressOptions
title?: string
cancellable?: boolean

Show a Cancel button; cancelled() answers true once it is pressed.

ProgressHandleinterface

interface ProgressHandle

A progress panel over the map. It does not block the editor — the user can still scroll and look — so a plugin doing long work should report often and check cancelled() in its loop.

report(fraction: number, text?: string): void

How far along (0…1), and optionally a line under the bar.

cancelled(): boolean

True once the user pressed Cancel or closed the panel. Poll it inside a loop.

readonly signal: AbortSignal

The same answer as a signal, for work that takes one: aborted when the user cancels, so fetch(url, { signal }) and anything built on AbortSignal stop with the panel. Never aborted by done().

done(): void
isOpen(): boolean

WidgetChildtype

type WidgetChild = Node | string | number | null | undefined | false;

Anything the widget builders accept as a child: a node, text, or nothing.

ButtonOptionsinterface

interface ButtonOptions
primary?: boolean
danger?: boolean
ghost?: boolean
onClick?: (event: MouseEvent) => void

CheckboxOptionsinterface

interface CheckboxOptions
value?: boolean
radio?: boolean

A radio button instead; give the group a name.

name?: string
onChange?: (value: boolean) => void

CheckboxElementtype

type CheckboxElement = HTMLLabelElement & {
	input: HTMLInputElement;
};

The <label> a checkbox is, with its <input> on it so you can read or set the value.

TextFieldOptionsinterface

interface TextFieldOptions
value?: string
placeholder?: string
password?: boolean
onChange?: (value: string) => void

NumberFieldOptionsinterface

interface NumberFieldOptions
value?: number
min?: number
max?: number
step?: number
onChange?: (value: number) => void

SelectOptioninterface

interface SelectOption
value: string | number
label: string
disabled?: boolean

SelectOptionsinterface

interface SelectOptions
value?: string | number
onChange?: (value: string) => void

FormRowinterface

interface FormRow
label: string
field: HTMLElement

ListIteminterface

interface ListItem
label: string
value: T
hint?: string

Dimmed text at the end of the row.

index?: number

A number in the row's gutter, as the editor's own lists show indices.

title?: string

ListOptionsinterface

interface ListOptions
selected?: number

Which row starts selected.

height?: number

Maximum height in pixels; the list scrolls past it.

className?: string
onPick?: (value: T, index: number) => void

WidgetsApiinterface

interface WidgetsApi

Buttons, fields, forms and lists in the editor's own styles, as plain DOM. A plugin dialog built from these looks like a built-in one; el is the escape hatch for anything they do not cover.

button(label: string, options?: ButtonOptions): HTMLButtonElement
checkbox(label: string, options?: CheckboxOptions): CheckboxElement
text(options?: TextFieldOptions): HTMLInputElement
number(options?: NumberFieldOptions): HTMLInputElement
select(items: SelectOption[], options?: SelectOptions): HTMLSelectElement
form(rows: (FormRow | null | undefined | false)[]): HTMLElement

A two-column grid of labelled fields.

group(title: string, ...children: WidgetChild[]): HTMLElement

A titled box (a fieldset with a legend, as the dialogs use).

row(...children: WidgetChild[]): HTMLDivElement
column(...children: WidgetChild[]): HTMLDivElement
hint(text: string): HTMLElement

Small dimmed explanatory text.

separator(): HTMLElement
list<T>(items: ListItem<T>[], options?: ListOptions<T>): HTMLElement

Seen in

scmJS 0.1.0 · Generated from the repository. StarCraft and Brood War are trademarks of Blizzard Entertainment; this project ships none of their data.