Compare commits

...

4 Commits

Author SHA1 Message Date
Jonas Dellinger
1e92d5c754 0.0.4 2022-05-30 20:51:27 +02:00
AAGaming
668ab618fc add patcher and react utils 2022-05-29 20:19:10 -04:00
AAGaming
5d59bf348c fix react 2022-05-28 21:49:38 -04:00
AAGaming
a5ac702820 fix typescript AGAIN, fix icons, ignore pnpm lock 2022-05-28 20:54:25 -04:00
9 changed files with 106 additions and 10 deletions

3
.gitignore vendored
View File

@@ -35,3 +35,6 @@ Thumbs.db
dist/
research/
# PNPM lockfile
pnpm-lock.yaml

5
globals.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
declare global {
interface Window {
SP_REACT: typeof React;
}
}

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "decky-frontend-lib",
"version": "0.0.3",
"version": "0.0.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "decky-frontend-lib",
"version": "0.0.3",
"version": "0.0.4",
"license": "GPL-2.0-or-later",
"devDependencies": {
"@types/jest": "^27.4.1",

View File

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

View File

@@ -12,5 +12,5 @@ import { IconsModule } from '../webpack';
// }
export const Spinner = Object.values(IconsModule).find((mod: any) =>
mod?.toString()?.includes("Spinner)}),a.createElement(\"path\",{d:\"M18 "),
mod?.toString && /Spinner\)}\),.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString())
) as FC<{}>;

View File

@@ -2,3 +2,4 @@
export * from './deck-components';
export * from './plugin';
export * from './webpack';
export * from './utils';

87
src/utils.ts Normal file
View File

@@ -0,0 +1,87 @@
import * as React from "react";
// this shouldn't need to be redeclared but it does for some reason
declare global {
interface Window {
SP_REACT: typeof React;
}
}
export function fakeRenderComponent(fun: Function): any {
const hooks = (window.SP_REACT as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher.current;
// TODO: add more hooks
let oldHooks = {
useContext: hooks.useContext,
useCallback: hooks.useCallback,
useLayoutEffect: hooks.useLayoutEffect,
useEffect: hooks.useEffect,
useMemo: hooks.useMemo,
useRef: hooks.useRef,
useState: hooks.useState,
}
hooks.useCallback = (cb: Function) => cb;
hooks.useContext = (cb: any) => cb._currentValue;
hooks.useLayoutEffect = (_: Function) => {}//cb();
hooks.useMemo = (cb: Function, _: any[]) => cb;
hooks.useEffect = (_: Function) => {}//cb();
hooks.useRef = (val: any) => ({current: val || {}});
hooks.useState = (v: any) => {
let val = v;
return [val, (n: any) => val = n];
};
const res = fun(hooks);
Object.assign(hooks, oldHooks);
return res;
}
export function beforePatch(obj: any, name: string, fnc: Function): void {
const orig = obj[name];
obj[name] = function (...args: any[]) {
fnc.call(this, args);
return orig.call(this, ...args);
}
Object.assign(obj[name], orig);
obj[name].toString = () => orig.toString();
obj[name].__deckyOrig = orig;
}
export function afterPatch(obj: any, name: string, fnc: Function): void {
const orig = obj[name];
obj[name] = function (...args: any[]) {
let ret = orig.call(this, ...args);
ret = fnc.call(this, args, ret);
return ret;
}
Object.assign(obj[name], orig);
obj[name].toString = () => orig.toString();
obj[name].__deckyOrig = orig;
}
export function replacePatch(obj: any, name: string, fnc: Function): void {
const orig = obj[name];
obj[name] = function (...args: any[]) {
const ret = fnc.call(this, args);
if (ret == 'CALL_ORIGINAL') return orig.call(this, ...args);
return ret;
};
Object.assign(obj[name], orig);
obj[name].toString = () => orig.toString();
obj[name].__deckyOrig = orig;
}
// TODO allow one method to be patched and unpatched multiple times independently using IDs in a Map or something
export function unpatch(obj: any, name: any): void {
obj[name] = obj[name].__deckyOrig;
}
export function getReactInstance(o: HTMLElement | Element | Node) {
return o[Object.keys(o).find(k => k.startsWith('__reactInternalInstance')) as string]
}

View File

@@ -58,14 +58,13 @@ export const CommonUIModule = allModules.find((m: Module) => {
return false;
});
export const IconsModule = allModules.find((m: Module) => {
if (typeof m !== "object") return undefined;
export const IconsModule = findModule((m: Module) => {
if (typeof m !== "object") return false;
for (let prop in m) {
if (m[prop]?.toString()?.includes("Spinner)}),a.createElement(\"path\",{d:\"M18 ")) return true;
if (m[prop]?.toString && /Spinner\)}\),.\.createElement\(\"path\",{d:\"M18 /.test(m[prop].toString())) return true;
}
return false;
})
export const Router = findModuleChild((m: Module) => {
if (typeof m !== "object") return undefined;
for (let prop in m) {

View File

@@ -3,7 +3,8 @@
"outDir": "dist",
"module": "ESNext",
"target": "ES2020",
"jsx": "react-jsx",
"jsx": "react",
"jsxFactory": "window.SP_REACT.createElement",
"declaration": true,
"moduleResolution": "node",
"noUnusedLocals": true,
@@ -17,6 +18,6 @@
"allowSyntheticDefaultImports": true,
"skipLibCheck": true
},
"include": ["src"],
"include": ["src", "globals.d.ts"],
"exclude": ["node_modules"]
}