@decky/ui 4.7.3 → 4.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,14 +1,7 @@
1
- import { findModule } from '../webpack';
2
- export const DialogCheckbox = Object.values(findModule((m) => {
3
- if (typeof m !== 'object')
4
- return false;
5
- for (const prop in m) {
6
- if (m[prop]?.prototype?.GetPanelElementProps)
7
- return true;
8
- }
9
- return false;
10
- })).find((m) => m?.prototype?.SetChecked &&
11
- m?.prototype?.Toggle &&
12
- m?.prototype?.GetPanelElementProps &&
13
- (m?.prototype?.render?.toString().includes('="DialogCheckbox"') || (m.contextType &&
14
- m.prototype?.render.toString().includes('fallback:'))));
1
+ import { findModuleExport } from '../webpack';
2
+ export const DialogCheckbox = findModuleExport(e => e.prototype &&
3
+ "GetPanelElementProps" in e?.prototype &&
4
+ "SetChecked" in e?.prototype &&
5
+ "Toggle" in e?.prototype &&
6
+ (e?.prototype?.render?.toString().includes('="DialogCheckbox"') || (e.contextType &&
7
+ e.prototype?.render?.toString().includes('fallback:'))));
@@ -5,7 +5,7 @@ export const showModal = (modal, parent, props = {
5
5
  strTitle: 'Decky Dialog',
6
6
  bHideMainWindowForPopouts: false,
7
7
  }) => {
8
- return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
8
+ return showModalRaw(modal, parent || findSP() || window, props.strTitle, props, undefined, {
9
9
  bHideActions: props.bHideActionIcons,
10
10
  });
11
11
  };
@@ -71,8 +71,8 @@ try {
71
71
  logger.warn("Navigation interface failed to call GetFocusedWindowInstance", e);
72
72
  }
73
73
  if (!win) {
74
- logger.warn("Navigation interface could not find any focused window. Falling back to GamepadUIMainWindowInstance");
75
- win = Router.WindowStore?.GamepadUIMainWindowInstance;
74
+ logger.warn("Navigation interface could not find any focused window. Falling back to Main Window Instance");
75
+ win = Router.WindowStore?.GamepadUIMainWindowInstance || Router?.WindowStore?.SteamUIWindows?.[0];
76
76
  }
