Compare commits

..

19 Commits

Author SHA1 Message Date
semantic-release-bot
6b3db72a14 chore(release): 3.18.8 [CI SKIP] 2023-01-16 01:23:38 +00:00
AAGaming
58b69f0d6c fix(Navigation): fix timing issue in decky-loader 2023-01-15 20:22:54 -05:00
semantic-release-bot
c62102e993 chore(release): 3.18.7 [CI SKIP] 2023-01-16 00:19:36 +00:00
AAGaming
2e66e5a555 fix: un-break navigation on stable 2023-01-15 19:18:47 -05:00
semantic-release-bot
ce525318d8 chore(release): 3.18.6 [CI SKIP] 2023-01-13 02:55:51 +00:00
AAGaming
aac2d520a6 fix(Router): fix Navigation for the millionth time 2023-01-12 21:55:08 -05:00
semantic-release-bot
a656f4e57f chore(release): 3.18.5 [CI SKIP] 2022-12-21 15:57:16 +00:00
noot
0b50f2cf0b fix: fixed prop interfaces (#70) 2022-12-21 10:56:39 -05:00
semantic-release-bot
e48c7bbadd chore(release): 3.18.4 [CI SKIP] 2022-12-16 02:04:28 +00:00
TrainDoctor
727fcc8186 Merge pull request #67 from SteamDeckHomebrew/aa/fix-modals-dec2022
fix(modals): fix ModalRoot again
2022-12-15 18:03:27 -08:00
semantic-release-bot
dc196d53f5 chore(release): 3.18.3 [CI SKIP] 2022-12-12 23:49:39 +00:00
Beebles
f0379e5d19 fix(Router): update Router interface to SteamOS3.4 and add Navigation (#52) 2022-12-12 18:48:52 -05:00
AAGaming
fd94842647 fix(modals): fix ModalRoot again 2022-12-11 19:52:20 -05:00
semantic-release-bot
ef6be8c6ec chore(release): 3.18.2 [CI SKIP] 2022-12-11 20:12:52 +00:00
Lukas Senionis
767dc2fcee fix(useQuickAccessVisible): remove invalid prop access (#66) 2022-12-11 15:12:22 -05:00
semantic-release-bot
52305987c5 chore(release): 3.18.1 [CI SKIP] 2022-12-11 20:02:11 +00:00
Lukas Senionis
6f14da152a fix(findSP): fallback to last active context (#53) 2022-12-11 15:01:41 -05:00
semantic-release-bot
bb291b211c chore(release): 3.18.0 [CI SKIP] 2022-12-11 15:10:33 +00:00
Jozen Blue Martinez
88f245d476 feat(DialogCheckbox): Add DialogCheckbox component (#58)
* feat(DialogCheckbox): Add DialogCheckbox component

* fix(DialogCheckbox): Better sibling match

* fix(DialogCheckbox): Extend FocusableProps

* fix(DialogCheckbox): Extend FooterLegendProps

i should have probably tested that

* feat(DialogCheckbox): add onClick() prop

* fix(DialogCheckbox): replace default export with named export
2022-12-11 16:10:01 +01:00
9 changed files with 248 additions and 39 deletions

View File

@@ -1,3 +1,66 @@
## [3.18.8](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.7...v3.18.8) (2023-01-16)
### Bug Fixes
* **Navigation:** fix timing issue in decky-loader ([58b69f0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/58b69f0d6c43356c4f0ed183802d5bf7fb80e978))
## [3.18.7](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.6...v3.18.7) (2023-01-16)
### Bug Fixes
* un-break navigation on stable ([2e66e5a](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/2e66e5a555f44009d24e332eca82453ba930baf7))
## [3.18.6](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.5...v3.18.6) (2023-01-13)
### Bug Fixes
* **Router:** fix Navigation for the millionth time ([aac2d52](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/aac2d520a68b1074ba1ae988d6c92f7881a296d7))
## [3.18.5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.4...v3.18.5) (2022-12-21)
### Bug Fixes
* fixed prop interfaces ([#70](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/70)) ([0b50f2c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/0b50f2cf0baa76fc00aa0a41a8435d7a512bff19))
## [3.18.4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.3...v3.18.4) (2022-12-16)
### Bug Fixes
* **modals:** fix ModalRoot again ([fd94842](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/fd94842647e51dd9a104e170e0c5ee2bebce12d6))
## [3.18.3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.2...v3.18.3) (2022-12-12)
### Bug Fixes
* **Router:** update Router interface to SteamOS3.4 and add Navigation ([#52](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/52)) ([f0379e5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/f0379e5d19279863b571e66918bc9107efedb612))
## [3.18.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.1...v3.18.2) (2022-12-11)
### Bug Fixes
* **useQuickAccessVisible:** remove invalid prop access ([#66](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/66)) ([767dc2f](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/767dc2fcee97d8b6c2d331ae29704d9b469de51a))
## [3.18.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.0...v3.18.1) (2022-12-11)
### Bug Fixes
* **findSP:** fallback to last active context ([#53](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/53)) ([6f14da1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/6f14da152acc4757b814844f1b77bf83dd98d77e))
# [3.18.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.17.0...v3.18.0) (2022-12-11)
### Features
* **DialogCheckbox:** Add DialogCheckbox component ([#58](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/58)) ([88f245d](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/88f245d476a6477e9fc0cd35e9b675961ecbc26c))
# [3.17.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.16.2...v3.17.0) (2022-12-11)

View File

@@ -1,6 +1,6 @@
{
"name": "decky-frontend-lib",
"version": "3.17.0",
"version": "3.18.8",
"description": "A library for building decky plugins",
"main": "dist/index.js",
"types": "dist/index.d.ts",

View File

@@ -6,7 +6,8 @@ declare global {
function getQuickAccessWindow(): Window | null {
try {
const navTrees = FocusNavController?.m_ActiveContext?.m_rgGamepadNavigationTrees || FocusNavController?.m_rgGamepadNavigationTrees;
const context = FocusNavController?.m_ActiveContext || FocusNavController?.m_LastActiveContext;
const navTrees = context?.m_rgGamepadNavigationTrees || FocusNavController?.m_rgGamepadNavigationTrees;
return navTrees?.find((tree: any) => tree?.id === "QuickAccess-NA")?.m_Root?.m_element?.ownerDocument.defaultView ?? null;
} catch (error) {
console.error(error);

View File

@@ -0,0 +1,33 @@
import { FC, ReactNode } from 'react';
import { findModule } from '../webpack';
import { DialogCommonProps } from './Dialog';
import { FooterLegendProps } from './FooterLegend';
export interface DialogCheckboxProps extends DialogCommonProps, FooterLegendProps {
onChange?(checked: boolean): void;
label?: ReactNode;
description?: ReactNode;
disabled?: boolean;
tooltip?: string;
color?: string;
highlightColor?: string;
bottomSeparator?: 'standard' | 'thick' | 'none';
controlled?: boolean;
checked?: boolean;
onClick?(evt: Event): void;
}
export const DialogCheckbox = Object.values(findModule((m: any) => {
if (typeof m !== 'object') return false;
for (const prop in m) {
if (m[prop]?.prototype?.GetPanelElementProps) return true;
}
return false;
})).find((m: any) =>
m.contextType &&
m.prototype?.render.toString().includes('fallback:') &&
m?.prototype?.SetChecked &&
m?.prototype?.Toggle &&
m?.prototype?.GetPanelElementProps
) as FC<DialogCheckboxProps>;

View File

@@ -38,7 +38,7 @@ const showModalRaw:
unknown1?: unknown,
hideActions?: { bHideActions?: boolean },
modalManager?: unknown,
) => Promise<ShowModalResult>)
) => ShowModalResult)
| void = findModuleChild((m) => {
if (typeof m !== 'object') return undefined;
for (let prop in m) {
@@ -52,16 +52,15 @@ const showModalRaw:
}
});
const oldShowModalRaw:
| ((modal: ReactNode, parent?: EventTarget, props?: ShowModalProps) => Promise<ShowModalResult>)
| void = findModuleChild((m) => {
if (typeof m !== 'object') return undefined;
for (let prop in m) {
if (typeof m[prop] === 'function' && m[prop].toString().includes('bHideMainWindowForPopouts:!0')) {
return m[prop];
const oldShowModalRaw: ((modal: ReactNode, parent?: EventTarget, props?: ShowModalProps) => ShowModalResult) | void =
findModuleChild((m) => {
if (typeof m !== 'object') return undefined;
for (let prop in m) {
if (typeof m[prop] === 'function' && m[prop].toString().includes('bHideMainWindowForPopouts:!0')) {
return m[prop];
}
}
}
});
});
export const showModal = (
modal: ReactNode,
@@ -70,7 +69,7 @@ export const showModal = (
strTitle: 'Decky Dialog',
bHideMainWindowForPopouts: false,
},
): Promise<ShowModalResult> => {
): ShowModalResult => {
if (showModalRaw) {
return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
bHideActions: props.bHideActionIcons,
@@ -118,13 +117,13 @@ export const ConfirmModal = findModuleChild((m) => {
}
}) as FC<ConfirmModalProps>;
// new
// new as of december 2022 on beta
export const ModalRoot = (Object.values(
findModule((m: any) => {
if (typeof m !== 'object') return false;
for (let prop in m) {
if (m[prop]?.toString()?.includes('"ModalManager","DialogWrapper"')) {
if (m[prop]?.m_mapModalManager) {
return true;
}
}
@@ -132,6 +131,20 @@ export const ModalRoot = (Object.values(
return false;
}) || {},
)?.find((x: any) => x?.type?.toString()?.includes('((function(){')) ||
// before december 2022 beta
Object.values(
findModule((m: any) => {
if (typeof m !== 'object') return false;
for (let prop in m) {
if (m[prop]?.toString()?.includes('"ModalManager","DialogWrapper"')) {
return true;
}
}
return false;
}) || {},
)?.find((x: any) => x?.type?.toString()?.includes('((function(){')) ||
// old
findModuleChild((m) => {
if (typeof m !== 'object') return undefined;

View File

@@ -1,10 +1,11 @@
import { FC } from 'react';
import { FC, ReactNode } from 'react';
import { findModuleChild } from '../webpack';
export interface PanelSectionProps {
title?: string;
spinner?: boolean;
children?: ReactNode
}
const [panelSection, mod] = findModuleChild((mod: any) => {
@@ -18,6 +19,10 @@ const [panelSection, mod] = findModuleChild((mod: any) => {
export const PanelSection = panelSection as FC<PanelSectionProps>;
export interface PanelSectionRowProps {
children?: ReactNode
}
export const PanelSectionRow = Object.values(mod).filter(
(exp: any) => !exp?.toString()?.includes('.PanelSection'),
)[0] as FC;
)[0] as FC<PanelSectionRowProps>;

View File

@@ -1,3 +1,4 @@
import { sleep } from '../utils';
import { Module, findModuleChild } from '../webpack';
export enum SideMenu {
@@ -63,28 +64,38 @@ export type AppOverview = {
sort_as: string;
};
export interface Router {
CloseSideMenus(): void;
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
GetQuickAccessTab(): QuickAccessTab;
Navigate(path: string): void;
NavigateBackOrOpenMenu(): void;
NavigateToAppProperties(): void;
NavigateToBugForum(): void;
NavigateToExternalWeb(url: string): void;
NavigateToHelp(): void;
NavigateToInvites(): void;
NavigateToRunningApp(replace?: boolean): void;
NavigateToStorage(): void;
NavigateToStore(): void;
NavigateToStoreApp(appId: number | string): void;
NavigateToStoreFreeToPlay(): void;
NavigateToStoreManual(): void;
NavigateToStoreNewReleases(): void;
NavigateToStoreOnSale(): void;
ToggleSideMenu(sideMenu: SideMenu): void;
CloseSideMenus(): void;
export interface MenuStore {
OpenSideMenu(sideMenu: SideMenu): void;
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
OpenMainMenu(): void;
}
export interface WindowRouter {
BrowserWindow: Window;
MenuStore: MenuStore;
Navigate(path: string): void;
NavigateToChat(): void;
NavigateToSteamWeb(url: string): void;
NavigateBack(): void;
NavigateToWebRoute(unknown?: any, unknown2?: any): void;
}
export interface WindowStore {
GamepadUIMainWindowInstance?: WindowRouter; // Current
SteamUIWindows: WindowRouter[];
OverlayWindows: WindowRouter[]; // Used by desktop GamepadUI
}
export interface Router {
WindowStore?: WindowStore;
CloseSideMenus(): void;
Navigate(path: string): void;
NavigateToAppProperties(): void;
NavigateToExternalWeb(url: string): void;
NavigateToInvites(): void;
NavigateToChat(): void;
NavigateToLibraryTab(): void;
NavigateToLayoutPreview(e: unknown): void;
OpenPowerMenu(unknown?: any): void;
get RunningApps(): AppOverview[];
get MainRunningApp(): AppOverview | undefined;
@@ -96,3 +107,84 @@ export const Router = findModuleChild((m: Module) => {
if (m[prop]?.Navigate && m[prop]?.NavigationManager) return m[prop];
}
}) as Router;
export interface Navigation {
Navigate(path: string): void;
NavigateBack(): void;
NavigateToAppProperties(): void;
NavigateToExternalWeb(url: string): void;
NavigateToInvites(): void;
NavigateToChat(): void;
NavigateToLibraryTab(): void;
NavigateToLayoutPreview(e: unknown): void;
NavigateToSteamWeb(url: string): void;
NavigateToWebRoute(unknown?: any, unknown2?: any): void;
OpenSideMenu(sideMenu: SideMenu): void;
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
OpenMainMenu(): void;
OpenPowerMenu(unknown?: any): void;
CloseSideMenus(): void;
}
export let Navigation = {} as Navigation;
try {
(async () => {
// With how much Valve is changing these, you really shouldn't use them directly, instead see Navigation
let InternalNavigators: any;
function initInternalNavigators() {
try {
InternalNavigators = findModuleChild((m: any) => {
if (typeof m !== 'object') return undefined;
for (let prop in m) {
if (m[prop]?.GetNavigator) {
return m[prop];
}
}
})?.GetNavigator();
} catch (e) {
console.error('[DFL:Router]: Failed to init internal navigators, trying again');
}
}
initInternalNavigators();
while (!InternalNavigators?.AppProperties) {
console.log('[DFL:Router]: Trying to init internal navigators again');
await sleep(100);
initInternalNavigators();
}
console.log("got navigators", InternalNavigators)
const newNavigation = {
Navigate: Router.Navigate.bind(Router),
NavigateBack: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateBack.bind(
Router.WindowStore.GamepadUIMainWindowInstance,
),
NavigateToAppProperties: InternalNavigators?.AppProperties || Router.NavigateToAppProperties.bind(Router),
NavigateToExternalWeb: Router.NavigateToExternalWeb.bind(Router),
NavigateToInvites: InternalNavigators?.Invites || Router.NavigateToInvites.bind(Router),
NavigateToChat: Router.NavigateToChat.bind(Router),
NavigateToLibraryTab: InternalNavigators?.LibraryTab || Router.NavigateToLibraryTab.bind(Router),
NavigateToLayoutPreview: Router.NavigateToLayoutPreview.bind(Router),
NavigateToSteamWeb: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateToSteamWeb.bind(
Router.WindowStore.GamepadUIMainWindowInstance,
),
NavigateToWebRoute: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateToWebRoute.bind(
Router.WindowStore.GamepadUIMainWindowInstance,
),
OpenSideMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenSideMenu.bind(
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
),
OpenQuickAccessMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenQuickAccessMenu.bind(
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
),
OpenMainMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenMainMenu.bind(
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
),
CloseSideMenus: Router.CloseSideMenus.bind(Router),
OpenPowerMenu: Router.OpenPowerMenu.bind(Router),
} as Navigation;
Object.assign(Navigation, newNavigation);
})();
} catch (e) {
console.error('[DFL:Router]: Error initializing Navigation interface', e);
}

View File

@@ -3,6 +3,7 @@ export * from './ButtonItem';
export * from './Carousel';
export * from './ControlsList';
export * from './Dialog';
export * from './DialogCheckbox';
export * from './Dropdown';
export * from './Field';
export * from './Focusable';

View File

@@ -16,6 +16,7 @@ export function findSP(): Window {
// old (SP as host)
if (document.title == 'SP') return window;
// new (SP as popup)
return FocusNavController.m_ActiveContext.m_rgGamepadNavigationTrees.find((x: any) => x.m_ID == 'root_1_').Root
const context = FocusNavController.m_ActiveContext || FocusNavController.m_LastActiveContext;
return context.m_rgGamepadNavigationTrees.find((x: any) => x.m_ID == 'root_1_').Root
.Element.ownerDocument.defaultView;
}