Skip to content

Commit

Permalink
fix(*): fixes for jun 26 beta
Browse files Browse the repository at this point in the history
  • Loading branch information
AAGaming00 committed Jun 27, 2024
1 parent b1e5038 commit 7e0cb15
Show file tree
Hide file tree
Showing 12 changed files with 63 additions and 23 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ If you would like a feature added to decky-frontend-lib, please request it via a
If you want to start making a plugin with decky-frontend-lib, please direct your attention to the [decky-plugin-template](https://github.com/SteamDeckHomebrew/decky-plugin-template) repository.

This library can be found on [npm](https://www.npmjs.com/package/decky-frontend-lib) and as such you can pull it without a local copy for your project as needed.

Tips for fixing failing module finds after Steam updates:
- `Object.entries(DFL)` can point out any undefined exports
6 changes: 4 additions & 2 deletions src/components/ButtonItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { FC } from 'react';

import { CommonUIModule } from '../webpack';
import { ItemProps } from './Item';
import { createPropListRegex } from '../utils';

export interface ButtonItemProps extends ItemProps {
onClick?(e: MouseEvent): void;
disabled?: boolean;
}
const buttonItemRegex = createPropListRegex(["highlightOnFocus", "childrenContainerWidth"], false);
export const ButtonItem = Object.values(CommonUIModule).find(
(mod: any) =>
mod?.render?.toString()?.includes('"highlightOnFocus","childrenContainerWidth"') ||
mod?.render?.toString()?.includes('childrenContainerWidth:"min"'),
(mod?.render?.toString && buttonItemRegex.test(mod.render.toString())) ||
mod?.render?.toString?.().includes('childrenContainerWidth:"min"'),
) as FC<ButtonItemProps>;
21 changes: 12 additions & 9 deletions src/components/Dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,19 @@ export interface DialogButtonProps extends DialogCommonProps, FooterLegendProps
}

const CommonDialogDivs = Object.values(CommonUIModule).filter(
(m: any) => typeof m === 'object' && m?.render?.toString().includes('"div",Object.assign({},'),
(m: any) => typeof m === 'object' && m?.render?.toString().includes('createElement("div",{...') ||
m?.render?.toString().includes('createElement("div",Object.assign({},'),
);
const MappedDialogDivs = new Map(
Object.values(CommonDialogDivs).map((m: any) => {
const renderedDiv = m.render({});
// Take only the first class name segment as it identifies the element we want
return [renderedDiv.props.className.split(' ')[0], m];
try {
const renderedDiv = m.render({});
// Take only the first class name segment as it identifies the element we want
return [renderedDiv.props.className.split(' ')[0], m];
} catch (e) {
console.error("[DFL:Dialog]: failed to render common dialog component", e);
return [null, null];
}
}),
);

Expand All @@ -72,14 +78,11 @@ export const DialogControlsSection = MappedDialogDivs.get('DialogControlsSection
export const DialogControlsSectionHeader = MappedDialogDivs.get('DialogControlsSectionHeader') as FC<DialogCommonProps>;

export const DialogButtonPrimary = Object.values(CommonUIModule).find(
(mod: any) => mod?.render?.toString()?.includes('DialogButton') && mod?.render?.toString()?.includes('Primary'),
(mod: any) => mod?.render?.toString()?.includes('"DialogButton","_DialogLayout","Primary"'),
) as FC<DialogButtonProps>;

export const DialogButtonSecondary = Object.values(CommonUIModule).find(
(mod: any) =>
mod?.render?.toString()?.includes('Object.assign({type:"button"') &&
mod?.render?.toString()?.includes('DialogButton') &&
mod?.render?.toString()?.includes('Secondary'),
(mod: any) => mod?.render?.toString()?.includes('"DialogButton","_DialogLayout","Secondary"')
) as FC<DialogButtonProps>;

// This is the "main" button. The Primary can act as a submit button,
Expand Down
4 changes: 3 additions & 1 deletion src/components/Dropdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ReactNode, FC } from 'react';

import { CommonUIModule } from '../webpack';
import { ItemProps } from './Item';
import { createPropListRegex } from '../utils';

export interface SingleDropdownOption {
data: any;
Expand Down Expand Up @@ -44,6 +45,7 @@ export const Dropdown = Object.values(CommonUIModule).find(

export interface DropdownItemProps extends DropdownProps, ItemProps {}

const dropdownItemRegex = createPropListRegex(["dropDownControlRef", "description"], false);
export const DropdownItem = Object.values(CommonUIModule).find((mod: any) =>
mod?.toString()?.includes('"dropDownControlRef","description"'),
mod?.toString && dropdownItemRegex.test(mod.toString()),
) as FC<DropdownItemProps>;
5 changes: 4 additions & 1 deletion src/components/Focusable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { HTMLAttributes, ReactNode, RefAttributes, FC } from 'react';

import { Export, findModuleExport } from '../webpack';
import { FooterLegendProps } from './FooterLegend';
import { createPropListRegex } from '../utils';

export interface FocusableProps extends HTMLAttributes<HTMLDivElement>, FooterLegendProps {
children: ReactNode;
Expand All @@ -13,6 +14,8 @@ export interface FocusableProps extends HTMLAttributes<HTMLDivElement>, FooterLe
onCancel?: (e: CustomEvent) => void;
}

const focusableRegex = createPropListRegex(["flow-children", "onActivate", "onCancel", "focusClassName", "focusWithinClassName"]);

export const Focusable = findModuleExport((e: Export) =>
e?.render?.toString()?.includes('["flow-children","onActivate","onCancel","focusClassName",'),
e?.render?.toString && focusableRegex.test(e.render.toString())
) as FC<FocusableProps & RefAttributes<HTMLDivElement>>;
3 changes: 2 additions & 1 deletion src/components/Menu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { Export, findModuleExport } from '../webpack';
import { FooterLegendProps } from './FooterLegend';

export const showContextMenu: (children: ReactNode, parent?: EventTarget) => void = findModuleExport(
(e: Export) => typeof e === 'function' && e.toString().includes('stopPropagation))'),
(e: Export) => typeof e === 'function' && e.toString().includes('GetContextMenuManagerFromWindow(')
&& e.toString().includes('.CreateContextMenuInstance('),
);

export interface MenuProps extends FooterLegendProps {
Expand Down
4 changes: 3 additions & 1 deletion src/components/ProgressBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ReactNode, FC } from 'react';

import { Export, findModuleExport } from '../webpack';
import { ItemProps } from './Item';
import { createPropListRegex } from '../utils';

export interface ProgressBarItemProps extends ItemProps {
indeterminate?: boolean;
Expand Down Expand Up @@ -30,6 +31,7 @@ export const ProgressBarWithInfo = findModuleExport((e: Export) =>
e?.toString()?.includes('.ProgressBarFieldStatus},'),
) as FC<ProgressBarWithInfoProps>;

const progressBarItemRegex = createPropListRegex(["indeterminate", "nTransitionSec", "nProgress"]);
export const ProgressBarItem = findModuleExport((e: Export) =>
e?.toString()?.includes('"indeterminate","nTransitionSec"'),
e?.toString && progressBarItemRegex.test(e.toString()),
) as FC<ProgressBarItemProps>;
4 changes: 3 additions & 1 deletion src/components/SidebarNavigation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReactNode, FC } from 'react';

import { Export, findModuleExport } from '../webpack';
import { createPropListRegex } from '../utils';

export interface SidebarNavigationPage {
title: ReactNode;
Expand All @@ -23,6 +24,7 @@ export interface SidebarNavigationProps {
onPageRequested?: (page: string) => void;
}

const sidebarNavigationRegex = createPropListRegex(["pages", "fnSetNavigateToPage", "disableRouteReporting"]);
export const SidebarNavigation = findModuleExport((e: Export) =>
e?.toString()?.includes('"disableRouteReporting"'),
e?.toString && sidebarNavigationRegex.test(e.toString()),
) as FC<SidebarNavigationProps>;
4 changes: 2 additions & 2 deletions src/components/Spinner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ import { FC, SVGAttributes } from 'react';
import { IconsModule } from '../webpack';

// TODO type this and other icons?
export const Spinner = Object.values(IconsModule).find(
(mod: any) => mod?.toString && /Spinner\)}\),.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()),
export const Spinner = Object.values(IconsModule)?.find(
(mod: any) => mod?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()),
) as FC<SVGAttributes<SVGElement>>;
8 changes: 4 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export * from './class-mapper';
* @deprecated use @decky/api instead
*/
export const definePlugin = (fn: any): any => {
return (...args: any[]) => {
// TODO: Maybe wrap this
return fn(...args);
};
return (...args: any[]) => {
// TODO: Maybe wrap this
return fn(...args);
};
};
22 changes: 22 additions & 0 deletions src/utils/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,28 @@ declare global {
}
}

/**
* Create a Regular Expression to search for a React component that uses certain props in order.
*
* @export
* @param {string[]} propList Ordererd list of properties to search for
* @returns {RegExp} RegEx to call .test(component.toString()) on
*/
export function createPropListRegex(propList: string[], fromStart: boolean = true): RegExp {
let regexString = fromStart ? "const\{" : "";
propList.forEach((prop: any, propIdx) => {
regexString += `"?${prop}"?:[a-zA-Z_$]{1,2}`;
if (propIdx < propList.length - 1) {
regexString += ",";
}
});

// TODO provide a way to enable this
// console.debug(`[DFL:Utils] createPropListRegex generated regex "${regexString}" for props`, propList);

return new RegExp(regexString);
}

export function fakeRenderComponent(fun: Function, customHooks: any = {}): any {
const hooks = (window.SP_REACT as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher
.current;
Expand Down
2 changes: 1 addition & 1 deletion src/webpack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const CommonUIModule = modules.find((m: Module) => {
});

export const IconsModule = findModuleByExport(
(e) => e?.toString && /Spinner\)}\),.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
(e) => e?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
);

export const ReactRouter = findModuleByExport((e) => e.computeRootMatch);

0 comments on commit 7e0cb15

Please sign in to comment.