77
77
  if (win) {
78
78
  try {
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { Ref } from 'react';
2
3
  declare global {
3
4
  interface Window {
4
5
  SP_REACT: typeof React;
@@ -19,3 +20,5 @@ export interface findInTreeOpts {
19
20
  export declare type findInTreeFilter = (element: any) => boolean;
20
21
  export declare const findInTree: (parent: any, filter: findInTreeFilter, opts: findInTreeOpts) => any;
21
22
  export declare const findInReactTree: (node: any, filter: findInTreeFilter) => any;
23
+ export declare function getParentWindow<WindowType = Window>(elem: HTMLElement | null): WindowType | null | undefined;
24
+ export declare function useWindowRef<RefElementType extends HTMLElement, WindowType = Window>(): [Ref<RefElementType>, WindowType | null | undefined];
@@ -2,6 +2,7 @@ var __setFunctionName = (this && this.__setFunctionName) || function (f, name, p
2
2
  if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
3
3
  return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
4
4
  };
5
+ import { useState } from 'react';
5
6
  export function createPropListRegex(propList, fromStart = true) {
6
7
  let regexString = fromStart ? "const\{" : "";
7
8
  propList.forEach((prop, propIdx) => {
@@ -98,3 +99,10 @@ export const findInTree = (parent, filter, opts) => {
98
99
  export const findInReactTree = (node, filter) => findInTree(node, filter, {
99
100
  walkable: ['props', 'children', 'child', 'sibling'],
100
101
  });
102
+ export function getParentWindow(elem) {
103
+ return elem?.ownerDocument?.defaultView;
104
+ }
105
+ export function useWindowRef() {
106
+ const [win, setWin] = useState(null);
107
+ return [(elem) => setWin(getParentWindow(elem)), win];
108
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@decky/ui",
3
- "version": "4.7.3",
3
+ "version": "4.8.0",
4
4
  "description": "A library for interacting with the Steam frontend in Decky plugins and elsewhere.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,6 +1,6 @@
1
1
  import { FC, ReactNode } from 'react';
2
2
 
3
- import { findModule } from '../webpack';
3
+ import { findModuleExport } from '../webpack';
4
4
  import { DialogCommonProps } from './Dialog';
5
5
  import { FooterLegendProps } from './FooterLegend';
6
6
 
@@ -18,22 +18,15 @@ export interface DialogCheckboxProps extends DialogCommonProps, FooterLegendProp
18
18
  onClick?(evt: Event): void;
19
19
  }
20
20
 
21
- export const DialogCheckbox = Object.values(
22
- findModule((m: any) => {
23
- if (typeof m !== 'object') return false;
24
- for (const prop in m) {
25
- if (m[prop]?.prototype?.GetPanelElementProps) return true;
26
- }
27
- return false;
28
- }),
29
- ).find(
30
- (m: any) =>
31
- m?.prototype?.SetChecked &&
32
- m?.prototype?.Toggle &&
33
- m?.prototype?.GetPanelElementProps &&
34
- // beta || stable as of oct 2 2024
35
- (m?.prototype?.render?.toString().includes('="DialogCheckbox"') || (
36
- m.contextType &&
37
- m.prototype?.render.toString().includes('fallback:')
38
- ))
21
+ // Do not access KeyDown, SetChecked, Toggle here as they are getters and accessing them outside of a render breaks them globally
22
+ export const DialogCheckbox = findModuleExport(e =>
23
+ e.prototype &&
24
+ "GetPanelElementProps" in e?.prototype &&
25
+ "SetChecked" in e?.prototype &&
26
+ "Toggle" in e?.prototype &&
27
+ // beta || stable as of oct 2 2024
28
+ (e?.prototype?.render?.toString().includes('="DialogCheckbox"') || (
29
+ e.contextType &&
30
+ e.prototype?.render?.toString().includes('fallback:')
31
+ ))
39
32
  ) as FC<DialogCheckboxProps>;
@@ -50,7 +50,7 @@ export const showModal = (
50
50
  bHideMainWindowForPopouts: false,
51
51
  },
52
52
  ): ShowModalResult => {
53
- return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
53
+ return showModalRaw(modal, parent || findSP() || window, props.strTitle, props, undefined, {
54
54
  bHideActions: props.bHideActionIcons,
55
55
  });
56
56
  };
@@ -144,8 +144,8 @@ try {
144
144
  logger.warn("Navigation interface failed to call GetFocusedWindowInstance", e);
145
145
  }
146
146
  if (!win) {
147
- logger.warn("Navigation interface could not find any focused window. Falling back to GamepadUIMainWindowInstance");
148
- win = Router.WindowStore?.GamepadUIMainWindowInstance;
147
+ logger.warn("Navigation interface could not find any focused window. Falling back to Main Window Instance");
148
+ win = Router.WindowStore?.GamepadUIMainWindowInstance || Router?.WindowStore?.SteamUIWindows?.[0];
149
149
  }
150
150
 
151
151
  if (win) {
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { Ref, useState } from 'react';
2
3
 
3
4
  // this shouldn't need to be redeclared but it does for some reason
4
5
 
@@ -150,3 +151,21 @@ export const findInReactTree = (node: any, filter: findInTreeFilter) =>
150
151
  // Specialised findInTree for React nodes
151
152
  walkable: ['props', 'children', 'child', 'sibling'],
152
153
  });
154
+
155
+ /**
156
+ * Finds the parent window of a DOM element
157
+ */
158
+ export function getParentWindow<WindowType = Window>(elem: HTMLElement | null): WindowType | null | undefined {
159
+ return elem?.ownerDocument?.defaultView as any;
160
+ }
161
+
162
+ /**
163
+ * React hook to find the host window of a component
164
+ * Pass the returned ref into a React element and window will be its host window.
165
+ * @returns [ref, window]
166
+ */
167
+ export function useWindowRef<RefElementType extends HTMLElement, WindowType = Window>(): [Ref<RefElementType>, WindowType | null | undefined] {
168
+ const [win, setWin] = useState<WindowType | null | undefined>(null);
169
+
170
+ return [(elem) => setWin(getParentWindow<WindowType>(elem)), win];
171
+ }