@scm-js/plugin-api 1.49.0 → 1.51.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.d.ts +139 -0
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -980,6 +980,8 @@ export interface UpgradesDat {
980
980
  broodWar: Uint8Array;
981
981
  /** The upgrade's name: a 1-based `stat_txt.tbl` index, 0 for none. */
982
982
  label: Uint16Array;
983
+ /** Its button picture: a frame of `unit\cmdbtns\cmdicons.grp`. */
984
+ icon: Uint16Array;
983
985
  }
984
986
  /** The columns Technology Settings shows as defaults. */
985
987
  export interface TechdataDat {
@@ -992,6 +994,8 @@ export interface TechdataDat {
992
994
  broodWar: Uint8Array;
993
995
  /** The technology's name: a 1-based `stat_txt.tbl` index, 0 for none. */
994
996
  label: Uint16Array;
997
+ /** Its button picture: a frame of `unit\cmdbtns\cmdicons.grp`. */
998
+ icon: Uint16Array;
995
999
  }
996
1000
  /**
997
1001
  * Unit edits as invertible change lists, in the same spirit as terrain's `TileChange`.
@@ -2329,6 +2333,8 @@ export interface StatusBarCells {
2329
2333
  export type PluginUpdateMode = "notify" | "manual" | "auto";
2330
2334
  /** The revisions a new map can start on; the two older ones are for opening old files, not making new ones. */
2331
2335
  export type NewMapVersion = Extract<MapVersion, "broodwar" | "remastered">;
2336
+ export type IconKind = "unit" | "upgrade" | "tech";
2337
+ export type IconLook = "normal" | "disabled" | "selected";
2332
2338
  /**
2333
2339
  * The version a host provides; a manifest that asks for a newer one is refused. It stays
2334
2340
  * at 1 while the API is only used by the plugins in the scm-js organisation and grows
@@ -4138,6 +4144,36 @@ export interface GraphicsApi {
4138
4144
  */
4139
4145
  requestUnit(unitId: number): boolean;
4140
4146
  requestSprite(kind: SpriteKind, id: number): boolean;
4147
+ /**
4148
+ * The game's own button picture for a unit type, an upgrade or a technology — the icon
4149
+ * its command card shows — 36 × 34 at most and transparent round the edges. `look`
4150
+ * colours it as the game does: `"normal"` yellow (the default), `"disabled"` grey,
4151
+ * `"selected"` white. It does not depend on the map or its tileset. Null for an id with
4152
+ * no picture (a unit type past 227, a turret) and until `requestIcons` has the pictures;
4153
+ * null for good from a game data copy made before the editor kept them (installing the
4154
+ * game data again brings them). The canvas is the editor's own cached one: draw from it.
4155
+ *
4156
+ * @example
4157
+ * // A row of what a player researched, as the game's icons, with the names where there are no pictures.
4158
+ * const show = () => list.replaceChildren(...done.map((r) => {
4159
+ * const icon = api.graphics.icon(r.kind, r.id);
4160
+ * if (!icon) return api.ui.el("span", {}, r.kind === "tech" ? api.names.tech(r.id) : api.names.upgrade(r.id));
4161
+ * const canvas = api.ui.el("canvas", { width: icon.width, height: icon.height });
4162
+ * canvas.getContext("2d")?.drawImage(icon.image, 0, 0);
4163
+ * return canvas;
4164
+ * }));
4165
+ * api.graphics.requestIcons();
4166
+ * api.graphics.onImageLoaded(show);
4167
+ * show();
4168
+ */
4169
+ icon(kind: IconKind, id: number, options?: {
4170
+ look?: IconLook;
4171
+ }): PluginImage | null;
4172
+ /**
4173
+ * Start fetching the icon pictures (one sheet holds them all), and say whether they are
4174
+ * in memory. `onImageLoaded` fires when they arrive.
4175
+ */
4176
+ requestIcons(): boolean;
4141
4177
  /** A GRP finished loading: anything drawn from one may look different now. */
4142
4178
  onImageLoaded(listener: () => void): Disposable;
4143
4179
  }
