@fcannizzaro/streamdeck-react 0.1.8 → 0.1.10

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 (49) hide show
  1. package/README.md +1 -1
  2. package/dist/action.js +2 -0
  3. package/dist/bundler-shared.js +5 -3
  4. package/dist/components/Box.js +2 -0
  5. package/dist/components/CircularGauge.js +2 -0
  6. package/dist/components/ErrorBoundary.js +2 -0
  7. package/dist/components/Icon.js +2 -0
  8. package/dist/components/Image.js +2 -0
  9. package/dist/components/ProgressBar.js +2 -0
  10. package/dist/components/Text.js +2 -0
  11. package/dist/context/event-bus.js +2 -0
  12. package/dist/context/providers.js +9 -7
  13. package/dist/context/touchbar-context.js +3 -1
  14. package/dist/devtools/bridge.js +2 -0
  15. package/dist/devtools/highlight.js +2 -0
  16. package/dist/devtools/index.d.ts +0 -1
  17. package/dist/devtools/index.js +4 -3
  18. package/dist/devtools/intercepts/console.js +3 -1
  19. package/dist/devtools/intercepts/fetch.js +2 -0
  20. package/dist/devtools/serialization/value.js +2 -0
  21. package/dist/devtools/serialization/vnode.js +2 -0
  22. package/dist/devtools/server.d.ts +5 -2
  23. package/dist/devtools/server.js +15 -5
  24. package/dist/font-inline.js +2 -0
  25. package/dist/hooks/context.js +2 -0
  26. package/dist/hooks/events.js +2 -0
  27. package/dist/hooks/gestures.d.ts +1 -1
  28. package/dist/hooks/gestures.js +2 -0
  29. package/dist/hooks/internal/useCallbackRef.js +2 -0
  30. package/dist/hooks/lifecycle.js +2 -0
  31. package/dist/hooks/sdk.js +2 -0
  32. package/dist/hooks/settings.js +2 -0
  33. package/dist/hooks/touchbar.js +2 -0
  34. package/dist/hooks/utility.js +2 -0
  35. package/dist/plugin.js +2 -1
  36. package/dist/reconciler/host-config.js +3 -1
  37. package/dist/reconciler/renderer.js +3 -1
  38. package/dist/reconciler/vnode.js +2 -0
  39. package/dist/render/cache.js +2 -0
  40. package/dist/render/pipeline.js +2 -0
  41. package/dist/render/png.js +2 -0
  42. package/dist/rollup.js +2 -0
  43. package/dist/roots/registry.js +2 -0
  44. package/dist/roots/root.js +2 -0
  45. package/dist/roots/touchbar-root.js +2 -0
  46. package/dist/tw/index.js +2 -0
  47. package/dist/types.d.ts +0 -2
  48. package/dist/vite.js +2 -0
  49. package/package.json +4 -4
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://fcannizzaro.com/_astro/streamdeck-react.BAjPov6j.webp" alt="illustration" />
2
+ <img src="https://fcannizzaro.com/_astro/streamdeck-react.tzWCgEgf.webp" alt="illustration" />
3
3
  </p>
4
4
 
5
5
  # @fcannizzaro/streamdeck-react
