@decky/ui 4.6.0 → 4.7.1
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/dist/components/Tabs.d.ts +2 -2
- package/dist/components/Tabs.js +2 -47
- package/dist/globals/stores.d.ts +7 -0
- package/dist/modules/Router.js +40 -31
- package/dist/utils/react/fc.js +39 -9
- package/package.json +1 -1
- package/src/components/Tabs.tsx +4 -61
- package/src/globals/stores.ts +7 -0
- package/src/modules/Router.ts +51 -42
- package/src/utils/react/fc.ts +40 -10
- package/src/utils/react/react.ts +4 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
2
|
import { FooterLegendProps } from './FooterLegend';
|
|
3
3
|
export interface Tab {
|
|
4
4
|
id: string;
|
|
@@ -13,4 +13,4 @@ export interface TabsProps {
|
|
|
13
13
|
onShowTab: (tab: string) => void;
|
|
14
14
|
autoFocusContents?: boolean;
|
|
15
15
|
}
|
|
16
|
-
export declare const Tabs:
|
|
16
|
+
export declare const Tabs: any;
|
package/dist/components/Tabs.js
CHANGED
|
@@ -1,48 +1,3 @@
|
|
|
1
|
-
import { createElement, useEffect, useState } from 'react';
|
|
2
|
-
import { fakeRenderComponent, findInReactTree, sleep } from '../utils';
|
|
3
1
|
import { findModuleByExport } from '../webpack';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const getTabs = async () => {
|
|
7
|
-
if (tabsComponent)
|
|
8
|
-
return tabsComponent;
|
|
9
|
-
while (!window?.DeckyPluginLoader?.routerHook?.routes) {
|
|
10
|
-
console.debug('[DFL:Tabs]: Waiting for Decky router...');
|
|
11
|
-
await sleep(500);
|
|
12
|
-
}
|
|
13
|
-
return (tabsComponent = fakeRenderComponent(() => {
|
|
14
|
-
return findInReactTree(findInReactTree(window.DeckyPluginLoader.routerHook.routes
|
|
15
|
-
.find((x) => x.props.path == '/library/app/:appid/achievements')
|
|
16
|
-
.props.children.type(), (x) => x?.props?.scrollTabsTop).type({ appid: 1 }), (x) => x?.props?.tabs).type;
|
|
17
|
-
}, {
|
|
18
|
-
useRef: () => ({ current: { reaction: { track: () => { } } } }),
|
|
19
|
-
useContext: () => ({ match: { params: { appid: 1 } } }),
|
|
20
|
-
useMemo: () => ({ data: {} }),
|
|
21
|
-
}));
|
|
22
|
-
};
|
|
23
|
-
let oldTabs;
|
|
24
|
-
try {
|
|
25
|
-
const oldTabsModule = findModuleByExport((e) => e.Unbleed);
|
|
26
|
-
if (oldTabsModule)
|
|
27
|
-
oldTabs = Object.values(oldTabsModule).find((x) => x?.type?.toString()?.includes('((function(){'));
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
console.error('Error finding oldTabs:', e);
|
|
31
|
-
}
|
|
32
|
-
export const Tabs = (oldTabs ||
|
|
33
|
-
((props) => {
|
|
34
|
-
const found = tabsComponent;
|
|
35
|
-
const [tc, setTC] = useState(found);
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
if (found)
|
|
38
|
-
return;
|
|
39
|
-
(async () => {
|
|
40
|
-
console.debug('[DFL:Tabs]: Finding component...');
|
|
41
|
-
const t = await getTabs();
|
|
42
|
-
console.debug('[DFL:Tabs]: Found!');
|
|
43
|
-
setTC(t);
|
|
44
|
-
})();
|
|
45
|
-
}, []);
|
|
46
|
-
console.log('tc', tc);
|
|
47
|
-
return tc ? createElement(tc, props) : window.SP_REACT.createElement(SteamSpinner, null);
|
|
48
|
-
}));
|
|
2
|
+
const tabsModule = findModuleByExport(e => e?.toString()?.includes(".TabRowTabs") && e?.toString()?.includes("activeTab:"));
|
|
3
|
+
export const Tabs = tabsModule && Object.values(tabsModule).find((e) => e?.type?.toString()?.includes("((function()"));
|
package/dist/globals/stores.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WindowRouter } from '../modules/Router';
|
|
1
2
|
import { AppDetails, LogoPosition, SteamAppOverview } from './SteamClient';
|
|
2
3
|
declare global {
|
|
3
4
|
interface Window {
|
|
@@ -46,5 +47,11 @@ declare global {
|
|
|
46
47
|
GetCustomLogoPosition: (app: SteamAppOverview) => LogoPosition | null;
|
|
47
48
|
SaveCustomLogoPosition: (app: SteamAppOverview, logoPositions: LogoPosition) => any;
|
|
48
49
|
};
|
|
50
|
+
SteamUIStore: {
|
|
51
|
+
GetFocusedWindowInstance: () => WindowRouter;
|
|
52
|
+
};
|
|
53
|
+
securitystore: {
|
|
54
|
+
IsLockScreenActive: () => boolean;
|
|
55
|
+
};
|
|
49
56
|
}
|
|
50
57
|
}
|
package/dist/modules/Router.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Logger from '../logger';
|
|
2
2
|
import { findModuleExport } from '../webpack';
|
|
3
3
|
export var SideMenu;
|
|
4
4
|
(function (SideMenu) {
|
|
@@ -59,44 +59,53 @@ export var DisplayStatus;
|
|
|
59
59
|
})(DisplayStatus || (DisplayStatus = {}));
|
|
60
60
|
export const Router = findModuleExport((e) => e.Navigate && e.NavigationManager);
|
|
61
61
|
export let Navigation = {};
|
|
62
|
+
const logger = new Logger("Navigation");
|
|
62
63
|
try {
|
|
63
|
-
(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
function createNavigationFunction(fncName, handler) {
|
|
65
|
+
return (...args) => {
|
|
66
|
+
let win;
|
|
67
|
+
try {
|
|
68
|
+
win = window.SteamUIStore.GetFocusedWindowInstance();
|
|
69
|
+
}
|
|
70
|
+
catch (e) {
|
|
71
|
+
logger.warn("Navigation interface failed to call GetFocusedWindowInstance", e);
|
|
72
|
+
}
|
|
73
|
+
if (!win) {
|
|
74
|
+
logger.warn("Navigation interface could not find any focused window. Falling back to GamepadUIMainWindowInstance");
|
|
75
|
+
win = Router.WindowStore?.GamepadUIMainWindowInstance;
|
|
76
|
+
}
|
|
77
|
+
if (win) {
|
|
67
78
|
try {
|
|
68
|
-
|
|
79
|
+
const thisObj = handler && handler(win);
|
|
80
|
+
(thisObj || win)[fncName](...args);
|
|
69
81
|
}
|
|
70
82
|
catch (e) {
|
|
71
|
-
|
|
83
|
+
logger.error("Navigation handler failed", e);
|
|
72
84
|
}
|
|
73
85
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
console.log('[DFL:Router]: Trying to init internal navigators again');
|
|
77
|
-
await sleep(2000);
|
|
78
|
-
initInternalNavigators();
|
|
86
|
+
else {
|
|
87
|
+
logger.error("Navigation interface could not find a window to navigate");
|
|
79
88
|
}
|
|
80
|
-
}
|
|
81
|
-
const newNavigation = {
|
|
82
|
-
Navigate: Router.Navigate?.bind(Router),
|
|
83
|
-
NavigateBack: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateBack?.bind(Router.WindowStore.GamepadUIMainWindowInstance),
|
|
84
|
-
NavigateToAppProperties: InternalNavigators?.AppProperties || Router.NavigateToAppProperties?.bind(Router),
|
|
85
|
-
NavigateToExternalWeb: InternalNavigators?.ExternalWeb || Router.NavigateToExternalWeb?.bind(Router),
|
|
86
|
-
NavigateToInvites: InternalNavigators?.Invites || Router.NavigateToInvites?.bind(Router),
|
|
87
|
-
NavigateToChat: InternalNavigators?.Chat || Router.NavigateToChat?.bind(Router),
|
|
88
|
-
NavigateToLibraryTab: InternalNavigators?.LibraryTab || Router.NavigateToLibraryTab?.bind(Router),
|
|
89
|
-
NavigateToLayoutPreview: Router.NavigateToLayoutPreview?.bind(Router),
|
|
90
|
-
NavigateToSteamWeb: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateToSteamWeb?.bind(Router.WindowStore.GamepadUIMainWindowInstance),
|
|
91
|
-
OpenSideMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenSideMenu?.bind(Router.WindowStore.GamepadUIMainWindowInstance.MenuStore),
|
|
92
|
-
OpenQuickAccessMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenQuickAccessMenu?.bind(Router.WindowStore.GamepadUIMainWindowInstance.MenuStore),
|
|
93
|
-
OpenMainMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenMainMenu?.bind(Router.WindowStore.GamepadUIMainWindowInstance.MenuStore),
|
|
94
|
-
CloseSideMenus: Router.CloseSideMenus?.bind(Router),
|
|
95
|
-
OpenPowerMenu: Router.OpenPowerMenu?.bind(Router),
|
|
96
89
|
};
|
|
97
|
-
|
|
98
|
-
|
|
90
|
+
}
|
|
91
|
+
const newNavigation = {
|
|
92
|
+
Navigate: createNavigationFunction("Navigate"),
|
|
93
|
+
NavigateBack: createNavigationFunction("NavigateBack"),
|
|
94
|
+
NavigateToAppProperties: createNavigationFunction("AppProperties", win => win.Navigator),
|
|
95
|
+
NavigateToExternalWeb: createNavigationFunction("ExternalWeb", win => win.Navigator),
|
|
96
|
+
NavigateToInvites: createNavigationFunction("Invites", win => win.Navigator),
|
|
97
|
+
NavigateToChat: createNavigationFunction("Chat", win => win.Navigator),
|
|
98
|
+
NavigateToLibraryTab: createNavigationFunction("LibraryTab", win => win.Navigator),
|
|
99
|
+
NavigateToLayoutPreview: Router.NavigateToLayoutPreview?.bind(Router),
|
|
100
|
+
NavigateToSteamWeb: createNavigationFunction("NavigateToSteamWeb"),
|
|
101
|
+
OpenSideMenu: createNavigationFunction("OpenSideMenu", win => win.MenuStore),
|
|
102
|
+
OpenQuickAccessMenu: createNavigationFunction("OpenQuickAccessMenu", win => win.MenuStore),
|
|
103
|
+
OpenMainMenu: createNavigationFunction("OpenMainMenu", win => win.MenuStore),
|
|
104
|
+
CloseSideMenus: createNavigationFunction("CloseSideMenus", win => win.MenuStore),
|
|
105
|
+
OpenPowerMenu: Router.OpenPowerMenu?.bind(Router),
|
|
106
|
+
};
|
|
107
|
+
Object.assign(Navigation, newNavigation);
|
|
99
108
|
}
|
|
100
109
|
catch (e) {
|
|
101
|
-
|
|
110
|
+
logger.error('Error initializing Navigation interface', e);
|
|
102
111
|
}
|
package/dist/utils/react/fc.js
CHANGED
|
@@ -25,6 +25,7 @@ export function injectFCTrampoline(component, customHooks) {
|
|
|
25
25
|
applyHookStubs(customHooks);
|
|
26
26
|
window.SP_REACT.createElement = () => {
|
|
27
27
|
loggingEnabled && logger.debug("createElement hook called");
|
|
28
|
+
loggingEnabled && console.trace("createElement trace");
|
|
28
29
|
return Object.create(component.prototype);
|
|
29
30
|
};
|
|
30
31
|
}
|
|
@@ -37,26 +38,36 @@ export function injectFCTrampoline(component, customHooks) {
|
|
|
37
38
|
window.SP_REACT.createElement = oldCreateElement;
|
|
38
39
|
}
|
|
39
40
|
};
|
|
41
|
+
let renderHookStep = 0;
|
|
40
42
|
Object.defineProperty(component, "contextType", {
|
|
41
43
|
configurable: true,
|
|
42
44
|
get: function () {
|
|
43
|
-
loggingEnabled && logger.debug("get contexttype", this, stubsApplied);
|
|
44
|
-
|
|
45
|
+
loggingEnabled && logger.debug("get contexttype", this, stubsApplied, renderHookStep);
|
|
46
|
+
loggingEnabled && console.trace("contextType trace");
|
|
47
|
+
if (renderHookStep == 0)
|
|
48
|
+
renderHookStep = 1;
|
|
49
|
+
else if (renderHookStep == 3)
|
|
50
|
+
renderHookStep = 4;
|
|
45
51
|
return this._contextType;
|
|
46
52
|
},
|
|
47
53
|
set: function (value) {
|
|
48
54
|
this._contextType = value;
|
|
49
55
|
}
|
|
50
56
|
});
|
|
51
|
-
Object.defineProperty(component, "
|
|
57
|
+
Object.defineProperty(component, "contextTypes", {
|
|
52
58
|
configurable: true,
|
|
53
59
|
get: function () {
|
|
54
|
-
loggingEnabled && logger.debug("get
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
loggingEnabled && logger.debug("get contexttypes", this, stubsApplied, renderHookStep);
|
|
61
|
+
loggingEnabled && console.trace("contextTypes trace");
|
|
62
|
+
if (renderHookStep == 1) {
|
|
63
|
+
renderHookStep = 2;
|
|
64
|
+
applyStubsIfNeeded();
|
|
65
|
+
}
|
|
66
|
+
;
|
|
67
|
+
return this._contextTypes;
|
|
57
68
|
},
|
|
58
69
|
set: function (value) {
|
|
59
|
-
this.
|
|
70
|
+
this._contextTypes = value;
|
|
60
71
|
}
|
|
61
72
|
});
|
|
62
73
|
Object.defineProperty(component.prototype, "updater", {
|
|
@@ -65,10 +76,29 @@ export function injectFCTrampoline(component, customHooks) {
|
|
|
65
76
|
return this._updater;
|
|
66
77
|
},
|
|
67
78
|
set: function (value) {
|
|
68
|
-
loggingEnabled && logger.debug("set updater", this, value, stubsApplied);
|
|
69
|
-
|
|
79
|
+
loggingEnabled && logger.debug("set updater", this, value, stubsApplied, renderHookStep);
|
|
80
|
+
loggingEnabled && console.trace("updater trace");
|
|
81
|
+
if (renderHookStep == 2) {
|
|
82
|
+
renderHookStep = 0;
|
|
83
|
+
removeStubsIfNeeded();
|
|
84
|
+
}
|
|
70
85
|
return this._updater = value;
|
|
71
86
|
}
|
|
72
87
|
});
|
|
88
|
+
Object.defineProperty(component, "getDerivedStateFromProps", {
|
|
89
|
+
configurable: true,
|
|
90
|
+
get: function () {
|
|
91
|
+
loggingEnabled && logger.debug("get getDerivedStateFromProps", this, stubsApplied, renderHookStep);
|
|
92
|
+
loggingEnabled && console.trace("getDerivedStateFromProps trace");
|
|
93
|
+
if (renderHookStep == 2) {
|
|
94
|
+
renderHookStep = 0;
|
|
95
|
+
removeStubsIfNeeded();
|
|
96
|
+
}
|
|
97
|
+
return this._getDerivedStateFromProps;
|
|
98
|
+
},
|
|
99
|
+
set: function (value) {
|
|
100
|
+
this._getDerivedStateFromProps = value;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
73
103
|
return userComponent;
|
|
74
104
|
}
|
package/package.json
CHANGED
package/src/components/Tabs.tsx
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import { FC, ReactNode
|
|
2
|
-
|
|
3
|
-
import { fakeRenderComponent, findInReactTree, sleep } from '../utils';
|
|
4
|
-
import { Export, findModuleByExport } from '../webpack';
|
|
1
|
+
import { FC, ReactNode } from 'react';
|
|
2
|
+
import { findModuleByExport } from '../webpack';
|
|
5
3
|
import { FooterLegendProps } from './FooterLegend';
|
|
6
|
-
import { SteamSpinner } from './SteamSpinner';
|
|
7
4
|
|
|
8
5
|
/**
|
|
9
6
|
* Individual tab objects for the Tabs component
|
|
@@ -65,63 +62,9 @@ export interface TabsProps {
|
|
|
65
62
|
autoFocusContents?: boolean;
|
|
66
63
|
}
|
|
67
64
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const getTabs = async () => {
|
|
71
|
-
if (tabsComponent) return tabsComponent;
|
|
72
|
-
// @ts-ignore
|
|
73
|
-
while (!window?.DeckyPluginLoader?.routerHook?.routes) {
|
|
74
|
-
console.debug('[DFL:Tabs]: Waiting for Decky router...');
|
|
75
|
-
await sleep(500);
|
|
76
|
-
}
|
|
77
|
-
return (tabsComponent = fakeRenderComponent(
|
|
78
|
-
() => {
|
|
79
|
-
return findInReactTree(
|
|
80
|
-
findInReactTree(
|
|
81
|
-
// @ts-ignore
|
|
82
|
-
window.DeckyPluginLoader.routerHook.routes
|
|
83
|
-
.find((x: any) => x.props.path == '/library/app/:appid/achievements')
|
|
84
|
-
.props.children.type(),
|
|
85
|
-
(x) => x?.props?.scrollTabsTop,
|
|
86
|
-
).type({ appid: 1 }),
|
|
87
|
-
(x) => x?.props?.tabs,
|
|
88
|
-
).type;
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
useRef: () => ({ current: { reaction: { track: () => {} } } }),
|
|
92
|
-
useContext: () => ({ match: { params: { appid: 1 } } }),
|
|
93
|
-
useMemo: () => ({ data: {} }),
|
|
94
|
-
},
|
|
95
|
-
));
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
let oldTabs: any;
|
|
99
|
-
|
|
100
|
-
try {
|
|
101
|
-
const oldTabsModule = findModuleByExport((e: Export) => e.Unbleed);
|
|
102
|
-
if (oldTabsModule)
|
|
103
|
-
oldTabs = Object.values(oldTabsModule).find((x: any) => x?.type?.toString()?.includes('((function(){'));
|
|
104
|
-
} catch (e) {
|
|
105
|
-
console.error('Error finding oldTabs:', e);
|
|
106
|
-
}
|
|
65
|
+
const tabsModule = findModuleByExport(e => e?.toString()?.includes(".TabRowTabs") && e?.toString()?.includes("activeTab:"));
|
|
107
66
|
|
|
108
67
|
/**
|
|
109
68
|
* Tabs component as used in the library and media tabs. See {@link TabsProps}.
|
|
110
|
-
* Unlike other components in `decky-frontend-lib`, this requires Decky Loader to be running.
|
|
111
69
|
*/
|
|
112
|
-
export const Tabs = (
|
|
113
|
-
((props: TabsProps) => {
|
|
114
|
-
const found = tabsComponent;
|
|
115
|
-
const [tc, setTC] = useState<FC<TabsProps>>(found);
|
|
116
|
-
useEffect(() => {
|
|
117
|
-
if (found) return;
|
|
118
|
-
(async () => {
|
|
119
|
-
console.debug('[DFL:Tabs]: Finding component...');
|
|
120
|
-
const t = await getTabs();
|
|
121
|
-
console.debug('[DFL:Tabs]: Found!');
|
|
122
|
-
setTC(t);
|
|
123
|
-
})();
|
|
124
|
-
}, []);
|
|
125
|
-
console.log('tc', tc);
|
|
126
|
-
return tc ? createElement(tc, props) : <SteamSpinner />;
|
|
127
|
-
})) as FC<TabsProps>;
|
|
70
|
+
export const Tabs = tabsModule && Object.values(tabsModule).find((e: any) => e?.type?.toString()?.includes("((function()")) as FC<TabsProps>;
|
package/src/globals/stores.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WindowRouter } from '../modules/Router';
|
|
1
2
|
import { AppDetails, LogoPosition, SteamAppOverview } from './SteamClient';
|
|
2
3
|
declare global {
|
|
3
4
|
interface Window {
|
|
@@ -46,5 +47,11 @@ declare global {
|
|
|
46
47
|
GetCustomLogoPosition: (app: SteamAppOverview) => LogoPosition | null;
|
|
47
48
|
SaveCustomLogoPosition: (app: SteamAppOverview, logoPositions: LogoPosition) => any;
|
|
48
49
|
};
|
|
50
|
+
SteamUIStore: {
|
|
51
|
+
GetFocusedWindowInstance: () => WindowRouter;
|
|
52
|
+
};
|
|
53
|
+
securitystore: {
|
|
54
|
+
IsLockScreenActive: () => boolean;
|
|
55
|
+
};
|
|
49
56
|
}
|
|
50
57
|
}
|
package/src/modules/Router.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Logger from '../logger';
|
|
2
2
|
import { Export, findModuleExport } from '../webpack';
|
|
3
3
|
|
|
4
4
|
export enum SideMenu {
|
|
@@ -88,14 +88,23 @@ export interface WindowStore {
|
|
|
88
88
|
|
|
89
89
|
export interface Router {
|
|
90
90
|
WindowStore?: WindowStore;
|
|
91
|
+
/** @deprecated use {@link Navigation} instead */
|
|
91
92
|
CloseSideMenus(): void;
|
|
93
|
+
/** @deprecated use {@link Navigation} instead */
|
|
92
94
|
Navigate(path: string): void;
|
|
95
|
+
/** @deprecated use {@link Navigation} instead */
|
|
93
96
|
NavigateToAppProperties(): void;
|
|
97
|
+
/** @deprecated use {@link Navigation} instead */
|
|
94
98
|
NavigateToExternalWeb(url: string): void;
|
|
99
|
+
/** @deprecated use {@link Navigation} instead */
|
|
95
100
|
NavigateToInvites(): void;
|
|
101
|
+
/** @deprecated use {@link Navigation} instead */
|
|
96
102
|
NavigateToChat(): void;
|
|
103
|
+
/** @deprecated use {@link Navigation} instead */
|
|
97
104
|
NavigateToLibraryTab(): void;
|
|
105
|
+
/** @deprecated use {@link Navigation} instead */
|
|
98
106
|
NavigateToLayoutPreview(e: unknown): void;
|
|
107
|
+
/** @deprecated use {@link Navigation} instead */
|
|
99
108
|
OpenPowerMenu(unknown?: any): void;
|
|
100
109
|
get RunningApps(): AppOverview[];
|
|
101
110
|
get MainRunningApp(): AppOverview | undefined;
|
|
@@ -117,58 +126,58 @@ export interface Navigation {
|
|
|
117
126
|
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
|
|
118
127
|
OpenMainMenu(): void;
|
|
119
128
|
OpenPowerMenu(unknown?: any): void;
|
|
129
|
+
/** if calling this to perform navigation, call it after Navigate to prevent a race condition in desktop Big Picture mode that hides the overlay unintentionally */
|
|
120
130
|
CloseSideMenus(): void;
|
|
121
131
|
}
|
|
122
132
|
|
|
123
133
|
export let Navigation = {} as Navigation;
|
|
124
134
|
|
|
135
|
+
const logger = new Logger("Navigation");
|
|
136
|
+
|
|
125
137
|
try {
|
|
126
|
-
(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
138
|
+
function createNavigationFunction(fncName: string, handler?: (win: any) => any) {
|
|
139
|
+
return (...args: any) => {
|
|
140
|
+
let win: WindowRouter | undefined;
|
|
141
|
+
try {
|
|
142
|
+
win = window.SteamUIStore.GetFocusedWindowInstance();
|
|
143
|
+
} catch (e) {
|
|
144
|
+
logger.warn("Navigation interface failed to call GetFocusedWindowInstance", e);
|
|
145
|
+
}
|
|
146
|
+
if (!win) {
|
|
147
|
+
logger.warn("Navigation interface could not find any focused window. Falling back to GamepadUIMainWindowInstance");
|
|
148
|
+
win = Router.WindowStore?.GamepadUIMainWindowInstance;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (win) {
|
|
130
152
|
try {
|
|
131
|
-
|
|
153
|
+
const thisObj = handler && handler(win);
|
|
154
|
+
(thisObj || win)[fncName](...args);
|
|
132
155
|
} catch (e) {
|
|
133
|
-
|
|
156
|
+
logger.error("Navigation handler failed", e);
|
|
134
157
|
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
while (!InternalNavigators?.AppProperties) {
|
|
138
|
-
console.log('[DFL:Router]: Trying to init internal navigators again');
|
|
139
|
-
await sleep(2000);
|
|
140
|
-
initInternalNavigators();
|
|
158
|
+
} else {
|
|
159
|
+
logger.error("Navigation interface could not find a window to navigate");
|
|
141
160
|
}
|
|
142
161
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
OpenQuickAccessMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenQuickAccessMenu?.bind(
|
|
161
|
-
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
|
|
162
|
-
),
|
|
163
|
-
OpenMainMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenMainMenu?.bind(
|
|
164
|
-
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
|
|
165
|
-
),
|
|
166
|
-
CloseSideMenus: Router.CloseSideMenus?.bind(Router),
|
|
167
|
-
OpenPowerMenu: Router.OpenPowerMenu?.bind(Router),
|
|
168
|
-
} as Navigation;
|
|
162
|
+
}
|
|
163
|
+
const newNavigation = {
|
|
164
|
+
Navigate: createNavigationFunction("Navigate"),
|
|
165
|
+
NavigateBack: createNavigationFunction("NavigateBack"),
|
|
166
|
+
NavigateToAppProperties: createNavigationFunction("AppProperties", win => win.Navigator),
|
|
167
|
+
NavigateToExternalWeb: createNavigationFunction("ExternalWeb", win => win.Navigator),
|
|
168
|
+
NavigateToInvites: createNavigationFunction("Invites", win => win.Navigator),
|
|
169
|
+
NavigateToChat: createNavigationFunction("Chat", win => win.Navigator),
|
|
170
|
+
NavigateToLibraryTab: createNavigationFunction("LibraryTab", win => win.Navigator),
|
|
171
|
+
NavigateToLayoutPreview: Router.NavigateToLayoutPreview?.bind(Router),
|
|
172
|
+
NavigateToSteamWeb: createNavigationFunction("NavigateToSteamWeb"),
|
|
173
|
+
OpenSideMenu: createNavigationFunction("OpenSideMenu", win => win.MenuStore),
|
|
174
|
+
OpenQuickAccessMenu: createNavigationFunction("OpenQuickAccessMenu", win => win.MenuStore),
|
|
175
|
+
OpenMainMenu: createNavigationFunction("OpenMainMenu", win => win.MenuStore),
|
|
176
|
+
CloseSideMenus: createNavigationFunction("CloseSideMenus", win => win.MenuStore),
|
|
177
|
+
OpenPowerMenu: Router.OpenPowerMenu?.bind(Router),
|
|
178
|
+
} as Navigation;
|
|
169
179
|
|
|
170
|
-
|
|
171
|
-
})();
|
|
180
|
+
Object.assign(Navigation, newNavigation);
|
|
172
181
|
} catch (e) {
|
|
173
|
-
|
|
182
|
+
logger.error('Error initializing Navigation interface', e);
|
|
174
183
|
}
|
package/src/utils/react/fc.ts
CHANGED
|
@@ -52,6 +52,7 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|
|
52
52
|
// we have to redirect this to return an object with component's prototype as a constructor returning a value overrides its prototype
|
|
53
53
|
window.SP_REACT.createElement = () => {
|
|
54
54
|
loggingEnabled && logger.debug("createElement hook called");
|
|
55
|
+
loggingEnabled && console.trace("createElement trace");
|
|
55
56
|
return Object.create(component.prototype);
|
|
56
57
|
};
|
|
57
58
|
}
|
|
@@ -66,12 +67,16 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
let renderHookStep = 0;
|
|
71
|
+
|
|
69
72
|
// Accessed two times, once directly before class instantiation, and again in some extra logic we don't need to worry about that we hanlde below just in case.
|
|
70
73
|
Object.defineProperty(component, "contextType", {
|
|
71
74
|
configurable: true,
|
|
72
75
|
get: function () {
|
|
73
|
-
loggingEnabled && logger.debug("get contexttype", this, stubsApplied);
|
|
74
|
-
|
|
76
|
+
loggingEnabled && logger.debug("get contexttype", this, stubsApplied, renderHookStep);
|
|
77
|
+
loggingEnabled && console.trace("contextType trace");
|
|
78
|
+
if (renderHookStep == 0) renderHookStep = 1;
|
|
79
|
+
else if (renderHookStep == 3) renderHookStep = 4;
|
|
75
80
|
return this._contextType;
|
|
76
81
|
},
|
|
77
82
|
set: function (value) {
|
|
@@ -79,16 +84,20 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|
|
79
84
|
}
|
|
80
85
|
});
|
|
81
86
|
|
|
82
|
-
//
|
|
83
|
-
Object.defineProperty(component, "
|
|
87
|
+
// Always accessed directly after contextType for the path we want to catch.
|
|
88
|
+
Object.defineProperty(component, "contextTypes", {
|
|
84
89
|
configurable: true,
|
|
85
90
|
get: function () {
|
|
86
|
-
loggingEnabled && logger.debug("get
|
|
87
|
-
|
|
88
|
-
|
|
91
|
+
loggingEnabled && logger.debug("get contexttypes", this, stubsApplied, renderHookStep);
|
|
92
|
+
loggingEnabled && console.trace("contextTypes trace");
|
|
93
|
+
if (renderHookStep == 1) {
|
|
94
|
+
renderHookStep = 2;
|
|
95
|
+
applyStubsIfNeeded();
|
|
96
|
+
};
|
|
97
|
+
return this._contextTypes;
|
|
89
98
|
},
|
|
90
99
|
set: function (value) {
|
|
91
|
-
this.
|
|
100
|
+
this._contextTypes = value;
|
|
92
101
|
}
|
|
93
102
|
});
|
|
94
103
|
|
|
@@ -99,11 +108,32 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|
|
99
108
|
return this._updater;
|
|
100
109
|
},
|
|
101
110
|
set: function (value) {
|
|
102
|
-
loggingEnabled && logger.debug("set updater", this, value, stubsApplied);
|
|
103
|
-
|
|
111
|
+
loggingEnabled && logger.debug("set updater", this, value, stubsApplied, renderHookStep);
|
|
112
|
+
loggingEnabled && console.trace("updater trace");
|
|
113
|
+
if (renderHookStep == 2) {
|
|
114
|
+
renderHookStep = 0;
|
|
115
|
+
removeStubsIfNeeded();
|
|
116
|
+
}
|
|
104
117
|
return this._updater = value;
|
|
105
118
|
}
|
|
106
119
|
});
|
|
107
120
|
|
|
121
|
+
// Prevents the second contextType+contextTypes access from leaving its hooks around
|
|
122
|
+
Object.defineProperty(component, "getDerivedStateFromProps", {
|
|
123
|
+
configurable: true,
|
|
124
|
+
get: function () {
|
|
125
|
+
loggingEnabled && logger.debug("get getDerivedStateFromProps", this, stubsApplied, renderHookStep);
|
|
126
|
+
loggingEnabled && console.trace("getDerivedStateFromProps trace");
|
|
127
|
+
if (renderHookStep == 2) {
|
|
128
|
+
renderHookStep = 0;
|
|
129
|
+
removeStubsIfNeeded();
|
|
130
|
+
}
|
|
131
|
+
return this._getDerivedStateFromProps;
|
|
132
|
+
},
|
|
133
|
+
set: function (value) {
|
|
134
|
+
this._getDerivedStateFromProps = value;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
|
|
108
138
|
return userComponent;
|
|
109
139
|
}
|
package/src/utils/react/react.ts
CHANGED
|
@@ -104,19 +104,15 @@ export function wrapReactClass(node: any, prop: any = 'type') {
|
|
|
104
104
|
|
|
105
105
|
export function getReactRoot(o: HTMLElement | Element | Node) {
|
|
106
106
|
return (
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
// @ts-expect-error 7053
|
|
110
|
-
o['_reactRootContainer']?._internalRoot?.current
|
|
107
|
+
(o as any)[Object.keys(o).find((k) => k.startsWith('__reactContainer$')) as string] ||
|
|
108
|
+
(o as any)['_reactRootContainer']?._internalRoot?.current
|
|
111
109
|
);
|
|
112
110
|
}
|
|
113
111
|
|
|
114
112
|
export function getReactInstance(o: HTMLElement | Element | Node) {
|
|
115
113
|
return (
|
|
116
|
-
|
|
117
|
-
o[Object.keys(o).find((k) => k.startsWith('
|
|
118
|
-
// @ts-expect-error 7053
|
|
119
|
-
o[Object.keys(o).find((k) => k.startsWith('__reactInternalInstance')) as string]
|
|
114
|
+
(o as any)[Object.keys(o).find((k) => k.startsWith('__reactFiber')) as string] ||
|
|
115
|
+
(o as any)[Object.keys(o).find((k) => k.startsWith('__reactInternalInstance')) as string]
|
|
120
116
|
);
|
|
121
117
|
}
|
|
122
118
|
|