@fcannizzaro/streamdeck-react 0.1.10 → 0.1.12
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/LICENSE +190 -21
- package/README.md +2 -0
- package/dist/action.d.ts +2 -2
- package/dist/action.js +1 -2
- 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 +11 -0
- package/dist/bundler-shared.js +11 -0
- package/dist/context/event-bus.d.ts +1 -1
- package/dist/context/event-bus.js +1 -1
- package/dist/context/touchstrip-context.d.ts +2 -0
- package/dist/context/touchstrip-context.js +5 -0
- package/dist/devtools/bridge.d.ts +35 -7
- package/dist/devtools/bridge.js +152 -46
- package/dist/devtools/highlight.d.ts +5 -0
- package/dist/devtools/highlight.js +107 -57
- package/dist/devtools/index.js +6 -0
- package/dist/devtools/observers/lifecycle.d.ts +4 -4
- package/dist/devtools/server.d.ts +6 -1
- package/dist/devtools/server.js +6 -1
- package/dist/devtools/types.d.ts +50 -6
- package/dist/font-inline.d.ts +5 -1
- package/dist/font-inline.js +8 -3
- package/dist/hooks/animation.d.ts +154 -0
- package/dist/hooks/animation.js +381 -0
- package/dist/hooks/events.js +2 -6
- package/dist/hooks/sdk.js +11 -11
- package/dist/hooks/touchstrip.d.ts +6 -0
- package/dist/hooks/touchstrip.js +37 -0
- package/dist/hooks/utility.js +3 -2
- package/dist/index.d.ts +9 -2
- package/dist/index.js +4 -2
- package/dist/manifest-codegen.d.ts +38 -0
- package/dist/manifest-codegen.js +110 -0
- package/dist/plugin.js +86 -106
- package/dist/reconciler/host-config.js +19 -1
- package/dist/reconciler/vnode.d.ts +26 -2
- package/dist/reconciler/vnode.js +40 -10
- package/dist/render/buffer-pool.d.ts +19 -0
- package/dist/render/buffer-pool.js +51 -0
- package/dist/render/cache.d.ts +29 -0
- package/dist/render/cache.js +137 -5
- package/dist/render/image-cache.d.ts +54 -0
- package/dist/render/image-cache.js +144 -0
- package/dist/render/metrics.d.ts +57 -0
- package/dist/render/metrics.js +98 -0
- package/dist/render/pipeline.d.ts +36 -1
- package/dist/render/pipeline.js +304 -34
- package/dist/render/png.d.ts +1 -1
- package/dist/render/png.js +26 -11
- package/dist/render/render-pool.d.ts +24 -0
- package/dist/render/render-pool.js +130 -0
- package/dist/render/svg.d.ts +7 -0
- package/dist/render/svg.js +139 -0
- package/dist/render/worker.d.ts +1 -0
- package/dist/rollup.d.ts +23 -9
- package/dist/rollup.js +24 -9
- package/dist/roots/registry.d.ts +9 -11
- package/dist/roots/registry.js +39 -42
- package/dist/roots/root.d.ts +9 -6
- package/dist/roots/root.js +52 -29
- package/dist/roots/settings-equality.d.ts +5 -0
- package/dist/roots/settings-equality.js +24 -0
- package/dist/roots/{touchbar-root.d.ts → touchstrip-root.d.ts} +30 -8
- package/dist/roots/touchstrip-root.js +263 -0
- package/dist/types.d.ts +73 -23
- package/dist/vite.d.ts +22 -8
- package/dist/vite.js +24 -8
- package/package.json +7 -4
- package/dist/context/touchbar-context.d.ts +0 -2
- package/dist/context/touchbar-context.js +0 -5
- package/dist/hooks/touchbar.d.ts +0 -6
- package/dist/hooks/touchbar.js +0 -37
- package/dist/roots/touchbar-root.js +0 -175
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import { usePrevious, useTick } from "./utility.js";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
//#region src/hooks/animation.ts
|
|
4
|
+
var SPRING_DEFAULTS = {
|
|
5
|
+
tension: 170,
|
|
6
|
+
friction: 26,
|
|
7
|
+
mass: 1,
|
|
8
|
+
velocityThreshold: .01,
|
|
9
|
+
displacementThreshold: .005,
|
|
10
|
+
clamp: false
|
|
11
|
+
};
|
|
12
|
+
var TWEEN_DEFAULTS = {
|
|
13
|
+
duration: 300,
|
|
14
|
+
easing: "easeOut",
|
|
15
|
+
fps: 30
|
|
16
|
+
};
|
|
17
|
+
/** Max dt cap to prevent spring explosion after long pauses.
|
|
18
|
+
* If the process is suspended (debugger, GC pause), dt could be
|
|
19
|
+
* seconds-long, causing the spring to overshoot wildly. Capping
|
|
20
|
+
* at ~64ms (roughly one frame at 15fps) keeps the simulation stable. */
|
|
21
|
+
var MAX_DT_SEC = .064;
|
|
22
|
+
/**
|
|
23
|
+
* Semi-implicit Euler step for a damped harmonic oscillator.
|
|
24
|
+
* Updates velocity first, then position — stable at low frame rates.
|
|
25
|
+
*/
|
|
26
|
+
function stepSpring(state, target, config, dtSeconds) {
|
|
27
|
+
const { tension, friction, mass } = config;
|
|
28
|
+
const displacement = state.position - target;
|
|
29
|
+
const acceleration = (-tension * displacement + -friction * state.velocity) / mass;
|
|
30
|
+
let velocity = state.velocity + acceleration * dtSeconds;
|
|
31
|
+
let position = state.position + velocity * dtSeconds;
|
|
32
|
+
if (config.clamp) {
|
|
33
|
+
if (displacement > 0 && position < target || displacement < 0 && position > target) {
|
|
34
|
+
position = target;
|
|
35
|
+
velocity = 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
position,
|
|
40
|
+
velocity
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Check if a spring channel has come to rest. */
|
|
44
|
+
function isSettled(state, target, config) {
|
|
45
|
+
return Math.abs(state.velocity) < config.velocityThreshold && Math.abs(state.position - target) < config.displacementThreshold;
|
|
46
|
+
}
|
|
47
|
+
var SpringPresets = {
|
|
48
|
+
default: {
|
|
49
|
+
tension: 170,
|
|
50
|
+
friction: 26,
|
|
51
|
+
mass: 1
|
|
52
|
+
},
|
|
53
|
+
stiff: {
|
|
54
|
+
tension: 400,
|
|
55
|
+
friction: 28,
|
|
56
|
+
mass: 1
|
|
57
|
+
},
|
|
58
|
+
wobbly: {
|
|
59
|
+
tension: 180,
|
|
60
|
+
friction: 12,
|
|
61
|
+
mass: 1
|
|
62
|
+
},
|
|
63
|
+
gentle: {
|
|
64
|
+
tension: 120,
|
|
65
|
+
friction: 14,
|
|
66
|
+
mass: 1
|
|
67
|
+
},
|
|
68
|
+
molasses: {
|
|
69
|
+
tension: 80,
|
|
70
|
+
friction: 30,
|
|
71
|
+
mass: 1
|
|
72
|
+
},
|
|
73
|
+
snap: {
|
|
74
|
+
tension: 300,
|
|
75
|
+
friction: 36,
|
|
76
|
+
mass: 1,
|
|
77
|
+
clamp: true
|
|
78
|
+
},
|
|
79
|
+
heavy: {
|
|
80
|
+
tension: 200,
|
|
81
|
+
friction: 20,
|
|
82
|
+
mass: 3
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var Easings = {
|
|
86
|
+
linear: (t) => t,
|
|
87
|
+
easeIn: (t) => t * t,
|
|
88
|
+
easeOut: (t) => t * (2 - t),
|
|
89
|
+
easeInOut: (t) => t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
|
|
90
|
+
easeInCubic: (t) => t * t * t,
|
|
91
|
+
easeOutCubic: (t) => 1 - (1 - t) ** 3,
|
|
92
|
+
easeInOutCubic: (t) => t < .5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2,
|
|
93
|
+
easeInBack: (t) => {
|
|
94
|
+
const c = 1.70158;
|
|
95
|
+
return (c + 1) * t * t * t - c * t * t;
|
|
96
|
+
},
|
|
97
|
+
easeOutBack: (t) => {
|
|
98
|
+
const c = 1.70158;
|
|
99
|
+
return 1 + (c + 1) * (t - 1) ** 3 + c * (t - 1) ** 2;
|
|
100
|
+
},
|
|
101
|
+
easeOutBounce: (t) => {
|
|
102
|
+
const n1 = 7.5625;
|
|
103
|
+
const d1 = 2.75;
|
|
104
|
+
if (t < 1 / d1) return n1 * t * t;
|
|
105
|
+
if (t < 2 / d1) return n1 * (t -= 1.5 / d1) * t + .75;
|
|
106
|
+
if (t < 2.5 / d1) return n1 * (t -= 2.25 / d1) * t + .9375;
|
|
107
|
+
return n1 * (t -= 2.625 / d1) * t + .984375;
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
function resolveEasing(easing) {
|
|
111
|
+
return typeof easing === "function" ? easing : Easings[easing];
|
|
112
|
+
}
|
|
113
|
+
var SCALAR_KEY = "_";
|
|
114
|
+
function toChannelMap(target) {
|
|
115
|
+
if (typeof target === "number") return new Map([[SCALAR_KEY, target]]);
|
|
116
|
+
return new Map(Object.entries(target));
|
|
117
|
+
}
|
|
118
|
+
function snapshotValue(target) {
|
|
119
|
+
if (typeof target === "number") return target;
|
|
120
|
+
const result = {};
|
|
121
|
+
for (const [key, val] of Object.entries(target)) result[key] = val;
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
function snapshotFromSpringState(state, isObject) {
|
|
125
|
+
if (!isObject) return state.get(SCALAR_KEY).position;
|
|
126
|
+
const result = {};
|
|
127
|
+
for (const [key, s] of state) result[key] = s.position;
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
function snapshotFromMap(map, isObject) {
|
|
131
|
+
if (!isObject) return map.get(SCALAR_KEY);
|
|
132
|
+
const result = {};
|
|
133
|
+
for (const [key, val] of map) result[key] = val;
|
|
134
|
+
return result;
|
|
135
|
+
}
|
|
136
|
+
function forEachChannel(target, fn) {
|
|
137
|
+
if (typeof target === "number") fn(SCALAR_KEY, target);
|
|
138
|
+
else for (const [key, val] of Object.entries(target)) fn(key, val);
|
|
139
|
+
}
|
|
140
|
+
function shallowEqual(a, b) {
|
|
141
|
+
if (typeof a === "number" && typeof b === "number") return a === b;
|
|
142
|
+
if (typeof a !== typeof b) return false;
|
|
143
|
+
const aObj = a;
|
|
144
|
+
const bObj = b;
|
|
145
|
+
const aKeys = Object.keys(aObj);
|
|
146
|
+
const bKeys = Object.keys(bObj);
|
|
147
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
148
|
+
return aKeys.every((k) => aObj[k] === bObj[k]);
|
|
149
|
+
}
|
|
150
|
+
function initializeSpringState(target) {
|
|
151
|
+
const map = /* @__PURE__ */ new Map();
|
|
152
|
+
forEachChannel(target, (key, value) => {
|
|
153
|
+
map.set(key, {
|
|
154
|
+
position: value,
|
|
155
|
+
velocity: 0
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
return map;
|
|
159
|
+
}
|
|
160
|
+
function snapSpringToTarget(state, target) {
|
|
161
|
+
forEachChannel(target, (key, value) => {
|
|
162
|
+
state.set(key, {
|
|
163
|
+
position: value,
|
|
164
|
+
velocity: 0
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Spring physics-based animation hook.
|
|
170
|
+
*
|
|
171
|
+
* Returns animated value(s) that follow the target with natural spring dynamics
|
|
172
|
+
* (damped harmonic oscillator). Supports single numbers and objects of numbers.
|
|
173
|
+
*
|
|
174
|
+
* Automatically starts/stops the tick loop when the spring is in motion or settled.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```tsx
|
|
178
|
+
* const { value: scale } = useSpring(pressed ? 0.85 : 1, SpringPresets.wobbly);
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* ```tsx
|
|
183
|
+
* const { value } = useSpring({ x: targetX, opacity: show ? 1 : 0 }, SpringPresets.gentle);
|
|
184
|
+
* // value.x and value.opacity are plain numbers
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
function useSpring(target, config) {
|
|
188
|
+
const resolvedConfig = useMemo(() => ({
|
|
189
|
+
...SPRING_DEFAULTS,
|
|
190
|
+
...config
|
|
191
|
+
}), [
|
|
192
|
+
config?.tension,
|
|
193
|
+
config?.friction,
|
|
194
|
+
config?.mass,
|
|
195
|
+
config?.velocityThreshold,
|
|
196
|
+
config?.displacementThreshold,
|
|
197
|
+
config?.clamp
|
|
198
|
+
]);
|
|
199
|
+
const fps = config?.fps ?? 30;
|
|
200
|
+
const isObject = typeof target === "object" && target !== null;
|
|
201
|
+
const stateRef = useRef(null);
|
|
202
|
+
if (stateRef.current === null) stateRef.current = initializeSpringState(target);
|
|
203
|
+
const targetRef = useRef(target);
|
|
204
|
+
targetRef.current = target;
|
|
205
|
+
const configRef = useRef(resolvedConfig);
|
|
206
|
+
configRef.current = resolvedConfig;
|
|
207
|
+
const [value, setValue] = useState(() => snapshotValue(target));
|
|
208
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
209
|
+
const prevTarget = usePrevious(target);
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
if (prevTarget !== void 0 && !shallowEqual(prevTarget, target)) {
|
|
212
|
+
const state = stateRef.current;
|
|
213
|
+
forEachChannel(target, (key, val) => {
|
|
214
|
+
if (!state.has(key)) state.set(key, {
|
|
215
|
+
position: val,
|
|
216
|
+
velocity: 0
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
setIsAnimating(true);
|
|
220
|
+
}
|
|
221
|
+
}, [prevTarget, target]);
|
|
222
|
+
useTick((deltaMs) => {
|
|
223
|
+
const dt = Math.min(deltaMs / 1e3, MAX_DT_SEC);
|
|
224
|
+
const state = stateRef.current;
|
|
225
|
+
const currentTarget = targetRef.current;
|
|
226
|
+
const cfg = configRef.current;
|
|
227
|
+
let allSettled = true;
|
|
228
|
+
forEachChannel(currentTarget, (key, targetVal) => {
|
|
229
|
+
const channelState = state.get(key);
|
|
230
|
+
if (!channelState) return;
|
|
231
|
+
const next = stepSpring(channelState, targetVal, cfg, dt);
|
|
232
|
+
state.set(key, next);
|
|
233
|
+
if (!isSettled(next, targetVal, cfg)) allSettled = false;
|
|
234
|
+
});
|
|
235
|
+
if (allSettled) {
|
|
236
|
+
snapSpringToTarget(state, currentTarget);
|
|
237
|
+
setValue(snapshotValue(currentTarget));
|
|
238
|
+
setIsAnimating(false);
|
|
239
|
+
} else setValue(snapshotFromSpringState(state, isObject));
|
|
240
|
+
}, isAnimating ? fps : false);
|
|
241
|
+
const set = useCallback((newTarget) => {
|
|
242
|
+
targetRef.current = newTarget;
|
|
243
|
+
const state = stateRef.current;
|
|
244
|
+
forEachChannel(newTarget, (key, val) => {
|
|
245
|
+
if (!state.has(key)) state.set(key, {
|
|
246
|
+
position: val,
|
|
247
|
+
velocity: 0
|
|
248
|
+
});
|
|
249
|
+
});
|
|
250
|
+
setIsAnimating(true);
|
|
251
|
+
}, []);
|
|
252
|
+
const jump = useCallback((newTarget) => {
|
|
253
|
+
targetRef.current = newTarget;
|
|
254
|
+
snapSpringToTarget(stateRef.current, newTarget);
|
|
255
|
+
setValue(snapshotValue(newTarget));
|
|
256
|
+
setIsAnimating(false);
|
|
257
|
+
}, []);
|
|
258
|
+
return useMemo(() => ({
|
|
259
|
+
value,
|
|
260
|
+
isAnimating,
|
|
261
|
+
set,
|
|
262
|
+
jump
|
|
263
|
+
}), [
|
|
264
|
+
value,
|
|
265
|
+
isAnimating,
|
|
266
|
+
set,
|
|
267
|
+
jump
|
|
268
|
+
]);
|
|
269
|
+
}
|
|
270
|
+
function interpolateTween(tween, easingFn) {
|
|
271
|
+
const easedT = easingFn(tween.duration > 0 ? Math.min(tween.elapsed / tween.duration, 1) : 1);
|
|
272
|
+
const result = /* @__PURE__ */ new Map();
|
|
273
|
+
for (const [key, fromVal] of tween.from) {
|
|
274
|
+
const toVal = tween.to.get(key) ?? fromVal;
|
|
275
|
+
result.set(key, fromVal + (toVal - fromVal) * easedT);
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Duration + easing-based animation hook.
|
|
281
|
+
*
|
|
282
|
+
* Returns animated value(s) that smoothly transition to the target over the
|
|
283
|
+
* specified duration using an easing curve. Supports single numbers and objects
|
|
284
|
+
* of numbers.
|
|
285
|
+
*
|
|
286
|
+
* When the target changes mid-tween, a new tween starts from the current
|
|
287
|
+
* interpolated position (no discontinuity).
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```tsx
|
|
291
|
+
* const { value: opacity } = useTween(visible ? 1 : 0, { duration: 500, easing: "easeInOut" });
|
|
292
|
+
* ```
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```tsx
|
|
296
|
+
* const { value } = useTween({ y: expanded ? 0 : -50, opacity: expanded ? 1 : 0 });
|
|
297
|
+
* // value.y and value.opacity are plain numbers
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
function useTween(target, config) {
|
|
301
|
+
const duration = config?.duration ?? TWEEN_DEFAULTS.duration;
|
|
302
|
+
const easingFn = resolveEasing(config?.easing ?? TWEEN_DEFAULTS.easing);
|
|
303
|
+
const fps = config?.fps ?? TWEEN_DEFAULTS.fps;
|
|
304
|
+
const isObject = typeof target === "object" && target !== null;
|
|
305
|
+
const tweenRef = useRef(null);
|
|
306
|
+
if (tweenRef.current === null) {
|
|
307
|
+
const initial = toChannelMap(target);
|
|
308
|
+
tweenRef.current = {
|
|
309
|
+
from: new Map(initial),
|
|
310
|
+
to: new Map(initial),
|
|
311
|
+
elapsed: duration,
|
|
312
|
+
duration
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const targetRef = useRef(target);
|
|
316
|
+
const easingRef = useRef(easingFn);
|
|
317
|
+
easingRef.current = easingFn;
|
|
318
|
+
const [value, setValue] = useState(() => snapshotValue(target));
|
|
319
|
+
const [progress, setProgress] = useState(1);
|
|
320
|
+
const [isAnimating, setIsAnimating] = useState(false);
|
|
321
|
+
const prevTarget = usePrevious(target);
|
|
322
|
+
useEffect(() => {
|
|
323
|
+
if (prevTarget !== void 0 && !shallowEqual(prevTarget, target)) {
|
|
324
|
+
const tween = tweenRef.current;
|
|
325
|
+
tween.from = interpolateTween(tween, easingRef.current);
|
|
326
|
+
tween.to = toChannelMap(target);
|
|
327
|
+
tween.elapsed = 0;
|
|
328
|
+
tween.duration = duration;
|
|
329
|
+
targetRef.current = target;
|
|
330
|
+
setIsAnimating(true);
|
|
331
|
+
}
|
|
332
|
+
}, [
|
|
333
|
+
prevTarget,
|
|
334
|
+
target,
|
|
335
|
+
duration
|
|
336
|
+
]);
|
|
337
|
+
useTick((deltaMs) => {
|
|
338
|
+
const tween = tweenRef.current;
|
|
339
|
+
tween.elapsed = Math.min(tween.elapsed + deltaMs, tween.duration);
|
|
340
|
+
const t = tween.duration > 0 ? tween.elapsed / tween.duration : 1;
|
|
341
|
+
const result = interpolateTween(tween, easingRef.current);
|
|
342
|
+
setProgress(t);
|
|
343
|
+
setValue(snapshotFromMap(result, isObject));
|
|
344
|
+
if (t >= 1) setIsAnimating(false);
|
|
345
|
+
}, isAnimating ? fps : false);
|
|
346
|
+
const set = useCallback((newTarget) => {
|
|
347
|
+
const tween = tweenRef.current;
|
|
348
|
+
tween.from = interpolateTween(tween, easingRef.current);
|
|
349
|
+
tween.to = toChannelMap(newTarget);
|
|
350
|
+
tween.elapsed = 0;
|
|
351
|
+
tween.duration = duration;
|
|
352
|
+
targetRef.current = newTarget;
|
|
353
|
+
setIsAnimating(true);
|
|
354
|
+
}, [duration]);
|
|
355
|
+
const jump = useCallback((newTarget) => {
|
|
356
|
+
const tween = tweenRef.current;
|
|
357
|
+
const map = toChannelMap(newTarget);
|
|
358
|
+
tween.from = new Map(map);
|
|
359
|
+
tween.to = new Map(map);
|
|
360
|
+
tween.elapsed = tween.duration;
|
|
361
|
+
targetRef.current = newTarget;
|
|
362
|
+
setValue(snapshotValue(newTarget));
|
|
363
|
+
setProgress(1);
|
|
364
|
+
setIsAnimating(false);
|
|
365
|
+
}, []);
|
|
366
|
+
return useMemo(() => ({
|
|
367
|
+
value,
|
|
368
|
+
progress,
|
|
369
|
+
isAnimating,
|
|
370
|
+
set,
|
|
371
|
+
jump
|
|
372
|
+
}), [
|
|
373
|
+
value,
|
|
374
|
+
progress,
|
|
375
|
+
isAnimating,
|
|
376
|
+
set,
|
|
377
|
+
jump
|
|
378
|
+
]);
|
|
379
|
+
}
|
|
380
|
+
//#endregion
|
|
381
|
+
export { Easings, SpringPresets, useSpring, useTween };
|
package/dist/hooks/events.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { EventBusContext, StreamDeckContext } from "../context/providers.js";
|
|
2
2
|
import { useCallbackRef } from "./internal/useCallbackRef.js";
|
|
3
|
-
import { useContext, useEffect
|
|
3
|
+
import { useContext, useEffect } from "react";
|
|
4
4
|
//#region src/hooks/events.ts
|
|
5
5
|
function useEvent(event, callback) {
|
|
6
6
|
const bus = useContext(EventBusContext);
|
|
@@ -37,12 +37,8 @@ function useTouchTap(callback) {
|
|
|
37
37
|
}
|
|
38
38
|
function useDialHint(hints) {
|
|
39
39
|
const { action } = useContext(StreamDeckContext);
|
|
40
|
-
const prevHints = useRef("");
|
|
41
40
|
useEffect(() => {
|
|
42
|
-
|
|
43
|
-
if (serialized === prevHints.current) return;
|
|
44
|
-
prevHints.current = serialized;
|
|
45
|
-
if ("setTriggerDescription" in action) action.setTriggerDescription({
|
|
41
|
+
action.setTriggerDescription({
|
|
46
42
|
rotate: hints.rotate,
|
|
47
43
|
push: hints.press,
|
|
48
44
|
touch: hints.touch,
|
package/dist/hooks/sdk.js
CHANGED
|
@@ -3,23 +3,23 @@ import { useCallbackRef } from "./internal/useCallbackRef.js";
|
|
|
3
3
|
import { useCallback, useContext, useEffect } from "react";
|
|
4
4
|
//#region src/hooks/sdk.ts
|
|
5
5
|
function useOpenUrl() {
|
|
6
|
-
const {
|
|
6
|
+
const { adapter } = useContext(StreamDeckContext);
|
|
7
7
|
return useCallback(async (url) => {
|
|
8
|
-
await
|
|
9
|
-
}, [
|
|
8
|
+
await adapter.openUrl(url);
|
|
9
|
+
}, [adapter]);
|
|
10
10
|
}
|
|
11
11
|
function useSwitchProfile() {
|
|
12
|
-
const {
|
|
12
|
+
const { adapter, action } = useContext(StreamDeckContext);
|
|
13
13
|
return useCallback(async (profile, deviceId) => {
|
|
14
14
|
const devId = deviceId ?? action.device.id;
|
|
15
|
-
await
|
|
16
|
-
}, [
|
|
15
|
+
await adapter.switchToProfile(devId, profile);
|
|
16
|
+
}, [adapter, action]);
|
|
17
17
|
}
|
|
18
18
|
function useSendToPI() {
|
|
19
|
-
const {
|
|
19
|
+
const { adapter } = useContext(StreamDeckContext);
|
|
20
20
|
return useCallback(async (payload) => {
|
|
21
|
-
await
|
|
22
|
-
}, [
|
|
21
|
+
await adapter.sendToPropertyInspector(payload);
|
|
22
|
+
}, [adapter]);
|
|
23
23
|
}
|
|
24
24
|
function usePropertyInspector(callback) {
|
|
25
25
|
const bus = useContext(EventBusContext);
|
|
@@ -41,13 +41,13 @@ function useShowAlert() {
|
|
|
41
41
|
function useShowOk() {
|
|
42
42
|
const { action } = useContext(StreamDeckContext);
|
|
43
43
|
return useCallback(async () => {
|
|
44
|
-
|
|
44
|
+
await action.showOk();
|
|
45
45
|
}, [action]);
|
|
46
46
|
}
|
|
47
47
|
function useTitle() {
|
|
48
48
|
const { action } = useContext(StreamDeckContext);
|
|
49
49
|
return useCallback(async (title) => {
|
|
50
|
-
|
|
50
|
+
await action.setTitle(title);
|
|
51
51
|
}, [action]);
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TouchStripInfo, TouchStripTapPayload, TouchStripDialRotatePayload, TouchStripDialPressPayload } from '../types';
|
|
2
|
+
export declare function useTouchStrip(): TouchStripInfo;
|
|
3
|
+
export declare function useTouchStripTap(callback: (payload: TouchStripTapPayload) => void): void;
|
|
4
|
+
export declare function useTouchStripDialRotate(callback: (payload: TouchStripDialRotatePayload) => void): void;
|
|
5
|
+
export declare function useTouchStripDialDown(callback: (payload: TouchStripDialPressPayload) => void): void;
|
|
6
|
+
export declare function useTouchStripDialUp(callback: (payload: TouchStripDialPressPayload) => void): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { EventBusContext } from "../context/providers.js";
|
|
2
|
+
import { TouchStripContext } from "../context/touchstrip-context.js";
|
|
3
|
+
import { useCallbackRef } from "./internal/useCallbackRef.js";
|
|
4
|
+
import { useContext, useEffect } from "react";
|
|
5
|
+
//#region src/hooks/touchstrip.ts
|
|
6
|
+
function useTouchStripEvent(event, callback) {
|
|
7
|
+
const bus = useContext(EventBusContext);
|
|
8
|
+
const callbackRef = useCallbackRef(callback);
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
const handler = (payload) => {
|
|
11
|
+
callbackRef.current(payload);
|
|
12
|
+
};
|
|
13
|
+
bus.on(event, handler);
|
|
14
|
+
return () => bus.off(event, handler);
|
|
15
|
+
}, [
|
|
16
|
+
bus,
|
|
17
|
+
callbackRef,
|
|
18
|
+
event
|
|
19
|
+
]);
|
|
20
|
+
}
|
|
21
|
+
function useTouchStrip() {
|
|
22
|
+
return useContext(TouchStripContext);
|
|
23
|
+
}
|
|
24
|
+
function useTouchStripTap(callback) {
|
|
25
|
+
useTouchStripEvent("touchStripTap", callback);
|
|
26
|
+
}
|
|
27
|
+
function useTouchStripDialRotate(callback) {
|
|
28
|
+
useTouchStripEvent("touchStripDialRotate", callback);
|
|
29
|
+
}
|
|
30
|
+
function useTouchStripDialDown(callback) {
|
|
31
|
+
useTouchStripEvent("touchStripDialDown", callback);
|
|
32
|
+
}
|
|
33
|
+
function useTouchStripDialUp(callback) {
|
|
34
|
+
useTouchStripEvent("touchStripDialUp", callback);
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { useTouchStrip, useTouchStripDialDown, useTouchStripDialRotate, useTouchStripDialUp, useTouchStripTap };
|
package/dist/hooks/utility.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { useCallbackRef } from "./internal/useCallbackRef.js";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef } from "react";
|
|
3
3
|
//#region src/hooks/utility.ts
|
|
4
|
-
var DEFAULT_TICK_FPS =
|
|
4
|
+
var DEFAULT_TICK_FPS = 30;
|
|
5
|
+
var MAX_TICK_FPS = 30;
|
|
5
6
|
function toTickIntervalMs(fps) {
|
|
6
7
|
if (!Number.isFinite(fps) || fps <= 0) return Math.round(1e3 / DEFAULT_TICK_FPS);
|
|
7
|
-
return Math.max(1, Math.round(1e3 / fps));
|
|
8
|
+
return Math.max(1, Math.round(1e3 / Math.min(fps, MAX_TICK_FPS)));
|
|
8
9
|
}
|
|
9
10
|
function useInterval(callback, delayMs) {
|
|
10
11
|
const callbackRef = useCallbackRef(callback);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
export { createPlugin } from './plugin';
|
|
2
2
|
export { defineAction } from './action';
|
|
3
|
+
export type { RenderProfile } from './render/pipeline';
|
|
4
|
+
export type { CacheStats } from './render/image-cache';
|
|
5
|
+
export type { RenderMetrics } from './render/metrics';
|
|
6
|
+
export { physicalDevice } from './adapter/physical-device';
|
|
7
|
+
export type { StreamDeckAdapter, AdapterActionHandle, AdapterActionCallbacks, AdapterWillAppearEvent, AdapterActionDevice, AdapterController, AdapterCoordinates, AdapterSize, AdapterTriggerDescription, } from './adapter/types';
|
|
3
8
|
export { useKeyDown, useKeyUp, useDialRotate, useDialDown, useDialUp, useTouchTap, useDialHint, } from './hooks/events';
|
|
4
9
|
export { useTap, useLongPress, useDoubleTap } from './hooks/gestures';
|
|
5
10
|
export { useSettings, useGlobalSettings } from './hooks/settings';
|
|
6
11
|
export { useDevice, useAction, useCanvas, useStreamDeck } from './hooks/context';
|
|
7
12
|
export { useWillAppear, useWillDisappear } from './hooks/lifecycle';
|
|
8
13
|
export { useInterval, useTimeout, usePrevious, useTick } from './hooks/utility';
|
|
14
|
+
export { useSpring, useTween, SpringPresets, Easings } from './hooks/animation';
|
|
15
|
+
export type { SpringConfig, SpringResult, TweenConfig, TweenResult, EasingName, EasingFn, AnimationTarget, AnimatedValue, } from './hooks/animation';
|
|
9
16
|
export { useOpenUrl, useSwitchProfile, useSendToPI, usePropertyInspector, useShowAlert, useShowOk, useTitle, } from './hooks/sdk';
|
|
10
|
-
export {
|
|
17
|
+
export { useTouchStrip, useTouchStripTap, useTouchStripDialRotate, useTouchStripDialDown, useTouchStripDialUp, } from './hooks/touchstrip';
|
|
11
18
|
export { Box } from './components/Box';
|
|
12
19
|
export { Text } from './components/Text';
|
|
13
20
|
export { Image } from './components/Image';
|
|
@@ -16,7 +23,7 @@ export { ProgressBar } from './components/ProgressBar';
|
|
|
16
23
|
export { CircularGauge } from './components/CircularGauge';
|
|
17
24
|
export { ErrorBoundary } from './components/ErrorBoundary';
|
|
18
25
|
export { tw } from './tw/index';
|
|
19
|
-
export type { PluginConfig, FontConfig, ActionConfig, ActionDefinition, EncoderLayout, WrapperComponent, DeviceInfo, ActionInfo, CanvasInfo, TouchStripLayout, TouchStripLayoutItem, KeyDownPayload, KeyUpPayload, DialRotatePayload, DialPressPayload, TouchTapPayload, DialHints, StreamDeckAccess,
|
|
26
|
+
export type { PluginConfig, FontConfig, ActionConfig, ActionConfigInput, ActionDefinition, ActionUUID, ManifestActions, EncoderLayout, WrapperComponent, Controller, Coordinates, Size, DeviceInfo, ActionInfo, CanvasInfo, TouchStripLayout, TouchStripLayoutItem, KeyDownPayload, KeyUpPayload, DialRotatePayload, DialPressPayload, TouchTapPayload, DialHints, StreamDeckAccess, TouchStripInfo, TouchStripTapPayload, TouchStripDialRotatePayload, TouchStripDialPressPayload, } from './types';
|
|
20
27
|
export type { TapOptions, LongPressOptions, DoubleTapOptions } from './hooks/gestures';
|
|
21
28
|
export type { BoxProps } from './components/Box';
|
|
22
29
|
export type { TextProps } from './components/Text';
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { physicalDevice } from "./adapter/physical-device.js";
|
|
1
2
|
import { createPlugin } from "./plugin.js";
|
|
2
3
|
import { defineAction } from "./action.js";
|
|
3
4
|
import { useDialDown, useDialHint, useDialRotate, useDialUp, useKeyDown, useKeyUp, useTouchTap } from "./hooks/events.js";
|
|
@@ -6,8 +7,9 @@ import { useGlobalSettings, useSettings } from "./hooks/settings.js";
|
|
|
6
7
|
import { useAction, useCanvas, useDevice, useStreamDeck } from "./hooks/context.js";
|
|
7
8
|
import { useWillAppear, useWillDisappear } from "./hooks/lifecycle.js";
|
|
8
9
|
import { useInterval, usePrevious, useTick, useTimeout } from "./hooks/utility.js";
|
|
10
|
+
import { Easings, SpringPresets, useSpring, useTween } from "./hooks/animation.js";
|
|
9
11
|
import { useOpenUrl, usePropertyInspector, useSendToPI, useShowAlert, useShowOk, useSwitchProfile, useTitle } from "./hooks/sdk.js";
|
|
10
|
-
import {
|
|
12
|
+
import { useTouchStrip, useTouchStripDialDown, useTouchStripDialRotate, useTouchStripDialUp, useTouchStripTap } from "./hooks/touchstrip.js";
|
|
11
13
|
import { Box } from "./components/Box.js";
|
|
12
14
|
import { Text } from "./components/Text.js";
|
|
13
15
|
import { Image } from "./components/Image.js";
|
|
@@ -16,4 +18,4 @@ import { ProgressBar } from "./components/ProgressBar.js";
|
|
|
16
18
|
import { CircularGauge } from "./components/CircularGauge.js";
|
|
17
19
|
import { ErrorBoundary } from "./components/ErrorBoundary.js";
|
|
18
20
|
import { tw } from "./tw/index.js";
|
|
19
|
-
export { Box, CircularGauge, ErrorBoundary, Icon, Image, ProgressBar, Text, createPlugin, defineAction, tw, useAction, useCanvas, useDevice, useDialDown, useDialHint, useDialRotate, useDialUp, useDoubleTap, useGlobalSettings, useInterval, useKeyDown, useKeyUp, useLongPress, useOpenUrl, usePrevious, usePropertyInspector, useSendToPI, useSettings, useShowAlert, useShowOk, useStreamDeck, useSwitchProfile, useTap, useTick, useTimeout, useTitle,
|
|
21
|
+
export { Box, CircularGauge, Easings, ErrorBoundary, Icon, Image, ProgressBar, SpringPresets, Text, createPlugin, defineAction, physicalDevice, tw, useAction, useCanvas, useDevice, useDialDown, useDialHint, useDialRotate, useDialUp, useDoubleTap, useGlobalSettings, useInterval, useKeyDown, useKeyUp, useLongPress, useOpenUrl, usePrevious, usePropertyInspector, useSendToPI, useSettings, useShowAlert, useShowOk, useSpring, useStreamDeck, useSwitchProfile, useTap, useTick, useTimeout, useTitle, useTouchStrip, useTouchStripDialDown, useTouchStripDialRotate, useTouchStripDialUp, useTouchStripTap, useTouchTap, useTween, useWillAppear, useWillDisappear };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export interface ParsedAction {
|
|
2
|
+
uuid: string;
|
|
3
|
+
controllers: readonly ("Keypad" | "Encoder")[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Find the manifest.json inside a `*.sdPlugin` directory.
|
|
7
|
+
*
|
|
8
|
+
* - If `explicit` is a string, it is resolved against `root`.
|
|
9
|
+
* - If `explicit` is `false`, codegen is disabled (returns `null`).
|
|
10
|
+
* - Otherwise, auto-detects by scanning `root` for `*.sdPlugin/manifest.json`.
|
|
11
|
+
*/
|
|
12
|
+
export declare function findManifestPath(root: string, explicit?: string | false, warn?: (msg: string) => void): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Parse a Stream Deck plugin manifest and extract action metadata.
|
|
15
|
+
* Returns an empty array on failure (with a warning).
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseManifest(path: string, warn?: (msg: string) => void): ParsedAction[];
|
|
18
|
+
/**
|
|
19
|
+
* Generate the `declare module` augmentation string from parsed actions.
|
|
20
|
+
* Returns an empty string when there are no actions.
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateManifestDts(actions: ParsedAction[]): string;
|
|
23
|
+
/**
|
|
24
|
+
* Write the generated `.d.ts` file only when the content has changed.
|
|
25
|
+
* Creates the parent directory if it does not exist.
|
|
26
|
+
*
|
|
27
|
+
* @returns `true` if the file was written, `false` if content was unchanged.
|
|
28
|
+
*/
|
|
29
|
+
export declare function writeManifestDtsIfChanged(outPath: string, content: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* High-level helper: find, parse, generate, and write manifest types.
|
|
32
|
+
*
|
|
33
|
+
* @returns The resolved manifest path (for watch registration), or `null`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function generateManifestTypes(root: string, manifestOption: string | false | undefined, warn?: (msg: string) => void): {
|
|
36
|
+
manifestPath: string;
|
|
37
|
+
written: boolean;
|
|
38
|
+
} | null;
|