mirror of
https://github.com/SteamDeckHomebrew/decky-frontend-lib.git
synced 2026-05-18 01:00:08 +02:00
fix(*): fixes for jun 26 beta
This commit is contained in:
@@ -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
|
||||
@@ -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>;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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>>;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user