@vestra-player/sdk 1.6.11 → 1.6.13
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.
- package/CHANGELOG.md +15 -0
- package/dist/docs-tree.json.gz +0 -0
- package/dist/plugin/runtime.js +21 -0
- package/dist/plugin/testing.d.ts +3 -2
- package/dist/plugin/testing.js +33 -14
- package/dist/plugin/types.d.ts +11 -3
- package/dist/plugin/ui.js +14 -2
- package/dist/wire.d.ts +7 -0
- package/llms.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.13
|
|
4
|
+
|
|
5
|
+
**Who must change: plugin tests that toggle a column in fullscreen.** In fullscreen `toggle()` now only switches the column on or off (user ruling 2026-11-08); a test that asserted `effective: true` after toggling a column on in fullscreen now sees `effective: false`, `reason: "fullscreen"` (on, revealed by the right edge). Plugin code needs no change; `apiVersion` stays `vestra/1`, and the wire gains one optional field.
|
|
6
|
+
|
|
7
|
+
- **`Panel.toggle` and `PanelSlot.toggle` are a switch, the same in every mode.** Compared with 1.6.11 and older, where turning a column on in fullscreen popped it out, it now only switches it on; 1.6.12's rule (a toggle on a collapsed column popped it out instead of turning it off) is withdrawn. No released player shipped 1.6.12: player 0.7.6, the first with the adjust column, is not released yet. On a column that is on, the toggle turns it off; on one that is off, it turns it on. In fullscreen "on" means the pointer at the right edge reveals the column; the toggle never pops it out (player 0.7.6), and a column switched off while it is out slides in at once. The player's own Adjust and Sidebar buttons, Toggle Sidebar and Alt+1…4 behave the same. `Panel.show` and `PanelSlot.setVisible(true)` still pop a column out in fullscreen, as documented.
|
|
8
|
+
- **Wire**: `layout.set` takes an optional `reveal` (with `visible: true`, `false` switches on without popping out; absent, it reveals as before). `toggle` sends `reveal: false`; older players ignore it and pop the column out as before.
|
|
9
|
+
- **`TestHost`**: `setMainWindow({ fullscreen: true })` collapses the adjust column too, `popSidebar` pops out or collapses both columns (those switched on), and `layout.set` with `reveal: false` in fullscreen leaves a column switched on but collapsed.
|
|
10
|
+
|
|
11
|
+
## 1.6.12
|
|
12
|
+
|
|
13
|
+
**Who must change: nobody.** Superseded by 1.6.13 for `toggle` in fullscreen: this release's rule is withdrawn, and no released player shipped it. A behaviour fix of `toggle` in fullscreen, an example fix and a development warning; no new API, `apiVersion` stays `vestra/1`.
|
|
14
|
+
|
|
15
|
+
- **`Panel.toggle` and `PanelSlot.toggle` slide a collapsed column out.** In fullscreen a sidebar or adjust column the user wants shown is collapsed at the right edge (`reason: "fullscreen"`). Toggling it then turned it off; it now shows it, which player 0.7.6 answers by sliding the column out, as its own Adjust button and Alt+1…4 do. Toggling a column that is on screen still turns it off. With players before 0.7.6 a show of a collapsed column changes nothing on screen, as before.
|
|
16
|
+
- **[adjust-panel](docs/examples/adjust-panel.md)** declares `events`: without it `plugin.player.state` changes only after the plugin's own calls, so a panel activated before a file was opened stayed disabled at 1×. A new test opens the file after activation. Its presets are four (0.5×, 1×, 1.5×, 2×), which fit the adjust column at its least width. No other example reads `player.state` without `events`.
|
|
17
|
+
- **A development warning for state followed without `events`.** A plugin that registers an `onChange` or a `bind` whose function reads changing state (`player.state`, a panel position, and the like) without the `events` capability gets one line in its log, once per plugin: changes made elsewhere never reach it. Only a warning; behaviour is unchanged. `TestHost` already behaved like the player here (it delivers `source.state` and the other state events only to a plugin that subscribed, which needs `events`): a new test pins that down. The example's old tests passed because they opened the file before starting the plugin or did not check `enabled`. No SDK example or test relied on the opposite, so nobody must change.
|
|
3
18
|
## 1.6.11
|
|
4
19
|
|
|
5
20
|
**Who must change: nobody.** Additions only: a mount slot, a panel position, a button icon and `TestHost` support; `apiVersion` stays `vestra/1`, no new capability. A plugin that mounts `"adjust"` sets `minPlayerVersion` to `0.7.6`: older players refuse the slot (`invalid`), which fails the activation like any refused mount.
|
package/dist/docs-tree.json.gz
CHANGED
|
Binary file
|
package/dist/plugin/runtime.js
CHANGED
|
@@ -208,6 +208,8 @@ export class Runtime {
|
|
|
208
208
|
/** The plugin was disposed: no safety pass is armed any more. */
|
|
209
209
|
#stopped = false;
|
|
210
210
|
#events = new Map();
|
|
211
|
+
/** The missing `events` warning was given (once per plugin). */
|
|
212
|
+
#warnedEvents = false;
|
|
211
213
|
views = new Map();
|
|
212
214
|
commands = new Map();
|
|
213
215
|
services = new Map();
|
|
@@ -617,6 +619,10 @@ export class Runtime {
|
|
|
617
619
|
group.active++;
|
|
618
620
|
group.whys.set(token, listenerWhy(this.callSite()));
|
|
619
621
|
}
|
|
622
|
+
if (created && needs === "events" && !this.can(needs))
|
|
623
|
+
group.unheard = true;
|
|
624
|
+
if (!mirror && group.unheard)
|
|
625
|
+
this.#warnUnheard(event);
|
|
620
626
|
if (created && (needs === null || this.can(needs))) {
|
|
621
627
|
group.told = group.active > 0;
|
|
622
628
|
const whys = group.told ? allWhys(group) : undefined;
|
|
@@ -658,6 +664,8 @@ export class Runtime {
|
|
|
658
664
|
const group = this.#events.get(event);
|
|
659
665
|
if (!group)
|
|
660
666
|
return { dispose: async () => { } };
|
|
667
|
+
if (group.unheard)
|
|
668
|
+
this.#warnUnheard(event);
|
|
661
669
|
group.active++;
|
|
662
670
|
const token = {};
|
|
663
671
|
group.whys.set(token, why ?? listenerWhy(this.callSite()));
|
|
@@ -675,6 +683,19 @@ export class Runtime {
|
|
|
675
683
|
},
|
|
676
684
|
};
|
|
677
685
|
}
|
|
686
|
+
/**
|
|
687
|
+
* A development warning, once per plugin, no behaviour change (SDK
|
|
688
|
+
* 1.6.12): the plugin follows `event` (an `onChange`, a `bind` that reads
|
|
689
|
+
* the state) without the `events` capability, so changes made elsewhere
|
|
690
|
+
* (the user, the player, another plugin) never reach it; the state moves
|
|
691
|
+
* only after its own calls.
|
|
692
|
+
*/
|
|
693
|
+
#warnUnheard(event) {
|
|
694
|
+
if (this.#warnedEvents)
|
|
695
|
+
return;
|
|
696
|
+
this.#warnedEvents = true;
|
|
697
|
+
console.warn(`[${this.manifest.id}] follows ${event} (onChange, or a bind() that reads the state) without the "events" capability: changes made elsewhere will not reach it, only its own calls refresh the state. Declare "events" in manifest.json.`);
|
|
698
|
+
}
|
|
678
699
|
/**
|
|
679
700
|
* Tell the player when `group` changes between mirror and listener, and
|
|
680
701
|
* why it listens when that changed.
|
package/dist/plugin/testing.d.ts
CHANGED
|
@@ -2396,8 +2396,9 @@ export declare class TestHost implements Transport {
|
|
|
2396
2396
|
}>): void;
|
|
2397
2397
|
/**
|
|
2398
2398
|
* The pointer reached the right edge in fullscreen (`true`) or left the
|
|
2399
|
-
* popped-out
|
|
2400
|
-
* (
|
|
2399
|
+
* popped-out columns (`false`): the attached sidebar and the adjust column
|
|
2400
|
+
* (SDK 1.6.13), those switched on, pop out or collapse (reference §6.3). No
|
|
2401
|
+
* effect outside fullscreen, or on a column switched off or floating.
|
|
2401
2402
|
*
|
|
2402
2403
|
* @capability None.
|
|
2403
2404
|
*
|
package/dist/plugin/testing.js
CHANGED
|
@@ -3005,19 +3005,22 @@ export class TestHost {
|
|
|
3005
3005
|
const entering = patch.fullscreen !== undefined &&
|
|
3006
3006
|
patch.fullscreen !== this.mainWindow.fullscreen;
|
|
3007
3007
|
Object.assign(this.mainWindow, patch);
|
|
3008
|
-
// Like the player (reference §6.3): in fullscreen the attached
|
|
3009
|
-
//
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3008
|
+
// Like the player (reference §6.3): in fullscreen the attached columns
|
|
3009
|
+
// (the sidebar, the adjust column) start collapsed at the right edge;
|
|
3010
|
+
// leaving fullscreen docks them again.
|
|
3011
|
+
for (const column of [this.layout.sidebar, this.layout.adjust]) {
|
|
3012
|
+
if (entering && column && column.preferred && !column.detached) {
|
|
3013
|
+
column.effective = !this.mainWindow.fullscreen;
|
|
3014
|
+
column.reason = this.mainWindow.fullscreen ? "fullscreen" : null;
|
|
3015
|
+
}
|
|
3014
3016
|
}
|
|
3015
3017
|
this.emit("window.state", this.#windowFacts());
|
|
3016
3018
|
}
|
|
3017
3019
|
/**
|
|
3018
3020
|
* The pointer reached the right edge in fullscreen (`true`) or left the
|
|
3019
|
-
* popped-out
|
|
3020
|
-
* (
|
|
3021
|
+
* popped-out columns (`false`): the attached sidebar and the adjust column
|
|
3022
|
+
* (SDK 1.6.13), those switched on, pop out or collapse (reference §6.3). No
|
|
3023
|
+
* effect outside fullscreen, or on a column switched off or floating.
|
|
3021
3024
|
*
|
|
3022
3025
|
* @capability None.
|
|
3023
3026
|
*
|
|
@@ -3036,11 +3039,14 @@ export class TestHost {
|
|
|
3036
3039
|
* @since 1.0.0
|
|
3037
3040
|
*/
|
|
3038
3041
|
popSidebar(popped) {
|
|
3039
|
-
|
|
3040
|
-
if (!this.mainWindow.fullscreen || !sidebar?.preferred || sidebar.detached)
|
|
3042
|
+
if (!this.mainWindow.fullscreen)
|
|
3041
3043
|
return;
|
|
3042
|
-
sidebar.
|
|
3043
|
-
|
|
3044
|
+
for (const column of [this.layout.sidebar, this.layout.adjust]) {
|
|
3045
|
+
if (!column?.preferred || column.detached)
|
|
3046
|
+
continue;
|
|
3047
|
+
column.effective = popped;
|
|
3048
|
+
column.reason = popped ? null : "fullscreen";
|
|
3049
|
+
}
|
|
3044
3050
|
this.emit("window.state", this.#windowFacts());
|
|
3045
3051
|
}
|
|
3046
3052
|
#windowFacts() {
|
|
@@ -4591,9 +4597,22 @@ export class TestHost {
|
|
|
4591
4597
|
state.owner = panel.owner;
|
|
4592
4598
|
}
|
|
4593
4599
|
if (typeof p.visible === "boolean") {
|
|
4600
|
+
const out = state.preferred && state.effective;
|
|
4594
4601
|
state.preferred = p.visible;
|
|
4595
|
-
|
|
4596
|
-
|
|
4602
|
+
// In fullscreen a column switched on by a toggle (`reveal: false`)
|
|
4603
|
+
// stays collapsed at the edge; `show()` and `setVisible` pop it out.
|
|
4604
|
+
const collapsed = p.visible &&
|
|
4605
|
+
p.reveal === false &&
|
|
4606
|
+
slot !== "bottom" &&
|
|
4607
|
+
this.mainWindow.fullscreen &&
|
|
4608
|
+
!state.detached &&
|
|
4609
|
+
!out;
|
|
4610
|
+
state.effective = p.visible && !collapsed;
|
|
4611
|
+
state.reason = !p.visible
|
|
4612
|
+
? "userHidden"
|
|
4613
|
+
: collapsed
|
|
4614
|
+
? "fullscreen"
|
|
4615
|
+
: null;
|
|
4597
4616
|
if (this.panel?.slot === slot)
|
|
4598
4617
|
this.panel.visible = p.visible;
|
|
4599
4618
|
}
|
package/dist/plugin/types.d.ts
CHANGED
|
@@ -2705,7 +2705,10 @@ export interface PanelSlot {
|
|
|
2705
2705
|
*
|
|
2706
2706
|
* @remarks
|
|
2707
2707
|
* Reads the state from the player first, so it is right even without
|
|
2708
|
-
* `events`.
|
|
2708
|
+
* `events`. It is a switch, the same in every mode: in fullscreen a column
|
|
2709
|
+
* switched on is revealed by the pointer at the right edge, and is not
|
|
2710
|
+
* popped out by the toggle (SDK 1.6.13, player 0.7.6; `setVisible(true)`
|
|
2711
|
+
* pops it out). Switching it off while it is out slides it in at once.
|
|
2709
2712
|
*
|
|
2710
2713
|
* @capability ui.mount
|
|
2711
2714
|
*
|
|
@@ -3009,8 +3012,13 @@ export interface Panel extends View, Disposable {
|
|
|
3009
3012
|
* @remarks
|
|
3010
3013
|
* Reads the state from the player first. When the position is shown
|
|
3011
3014
|
* (`preferred`) and this panel's tab is the current one, it hides the
|
|
3012
|
-
* position; otherwise it
|
|
3013
|
-
* tab comes to the front instead of the sidebar
|
|
3015
|
+
* position; otherwise it switches the position on at this panel's tab: a
|
|
3016
|
+
* panel in a background tab comes to the front instead of the sidebar
|
|
3017
|
+
* closing. It is a switch, the same in every mode, like the player's own
|
|
3018
|
+
* Alt+1…4 and Adjust button: in fullscreen a column switched on is revealed
|
|
3019
|
+
* by the pointer at the right edge, not popped out (SDK 1.6.13, player
|
|
3020
|
+
* 0.7.6; {@link Panel.show} pops it out), and one switched off while out
|
|
3021
|
+
* slides in at once. A "Show list"
|
|
3014
3022
|
* command checked by `state.preferred && state.active` matches it. Waits
|
|
3015
3023
|
* for {@link Panel.ready} first.
|
|
3016
3024
|
*
|
package/dist/plugin/ui.js
CHANGED
|
@@ -917,10 +917,18 @@ class PanelHandle extends ViewBase {
|
|
|
917
917
|
throw failure("invalid", "the player shows the backdrop by itself");
|
|
918
918
|
await layoutOf(this.scope.runtime).read();
|
|
919
919
|
const state = this.state;
|
|
920
|
+
// A switch, the same in every mode (user ruling 2026-11-08): off when
|
|
921
|
+
// on and current, else on at this tab. `reveal: false`: in fullscreen
|
|
922
|
+
// nothing pops out, the right edge reveals it (player 0.7.6; older
|
|
923
|
+
// players ignore it and pop it out).
|
|
920
924
|
if (state?.preferred && state.active)
|
|
921
925
|
await layoutOf(this.scope.runtime).set(this.#slot, { visible: false });
|
|
922
926
|
else
|
|
923
|
-
await this.
|
|
927
|
+
await layoutOf(this.scope.runtime).set(this.#slot, {
|
|
928
|
+
active: this.scope.runtime.manifest.id,
|
|
929
|
+
visible: true,
|
|
930
|
+
reveal: false,
|
|
931
|
+
});
|
|
924
932
|
}
|
|
925
933
|
async showMenu(items, at) {
|
|
926
934
|
await this.ready;
|
|
@@ -1117,7 +1125,11 @@ function slot(scope, name) {
|
|
|
1117
1125
|
async toggle() {
|
|
1118
1126
|
await service().read();
|
|
1119
1127
|
const current = service().state[name];
|
|
1120
|
-
|
|
1128
|
+
// A switch (see Panel.toggle): nothing pops out in fullscreen.
|
|
1129
|
+
await service().set(name, {
|
|
1130
|
+
visible: !(current?.preferred ?? true),
|
|
1131
|
+
reveal: false,
|
|
1132
|
+
});
|
|
1121
1133
|
},
|
|
1122
1134
|
setDetached: (detached) => service().set(name, { detached }),
|
|
1123
1135
|
activate: (plugin) => service().set(name, { active: plugin }),
|
package/dist/wire.d.ts
CHANGED
|
@@ -710,6 +710,13 @@ export declare function createWire(transport: Transport): {
|
|
|
710
710
|
detached?: boolean;
|
|
711
711
|
/** The plugin id of the panel whose tab becomes the current one. */
|
|
712
712
|
active?: string;
|
|
713
|
+
/**
|
|
714
|
+
* With `visible: true`: `false` switches the position on without
|
|
715
|
+
* popping a column out in fullscreen (`toggle()`, SDK 1.6.13; player
|
|
716
|
+
* 0.7.6). Absent: reveal, as `show()` and `setVisible` do. Older
|
|
717
|
+
* players ignore it.
|
|
718
|
+
*/
|
|
719
|
+
reveal?: boolean;
|
|
713
720
|
}) => Promise<void>;
|
|
714
721
|
};
|
|
715
722
|
events: {
|
package/llms.txt
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Vestra Player SDK
|
|
2
2
|
|
|
3
|
-
> @vestra-player/sdk 1.6.
|
|
3
|
+
> @vestra-player/sdk 1.6.13: write plugins for Vestra Player in TypeScript (plugin API `vestra/1`). A plugin is a folder with `manifest.json` and an entry module whose default export `activate(plugin)` the player calls. The documentation is a tree of short pages read by path, like `go doc`: the same pages and API as https://vestrasys.github.io/vestra-player-sdk/.
|
|
4
4
|
|
|
5
5
|
## Read the documentation
|
|
6
6
|
|