mirror of
https://github.com/SteamDeckHomebrew/decky-frontend-lib.git
synced 2026-05-23 11:28:48 +02:00
Compare commits
19 Commits
globals-wo
...
v4.11.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8596294667 | ||
|
|
772a85523b | ||
|
|
aabc522740 | ||
|
|
66e0afccae | ||
|
|
77e6acd828 | ||
|
|
261162c8bc | ||
|
|
f8fda380f1 | ||
|
|
7242c69758 | ||
|
|
fd651eb989 | ||
|
|
6e443c06d3 | ||
|
|
25b4b60e34 | ||
|
|
cf6572cd7b | ||
|
|
779b1ae0de | ||
|
|
366357d9a3 | ||
|
|
37dd88513e | ||
|
|
ed87f73602 | ||
|
|
3d5de65077 | ||
|
|
33d224bc3f | ||
|
|
aa0678c857 |
7
.github/workflows/release.yaml
vendored
7
.github/workflows/release.yaml
vendored
@@ -6,6 +6,10 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
@@ -18,7 +22,7 @@ jobs:
|
|||||||
- name: Setup | Node.js
|
- name: Setup | Node.js
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 20
|
node-version: 24
|
||||||
- name: Setup | Dependencies
|
- name: Setup | Dependencies
|
||||||
run: npm i -g pnpm && pnpm i --frozen-lockfile
|
run: npm i -g pnpm && pnpm i --frozen-lockfile
|
||||||
- name: Build
|
- name: Build
|
||||||
@@ -29,5 +33,4 @@ jobs:
|
|||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN_DECKY_ORG }}
|
|
||||||
run: pnpm exec semantic-release
|
run: pnpm exec semantic-release
|
||||||
|
|||||||
@@ -1,4 +1 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
. "$(dirname -- "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npx --no -- commitlint --edit "${1}"
|
npx --no -- commitlint --edit "${1}"
|
||||||
|
|||||||
53
CHANGELOG.md
53
CHANGELOG.md
@@ -1,3 +1,56 @@
|
|||||||
|
## [4.11.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.11.1...v4.11.2) (2026-03-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **ci:** microsoft ([aabc522](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/aabc5227400f1660ddcb7917fa8f305ad2fce3d7))
|
||||||
|
* **ci:** microsoft stinks ([66e0afc](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/66e0afccae6803ee57d817621340d09a12ba75d8))
|
||||||
|
* **ci:** update semantic release ([772a855](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/772a85523b8c4bbf80ccd4827a89801e3a51cfd6))
|
||||||
|
* **ci:** use new npm publishing auth ([77e6acd](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/77e6acd828b1d0f0978356292b1c46bfc3b8e422))
|
||||||
|
* **components:** update for latest beta ([261162c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/261162c8bceecc50afad07d57a78b85b98936fe1))
|
||||||
|
|
||||||
|
## [4.11.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.11.0...v4.11.1) (2025-11-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **webpack:** ignore window module (lol), ignore filter errors ([7242c69](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/7242c697580f3a6a6d373eaacc4fb83ccff9bd2a))
|
||||||
|
|
||||||
|
# [4.11.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.6...v4.11.0) (2025-10-15)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* react 19 support update ([6e443c0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/6e443c06d3b7f2790da8b44a5c907517fcf12152))
|
||||||
|
|
||||||
|
## [4.10.6](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.5...v4.10.6) (2025-09-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **ci:** update to resolve deprecation in sem. rel. due to octokit ([779b1ae](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/779b1ae0defac84dd0d93517858d5aa5e51a2328))
|
||||||
|
|
||||||
|
## [4.10.5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.4...v4.10.5) (2025-08-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **DialogHeader:** valve rewrote component on beta, update filter to search for both versions ([37dd885](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/37dd88513ed7360d3bcdc99630d6cb0c8d31db3e))
|
||||||
|
|
||||||
|
## [4.10.4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.3...v4.10.4) (2025-07-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **modals:** fix ModalRoot on beta ([3d5de65](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/3d5de65077098ff3fb5192cb55fb1534336411f5))
|
||||||
|
|
||||||
|
## [4.10.3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.2...v4.10.3) (2025-07-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **modals:** fix `<ConfirmModal />` for new Steam beta ([#123](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/123)) ([aa0678c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/aa0678c857e07f58de58e5d20565bf2718fff6dc))
|
||||||
|
|
||||||
## [4.10.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.1...v4.10.2) (2025-06-28)
|
## [4.10.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.1...v4.10.2) (2025-06-28)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
5
global.d.ts
vendored
5
global.d.ts
vendored
@@ -1,5 +1,10 @@
|
|||||||
|
import type * as React from 'react';
|
||||||
|
import type * as ReactDOM from 'react-dom';
|
||||||
|
import type * as JSXRuntime from 'react/jsx-runtime';
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
SP_REACT: typeof React;
|
SP_REACT: typeof React;
|
||||||
|
SP_REACTDOM: typeof ReactDOM;
|
||||||
|
SP_JSX: typeof JSXRuntime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
28
package.json
28
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@decky/ui",
|
"name": "@decky/ui",
|
||||||
"version": "4.10.2",
|
"version": "4.11.2",
|
||||||
"description": "A library for interacting with the Steam frontend in Decky plugins and elsewhere.",
|
"description": "A library for interacting with the Steam frontend in Decky plugins and elsewhere.",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
@@ -41,30 +41,30 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^19.3.0",
|
"@commitlint/cli": "^19.8.1",
|
||||||
"@commitlint/config-conventional": "^19.2.2",
|
"@commitlint/config-conventional": "^19.8.1",
|
||||||
"@commitlint/cz-commitlint": "^19.2.0",
|
"@commitlint/cz-commitlint": "^19.8.1",
|
||||||
"@semantic-release/changelog": "^6.0.3",
|
"@semantic-release/changelog": "^6.0.3",
|
||||||
"@semantic-release/git": "^10.0.1",
|
"@semantic-release/git": "^10.0.1",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.14",
|
||||||
"@types/react": "18.3.3",
|
"@types/react": "19.1.1",
|
||||||
"@types/react-dom": "18.3.0",
|
"@types/react-dom": "19.1.1",
|
||||||
"@types/react-router": "5.1.20",
|
"@types/react-router": "5.1.20",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.1",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.1.7",
|
||||||
"import-sort-style-module": "^6.0.0",
|
"import-sort-style-module": "^6.0.0",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"minimist": "^1.2.8",
|
"minimist": "^1.2.8",
|
||||||
"prettier": "^3.3.2",
|
"prettier": "^3.6.2",
|
||||||
"prettier-plugin-import-sort": "^0.0.7",
|
"prettier-plugin-import-sort": "^0.0.7",
|
||||||
"semantic-release": "^24.0.0",
|
"semantic-release": "^25.0.3",
|
||||||
"shx": "^0.3.4",
|
"shx": "^0.3.4",
|
||||||
"ts-jest": "^29.1.4",
|
"ts-jest": "^29.4.1",
|
||||||
"typedoc": "^0.25.13",
|
"typedoc": "^0.25.13",
|
||||||
"typedoc-plugin-mdn-links": "^3.1.29",
|
"typedoc-plugin-mdn-links": "^3.3.8",
|
||||||
"typedoc-plugin-missing-exports": "^2.3.0",
|
"typedoc-plugin-missing-exports": "^2.3.0",
|
||||||
"typedoc-wikijs-theme": "^1.0.5",
|
"typedoc-wikijs-theme": "^1.0.5",
|
||||||
"typescript": "^5.4.5"
|
"typescript": "^5.9.2"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"peerDependencyRules": {
|
"peerDependencyRules": {
|
||||||
|
|||||||
3194
pnpm-lock.yaml
generated
3194
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
import { CSSProperties, FC, ReactNode, RefAttributes } from 'react';
|
import { CSSProperties, FC, ReactNode, RefAttributes } from 'react';
|
||||||
|
|
||||||
import { CommonUIModule } from '../webpack';
|
import { CommonUIModule, Module } from '../webpack';
|
||||||
import { FooterLegendProps } from './FooterLegend';
|
import { FooterLegendProps } from './FooterLegend';
|
||||||
|
|
||||||
export interface DialogCommonProps extends RefAttributes<HTMLDivElement> {
|
export interface DialogCommonProps extends RefAttributes<HTMLDivElement> {
|
||||||
@@ -52,8 +52,17 @@ export interface DialogButtonProps extends DialogCommonProps, FooterLegendProps
|
|||||||
}
|
}
|
||||||
|
|
||||||
const CommonDialogDivs = Object.values(CommonUIModule).filter(
|
const CommonDialogDivs = Object.values(CommonUIModule).filter(
|
||||||
(m: any) => typeof m === 'object' && m?.render?.toString().includes('createElement("div",{...') ||
|
(m: any) => typeof m === 'object' &&
|
||||||
m?.render?.toString().includes('createElement("div",Object.assign({},'),
|
// New
|
||||||
|
(
|
||||||
|
m?.render?.toString().includes('jsx)("div",{...') ||
|
||||||
|
m?.render?.toString().includes('jsx)("div",Object.assign({},')
|
||||||
|
) ||
|
||||||
|
// Old
|
||||||
|
(
|
||||||
|
m?.render?.toString().includes('createElement("div",{...') ||
|
||||||
|
m?.render?.toString().includes('createElement("div",Object.assign({},')
|
||||||
|
)
|
||||||
);
|
);
|
||||||
const MappedDialogDivs = new Map(
|
const MappedDialogDivs = new Map(
|
||||||
Object.values(CommonDialogDivs).map((m: any) => {
|
Object.values(CommonDialogDivs).map((m: any) => {
|
||||||
@@ -68,7 +77,12 @@ const MappedDialogDivs = new Map(
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const DialogHeader = MappedDialogDivs.get('DialogHeader') as FC<DialogCommonProps>;
|
// Old | New
|
||||||
|
export const DialogHeader = (MappedDialogDivs.get('DialogHeader') || Object.values(CommonUIModule).find((component: Module) => {
|
||||||
|
const str = component?.render?.toString?.();
|
||||||
|
return str?.includes("role:\"heading\"") && str.includes(")(\"DialogHeader\",");
|
||||||
|
})) as FC<DialogCommonProps>;
|
||||||
|
|
||||||
export const DialogSubHeader = MappedDialogDivs.get('DialogSubHeader') as FC<DialogCommonProps>;
|
export const DialogSubHeader = MappedDialogDivs.get('DialogSubHeader') as FC<DialogCommonProps>;
|
||||||
export const DialogFooter = MappedDialogDivs.get('DialogFooter') as FC<DialogCommonProps>;
|
export const DialogFooter = MappedDialogDivs.get('DialogFooter') as FC<DialogCommonProps>;
|
||||||
export const DialogLabel = MappedDialogDivs.get('DialogLabel') as FC<DialogCommonProps>;
|
export const DialogLabel = MappedDialogDivs.get('DialogLabel') as FC<DialogCommonProps>;
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ export interface FocusableProps extends HTMLAttributes<HTMLDivElement>, FooterLe
|
|||||||
const focusableRegex = createPropListRegex(["flow-children", "onActivate", "onCancel", "focusClassName", "focusWithinClassName"]);
|
const focusableRegex = createPropListRegex(["flow-children", "onActivate", "onCancel", "focusClassName", "focusWithinClassName"]);
|
||||||
|
|
||||||
export const Focusable = findModuleExport((e: Export) =>
|
export const Focusable = findModuleExport((e: Export) =>
|
||||||
e?.render?.toString && focusableRegex.test(e.render.toString())
|
(typeof e == 'function' && e?.toString && focusableRegex.test(e.toString())) || (e?.render?.toString && focusableRegex.test(e.render.toString()))
|
||||||
) as FC<FocusableProps & RefAttributes<HTMLDivElement>>;
|
) as FC<FocusableProps & RefAttributes<HTMLDivElement>>;
|
||||||
|
|||||||
@@ -83,22 +83,26 @@ export interface ConfirmModalProps extends ModalRootProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const ConfirmModal = findModuleExport(
|
export const ConfirmModal = findModuleExport(
|
||||||
(e: Export) => !e?.prototype?.OK && e?.prototype?.Cancel && e?.prototype?.render,
|
(e: Export) => e?.toString()?.includes('bUpdateDisabled') && e?.toString()?.includes('closeModal') && e?.toString()?.includes('onGamepadCancel'),
|
||||||
) as FC<ConfirmModalProps>;
|
) as FC<ConfirmModalProps>;
|
||||||
|
|
||||||
export const ModalRoot = Object.values(
|
export const ModalRoot =
|
||||||
findModule((m: any) => {
|
// new
|
||||||
if (typeof m !== 'object') return false;
|
findModuleExport((e: Export) => typeof e === 'function' && e.toString().includes('Either closeModal or onCancel should be passed to GenericDialog. Classes: ')) ||
|
||||||
|
// old
|
||||||
|
Object.values(
|
||||||
|
findModule((m: any) => {
|
||||||
|
if (typeof m !== 'object') return false;
|
||||||
|
|
||||||
for (let prop in m) {
|
for (let prop in m) {
|
||||||
if (m[prop]?.m_mapModalManager && Object.values(m)?.find((x: any) => x?.type)) {
|
if (m[prop]?.m_mapModalManager && Object.values(m)?.find((x: any) => x?.type)) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}) || {},
|
}) || {},
|
||||||
)?.find((x: any) => x?.type?.toString?.()?.includes('((function(){')) as FC<ModalRootProps>;
|
)?.find((x: any) => x?.type?.toString?.()?.includes('((function(){')) as FC<ModalRootProps>;
|
||||||
|
|
||||||
interface SimpleModalProps {
|
interface SimpleModalProps {
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ export const ProgressBar = findModuleExport((e: Export) =>
|
|||||||
) as FC<ProgressBarProps>;
|
) as FC<ProgressBarProps>;
|
||||||
|
|
||||||
export const ProgressBarWithInfo = findModuleExport((e: Export) =>
|
export const ProgressBarWithInfo = findModuleExport((e: Export) =>
|
||||||
e?.toString?.()?.includes('.ProgressBarFieldStatus},'),
|
// new || old
|
||||||
|
e?.toString?.()?.includes('.ProgressBarFieldStatus,children') || e?.toString?.()?.includes('.ProgressBarFieldStatus},'),
|
||||||
) as FC<ProgressBarWithInfoProps>;
|
) as FC<ProgressBarWithInfoProps>;
|
||||||
|
|
||||||
const progressBarItemRegex = createPropListRegex(["indeterminate", "nTransitionSec", "nProgress"]);
|
const progressBarItemRegex = createPropListRegex(["indeterminate", "nTransitionSec", "nProgress"]);
|
||||||
|
|||||||
@@ -11,5 +11,6 @@ export const ScrollPanel = ScrollingModuleProps.find((prop: any) =>
|
|||||||
) as FC<{ children?: ReactNode }>;
|
) as FC<{ children?: ReactNode }>;
|
||||||
|
|
||||||
export const ScrollPanelGroup: FC<{ children?: ReactNode }> = findModuleExport((e: Export) =>
|
export const ScrollPanelGroup: FC<{ children?: ReactNode }> = findModuleExport((e: Export) =>
|
||||||
e?.render?.toString().includes('.FocusVisibleChild()),[])'),
|
// new || old
|
||||||
|
e?.render?.toString().includes('.FocusVisibleChild(),[])') || e?.render?.toString().includes('.FocusVisibleChild()),[])'),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ import { FC, SVGAttributes } from 'react';
|
|||||||
import { IconsModule } from '../webpack';
|
import { IconsModule } from '../webpack';
|
||||||
|
|
||||||
// TODO type this and other icons?
|
// TODO type this and other icons?
|
||||||
export const Spinner = Object.values(IconsModule)?.find(
|
export const Spinner = IconsModule && Object.values(IconsModule)?.find(
|
||||||
(mod: any) => mod?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()),
|
(mod: any) => mod?.toString && /Spinner\),children:\[\(0,\w+\.jsx\)\("path",\{d:"M18 /.test(mod.toString()) || /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()),
|
||||||
) as FC<SVGAttributes<SVGElement>>;
|
) as FC<SVGAttributes<SVGElement>>;
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export type ReorderableListEntryProps<T> = {
|
|||||||
reorderEntryFunc: CallableFunction;
|
reorderEntryFunc: CallableFunction;
|
||||||
reorderEnabled: boolean;
|
reorderEnabled: boolean;
|
||||||
animate: boolean;
|
animate: boolean;
|
||||||
children: ReactElement | null;
|
children: ReactElement<any> | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ReorderableItem<T>(props: ReorderableListEntryProps<T>) {
|
function ReorderableItem<T>(props: ReorderableListEntryProps<T>) {
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ export interface Input {
|
|||||||
* @returns an object that can be used to unregister the callback.
|
* @returns an object that can be used to unregister the callback.
|
||||||
*/
|
*/
|
||||||
RegisterForControllerInputMessages(
|
RegisterForControllerInputMessages(
|
||||||
callback: (msgs: ControllerInputMessage[]) => void,
|
callback: (controllerIndex: number, gamepadButton: ControllerInputGamepadButton, isButtonPressed: boolean) => void,
|
||||||
): Unregisterable;
|
): Unregisterable;
|
||||||
|
|
||||||
RegisterForControllerListChanges(callback: (controllerListChanges: ControllerInfo[]) => void): Unregisterable;
|
RegisterForControllerListChanges(callback: (controllerListChanges: ControllerInfo[]) => void): Unregisterable;
|
||||||
@@ -560,6 +560,60 @@ export enum EControllerRumbleSetting {
|
|||||||
On,
|
On,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ControllerInputGamepadButton {
|
||||||
|
GAMEPAD_BUTTON_A = 0,
|
||||||
|
GAMEPAD_BUTTON_B = 1,
|
||||||
|
GAMEPAD_BUTTON_X = 2,
|
||||||
|
GAMEPAD_BUTTON_Y = 3,
|
||||||
|
GAMEPAD_BUTTON_DPAD_UP = 4,
|
||||||
|
GAMEPAD_BUTTON_DPAD_RIGHT = 5,
|
||||||
|
GAMEPAD_BUTTON_DPAD_DOWN = 6,
|
||||||
|
GAMEPAD_BUTTON_DPAD_LEFT = 7,
|
||||||
|
GAMEPAD_BUTTON_MENU = 8,
|
||||||
|
GAMEPAD_BUTTON_VIEW = 9,
|
||||||
|
GAMEPAD_LEFTPAD_UP = 10,
|
||||||
|
GAMEPAD_LEFTPAD_DOWN = 11,
|
||||||
|
GAMEPAD_LEFTPAD_LEFT = 12,
|
||||||
|
GAMEPAD_LEFTPAD_RIGHT = 13,
|
||||||
|
GAMEPAD_LEFTPAD_ANALOG = 14,
|
||||||
|
GAMEPAD_RIGHTPAD_UP = 15,
|
||||||
|
GAMEPAD_RIGHTPAD_DOWN = 16,
|
||||||
|
GAMEPAD_RIGHTPAD_LEFT = 17,
|
||||||
|
GAMEPAD_RIGHTPAD_RIGHT = 18,
|
||||||
|
GAMEPAD_RIGHTPAD_ANALOG = 19,
|
||||||
|
GAMEPAD_LEFTSTICK_UP = 20,
|
||||||
|
GAMEPAD_LEFTSTICK_DOWN = 21,
|
||||||
|
GAMEPAD_LEFTSTICK_LEFT = 22,
|
||||||
|
GAMEPAD_LEFTSTICK_RIGHT = 23,
|
||||||
|
GAMEPAD_LEFTSTICK_ANALOG = 24,
|
||||||
|
GAMEPAD_LEFTSTICK_CLICK = 25,
|
||||||
|
GAMEPAD_LTRIGGER_ANALOG = 26,
|
||||||
|
GAMEPAD_RTRIGGER_ANALOG = 27,
|
||||||
|
GAMEPAD_BUTTON_LTRIGGER = 28,
|
||||||
|
GAMEPAD_BUTTON_RTRIGGER = 29,
|
||||||
|
GAMEPAD_BUTTON_LSHOULDER = 30,
|
||||||
|
GAMEPAD_BUTTON_RSHOULDER = 31,
|
||||||
|
GAMEPAD_BUTTON_LBACK = 32,
|
||||||
|
GAMEPAD_BUTTON_RBACK = 33,
|
||||||
|
GAMEPAD_BUTTON_GUIDE = 34,
|
||||||
|
GAMEPAD_BUTTON_SELECT = 35,
|
||||||
|
GAMEPAD_BUTTON_START = 36,
|
||||||
|
GAMEPAD_BUTTON_LPAD_CLICKED = 37,
|
||||||
|
GAMEPAD_BUTTON_LPAD_TOUCH = 38,
|
||||||
|
GAMEPAD_BUTTON_RPAD_CLICKED = 39,
|
||||||
|
GAMEPAD_BUTTON_RPAD_TOUCH = 40,
|
||||||
|
GAMEPAD_RIGHTSTICK_CLICK = 41,
|
||||||
|
GAMEPAD_RIGHTSTICK_TOUCH = 42,
|
||||||
|
GAMEPAD_LEFTSTICK_TOUCH = 43,
|
||||||
|
GAMEPAD_BUTTON_LBACK_UPPER = 44,
|
||||||
|
GAMEPAD_BUTTON_RBACK_UPPER = 45,
|
||||||
|
GAMEPAD_BUTTON_LAST = 46,
|
||||||
|
GAMEPAD_ANALOG_SCROLL = 47,
|
||||||
|
GAMEPAD_ANALOG_LEFT_KEYBOARD_CURSOR = 48,
|
||||||
|
GAMEPAD_ANALOG_RIGHT_KEYBOARD_CURSOR = 49,
|
||||||
|
GAMEPAD_ANALOG_LAST = 50
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Not the actual name, but the enum is only represented in a dropdown
|
// TODO: Not the actual name, but the enum is only represented in a dropdown
|
||||||
// options vector, ty valve
|
// options vector, ty valve
|
||||||
export enum EThirdPartyControllerConfiguration {
|
export enum EThirdPartyControllerConfiguration {
|
||||||
@@ -568,12 +622,6 @@ export enum EThirdPartyControllerConfiguration {
|
|||||||
On,
|
On,
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ControllerInputMessage {
|
|
||||||
nA: number;
|
|
||||||
bS: boolean;
|
|
||||||
nC: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ActiveAccount {
|
export interface ActiveAccount {
|
||||||
strActiveAccountID: string;
|
strActiveAccountID: string;
|
||||||
strName: string;
|
strName: string;
|
||||||
|
|||||||
@@ -42,6 +42,9 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|||||||
};
|
};
|
||||||
component.prototype.isReactComponent = true;
|
component.prototype.isReactComponent = true;
|
||||||
let stubsApplied = false;
|
let stubsApplied = false;
|
||||||
|
const patchJsx = window.SP_REACTDOM.version.startsWith("19.");
|
||||||
|
let oldJsx = window.SP_JSX?.jsx;
|
||||||
|
let oldJsxs = window.SP_JSX?.jsxs;
|
||||||
let oldCreateElement = window.SP_REACT.createElement;
|
let oldCreateElement = window.SP_REACT.createElement;
|
||||||
|
|
||||||
const applyStubsIfNeeded = () => {
|
const applyStubsIfNeeded = () => {
|
||||||
@@ -55,6 +58,18 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|||||||
loggingEnabled && console.trace("createElement trace");
|
loggingEnabled && console.trace("createElement trace");
|
||||||
return Object.create(component.prototype);
|
return Object.create(component.prototype);
|
||||||
};
|
};
|
||||||
|
if (patchJsx) {
|
||||||
|
window.SP_JSX.jsx = () => {
|
||||||
|
loggingEnabled && logger.debug("jsx hook called");
|
||||||
|
loggingEnabled && console.trace("jsx trace");
|
||||||
|
return Object.create(component.prototype);
|
||||||
|
}
|
||||||
|
window.SP_JSX.jsxs = () => {
|
||||||
|
loggingEnabled && logger.debug("jsxs hook called");
|
||||||
|
loggingEnabled && console.trace("jsxs trace");
|
||||||
|
return Object.create(component.prototype);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,76 +79,154 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
|||||||
stubsApplied = false;
|
stubsApplied = false;
|
||||||
removeHookStubs();
|
removeHookStubs();
|
||||||
window.SP_REACT.createElement = oldCreateElement;
|
window.SP_REACT.createElement = oldCreateElement;
|
||||||
|
if (patchJsx) {
|
||||||
|
window.SP_JSX.jsx = oldJsx;
|
||||||
|
window.SP_JSX.jsxs = oldJsxs;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let renderHookStep = 0;
|
let renderHookStep = 0;
|
||||||
|
|
||||||
// Accessed two times, once directly before class instantiation, and again in some extra logic we don't need to worry about that we hanlde below just in case.
|
if (window.SP_REACTDOM.version.startsWith("19.")) {
|
||||||
Object.defineProperty(component, "contextType", {
|
// Accessed two times directly before class instantiation on path A and once on path B
|
||||||
configurable: true,
|
Object.defineProperty(component, "contextType", {
|
||||||
get: function () {
|
configurable: true,
|
||||||
loggingEnabled && logger.debug("get contexttype", this, stubsApplied, renderHookStep);
|
get: function () {
|
||||||
loggingEnabled && console.trace("contextType trace");
|
loggingEnabled && logger.debug("get contexttype", this, this._contextType, stubsApplied, renderHookStep);
|
||||||
if (renderHookStep == 0) renderHookStep = 1;
|
loggingEnabled && console.trace("contextType trace");
|
||||||
else if (renderHookStep == 3) renderHookStep = 4;
|
if (renderHookStep == 0) {
|
||||||
return this._contextType;
|
renderHookStep = 1;
|
||||||
},
|
}
|
||||||
set: function (value) {
|
if (this._contextType == null) {
|
||||||
this._contextType = value;
|
this._contextType = {};
|
||||||
}
|
}
|
||||||
});
|
if (!this._contextType.appliedCurrentValueHook) {
|
||||||
|
logger.debug("applied currentvalue hook");
|
||||||
// Always accessed directly after contextType for the path we want to catch.
|
this._contextType.appliedCurrentValueHook = true;
|
||||||
Object.defineProperty(component, "contextTypes", {
|
Object.defineProperty(this._contextType, "_currentValue", {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: function () {
|
get: function () {
|
||||||
loggingEnabled && logger.debug("get contexttypes", this, stubsApplied, renderHookStep);
|
loggingEnabled && logger.debug("get currentValue", this, stubsApplied, renderHookStep);
|
||||||
loggingEnabled && console.trace("contextTypes trace");
|
loggingEnabled && console.trace("currentValue trace");
|
||||||
if (renderHookStep == 1) {
|
if (renderHookStep == 1) {
|
||||||
renderHookStep = 2;
|
renderHookStep = 2;
|
||||||
applyStubsIfNeeded();
|
applyStubsIfNeeded();
|
||||||
};
|
}
|
||||||
return this._contextTypes;
|
return this.__currentValue;
|
||||||
},
|
},
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
this._contextTypes = value;
|
return this.__currentValue = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// Set directly after class is instantiated
|
return this._contextType;
|
||||||
Object.defineProperty(component.prototype, "updater", {
|
},
|
||||||
configurable: true,
|
set: function (value) {
|
||||||
get: function () {
|
this._contextType = value;
|
||||||
return this._updater;
|
|
||||||
},
|
|
||||||
set: function (value) {
|
|
||||||
loggingEnabled && logger.debug("set updater", this, value, stubsApplied, renderHookStep);
|
|
||||||
loggingEnabled && console.trace("updater trace");
|
|
||||||
if (renderHookStep == 2) {
|
|
||||||
renderHookStep = 0;
|
|
||||||
removeStubsIfNeeded();
|
|
||||||
}
|
}
|
||||||
return this._updater = value;
|
});
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Prevents the second contextType+contextTypes access from leaving its hooks around
|
// Set directly after class is instantiated
|
||||||
Object.defineProperty(component, "getDerivedStateFromProps", {
|
Object.defineProperty(component.prototype, "updater", {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
get: function () {
|
get: function () {
|
||||||
loggingEnabled && logger.debug("get getDerivedStateFromProps", this, stubsApplied, renderHookStep);
|
return this._updater;
|
||||||
loggingEnabled && console.trace("getDerivedStateFromProps trace");
|
},
|
||||||
if (renderHookStep == 2) {
|
set: function (value) {
|
||||||
renderHookStep = 0;
|
loggingEnabled && logger.debug("set updater", this, value, stubsApplied, renderHookStep);
|
||||||
removeStubsIfNeeded();
|
loggingEnabled && console.trace("updater trace");
|
||||||
|
if (renderHookStep == 1 || renderHookStep == 2) {
|
||||||
|
renderHookStep = 0;
|
||||||
|
removeStubsIfNeeded();
|
||||||
|
}
|
||||||
|
return this._updater = value;
|
||||||
}
|
}
|
||||||
return this._getDerivedStateFromProps;
|
});
|
||||||
},
|
|
||||||
set: function (value) {
|
// Prevents the second contextType access from leaving its hooks around
|
||||||
this._getDerivedStateFromProps = value;
|
Object.defineProperty(component, "getDerivedStateFromProps", {
|
||||||
}
|
configurable: true,
|
||||||
});
|
get: function () {
|
||||||
|
loggingEnabled && logger.debug("get getDerivedStateFromProps", this, stubsApplied, renderHookStep);
|
||||||
|
loggingEnabled && console.trace("getDerivedStateFromProps trace");
|
||||||
|
if (renderHookStep == 1|| renderHookStep == 2) {
|
||||||
|
renderHookStep = 0;
|
||||||
|
removeStubsIfNeeded();
|
||||||
|
}
|
||||||
|
return this._getDerivedStateFromProps;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this._getDerivedStateFromProps = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (window.SP_REACTDOM.version.startsWith("18.")) {
|
||||||
|
// Accessed two times, once directly before class instantiation, and again in some extra logic we don't need to worry about that we hanlde below just in case.
|
||||||
|
Object.defineProperty(component, "contextType", {
|
||||||
|
configurable: true,
|
||||||
|
get: function () {
|
||||||
|
loggingEnabled && logger.debug("get contexttype", this, stubsApplied, renderHookStep);
|
||||||
|
loggingEnabled && console.trace("contextType trace");
|
||||||
|
if (renderHookStep == 0) renderHookStep = 1;
|
||||||
|
else if (renderHookStep == 3) renderHookStep = 4;
|
||||||
|
return this._contextType;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this._contextType = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Always accessed directly after contextType for the path we want to catch.
|
||||||
|
Object.defineProperty(component, "contextTypes", {
|
||||||
|
configurable: true,
|
||||||
|
get: function () {
|
||||||
|
loggingEnabled && logger.debug("get contexttypes", this, stubsApplied, renderHookStep);
|
||||||
|
loggingEnabled && console.trace("contextTypes trace");
|
||||||
|
if (renderHookStep == 1) {
|
||||||
|
renderHookStep = 2;
|
||||||
|
applyStubsIfNeeded();
|
||||||
|
};
|
||||||
|
return this._contextTypes;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this._contextTypes = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set directly after class is instantiated
|
||||||
|
Object.defineProperty(component.prototype, "updater", {
|
||||||
|
configurable: true,
|
||||||
|
get: function () {
|
||||||
|
return this._updater;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
loggingEnabled && logger.debug("set updater", this, value, stubsApplied, renderHookStep);
|
||||||
|
loggingEnabled && console.trace("updater trace");
|
||||||
|
if (renderHookStep == 2) {
|
||||||
|
renderHookStep = 0;
|
||||||
|
removeStubsIfNeeded();
|
||||||
|
}
|
||||||
|
return this._updater = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Prevents the second contextType+contextTypes access from leaving its hooks around
|
||||||
|
Object.defineProperty(component, "getDerivedStateFromProps", {
|
||||||
|
configurable: true,
|
||||||
|
get: function () {
|
||||||
|
loggingEnabled && logger.debug("get getDerivedStateFromProps", this, stubsApplied, renderHookStep);
|
||||||
|
loggingEnabled && console.trace("getDerivedStateFromProps trace");
|
||||||
|
if (renderHookStep == 2) {
|
||||||
|
renderHookStep = 0;
|
||||||
|
removeStubsIfNeeded();
|
||||||
|
}
|
||||||
|
return this._getDerivedStateFromProps;
|
||||||
|
},
|
||||||
|
set: function (value) {
|
||||||
|
this._getDerivedStateFromProps = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return userComponent;
|
return userComponent;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import * as React from 'react';
|
import type * as React from 'react';
|
||||||
|
import type * as ReactDOM from 'react-dom';
|
||||||
|
import type * as JSXRuntime from 'react/jsx-runtime';
|
||||||
import { Ref, useState } from 'react';
|
import { Ref, useState } from 'react';
|
||||||
|
|
||||||
// this shouldn't need to be redeclared but it does for some reason
|
// this shouldn't need to be redeclared but it does for some reason
|
||||||
@@ -6,6 +8,8 @@ import { Ref, useState } from 'react';
|
|||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
SP_REACT: typeof React;
|
SP_REACT: typeof React;
|
||||||
|
SP_REACTDOM: typeof ReactDOM;
|
||||||
|
SP_JSX: typeof JSXRuntime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,9 +37,11 @@ export function createPropListRegex(propList: string[], fromStart: boolean = tru
|
|||||||
|
|
||||||
let oldHooks = {};
|
let oldHooks = {};
|
||||||
|
|
||||||
|
export let INTERNAL_HOOKS = (window.SP_REACT as any)?.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentDispatcher
|
||||||
|
.current || Object.values((window.SP_REACT as any)?.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE).find((p: any) => p?.useEffect);
|
||||||
|
|
||||||
export function applyHookStubs(customHooks: any = {}): any {
|
export function applyHookStubs(customHooks: any = {}): any {
|
||||||
const hooks = (window.SP_REACT as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher
|
const hooks = INTERNAL_HOOKS;
|
||||||
.current;
|
|
||||||
|
|
||||||
// TODO: add more hooks
|
// TODO: add more hooks
|
||||||
|
|
||||||
@@ -50,7 +56,7 @@ export function applyHookStubs(customHooks: any = {}): any {
|
|||||||
};
|
};
|
||||||
|
|
||||||
hooks.useCallback = (cb: Function) => cb;
|
hooks.useCallback = (cb: Function) => cb;
|
||||||
hooks.useContext = (cb: any) => cb._currentValue;
|
hooks.useContext = (cb: any) => cb?._currentValue;
|
||||||
hooks.useLayoutEffect = (_: Function) => {}; //cb();
|
hooks.useLayoutEffect = (_: Function) => {}; //cb();
|
||||||
hooks.useMemo = (cb: Function, _: any[]) => cb;
|
hooks.useMemo = (cb: Function, _: any[]) => cb;
|
||||||
hooks.useEffect = (_: Function) => {}; //cb();
|
hooks.useEffect = (_: Function) => {}; //cb();
|
||||||
@@ -67,8 +73,7 @@ export function applyHookStubs(customHooks: any = {}): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function removeHookStubs() {
|
export function removeHookStubs() {
|
||||||
const hooks = (window.SP_REACT as any).__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentDispatcher
|
const hooks = INTERNAL_HOOKS;
|
||||||
.current;
|
|
||||||
Object.assign(hooks, oldHooks);
|
Object.assign(hooks, oldHooks);
|
||||||
oldHooks = {};
|
oldHooks = {};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export let modules = new Map<ModuleID, Module>();
|
|||||||
function initModuleCache() {
|
function initModuleCache() {
|
||||||
const startTime = performance.now();
|
const startTime = performance.now();
|
||||||
logger.group('Webpack Module Init');
|
logger.group('Webpack Module Init');
|
||||||
// Webpack 5, currently on beta
|
// Webpack 5
|
||||||
// Generate a fake module ID
|
// Generate a fake module ID
|
||||||
const id = Symbol("@decky/ui");
|
const id = Symbol("@decky/ui");
|
||||||
let webpackRequire!: ((id: any) => Module) & { m: object };
|
let webpackRequire!: ((id: any) => Module) & { m: object };
|
||||||
@@ -70,15 +70,22 @@ export const findModuleDetailsByExport = (
|
|||||||
for (const [id, m] of modules) {
|
for (const [id, m] of modules) {
|
||||||
if (!m) continue;
|
if (!m) continue;
|
||||||
for (const mod of [m.default, m]) {
|
for (const mod of [m.default, m]) {
|
||||||
|
// special cases
|
||||||
if (typeof mod !== 'object') continue;
|
if (typeof mod !== 'object') continue;
|
||||||
|
if (mod == window) continue; // wtf
|
||||||
if (minExports && Object.keys(mod).length < minExports) continue;
|
if (minExports && Object.keys(mod).length < minExports) continue;
|
||||||
|
|
||||||
for (let exportName in mod) {
|
for (let exportName in mod) {
|
||||||
if (mod?.[exportName]) {
|
if (mod?.[exportName]) {
|
||||||
const filterRes = filter(mod[exportName], exportName);
|
try {
|
||||||
if (filterRes) {
|
const filterRes = filter(mod[exportName], exportName);
|
||||||
return [mod, mod[exportName], exportName, id];
|
if (filterRes) {
|
||||||
} else {
|
return [mod, mod[exportName], exportName, id];
|
||||||
continue;
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.warn("Webpack filter threw exception: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,6 +106,7 @@ export const findModuleExport = (filter: ExportFilterFn, minExports?: number) =>
|
|||||||
* @deprecated use findModuleExport instead
|
* @deprecated use findModuleExport instead
|
||||||
*/
|
*/
|
||||||
export const findModuleChild = (filter: FindFn) => {
|
export const findModuleChild = (filter: FindFn) => {
|
||||||
|
logger.warn("findModuleChild is deprecated and will be removed soon. Use findModuleExport instead. Used in:", new Error().stack?.substring(5))
|
||||||
for (const m of modules.values()) {
|
for (const m of modules.values()) {
|
||||||
for (const mod of [m.default, m]) {
|
for (const mod of [m.default, m]) {
|
||||||
const filterRes = filter(mod);
|
const filterRes = filter(mod);
|
||||||
@@ -115,6 +123,7 @@ export const findModuleChild = (filter: FindFn) => {
|
|||||||
* @deprecated use createModuleMapping instead
|
* @deprecated use createModuleMapping instead
|
||||||
*/
|
*/
|
||||||
export const findAllModules = (filter: FilterFn) => {
|
export const findAllModules = (filter: FilterFn) => {
|
||||||
|
logger.warn("findAllModules is deprecated and will be removed soon. Use createModuleMapping instead. Used in:", new Error().stack?.substring(5))
|
||||||
const out = [];
|
const out = [];
|
||||||
|
|
||||||
for (const m of modules.values()) {
|
for (const m of modules.values()) {
|
||||||
@@ -145,7 +154,7 @@ export const CommonUIModule = findModule((m: Module) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const IconsModule = findModuleByExport(
|
export const IconsModule = findModuleByExport(
|
||||||
(e) => e?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
|
(e) => e?.toString && /Spinner\),children:\[\(0,\w+\.jsx\)\("path",\{d:"M18 /.test(e.toString()) || /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
|
||||||
);
|
);
|
||||||
|
|
||||||
export const ReactRouter = findModuleByExport((e) => e.computeRootMatch);
|
export const ReactRouter = findModuleByExport((e) => e.computeRootMatch);
|
||||||
|
|||||||
@@ -3,8 +3,7 @@
|
|||||||
"outDir": "dist",
|
"outDir": "dist",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"jsx": "react",
|
"jsx": "react-jsx",
|
||||||
"jsxFactory": "window.SP_REACT.createElement",
|
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
|
|||||||
Reference in New Issue
Block a user