@fcannizzaro/streamdeck-react 0.1.11 → 0.1.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/README.md +11 -8
- package/dist/action.js +0 -1
- package/dist/adapter/index.d.ts +2 -0
- package/dist/adapter/physical-device.d.ts +2 -0
- package/dist/adapter/physical-device.js +153 -0
- package/dist/adapter/types.d.ts +127 -0
- package/dist/bundler-shared.d.ts +10 -0
- package/dist/bundler-shared.js +28 -1
- package/dist/devtools/bridge.d.ts +2 -2
- package/dist/devtools/bridge.js +7 -8
- package/dist/devtools/highlight.d.ts +1 -2
- package/dist/devtools/highlight.js +4 -3
- package/dist/devtools/types.d.ts +5 -5
- package/dist/font-inline.js +1 -1
- package/dist/google-font.d.ts +61 -0
- package/dist/google-font.js +124 -0
- package/dist/hooks/animation.d.ts +1 -1
- package/dist/hooks/animation.js +2 -2
- package/dist/hooks/events.js +1 -1
- package/dist/hooks/sdk.js +11 -11
- package/dist/hooks/utility.js +3 -2
- package/dist/index.d.ts +5 -1
- package/dist/index.js +3 -1
- package/dist/plugin.js +102 -124
- package/dist/reconciler/vnode.d.ts +0 -2
- package/dist/reconciler/vnode.js +0 -1
- package/dist/render/cache.d.ts +5 -17
- package/dist/render/cache.js +7 -29
- package/dist/render/image-cache.d.ts +8 -7
- package/dist/render/image-cache.js +33 -17
- package/dist/render/metrics.d.ts +9 -10
- package/dist/render/metrics.js +36 -39
- package/dist/render/pipeline.d.ts +4 -14
- package/dist/render/pipeline.js +47 -111
- package/dist/render/png.d.ts +0 -9
- package/dist/render/png.js +5 -8
- package/dist/render/render-pool.d.ts +0 -2
- package/dist/render/render-pool.js +1 -12
- package/dist/rollup.d.ts +1 -1
- package/dist/rollup.js +3 -1
- package/dist/roots/registry.d.ts +5 -9
- package/dist/roots/registry.js +30 -47
- package/dist/roots/root.d.ts +7 -34
- package/dist/roots/root.js +23 -90
- package/dist/roots/touchstrip-root.d.ts +6 -32
- package/dist/roots/touchstrip-root.js +61 -181
- package/dist/types.d.ts +38 -20
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +3 -1
- package/package.json +14 -8
- package/dist/node_modules/.bun/xxhash-wasm@1.1.0/node_modules/xxhash-wasm/esm/xxhash-wasm.js +0 -3157
- package/dist/roots/flush-coordinator.d.ts +0 -18
- package/dist/roots/flush-coordinator.js +0 -38
package/dist/roots/registry.js
CHANGED
|
@@ -1,49 +1,48 @@
|
|
|
1
1
|
import { shallowEqualSettings } from "./settings-equality.js";
|
|
2
2
|
import { ReactRoot } from "./root.js";
|
|
3
3
|
import { TouchStripRoot } from "./touchstrip-root.js";
|
|
4
|
-
import { FlushCoordinator } from "./flush-coordinator.js";
|
|
5
4
|
//#region src/roots/registry.ts
|
|
6
5
|
var SEGMENT_WIDTH = 200;
|
|
7
6
|
var KEY_SIZES = {
|
|
8
7
|
0: {
|
|
9
|
-
width:
|
|
10
|
-
height:
|
|
8
|
+
width: 144,
|
|
9
|
+
height: 144
|
|
11
10
|
},
|
|
12
11
|
1: {
|
|
13
|
-
width:
|
|
14
|
-
height:
|
|
12
|
+
width: 144,
|
|
13
|
+
height: 144
|
|
15
14
|
},
|
|
16
15
|
2: {
|
|
17
|
-
width:
|
|
18
|
-
height:
|
|
16
|
+
width: 144,
|
|
17
|
+
height: 144
|
|
19
18
|
},
|
|
20
19
|
3: {
|
|
21
|
-
width:
|
|
22
|
-
height:
|
|
20
|
+
width: 144,
|
|
21
|
+
height: 144
|
|
23
22
|
},
|
|
24
23
|
4: {
|
|
25
|
-
width:
|
|
26
|
-
height:
|
|
24
|
+
width: 144,
|
|
25
|
+
height: 144
|
|
27
26
|
},
|
|
28
27
|
5: {
|
|
29
|
-
width:
|
|
30
|
-
height:
|
|
28
|
+
width: 144,
|
|
29
|
+
height: 144
|
|
31
30
|
},
|
|
32
31
|
6: {
|
|
33
|
-
width:
|
|
34
|
-
height:
|
|
32
|
+
width: 144,
|
|
33
|
+
height: 144
|
|
35
34
|
},
|
|
36
35
|
7: {
|
|
37
36
|
width: 144,
|
|
38
37
|
height: 144
|
|
39
38
|
},
|
|
40
39
|
8: {
|
|
41
|
-
width:
|
|
42
|
-
height:
|
|
40
|
+
width: 144,
|
|
41
|
+
height: 144
|
|
43
42
|
},
|
|
44
43
|
9: {
|
|
45
|
-
width:
|
|
46
|
-
height:
|
|
44
|
+
width: 144,
|
|
45
|
+
height: 144
|
|
47
46
|
},
|
|
48
47
|
10: {
|
|
49
48
|
width: 144,
|
|
@@ -73,29 +72,26 @@ function getCanvasInfo(deviceType, surfaceType) {
|
|
|
73
72
|
};
|
|
74
73
|
return {
|
|
75
74
|
...KEY_SIZES[deviceType] ?? {
|
|
76
|
-
width:
|
|
77
|
-
height:
|
|
75
|
+
width: 144,
|
|
76
|
+
height: 144
|
|
78
77
|
},
|
|
79
78
|
type: "key"
|
|
80
79
|
};
|
|
81
80
|
}
|
|
82
|
-
var RootRegistry = class
|
|
81
|
+
var RootRegistry = class {
|
|
83
82
|
roots = /* @__PURE__ */ new Map();
|
|
84
83
|
touchStripRoots = /* @__PURE__ */ new Map();
|
|
85
84
|
touchStripActions = /* @__PURE__ */ new Map();
|
|
86
85
|
renderConfig;
|
|
87
|
-
|
|
88
|
-
sdkInstance;
|
|
86
|
+
adapter;
|
|
89
87
|
globalSettings = {};
|
|
90
88
|
onGlobalSettingsChange;
|
|
91
89
|
wrapper;
|
|
92
|
-
flushCoordinator = new FlushCoordinator();
|
|
93
90
|
/** DevTools observer. Set externally by startDevtoolsServer(). null when devtools is off. */
|
|
94
91
|
observer = null;
|
|
95
|
-
constructor(renderConfig,
|
|
92
|
+
constructor(renderConfig, adapter, onGlobalSettingsChange, wrapper) {
|
|
96
93
|
this.renderConfig = renderConfig;
|
|
97
|
-
this.
|
|
98
|
-
this.sdkInstance = sdkInstance;
|
|
94
|
+
this.adapter = adapter;
|
|
99
95
|
this.onGlobalSettingsChange = onGlobalSettingsChange;
|
|
100
96
|
this.wrapper = wrapper;
|
|
101
97
|
}
|
|
@@ -127,13 +123,13 @@ var RootRegistry = class RootRegistry {
|
|
|
127
123
|
id: contextId,
|
|
128
124
|
uuid: definition.uuid,
|
|
129
125
|
controller,
|
|
130
|
-
coordinates:
|
|
126
|
+
coordinates: ev.action.coordinates,
|
|
131
127
|
isInMultiAction: ev.payload.isInMultiAction
|
|
132
128
|
};
|
|
133
129
|
const canvas = getCanvasInfo(device.type, surfaceType);
|
|
134
|
-
const root = new ReactRoot(component, actionInfo, deviceInfo, canvas, ev.payload.settings, this.globalSettings, ev.action, this.
|
|
130
|
+
const root = new ReactRoot(component, actionInfo, deviceInfo, canvas, ev.payload.settings, this.globalSettings, ev.action, this.adapter, this.renderConfig, async (settings) => {
|
|
135
131
|
await ev.action.setSettings(settings);
|
|
136
|
-
}, this.onGlobalSettingsChange, this.
|
|
132
|
+
}, this.onGlobalSettingsChange, this.wrapper, definition.wrapper, definition.dialLayout);
|
|
137
133
|
root.eventBus.emitSticky("willAppear", {
|
|
138
134
|
settings: ev.payload.settings,
|
|
139
135
|
controller,
|
|
@@ -155,9 +151,9 @@ var RootRegistry = class RootRegistry {
|
|
|
155
151
|
const actionId = ev.action.id;
|
|
156
152
|
const device = ev.action.device;
|
|
157
153
|
const deviceId = device.id;
|
|
158
|
-
const column =
|
|
154
|
+
const column = ev.action.coordinates?.column;
|
|
159
155
|
if (column === void 0) {
|
|
160
|
-
console.warn("[@fcannizzaro/streamdeck-react] Cannot determine encoder column for
|
|
156
|
+
console.warn("[@fcannizzaro/streamdeck-react] Cannot determine encoder column for TouchStrip action:", actionId);
|
|
161
157
|
return;
|
|
162
158
|
}
|
|
163
159
|
let tbRoot = this.touchStripRoots.get(deviceId);
|
|
@@ -168,7 +164,7 @@ var RootRegistry = class RootRegistry {
|
|
|
168
164
|
size: device.size,
|
|
169
165
|
name: device.name
|
|
170
166
|
};
|
|
171
|
-
tbRoot = new TouchStripRoot(definition.touchStrip, deviceInfo, this.globalSettings, this.renderConfig, this.
|
|
167
|
+
tbRoot = new TouchStripRoot(definition.touchStrip, deviceInfo, this.globalSettings, this.renderConfig, this.onGlobalSettingsChange, this.wrapper);
|
|
172
168
|
this.touchStripRoots.set(deviceId, tbRoot);
|
|
173
169
|
this.observer?.onTouchStripCreated(deviceId, tbRoot, deviceInfo);
|
|
174
170
|
}
|
|
@@ -176,9 +172,6 @@ var RootRegistry = class RootRegistry {
|
|
|
176
172
|
this.observer?.onTouchStripColumnChanged(deviceId, [...tbRoot.columnNumbers], tbRoot.columnActionMap);
|
|
177
173
|
this.touchStripActions.set(actionId, deviceId);
|
|
178
174
|
}
|
|
179
|
-
getEncoderColumn(ev) {
|
|
180
|
-
return ev.action.coordinates?.column;
|
|
181
|
-
}
|
|
182
175
|
destroy(contextId) {
|
|
183
176
|
const deviceId = this.touchStripActions.get(contextId);
|
|
184
177
|
if (deviceId) {
|
|
@@ -202,18 +195,9 @@ var RootRegistry = class RootRegistry {
|
|
|
202
195
|
this.roots.delete(contextId);
|
|
203
196
|
}
|
|
204
197
|
}
|
|
205
|
-
static INTERACTION_EVENTS = new Set([
|
|
206
|
-
"keyDown",
|
|
207
|
-
"keyUp",
|
|
208
|
-
"dialRotate",
|
|
209
|
-
"dialDown",
|
|
210
|
-
"dialUp",
|
|
211
|
-
"touchTap"
|
|
212
|
-
]);
|
|
213
198
|
dispatch(contextId, event, payload) {
|
|
214
199
|
const root = this.roots.get(contextId);
|
|
215
200
|
if (root) {
|
|
216
|
-
if (RootRegistry.INTERACTION_EVENTS.has(event)) root.markInteraction();
|
|
217
201
|
root.eventBus.emit(event, payload);
|
|
218
202
|
this.observer?.onDispatch(contextId, event, payload);
|
|
219
203
|
return;
|
|
@@ -222,7 +206,6 @@ var RootRegistry = class RootRegistry {
|
|
|
222
206
|
if (deviceId) {
|
|
223
207
|
const tbRoot = this.touchStripRoots.get(deviceId);
|
|
224
208
|
if (tbRoot) {
|
|
225
|
-
if (RootRegistry.INTERACTION_EVENTS.has(event)) tbRoot.markInteraction();
|
|
226
209
|
this.dispatchToTouchStrip(tbRoot, contextId, event, payload);
|
|
227
210
|
this.observer?.onDispatch(contextId, event, payload);
|
|
228
211
|
}
|
package/dist/roots/root.d.ts
CHANGED
|
@@ -2,15 +2,13 @@ import { ComponentType } from 'react';
|
|
|
2
2
|
import { VContainer } from '../reconciler/vnode';
|
|
3
3
|
import { RenderConfig } from '../render/pipeline';
|
|
4
4
|
import { EventBus } from '../context/event-bus';
|
|
5
|
-
import { ActionInfo, CanvasInfo, DeviceInfo, EncoderLayout,
|
|
6
|
-
import { FlushCoordinator, FlushableRoot } from './flush-coordinator';
|
|
5
|
+
import { ActionInfo, CanvasInfo, DeviceInfo, EncoderLayout, WrapperComponent } from '../types';
|
|
7
6
|
import { JsonObject } from '@elgato/utils';
|
|
8
|
-
import {
|
|
9
|
-
export declare class ReactRoot
|
|
7
|
+
import { AdapterActionHandle, StreamDeckAdapter } from '../adapter/types';
|
|
8
|
+
export declare class ReactRoot {
|
|
10
9
|
private component;
|
|
11
10
|
private actionInfo;
|
|
12
11
|
private deviceInfo;
|
|
13
|
-
private flushCoordinator?;
|
|
14
12
|
private pluginWrapper?;
|
|
15
13
|
private actionWrapper?;
|
|
16
14
|
readonly eventBus: EventBus;
|
|
@@ -20,27 +18,16 @@ export declare class ReactRoot implements FlushableRoot {
|
|
|
20
18
|
private globalSettings;
|
|
21
19
|
private setSettingsFn;
|
|
22
20
|
private setGlobalSettingsFn;
|
|
23
|
-
private renderDebounceMs;
|
|
21
|
+
private readonly renderDebounceMs;
|
|
24
22
|
private renderConfig;
|
|
25
23
|
private canvas;
|
|
26
24
|
private resolvedDialLayout;
|
|
27
|
-
private
|
|
28
|
-
private
|
|
25
|
+
private action;
|
|
26
|
+
private adapter;
|
|
29
27
|
private disposed;
|
|
30
28
|
private _renderCount;
|
|
31
29
|
private _lastRenderReport;
|
|
32
30
|
private static readonly RENDER_WARN_THRESHOLD;
|
|
33
|
-
private _rendering;
|
|
34
|
-
private _pendingFlush;
|
|
35
|
-
private _recentRenders;
|
|
36
|
-
private _lastInteraction;
|
|
37
|
-
private static readonly ANIMATION_WINDOW_MS;
|
|
38
|
-
private static readonly ANIMATION_THRESHOLD;
|
|
39
|
-
private static readonly INTERACTION_COOLDOWN_MS;
|
|
40
|
-
private static readonly IDLE_THRESHOLD_MS;
|
|
41
|
-
private _lastFlushTime;
|
|
42
|
-
/** Current render priority (lower = higher priority). Used by flush coordinator for ordering. */
|
|
43
|
-
get priority(): number;
|
|
44
31
|
/** Last data URI successfully sent to hardware. Used by devtools snapshots. */
|
|
45
32
|
lastDataUri: string | null;
|
|
46
33
|
/**
|
|
@@ -57,25 +44,11 @@ export declare class ReactRoot implements FlushableRoot {
|
|
|
57
44
|
private streamDeckValue;
|
|
58
45
|
private settingsValue;
|
|
59
46
|
private globalSettingsValue;
|
|
60
|
-
constructor(component: ComponentType, actionInfo: ActionInfo, deviceInfo: DeviceInfo, canvas: CanvasInfo, initialSettings: JsonObject, initialGlobalSettings: JsonObject,
|
|
47
|
+
constructor(component: ComponentType, actionInfo: ActionInfo, deviceInfo: DeviceInfo, canvas: CanvasInfo, initialSettings: JsonObject, initialGlobalSettings: JsonObject, action: AdapterActionHandle, adapter: StreamDeckAdapter, renderConfig: RenderConfig, onSettingsChange: (settings: JsonObject) => Promise<void>, onGlobalSettingsChange: (settings: JsonObject) => Promise<void>, pluginWrapper?: WrapperComponent | undefined, actionWrapper?: WrapperComponent | undefined, dialLayout?: EncoderLayout);
|
|
61
48
|
private render;
|
|
62
49
|
private buildTree;
|
|
63
50
|
private scheduleRerender;
|
|
64
|
-
/** Record a user interaction (keyDown, dialRotate, etc.) for adaptive debounce. */
|
|
65
|
-
markInteraction(): void;
|
|
66
|
-
/** Compute effective debounce based on recent render frequency and interaction state. */
|
|
67
|
-
private get effectiveDebounceMs();
|
|
68
51
|
private flush;
|
|
69
|
-
/**
|
|
70
|
-
* Submit this root for flushing. Routes through the coordinator
|
|
71
|
-
* (priority-ordered) when available, or flushes directly.
|
|
72
|
-
*/
|
|
73
|
-
private submitFlush;
|
|
74
|
-
/**
|
|
75
|
-
* Execute the flush. Called by FlushCoordinator in priority order,
|
|
76
|
-
* or directly when no coordinator is present.
|
|
77
|
-
*/
|
|
78
|
-
executeFlush(): Promise<void>;
|
|
79
52
|
private doFlush;
|
|
80
53
|
updateSettings(settings: JsonObject): void;
|
|
81
54
|
updateGlobalSettings(settings: JsonObject): void;
|
package/dist/roots/root.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createVContainer } from "../reconciler/vnode.js";
|
|
1
|
+
import { clearDirtyFlags, createVContainer } from "../reconciler/vnode.js";
|
|
2
2
|
import { reconciler } from "../reconciler/renderer.js";
|
|
3
3
|
import { renderToDataUri } from "../render/pipeline.js";
|
|
4
4
|
import { EventBus } from "../context/event-bus.js";
|
|
@@ -27,35 +27,16 @@ var ReactRoot = class ReactRoot {
|
|
|
27
27
|
globalSettings;
|
|
28
28
|
setSettingsFn;
|
|
29
29
|
setGlobalSettingsFn;
|
|
30
|
-
renderDebounceMs;
|
|
30
|
+
renderDebounceMs = 17;
|
|
31
31
|
renderConfig;
|
|
32
32
|
canvas;
|
|
33
33
|
resolvedDialLayout;
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
action;
|
|
35
|
+
adapter;
|
|
36
36
|
disposed = false;
|
|
37
37
|
_renderCount = 0;
|
|
38
38
|
_lastRenderReport = 0;
|
|
39
39
|
static RENDER_WARN_THRESHOLD = 30;
|
|
40
|
-
_rendering = false;
|
|
41
|
-
_pendingFlush = false;
|
|
42
|
-
_recentRenders = [];
|
|
43
|
-
_lastInteraction = 0;
|
|
44
|
-
static ANIMATION_WINDOW_MS = 100;
|
|
45
|
-
static ANIMATION_THRESHOLD = 2;
|
|
46
|
-
static INTERACTION_COOLDOWN_MS = 500;
|
|
47
|
-
static IDLE_THRESHOLD_MS = 2e3;
|
|
48
|
-
_lastFlushTime = 0;
|
|
49
|
-
/** Current render priority (lower = higher priority). Used by flush coordinator for ordering. */
|
|
50
|
-
get priority() {
|
|
51
|
-
const now = Date.now();
|
|
52
|
-
const cutoff = now - ReactRoot.ANIMATION_WINDOW_MS;
|
|
53
|
-
while (this._recentRenders.length > 0 && this._recentRenders[0] < cutoff) this._recentRenders.shift();
|
|
54
|
-
if (this._recentRenders.length > ReactRoot.ANIMATION_THRESHOLD) return 0;
|
|
55
|
-
if (now - this._lastInteraction < ReactRoot.INTERACTION_COOLDOWN_MS) return 1;
|
|
56
|
-
if (this._lastFlushTime > 0 && now - this._lastFlushTime > ReactRoot.IDLE_THRESHOLD_MS) return 3;
|
|
57
|
-
return 2;
|
|
58
|
-
}
|
|
59
40
|
/** Last data URI successfully sent to hardware. Used by devtools snapshots. */
|
|
60
41
|
lastDataUri = null;
|
|
61
42
|
/**
|
|
@@ -68,16 +49,12 @@ var ReactRoot = class ReactRoot {
|
|
|
68
49
|
/** Push an arbitrary data URI to the hardware. Used by devtools highlight overlay. */
|
|
69
50
|
async pushImage(dataUri) {
|
|
70
51
|
if (this.disposed) return;
|
|
71
|
-
if (this.canvas.type === "key")
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
});
|
|
78
|
-
} else if (this.canvas.type === "touch") {
|
|
79
|
-
if ("setFeedback" in this.sdkAction) await this.sdkAction.setFeedback({ canvas: dataUri });
|
|
80
|
-
}
|
|
52
|
+
if (this.canvas.type === "key") await this.action.setImage(dataUri);
|
|
53
|
+
else if (this.canvas.type === "dial") await this.action.setFeedback({
|
|
54
|
+
canvas: dataUri,
|
|
55
|
+
title: ""
|
|
56
|
+
});
|
|
57
|
+
else if (this.canvas.type === "touch") await this.action.setFeedback({ canvas: dataUri });
|
|
81
58
|
}
|
|
82
59
|
/** Exposes the VContainer for devtools inspection. */
|
|
83
60
|
get vcontainer() {
|
|
@@ -86,20 +63,18 @@ var ReactRoot = class ReactRoot {
|
|
|
86
63
|
streamDeckValue;
|
|
87
64
|
settingsValue;
|
|
88
65
|
globalSettingsValue;
|
|
89
|
-
constructor(component, actionInfo, deviceInfo, canvas, initialSettings, initialGlobalSettings,
|
|
66
|
+
constructor(component, actionInfo, deviceInfo, canvas, initialSettings, initialGlobalSettings, action, adapter, renderConfig, onSettingsChange, onGlobalSettingsChange, pluginWrapper, actionWrapper, dialLayout) {
|
|
90
67
|
this.component = component;
|
|
91
68
|
this.actionInfo = actionInfo;
|
|
92
69
|
this.deviceInfo = deviceInfo;
|
|
93
|
-
this.flushCoordinator = flushCoordinator;
|
|
94
70
|
this.pluginWrapper = pluginWrapper;
|
|
95
71
|
this.actionWrapper = actionWrapper;
|
|
96
72
|
this.canvas = canvas;
|
|
97
73
|
this.settings = { ...initialSettings };
|
|
98
74
|
this.globalSettings = { ...initialGlobalSettings };
|
|
99
|
-
this.
|
|
100
|
-
this.
|
|
75
|
+
this.action = action;
|
|
76
|
+
this.adapter = adapter;
|
|
101
77
|
this.renderConfig = renderConfig;
|
|
102
|
-
this.renderDebounceMs = renderDebounceMs;
|
|
103
78
|
this.resolvedDialLayout = resolveDialLayout(dialLayout);
|
|
104
79
|
this.setSettingsFn = (partial) => {
|
|
105
80
|
const hasChanges = partialHasChanges(this.settings, partial);
|
|
@@ -132,8 +107,8 @@ var ReactRoot = class ReactRoot {
|
|
|
132
107
|
this.scheduleRerender();
|
|
133
108
|
};
|
|
134
109
|
this.streamDeckValue = {
|
|
135
|
-
action: this.
|
|
136
|
-
|
|
110
|
+
action: this.action,
|
|
111
|
+
adapter: this.adapter
|
|
137
112
|
};
|
|
138
113
|
this.settingsValue = {
|
|
139
114
|
settings: this.settings,
|
|
@@ -154,7 +129,8 @@ var ReactRoot = class ReactRoot {
|
|
|
154
129
|
console.error("[@fcannizzaro/streamdeck-react] Recoverable error:", err);
|
|
155
130
|
}, () => {});
|
|
156
131
|
if (canvas.type === "dial" || canvas.type === "touch") {
|
|
157
|
-
|
|
132
|
+
const layout = this.resolvedDialLayout;
|
|
133
|
+
this.action.setFeedbackLayout(typeof layout === "string" ? layout : layout);
|
|
158
134
|
}
|
|
159
135
|
this.eventBus.ownerId = actionInfo.id;
|
|
160
136
|
this.eventBus.ownerUuid = actionInfo.uuid;
|
|
@@ -174,55 +150,17 @@ var ReactRoot = class ReactRoot {
|
|
|
174
150
|
if (this.disposed) return;
|
|
175
151
|
this.render();
|
|
176
152
|
}
|
|
177
|
-
/** Record a user interaction (keyDown, dialRotate, etc.) for adaptive debounce. */
|
|
178
|
-
markInteraction() {
|
|
179
|
-
this._lastInteraction = Date.now();
|
|
180
|
-
}
|
|
181
|
-
/** Compute effective debounce based on recent render frequency and interaction state. */
|
|
182
|
-
get effectiveDebounceMs() {
|
|
183
|
-
const now = Date.now();
|
|
184
|
-
const cutoff = now - ReactRoot.ANIMATION_WINDOW_MS;
|
|
185
|
-
while (this._recentRenders.length > 0 && this._recentRenders[0] < cutoff) this._recentRenders.shift();
|
|
186
|
-
if (this._recentRenders.length > ReactRoot.ANIMATION_THRESHOLD) return 0;
|
|
187
|
-
if (now - this._lastInteraction < ReactRoot.INTERACTION_COOLDOWN_MS) return Math.min(this.renderDebounceMs, 16);
|
|
188
|
-
return this.renderDebounceMs;
|
|
189
|
-
}
|
|
190
153
|
async flush() {
|
|
191
154
|
if (this.disposed) return;
|
|
192
|
-
if (this.
|
|
193
|
-
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
this._recentRenders.push(Date.now());
|
|
197
|
-
const debounce = this.effectiveDebounceMs;
|
|
198
|
-
if (debounce > 0 && this.container.renderTimer !== null) clearTimeout(this.container.renderTimer);
|
|
199
|
-
if (debounce > 0) this.container.renderTimer = setTimeout(() => {
|
|
155
|
+
if (this.renderDebounceMs > 0 && this.container.renderTimer !== null) clearTimeout(this.container.renderTimer);
|
|
156
|
+
if (this.renderDebounceMs > 0) this.container.renderTimer = setTimeout(async () => {
|
|
200
157
|
this.container.renderTimer = null;
|
|
201
|
-
this.
|
|
202
|
-
},
|
|
203
|
-
else this.
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Submit this root for flushing. Routes through the coordinator
|
|
207
|
-
* (priority-ordered) when available, or flushes directly.
|
|
208
|
-
*/
|
|
209
|
-
submitFlush() {
|
|
210
|
-
if (this.disposed) return;
|
|
211
|
-
if (this.flushCoordinator) this.flushCoordinator.requestFlush(this);
|
|
212
|
-
else this.doFlush();
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Execute the flush. Called by FlushCoordinator in priority order,
|
|
216
|
-
* or directly when no coordinator is present.
|
|
217
|
-
*/
|
|
218
|
-
async executeFlush() {
|
|
219
|
-
await this.doFlush();
|
|
158
|
+
await this.doFlush();
|
|
159
|
+
}, this.renderDebounceMs);
|
|
160
|
+
else await this.doFlush();
|
|
220
161
|
}
|
|
221
162
|
async doFlush() {
|
|
222
163
|
if (this.disposed) return;
|
|
223
|
-
this._rendering = true;
|
|
224
|
-
this._pendingFlush = false;
|
|
225
|
-
this._lastFlushTime = Date.now();
|
|
226
164
|
if (this.renderConfig.debug) {
|
|
227
165
|
this._renderCount++;
|
|
228
166
|
const now = Date.now();
|
|
@@ -234,6 +172,7 @@ var ReactRoot = class ReactRoot {
|
|
|
234
172
|
}
|
|
235
173
|
try {
|
|
236
174
|
const dataUri = await renderToDataUri(this.container, this.canvas.width, this.canvas.height, this.renderConfig);
|
|
175
|
+
clearDirtyFlags(this.container);
|
|
237
176
|
if (dataUri === null || this.disposed) return;
|
|
238
177
|
this.lastDataUri = dataUri;
|
|
239
178
|
if (!this.suppressHardwarePush) this.pushImage(dataUri).catch((err) => {
|
|
@@ -241,12 +180,6 @@ var ReactRoot = class ReactRoot {
|
|
|
241
180
|
});
|
|
242
181
|
} catch (err) {
|
|
243
182
|
console.error("[@fcannizzaro/streamdeck-react] Render error:", err);
|
|
244
|
-
} finally {
|
|
245
|
-
this._rendering = false;
|
|
246
|
-
if (this._pendingFlush && !this.disposed) {
|
|
247
|
-
this._pendingFlush = false;
|
|
248
|
-
await this.doFlush();
|
|
249
|
-
}
|
|
250
183
|
}
|
|
251
184
|
}
|
|
252
185
|
updateSettings(settings) {
|
|
@@ -3,38 +3,25 @@ import { VContainer } from '../reconciler/vnode';
|
|
|
3
3
|
import { RenderConfig } from '../render/pipeline';
|
|
4
4
|
import { EventBus } from '../context/event-bus';
|
|
5
5
|
import { DeviceInfo, WrapperComponent } from '../types';
|
|
6
|
-
import {
|
|
7
|
-
import { DialAction } from '@elgato/streamdeck';
|
|
6
|
+
import { AdapterActionHandle } from '../adapter/types';
|
|
8
7
|
import { JsonObject } from '@elgato/utils';
|
|
9
|
-
export declare class TouchStripRoot
|
|
8
|
+
export declare class TouchStripRoot {
|
|
10
9
|
private component;
|
|
11
|
-
private flushCoordinator?;
|
|
12
10
|
readonly eventBus: EventBus;
|
|
13
11
|
private container;
|
|
14
12
|
private fiberRoot;
|
|
15
13
|
private columns;
|
|
16
14
|
private globalSettings;
|
|
17
15
|
private setGlobalSettingsFn;
|
|
18
|
-
private renderDebounceMs;
|
|
19
16
|
private renderConfig;
|
|
20
17
|
private deviceInfo;
|
|
21
18
|
private disposed;
|
|
22
|
-
private fps;
|
|
23
19
|
private pluginWrapper?;
|
|
20
|
+
private readonly renderDebounceMs;
|
|
24
21
|
private _renderCount;
|
|
25
22
|
private _lastRenderReport;
|
|
26
23
|
private static readonly RENDER_WARN_THRESHOLD;
|
|
27
|
-
private
|
|
28
|
-
private _pendingFlush;
|
|
29
|
-
private _recentRenders;
|
|
30
|
-
private _lastInteraction;
|
|
31
|
-
private static readonly ANIMATION_WINDOW_MS;
|
|
32
|
-
private static readonly ANIMATION_THRESHOLD;
|
|
33
|
-
private static readonly INTERACTION_COOLDOWN_MS;
|
|
34
|
-
private static readonly IDLE_THRESHOLD_MS;
|
|
35
|
-
private _lastFlushTime;
|
|
36
|
-
/** Current render priority (lower = higher priority). Used by flush coordinator. */
|
|
37
|
-
get priority(): number;
|
|
24
|
+
private _lastSegmentUriHash;
|
|
38
25
|
/** Last rendered per-column data URIs. Used by devtools snapshots. */
|
|
39
26
|
lastSegmentUris: Map<number, string>;
|
|
40
27
|
/**
|
|
@@ -64,8 +51,8 @@ export declare class TouchStripRoot implements FlushableRoot {
|
|
|
64
51
|
get columnActionMap(): Map<number, string>;
|
|
65
52
|
private globalSettingsValue;
|
|
66
53
|
private touchStripValue;
|
|
67
|
-
constructor(component: ComponentType, deviceInfo: DeviceInfo, initialGlobalSettings: JsonObject, renderConfig: RenderConfig,
|
|
68
|
-
addColumn(column: number, actionId: string, sdkAction:
|
|
54
|
+
constructor(component: ComponentType, deviceInfo: DeviceInfo, initialGlobalSettings: JsonObject, renderConfig: RenderConfig, onGlobalSettingsChange: (settings: JsonObject) => Promise<void>, pluginWrapper?: WrapperComponent);
|
|
55
|
+
addColumn(column: number, actionId: string, sdkAction: AdapterActionHandle): void;
|
|
69
56
|
removeColumn(column: number): void;
|
|
70
57
|
get isEmpty(): boolean;
|
|
71
58
|
findColumnByActionId(actionId: string): number | undefined;
|
|
@@ -73,20 +60,7 @@ export declare class TouchStripRoot implements FlushableRoot {
|
|
|
73
60
|
private render;
|
|
74
61
|
private buildTree;
|
|
75
62
|
private scheduleRerender;
|
|
76
|
-
/** Record a user interaction for adaptive debounce. */
|
|
77
|
-
markInteraction(): void;
|
|
78
|
-
private get effectiveDebounceMs();
|
|
79
63
|
private flush;
|
|
80
|
-
/**
|
|
81
|
-
* Submit this root for flushing. Routes through the coordinator
|
|
82
|
-
* (priority-ordered) when available, or flushes directly.
|
|
83
|
-
*/
|
|
84
|
-
private submitFlush;
|
|
85
|
-
/**
|
|
86
|
-
* Execute the flush. Called by FlushCoordinator in priority order,
|
|
87
|
-
* or directly when no coordinator is present.
|
|
88
|
-
*/
|
|
89
|
-
executeFlush(): Promise<void>;
|
|
90
64
|
private doFlush;
|
|
91
65
|
updateGlobalSettings(settings: JsonObject): void;
|
|
92
66
|
unmount(): void;
|