package/dist/action.js CHANGED
@@ -1,3 +1,4 @@
1
+ //#region src/action.ts
1
2
  function defineAction(config) {
2
3
  return {
3
4
  uuid: config.uuid,
@@ -10,4 +11,5 @@ function defineAction(config) {
10
11
  defaultSettings: config.defaultSettings ?? {}
11
12
  };
12
13
  }
14
+ //#endregion
13
15
  export { defineAction };
@@ -1,7 +1,8 @@
1
1
  import { dirname, join } from "node:path";
2
2
  import { createRequire } from "node:module";
3
3
  import { copyFileSync, existsSync } from "node:fs";
4
- const TARGETS = [
4
+ //#region src/bundler-shared.ts
5
+ var TARGETS = [
5
6
  {
6
7
  platform: "darwin",
7
8
  arch: "arm64",
@@ -36,8 +37,8 @@ function isArch(value) {
36
37
  function isDevelopmentMode(watchMode) {
37
38
  return watchMode || process.env.NODE_ENV === "development";
38
39
  }
39
- const NOOP_DEVTOOLS_ID = "\0streamdeck-react:noop-devtools";
40
- const NOOP_DEVTOOLS_CODE = "export function startDevtoolsServer() {}";
40
+ var NOOP_DEVTOOLS_ID = "\0streamdeck-react:noop-devtools";
41
+ var NOOP_DEVTOOLS_CODE = "export function startDevtoolsServer() {}";
41
42
  var DEVTOOLS_IMPORT_SOURCE = "./devtools/index.js";
42
43
  /**
43
44
  * Returns true when devtools should be stripped from the bundle.
@@ -116,4 +117,5 @@ function copyNativeBindings(outDir, isDevelopment, options, warn) {
116
117
  throw new Error(`[@fcannizzaro/streamdeck-react] Failed to copy native binding: ${String(err)}`);
117
118
  }
118
119
  }
120
+ //#endregion
119
121
  export { NOOP_DEVTOOLS_CODE, NOOP_DEVTOOLS_ID, copyNativeBindings, isDevelopmentMode, isLibraryDevtoolsImport, shouldStripDevtools };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/components/Box.tsx
2
3
  function Box({ className, center, padding, background, borderRadius, gap, direction, style, children }) {
3
4
  return createElement("div", {
4
5
  className,
@@ -17,4 +18,5 @@ function Box({ className, center, padding, background, borderRadius, gap, direct
17
18
  }
18
19
  }, children);
19
20
  }
21
+ //#endregion
20
22
  export { Box };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/components/CircularGauge.tsx
2
3
  function CircularGauge({ className, value, max = 100, size = 80, strokeWidth = 6, color = "#2196F3", background = "#333", style }) {
3
4
  const percent = Math.max(0, Math.min(100, value / max * 100));
4
5
  const radius = (size - strokeWidth) / 2;
@@ -31,4 +32,5 @@ function CircularGauge({ className, value, max = 100, size = 80, strokeWidth = 6
31
32
  transform: `rotate(-90 ${center} ${center})`
32
33
  }));
33
34
  }
35
+ //#endregion
34
36
  export { CircularGauge };
@@ -1,4 +1,5 @@
1
1
  import { Component, createElement } from "react";
2
+ //#region src/components/ErrorBoundary.tsx
2
3
  var ErrorBoundary = class extends Component {
3
4
  constructor(props) {
4
5
  super(props);
@@ -30,4 +31,5 @@ var ErrorBoundary = class extends Component {
30
31
  return this.props.children;
31
32
  }
32
33
  };
34
+ //#endregion
33
35
  export { ErrorBoundary };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/components/Icon.tsx
2
3
  function Icon({ className, path, size = 24, color = "white", viewBox = "0 0 24 24", style }) {
3
4
  return createElement("svg", {
4
5
  className,
@@ -11,4 +12,5 @@ function Icon({ className, path, size = 24, color = "white", viewBox = "0 0 24 2
11
12
  fill: color
12
13
  }));
13
14
  }
15
+ //#endregion
14
16
  export { Icon };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/components/Image.tsx
2
3
  function Image({ className, src, width, height, fit, borderRadius, style }) {
3
4
  return createElement("img", {
4
5
  className,
@@ -12,4 +13,5 @@ function Image({ className, src, width, height, fit, borderRadius, style }) {
12
13
  }
13
14
  });
14
15
  }
16
+ //#endregion
15
17
  export { Image };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/components/ProgressBar.tsx
2
3
  function ProgressBar({ className, value, max = 100, height = 8, color = "#4CAF50", background = "#333", borderRadius = 4, style }) {
3
4
  const percent = Math.max(0, Math.min(100, value / max * 100));
4
5
  return createElement("div", {
@@ -19,4 +20,5 @@ function ProgressBar({ className, value, max = 100, height = 8, color = "#4CAF50
19
20
  borderRadius
20
21
  } }));
21
22
  }
23
+ //#endregion
22
24
  export { ProgressBar };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/components/Text.tsx
2
3
  function Text({ className, size, color, weight, align, font, lineHeight, style, children }) {
3
4
  return createElement("span", {
4
5
  className,
@@ -13,4 +14,5 @@ function Text({ className, size, color, weight, align, font, lineHeight, style,
13
14
  }
14
15
  }, children);
15
16
  }
17
+ //#endregion
16
18
  export { Text };
@@ -1,3 +1,4 @@
1
+ //#region src/context/event-bus.ts
1
2
  var EventBus = class EventBus {
2
3
  listeners = /* @__PURE__ */ new Map();
3
4
  sticky = /* @__PURE__ */ new Map();
@@ -36,4 +37,5 @@ var EventBus = class EventBus {
36
37
  }
37
38
  }
38
39
  };
40
+ //#endregion
39
41
  export { EventBus };
@@ -1,9 +1,11 @@
1
1
  import { createContext } from "react";
2
- const SettingsContext = createContext(null);
3
- const GlobalSettingsContext = createContext(null);
4
- const ActionContext = createContext(null);
5
- const DeviceContext = createContext(null);
6
- const CanvasContext = createContext(null);
7
- const EventBusContext = createContext(null);
8
- const StreamDeckContext = createContext(null);
2
+ //#region src/context/providers.ts
3
+ var SettingsContext = createContext(null);
4
+ var GlobalSettingsContext = createContext(null);
5
+ var ActionContext = createContext(null);
6
+ var DeviceContext = createContext(null);
7
+ var CanvasContext = createContext(null);
8
+ var EventBusContext = createContext(null);
9
+ var StreamDeckContext = createContext(null);
10
+ //#endregion
9
11
  export { ActionContext, CanvasContext, DeviceContext, EventBusContext, GlobalSettingsContext, SettingsContext, StreamDeckContext };
@@ -1,3 +1,5 @@
1
1
  import { createContext } from "react";
2
- const TouchBarContext = createContext(null);
2
+ //#region src/context/touchbar-context.ts
3
+ var TouchBarContext = createContext(null);
4
+ //#endregion
3
5
  export { TouchBarContext };
@@ -1,6 +1,7 @@
1
1
  import { serializeValue } from "./serialization/value.js";
2
2
  import { serializeVNode } from "./serialization/vnode.js";
3
3
  import { renderWithHighlight } from "./highlight.js";
4
+ //#region src/devtools/bridge.ts
4
5
  var RingBuffer = class {
5
6
  items;
6
7
  head = 0;
@@ -435,4 +436,5 @@ var DevtoolsBridge = class {
435
436
  };
436
437
  }
437
438
  };
439
+ //#endregion
438
440
  export { DevtoolsBridge };
@@ -2,6 +2,7 @@ import { vnodeToElement } from "../reconciler/vnode.js";
2
2
  import { bufferToDataUri } from "../render/pipeline.js";
3
3
  import { createElement } from "react";
4
4
  import { fromJsx } from "@takumi-rs/helpers/jsx";
5
+ //#region src/devtools/highlight.ts
5
6
  var HIGHLIGHT_BORDER_COLOR = "rgba(111, 168, 220, 0.85)";
6
7
  var HIGHLIGHT_BORDER_WIDTH = 2;
7
8
  var HIGHLIGHT_BG = "rgba(111, 168, 220, 0.66)";
@@ -87,4 +88,5 @@ function resolveInSubtree(node, targetNid, counter, parentNid) {
87
88
  }
88
89
  return null;
89
90
  }
91
+ //#endregion
90
92
  export { renderWithHighlight };
@@ -1,7 +1,6 @@
1
1
  import { RootRegistry } from '../roots/registry';
2
2
  import { RenderConfig } from '../render/pipeline';
3
3
  export declare function startDevtoolsServer(config: {
4
- port?: number;
5
4
  devtoolsName: string;
6
5
  registry: RootRegistry;
7
6
  renderConfig: RenderConfig;
@@ -1,11 +1,11 @@
1
1
  import { EventBus } from "../context/event-bus.js";
2
2
  import { DevtoolsBridge } from "./bridge.js";
3
3
  import { patchConsole } from "./intercepts/console.js";
4
- import { DevtoolsServer } from "./server.js";
4
+ import { DevtoolsServer, hashToPort } from "./server.js";
5
5
  import { patchFetch } from "./intercepts/fetch.js";
6
- var DEFAULT_PORT = 39400;
6
+ //#region src/devtools/index.ts
7
7
  function startDevtoolsServer(config) {
8
- const server = new DevtoolsServer(config.port ?? DEFAULT_PORT);
8
+ const server = new DevtoolsServer(hashToPort(config.devtoolsName), config.devtoolsName);
9
9
  const bridge = new DevtoolsBridge(server, config.devtoolsName, config.renderConfig);
10
10
  config.registry.observer = bridge;
11
11
  config.renderConfig.onRender = (container, dataUri) => {
@@ -32,4 +32,5 @@ function startDevtoolsServer(config) {
32
32
  server.stop();
33
33
  });
34
34
  }
35
+ //#endregion
35
36
  export { startDevtoolsServer };
@@ -1,3 +1,4 @@
1
+ //#region src/devtools/intercepts/console.ts
1
2
  /**
2
3
  * Patches console methods to forward output to the devtools bridge.
3
4
  * Returns a restore function that undoes the patch.
@@ -42,11 +43,12 @@ function patchConsole(cb) {
42
43
  * Stored originals for use by the devtools server when it needs to log
43
44
  * without triggering the interceptor.
44
45
  */
45
- const origConsole = {
46
+ var origConsole = {
46
47
  log: console.log,
47
48
  warn: console.warn,
48
49
  error: console.error,
49
50
  info: console.info,
50
51
  debug: console.debug
51
52
  };
53
+ //#endregion
52
54
  export { origConsole, patchConsole };
@@ -1,3 +1,4 @@
1
+ //#region src/devtools/intercepts/fetch.ts
1
2
  var MAX_BODY_BYTES = 256 * 1024;
2
3
  var BINARY_CONTENT_TYPES = /^(image|audio|video|application\/octet-stream|application\/zip|application\/pdf)/;
3
4
  function headersToRecord(headers) {
@@ -65,4 +66,5 @@ async function readBodySafe(reqOrRes) {
65
66
  return "[body read error]";
66
67
  }
67
68
  }
69
+ //#endregion
68
70
  export { patchFetch };
@@ -1,3 +1,4 @@
1
+ //#region src/devtools/serialization/value.ts
1
2
  var MAX_STRING_LENGTH = 1e4;
2
3
  var MAX_ARRAY_ITEMS = 100;
3
4
  var MAX_OBJECT_KEYS = 100;
@@ -96,4 +97,5 @@ function serializeValue(value, maxDepth, seen = /* @__PURE__ */ new WeakSet()) {
96
97
  hint: String(typeof value)
97
98
  };
98
99
  }
100
+ //#endregion
99
101
  export { serializeValue };
@@ -1,4 +1,5 @@
1
1
  import { serializeValue } from "./value.js";
2
+ //#region src/devtools/serialization/vnode.ts
2
3
  var MAX_TREE_DEPTH = 50;
3
4
  var MAX_TOTAL_NODES = 1e3;
4
5
  var nodeCounter = 0;
@@ -38,4 +39,5 @@ function serializeNode(node, depth) {
38
39
  children: node.children.map((child) => serializeNode(child, depth + 1))
39
40
  };
40
41
  }
42
+ //#endregion
41
43
  export { serializeVNode };
@@ -1,17 +1,20 @@
1
1
  import { BaseMessage, ClientMessage } from './types';
2
+ /** djb2 hash of a string mapped to a port in [PORT_MIN, PORT_MAX]. */
3
+ export declare function hashToPort(str: string): number;
2
4
  export declare class DevtoolsServer {
5
+ private uuid;
3
6
  private httpServer;
4
7
  private clients;
5
8
  private port;
6
9
  private actualPort;
7
10
  private onConnectCb;
8
11
  private onMessageCb;
9
- constructor(port: number);
12
+ constructor(port: number, uuid: string);
10
13
  /** Set a callback invoked when a new browser client connects via SSE. */
11
14
  setOnConnect(cb: (clientId: string) => void): void;
12
15
  /** Set a callback for client→server messages (request:snapshot, highlight:action). */
13
16
  setOnMessage(cb: (msg: ClientMessage) => void): void;
14
- /** Start listening. Tries the configured port, then random ports in range on EADDRINUSE. */
17
+ /** Start listening. Tries the configured port, then sequential ports in range on EADDRINUSE. */
15
18
  start(): Promise<void>;
16
19
  /** Stop the server and disconnect all clients. */
17
20
  stop(): void;
@@ -1,8 +1,15 @@
1
1
  import { origConsole } from "./intercepts/console.js";
2
2
  import { createServer } from "node:http";
3
+ //#region src/devtools/server.ts
3
4
  var PORT_MIN = 39400;
4
- var PORT_MAX = 39499;
5
+ var PORT_RANGE = 39499 - PORT_MIN + 1;
5
6
  var MAX_RETRIES = 10;
7
+ /** djb2 hash of a string mapped to a port in [PORT_MIN, PORT_MAX]. */
8
+ function hashToPort(str) {
9
+ let hash = 5381;
10
+ for (let i = 0; i < str.length; i++) hash = (hash << 5) + hash + str.charCodeAt(i) | 0;
11
+ return PORT_MIN + (hash % PORT_RANGE + PORT_RANGE) % PORT_RANGE;
12
+ }
6
13
  var clientIdCounter = 0;
7
14
  var DevtoolsServer = class {
8
15
  httpServer = null;
@@ -11,7 +18,8 @@ var DevtoolsServer = class {
11
18
  actualPort = null;
12
19
  onConnectCb = null;
13
20
  onMessageCb = null;
14
- constructor(port) {
21
+ constructor(port, uuid) {
22
+ this.uuid = uuid;
15
23
  this.port = port;
16
24
  }
17
25
  /** Set a callback invoked when a new browser client connects via SSE. */
@@ -22,10 +30,11 @@ var DevtoolsServer = class {
22
30
  setOnMessage(cb) {
23
31
  this.onMessageCb = cb;
24
32
  }
25
- /** Start listening. Tries the configured port, then random ports in range on EADDRINUSE. */
33
+ /** Start listening. Tries the configured port, then sequential ports in range on EADDRINUSE. */
26
34
  async start() {
27
35
  let port = this.port;
28
36
  let retries = 0;
37
+ const baseOffset = hashToPort(this.uuid) - PORT_MIN;
29
38
  while (retries < MAX_RETRIES) try {
30
39
  await this.listen(port);
31
40
  this.actualPort = port;
@@ -34,7 +43,7 @@ var DevtoolsServer = class {
34
43
  } catch (err) {
35
44
  if (err.code === "EADDRINUSE") {
36
45
  retries++;
37
- port = PORT_MIN + Math.floor(Math.random() * (PORT_MAX - PORT_MIN + 1));
46
+ port = PORT_MIN + (baseOffset + retries) % PORT_RANGE;
38
47
  continue;
39
48
  }
40
49
  throw err;
@@ -180,4 +189,5 @@ var DevtoolsServer = class {
180
189
  });
181
190
  }
182
191
  };
183
- export { DevtoolsServer };
192
+ //#endregion
193
+ export { DevtoolsServer, hashToPort };
@@ -1,6 +1,7 @@
1
1
  import { dirname, resolve } from "node:path";
2
2
  import { createRequire } from "node:module";
3
3
  import { readFileSync, realpathSync } from "node:fs";
4
+ //#region src/font-inline.ts
4
5
  var FONT_RE = /\.(ttf|otf|woff2?)$/;
5
6
  /**
6
7
  * Returns `true` when the given module specifier or resolved id looks like
@@ -44,4 +45,5 @@ function safeRealpath(p) {
44
45
  return null;
45
46
  }
46
47
  }
48
+ //#endregion
47
49
  export { loadFont, resolveFontId };
@@ -1,5 +1,6 @@
1
1
  import { ActionContext, CanvasContext, DeviceContext, StreamDeckContext } from "../context/providers.js";
2
2
  import { useContext } from "react";
3
+ //#region src/hooks/context.ts
3
4
  function useDevice() {
4
5
  return useContext(DeviceContext);
5
6
  }
@@ -12,4 +13,5 @@ function useCanvas() {
12
13
  function useStreamDeck() {
13
14
  return useContext(StreamDeckContext);
14
15
  }
16
+ //#endregion
15
17
  export { useAction, useCanvas, useDevice, useStreamDeck };
@@ -1,6 +1,7 @@
1
1
  import { EventBusContext, StreamDeckContext } from "../context/providers.js";
2
2
  import { useCallbackRef } from "./internal/useCallbackRef.js";
3
3
  import { useContext, useEffect, useRef } from "react";
4
+ //#region src/hooks/events.ts
4
5
  function useEvent(event, callback) {
5
6
  const bus = useContext(EventBusContext);
6
7
  const callbackRef = useCallbackRef(callback);
@@ -55,4 +56,5 @@ function useDialHint(hints) {
55
56
  hints.longTouch
56
57
  ]);
57
58
  }
59
+ //#endregion
58
60
  export { useDialDown, useDialHint, useDialRotate, useDialUp, useKeyDown, useKeyUp, useTouchTap };
@@ -8,7 +8,7 @@ export interface LongPressOptions {
8
8
  timeout?: number;
9
9
  }
10
10
  export interface DoubleTapOptions {
11
- /** Max milliseconds between two key-up events. @default 300 */
11
+ /** Max milliseconds between two key-up events. @default 250 */
12
12
  timeout?: number;
13
13
  }
14
14
  export declare function useTap(callback: (payload: KeyUpPayload) => void, options?: TapOptions): void;
@@ -1,6 +1,7 @@
1
1
  import { EventBusContext } from "../context/providers.js";
2
2
  import { useCallbackRef } from "./internal/useCallbackRef.js";
3
3
  import { useContext, useEffect, useRef } from "react";
4
+ //#region src/hooks/gestures.ts
4
5
  var DEFAULT_LONG_PRESS_TIMEOUT = 500;
5
6
  var DEFAULT_DOUBLE_TAP_TIMEOUT = 250;
6
7
  var TapGate = class {
@@ -137,4 +138,5 @@ function useDoubleTap(callback, options) {
137
138
  timeout
138
139
  ]);
139
140
  }
141
+ //#endregion
140
142
  export { useDoubleTap, useLongPress, useTap };
@@ -1,4 +1,5 @@
1
1
  import { useEffect, useRef } from "react";
2
+ //#region src/hooks/internal/useCallbackRef.ts
2
3
  function useCallbackRef(callback) {
3
4
  const callbackRef = useRef(callback);
4
5
  useEffect(() => {
@@ -6,4 +7,5 @@ function useCallbackRef(callback) {
6
7
  });
7
8
  return callbackRef;
8
9
  }
10
+ //#endregion
9
11
  export { useCallbackRef };
@@ -1,6 +1,7 @@
1
1
  import { EventBusContext } from "../context/providers.js";
2
2
  import { useCallbackRef } from "./internal/useCallbackRef.js";
3
3
  import { useContext, useEffect } from "react";
4
+ //#region src/hooks/lifecycle.ts
4
5
  function useWillAppear(callback) {
5
6
  const bus = useContext(EventBusContext);
6
7
  const callbackRef = useCallbackRef(callback);
@@ -23,4 +24,5 @@ function useWillDisappear(callback) {
23
24
  return () => bus.off("willDisappear", handler);
24
25
  }, [bus, callbackRef]);
25
26
  }
27
+ //#endregion
26
28
  export { useWillAppear, useWillDisappear };
package/dist/hooks/sdk.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { EventBusContext, StreamDeckContext } from "../context/providers.js";
2
2
  import { useCallbackRef } from "./internal/useCallbackRef.js";
3
3
  import { useCallback, useContext, useEffect } from "react";
4
+ //#region src/hooks/sdk.ts
4
5
  function useOpenUrl() {
5
6
  const { sdk } = useContext(StreamDeckContext);
6
7
  return useCallback(async (url) => {
@@ -49,4 +50,5 @@ function useTitle() {
49
50
  if ("setTitle" in action) await action.setTitle(title);
50
51
  }, [action]);
51
52
  }
53
+ //#endregion
52
54
  export { useOpenUrl, usePropertyInspector, useSendToPI, useShowAlert, useShowOk, useSwitchProfile, useTitle };
@@ -1,5 +1,6 @@
1
1
  import { GlobalSettingsContext, SettingsContext } from "../context/providers.js";
2
2
  import { useCallback, useContext } from "react";
3
+ //#region src/hooks/settings.ts
3
4
  function useSettings() {
4
5
  const ctx = useContext(SettingsContext);
5
6
  const setSettings = useCallback((partial) => {
@@ -14,4 +15,5 @@ function useGlobalSettings() {
14
15
  }, [ctx]);
15
16
  return [ctx.settings, setSettings];
16
17
  }
18
+ //#endregion
17
19
  export { useGlobalSettings, useSettings };
@@ -2,6 +2,7 @@ import { EventBusContext } from "../context/providers.js";
2
2
  import { TouchBarContext } from "../context/touchbar-context.js";
3
3
  import { useCallbackRef } from "./internal/useCallbackRef.js";
4
4
  import { useContext, useEffect } from "react";
5
+ //#region src/hooks/touchbar.ts
5
6
  function useTouchBarEvent(event, callback) {
6
7
  const bus = useContext(EventBusContext);
7
8
  const callbackRef = useCallbackRef(callback);
@@ -32,4 +33,5 @@ function useTouchBarDialDown(callback) {
32
33
  function useTouchBarDialUp(callback) {
33
34
  useTouchBarEvent("touchBarDialUp", callback);
34
35
  }
36
+ //#endregion
35
37
  export { useTouchBar, useTouchBarDialDown, useTouchBarDialRotate, useTouchBarDialUp, useTouchBarTap };
@@ -1,5 +1,6 @@
1
1
  import { useCallbackRef } from "./internal/useCallbackRef.js";
2
2
  import { useCallback, useEffect, useMemo, useRef } from "react";
3
+ //#region src/hooks/utility.ts
3
4
  var DEFAULT_TICK_FPS = 60;
4
5
  function toTickIntervalMs(fps) {
5
6
  if (!Number.isFinite(fps) || fps <= 0) return Math.round(1e3 / DEFAULT_TICK_FPS);
@@ -97,4 +98,5 @@ function useTick(callback, fpsOrActive = DEFAULT_TICK_FPS) {
97
98
  callbackRef.current(delta);
98
99
  }, delayMs);
99
100
  }
101
+ //#endregion
100
102
  export { useInterval, usePrevious, useTick, useTimeout };
package/dist/plugin.js CHANGED
@@ -2,6 +2,7 @@ import { RootRegistry } from "./roots/registry.js";
2
2
  import { startDevtoolsServer } from "./devtools/index.js";
3
3
  import streamDeck, { SingletonAction } from "@elgato/streamdeck";
4
4
  import { Renderer } from "@takumi-rs/core";
5
+ //#region src/plugin.ts
5
6
  function createPlugin(config) {
6
7
  const renderConfig = {
7
8
  renderer: new Renderer({ fonts: config.fonts.map((f) => ({
@@ -30,7 +31,6 @@ function createPlugin(config) {
30
31
  streamDeck.actions.registerAction(singletonAction);
31
32
  }
32
33
  if (config.devtools) startDevtoolsServer({
33
- port: config.devtoolsPort,
34
34
  devtoolsName: streamDeck.info.plugin.uuid,
35
35
  registry,
36
36
  renderConfig
@@ -174,4 +174,5 @@ function createSingletonAction(definition, registry, onError) {
174
174
  }
175
175
  }();
176
176
  }
177
+ //#endregion
177
178
  export { createPlugin };
@@ -1,8 +1,9 @@
1
1
  import { createTextVNode, createVNode } from "./vnode.js";
2
2
  import { createContext } from "react";
3
3
  import { DefaultEventPriority } from "react-reconciler/constants.js";
4
+ //#region src/reconciler/host-config.ts
4
5
  var NO_CONTEXT = {};
5
- const hostConfig = {
6
+ var hostConfig = {
6
7
  supportsMutation: true,
7
8
  supportsPersistence: false,
8
9
  supportsHydration: false,
@@ -122,4 +123,5 @@ const hostConfig = {
122
123
  scheduleMicrotask: queueMicrotask,
123
124
  preparePortalMount: () => {}
124
125
  };
126
+ //#endregion
125
127
  export { hostConfig };
@@ -1,9 +1,11 @@
1
1
  import { hostConfig } from "./host-config.js";
2
2
  import Reconciler from "react-reconciler";
3
- const reconciler = Reconciler(hostConfig);
3
+ //#region src/reconciler/renderer.ts
4
+ var reconciler = Reconciler(hostConfig);
4
5
  reconciler.injectIntoDevTools({
5
6
  bundleType: process.env.NODE_ENV === "production" ? 0 : 1,
6
7
  rendererPackageName: "@fcannizzaro/streamdeck-react",
7
8
  version: "0.1.0"
8
9
  });
10
+ //#endregion
9
11
  export { reconciler };
@@ -1,4 +1,5 @@
1
1
  import { createElement } from "react";
2
+ //#region src/reconciler/vnode.ts
2
3
  function createVNode(type, props) {
3
4
  return {
4
5
  type,
@@ -30,4 +31,5 @@ function vnodeToElement(node) {
30
31
  const childElements = node.children.map(vnodeToElement);
31
32
  return createElement(node.type, restProps, ...childElements);
32
33
  }
34
+ //#endregion
33
35
  export { createTextVNode, createVContainer, createVNode, vnodeToElement };
@@ -1,3 +1,4 @@
1
+ //#region src/render/cache.ts
1
2
  function fnv1a(input) {
2
3
  let hash = 2166136261;
3
4
  if (typeof input === "string") for (let i = 0; i < input.length; i++) {
@@ -10,4 +11,5 @@ function fnv1a(input) {
10
11
  }
11
12
  return hash >>> 0;
12
13
  }
14
+ //#endregion
13
15
  export { fnv1a };
@@ -3,6 +3,7 @@ import { fnv1a } from "./cache.js";
3
3
  import { encodePng } from "./png.js";
4
4
  import { createElement } from "react";
5
5
  import { fromJsx } from "@takumi-rs/helpers/jsx";
6
+ //#region src/render/pipeline.ts
6
7
  function bufferToDataUri(buffer, format) {
7
8
  return `data:image/${format};base64,${(Buffer.isBuffer(buffer) ? buffer : Buffer.from(buffer)).toString("base64")}`;
8
9
  }
@@ -69,4 +70,5 @@ function cropSlice(raw, fullWidth, column, segmentWidth, segmentHeight) {
69
70
  function sliceToDataUri(raw, fullWidth, fullHeight, column, segmentWidth, segmentHeight) {
70
71
  return bufferToDataUri(encodePng(segmentWidth, segmentHeight, cropSlice(raw, fullWidth, column, segmentWidth, segmentHeight)), "png");
71
72
  }
73
+ //#endregion
72
74
  export { bufferToDataUri, renderToDataUri, renderToRaw, sliceToDataUri };
@@ -1,4 +1,5 @@
1
1
  import { deflateSync } from "node:zlib";
2
+ //#region src/render/png.ts
2
3
  var crcTable = new Uint32Array(256);
3
4
  for (let n = 0; n < 256; n++) {
4
5
  let c = n;
@@ -66,4 +67,5 @@ function encodePng(width, height, rgba) {
66
67
  pngChunk("IEND", Buffer.alloc(0))
67
68
  ]);
68
69
  }
70
+ //#endregion
69
71
  export { encodePng };
package/dist/rollup.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { NOOP_DEVTOOLS_CODE, NOOP_DEVTOOLS_ID, copyNativeBindings, isDevelopmentMode, isLibraryDevtoolsImport, shouldStripDevtools } from "./bundler-shared.js";
2
2
  import { loadFont, resolveFontId } from "./font-inline.js";
3
3
  import { dirname } from "node:path";
4
+ //#region src/rollup.ts
4
5
  /**
5
6
  * Rollup plugin that copies the `@takumi-rs/core` platform-specific native
6
7
  * binding (`.node` file) into the bundle output directory so the Stream Deck
@@ -41,4 +42,5 @@ function streamDeckReact(options = {}) {
41
42
  }
42
43
  };
43
44
  }
45
+ //#endregion
44
46
  export { streamDeckReact };
@@ -1,5 +1,6 @@
1
1
  import { ReactRoot } from "./root.js";
2
2
  import { TouchBarRoot } from "./touchbar-root.js";
3
+ //#region src/roots/registry.ts
3
4
  var SEGMENT_WIDTH = 200;
4
5
  var KEY_SIZES = {
5
6
  0: {
@@ -255,4 +256,5 @@ var RootRegistry = class {
255
256
  this.touchBarActions.clear();
256
257
  }
257
258
  };
259
+ //#endregion
258
260
  export { RootRegistry };
@@ -4,6 +4,7 @@ import { renderToDataUri } from "../render/pipeline.js";
4
4
  import { EventBus } from "../context/event-bus.js";
5
5
  import { ActionContext, CanvasContext, DeviceContext, EventBusContext, GlobalSettingsContext, SettingsContext, StreamDeckContext } from "../context/providers.js";
6
6
  import { createElement } from "react";
7
+ //#region src/roots/root.ts
7
8
  var DEFAULT_DIAL_LAYOUT = {
8
9
  id: "com.example.plugin.react-layout",
9
10
  items: [{
@@ -195,4 +196,5 @@ function resolveDialLayout(layout) {
195
196
  items: DEFAULT_DIAL_LAYOUT.items.map((item) => ({ ...item }))
196
197
  };
197
198
  }
199
+ //#endregion
198
200
  export { ReactRoot };
@@ -5,6 +5,7 @@ import { EventBus } from "../context/event-bus.js";
5
5
  import { DeviceContext, EventBusContext, GlobalSettingsContext } from "../context/providers.js";
6
6
  import { TouchBarContext } from "../context/touchbar-context.js";
7
7
  import { createElement } from "react";
8
+ //#region src/roots/touchbar-root.ts
8
9
  var SEGMENT_WIDTH = 200;
9
10
  var SEGMENT_HEIGHT = 100;
10
11
  var DEFAULT_TOUCHBAR_FPS = 60;
@@ -170,4 +171,5 @@ var TouchBarRoot = class {
170
171
  this.columns.clear();
171
172
  }
172
173
  };
174
+ //#endregion
173
175
  export { TouchBarRoot };
package/dist/tw/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ //#region src/tw/index.ts
1
2
  /**
2
3
  * Concatenates Tailwind class strings, filtering out falsy values.
3
4
  *
@@ -9,4 +10,5 @@
9
10
  function tw(...args) {
10
11
  return args.filter(Boolean).join(" ");
11
12
  }
13
+ //#endregion
12
14
  export { tw };
package/dist/types.d.ts CHANGED
@@ -72,8 +72,6 @@ export interface PluginConfig {
72
72
  onActionError?: (uuid: string, actionId: string, error: Error) => void;
73
73
  /** Enable the devtools WebSocket server. Browser devtools UI discovers it via port scanning. @default false */
74
74
  devtools?: boolean;
75
- /** Port for the devtools WebSocket server. If omitted, picks a random port in range 39400-39499. */
76
- devtoolsPort?: number;
77
75
  }
78
76
  export interface Plugin {
79
77
  connect(): Promise<void>;
package/dist/vite.js CHANGED
@@ -2,6 +2,7 @@ import { NOOP_DEVTOOLS_CODE, NOOP_DEVTOOLS_ID, copyNativeBindings, isLibraryDevt
2
2
  import { loadFont, resolveFontId } from "./font-inline.js";
3
3
  import { resolve } from "node:path";
4
4
  import { exec } from "node:child_process";
5
+ //#region src/vite.ts
5
6
  /**
6
7
  * Vite plugin for Stream Deck React projects.
7
8
  *
@@ -49,4 +50,5 @@ function streamDeckReact(options = {}) {
49
50
  }
50
51
  };
51
52
  }
53
+ //#endregion
52
54
  export { streamDeckReact };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fcannizzaro/streamdeck-react",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Build Stream Deck plugins with React — render components directly to keys, dials, and touch screens",
5
5
  "keywords": [
6
6
  "elgato",
@@ -61,8 +61,8 @@
61
61
  },
62
62
  "dependencies": {
63
63
  "@elgato/streamdeck": "^2.0.2",
64
- "@takumi-rs/core": "^0.70.4",
65
- "@takumi-rs/helpers": "^0.70.4",
64
+ "@takumi-rs/core": "^0.71.7",
65
+ "@takumi-rs/helpers": "^0.71.7",
66
66
  "react-reconciler": "^0.33.0"
67
67
  },
68
68
  "devDependencies": {
@@ -72,7 +72,7 @@
72
72
  "@types/react-reconciler": "^0.33.0",
73
73
  "react-dom": "^19.2.4",
74
74
  "rollup": "^4.59.0",
75
- "vite": "8.0.0-beta.16",
75
+ "vite": "8.0.0-beta.18",
76
76
  "vite-plugin-dts": "^4.5.4"
77
77
  },
78
78
  "peerDependencies": {