fix(*): fixes for jun 26 beta

This commit is contained in:
AAGaming
2024-06-26 22:28:58 -04:00
parent b1e503853f
commit 7e0cb153b1
12 changed files with 63 additions and 23 deletions

View File

@@ -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

View File

@@ -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>;

View File

@@ -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];
}
}),
);
@@ -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,

View File

@@ -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;
@@ -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>;

View File

@@ -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;
@@ -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>>;

View File

@@ -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 {

View File

@@ -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;
@@ -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>;

View File

@@ -1,6 +1,7 @@
import { ReactNode, FC } from 'react';
import { Export, findModuleExport } from '../webpack';
import { createPropListRegex } from '../utils';
export interface SidebarNavigationPage {
title: ReactNode;
@@ -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>;

View File

@@ -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>>;

View File

@@ -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);
};
};

View File

@@ -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;

View File

@@ -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);