@@ -5012,6 +5048,12 @@ export interface PanelSpec {
5012
5048
  grow?: boolean;
5013
5049
  /** Floating only: the body runs edge to edge, without the panel's padding — for content that draws its own frame. */
5014
5050
  flush?: boolean;
5051
+ /**
5052
+ * Floating only: a button in the title strip (and a double-click on it) makes the panel
5053
+ * fill the map's area, and puts it back. For a window of charts or tables read at length
5054
+ * beside a map that is still there underneath. `PanelHandle.maximize` does the same.
5055
+ */
5056
+ maximizable?: boolean;
5015
5057
  /** Fill `body` (an empty `<div>` inside the panel); return a cleanup if you need one. */
5016
5058
  mount(body: HTMLElement, panel: PanelHandle): void | (() => void);
5017
5059
  /** The panel closed, whichever way. */
@@ -5138,6 +5180,10 @@ export interface PanelHandle {
5138
5180
  close(): void;
5139
5181
  isOpen(): boolean;
5140
5182
  setTitle(title: string): void;
5183
+ /** A `maximizable` panel: fill the map's area (`true`), go back (`false`), or toggle. Nothing for another panel. */
5184
+ maximize(on?: boolean): void;
5185
+ /** Whether it fills the map's area now. */
5186
+ isMaximized(): boolean;
5141
5187
  }
5142
5188
  /**
5143
5189
  * One cell in the status bar (`ui.statusItem`): a line of text with the plugin's icon,
@@ -5637,6 +5683,24 @@ export interface UiApi {
5637
5683
  * }
5638
5684
  */
5639
5685
  progress(label: string, options?: ProgressOptions): ProgressHandle;
5686
+ /**
5687
+ * A tooltip in the editor's own style over an element of yours, in place of the
5688
+ * browser's `title`. `content` is a line of text, or a function asked for what to show
5689
+ * at the pointer — rows, bars, pictures, built with `el` and the widgets — which is how
5690
+ * a chart says what is under the pointer: it is asked again as the pointer moves, and
5691
+ * answering null hides the tip there. The editor places it beside the pointer, keeps it
5692
+ * on screen and takes it away when the pointer leaves, the element leaves the page, or
5693
+ * the plugin stops. `refresh()` asks again where the pointer stands (a picture arrived,
5694
+ * the data moved). Remove the element's `title`, or both show.
5695
+ *
5696
+ * @example
5697
+ * // A chart that reads out the value under the pointer.
5698
+ * api.ui.tooltip(canvas, (at) => {
5699
+ * const i = Math.floor((at.offsetX / canvas.clientWidth) * values.length);
5700
+ * return values[i] === undefined ? null : api.ui.el("div", {}, api.ui.el("b", {}, `${values[i]}`), " minerals");
5701
+ * });
5702
+ */
5703
+ tooltip(target: HTMLElement, content: string | ((at: TooltipPointer) => HTMLElement | string | null), options?: TooltipOptions): TooltipHandle;
5640
5704
  /** `el("div", { className: "row" }, …)`: the DOM helper the widgets are built from. */
5641
5705
  el<K extends keyof HTMLElementTagNameMap>(tag: K, props?: Record<string, unknown>, ...children: WidgetChild[]): HTMLElementTagNameMap[K];
5642
5706
  /** Buttons, fields, forms and lists in the editor's own styles. */
@@ -5651,6 +5715,33 @@ export interface UiApi {
5651
5715
  /** Ask the viewport to repaint (a transaction does this by itself). Raises no event. */
5652
5716
  repaint(): void;
5653
5717
  }
5718
+ /** Where the pointer is, for a tooltip's `content`. */
5719
+ export interface TooltipPointer {
5720
+ /** In the page, CSS pixels (`clientX` / `clientY`). */
5721
+ x: number;
5722
+ y: number;
5723
+ /** From the target's top-left corner, CSS pixels. */
5724
+ offsetX: number;
5725
+ offsetY: number;
5726
+ /** Whether a button is held — a drag across a chart. */
5727
+ pressed: boolean;
5728
+ }
5729
+ export interface TooltipOptions {
5730
+ /**
5731
+ * Milliseconds the pointer rests before the tip shows. 500 for text, as the editor's own
5732
+ * tooltips; 0 for a function, which reads out what is under the pointer and should keep
5733
+ * up with it.
5734
+ */
5735
+ delay?: number;
5736
+ /** A width the tip does not grow past, CSS pixels; 320 by default. */
5737
+ maxWidth?: number;
5738
+ }
5739
+ export interface TooltipHandle extends Disposable {
5740
+ /** Ask `content` again where the pointer stands; nothing when the tip is not showing. */
5741
+ refresh(): void;
5742
+ /** Take the tip away until the pointer next moves over the target. */
5743
+ hide(): void;
5744
+ }
5654
5745
  export interface ConfirmOptions {
5655
5746
  title?: string;
5656
5747
  /** The primary button; `OK` by default. */
@@ -5741,6 +5832,35 @@ export interface SelectOption {
5741
5832
  label: string;
5742
5833
  disabled?: boolean;
5743
5834
  }
5835
+ /** `widgets.segmented`: the value picked, and a way to pick another. */
5836
+ export type SegmentedElement = HTMLElement & {
5837
+ get(): string;
5838
+ /** Pick `value` without calling `onChange`. */
5839
+ set(value: string | number): void;
5840
+ };
5841
+ export interface TabItem {
5842
+ value: string;
5843
+ label: string;
5844
+ disabled?: boolean;
5845
+ /** Fill the tab's panel, the first time it is shown. What it starts ends with the panel or dialog the tabs are in. */
5846
+ mount(body: HTMLElement): void;
5847
+ }
5848
+ export interface TabsOptions {
5849
+ /** The tab shown first; the first that is not disabled otherwise. */
5850
+ value?: string;
5851
+ onChange?: (value: string) => void;
5852
+ /** Smaller tabs, for a narrow panel. */
5853
+ compact?: boolean;
5854
+ className?: string;
5855
+ }
5856
+ /** `widgets.tabs`: the tab shown, and a way to show another. */
5857
+ export type TabsElement = HTMLElement & {
5858
+ get(): string;
5859
+ /** Show the tab `value` (mounting it the first time) without calling `onChange`. */
5860
+ set(value: string): void;
5861
+ /** The panel of a tab that has been shown, or null. */
5862
+ panel(value: string): HTMLElement | null;
5863
+ };
5744
5864
  export interface SelectOptions extends WidgetOptions {
5745
5865
  value?: string | number;
5746
5866
  onChange?: (value: string) => void;
@@ -5925,6 +6045,25 @@ export interface WidgetsApi {
5925
6045
  text(options?: TextFieldOptions): HTMLInputElement;
5926
6046
  number(options?: NumberFieldOptions): HTMLInputElement;
5927
6047
  select(items: SelectOption[], options?: SelectOptions): HTMLSelectElement;
6048
+ /**
6049
+ * Buttons side by side of which one is on: a choice of a few short options seen at once
6050
+ * ("Both", "Minerals", "Gas"), where a `select` would hide them. `onChange` hears the
6051
+ * value picked; `set` moves the choice without it.
6052
+ */
6053
+ segmented(items: SelectOption[], options?: SelectOptions): SegmentedElement;
6054
+ /**
6055
+ * Tabs in the editor's style: a row of tabs over a panel a tab. A tab's `mount` runs the
6056
+ * first time it is shown and its panel is kept after, so what the user did there stays
6057
+ * when they come back. Arrow keys move between the tabs.
6058
+ *
6059
+ * @example
6060
+ * const tabs = api.ui.widgets.tabs([
6061
+ * { value: "economy", label: "Economy", mount: (body) => body.append(economyView()) },
6062
+ * { value: "army", label: "Army", mount: (body) => body.append(armyView()) },
6063
+ * ], { value: saved.tab, onChange: (tab) => { saved.tab = tab; } });
6064
+ * body.append(tabs);
6065
+ */
6066
+ tabs(items: TabItem[], options?: TabsOptions): TabsElement;
5928
6067
  /** A two-column grid of labelled fields. */
5929
6068
  form(rows: (FormRow | null | undefined | false)[]): HTMLElement;
5930
6069
  /** A titled box (a `fieldset` with a legend, as the dialogs use). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-js/plugin-api",
3
- "version": "1.49.0",
3
+ "version": "1.51.0",
4
4
  "description": "Type declarations for the scmJS plugin API",
5
5
  "license": "MIT",
6
6
  "types": "index.d.ts",