mirror of
https://github.com/SteamDeckHomebrew/decky-frontend-lib.git
synced 2026-05-20 10:00:08 +02:00
Compare commits
186 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f2692a3f2 | ||
|
|
ebf496bf61 | ||
|
|
0a5170e412 | ||
|
|
11dd82bbb1 | ||
|
|
153bb209d1 | ||
|
|
e27b638d26 | ||
|
|
7d287f10d6 | ||
|
|
9925bc8cfb | ||
|
|
179a93d5e1 | ||
|
|
5203ce348a | ||
|
|
3f47b5ccce | ||
|
|
d22d32677b | ||
|
|
30e319425b | ||
|
|
aebdfaa089 | ||
|
|
de914b1a35 | ||
|
|
4c4fda47e3 | ||
|
|
678084e4fd | ||
|
|
4f8f65d429 | ||
|
|
8a352d288d | ||
|
|
fd0d011cbf | ||
|
|
70219d90bc | ||
|
|
1ff9351f96 | ||
|
|
c256d341c8 | ||
|
|
c9b583945c | ||
|
|
c213204ff4 | ||
|
|
9128c1e7da | ||
|
|
a06650cf09 | ||
|
|
3170779c6b | ||
|
|
5ffa14bec8 | ||
|
|
ee51dc5fc0 | ||
|
|
b38ec17d8f | ||
|
|
8b54ee990e | ||
|
|
7e01781d40 | ||
|
|
2b31473614 | ||
|
|
8bfeae4b35 | ||
|
|
a7761321bc | ||
|
|
979a630f2b | ||
|
|
a4d1fcf086 | ||
|
|
e9e7f5c026 | ||
|
|
9a691cea09 | ||
|
|
44d9b90cdc | ||
|
|
585c3b8348 | ||
|
|
1287493b63 | ||
|
|
bf01a0184b | ||
|
|
fb5f043ba9 | ||
|
|
26f2c92dce | ||
|
|
01e53d4c13 | ||
|
|
18d341f82a | ||
|
|
3ca8c43a54 | ||
|
|
99353467ad | ||
|
|
b093ce93ba | ||
|
|
74a7cbaf94 | ||
|
|
8fb35e3c09 | ||
|
|
5d5cb31638 | ||
|
|
21f1e5f0af | ||
|
|
0fa43701a9 | ||
|
|
4d52eaea12 | ||
|
|
7e1182a83f | ||
|
|
167ded103a | ||
|
|
b8ddf3d927 | ||
|
|
62f4b354a8 | ||
|
|
79d229be50 | ||
|
|
f43157fde5 | ||
|
|
19819b7a5b | ||
|
|
8752f576a7 | ||
|
|
102a441124 | ||
|
|
62f40bd48f | ||
|
|
a7acc9ae45 | ||
|
|
be7f17a3c3 | ||
|
|
5d097b6108 | ||
|
|
ae98930eeb | ||
|
|
6ce0da996d | ||
|
|
b1591f86bb | ||
|
|
f7318f0210 | ||
|
|
1a34501868 | ||
|
|
7dacb23e8b | ||
|
|
7e5c7b5ac3 | ||
|
|
f71e4dedc8 | ||
|
|
419835204e | ||
|
|
86f33de2c0 | ||
|
|
0b6dc24c0d | ||
|
|
18ce1ad790 | ||
|
|
5a074b5bb6 | ||
|
|
26fae13c8e | ||
|
|
53faf55df1 | ||
|
|
b480d397c4 | ||
|
|
dfcb3bec19 | ||
|
|
cf7dc26a0c | ||
|
|
d3b87b26c5 | ||
|
|
b64dd9f723 | ||
|
|
82214fef4c | ||
|
|
e559a43af9 | ||
|
|
c53d7f8448 | ||
|
|
68a46263a4 | ||
|
|
56e7b2c492 | ||
|
|
1282636b0b | ||
|
|
2343274a5b | ||
|
|
f965c05c27 | ||
|
|
f8c8ae7c29 | ||
|
|
3085efd439 | ||
|
|
db8d91a7ff | ||
|
|
2091daaeac | ||
|
|
b1b2f4fa2d | ||
|
|
b146eab8d7 | ||
|
|
667933bd7c | ||
|
|
dbd01b11ca | ||
|
|
47a6fddc89 | ||
|
|
c57e0eed34 | ||
|
|
5adc5e14ed | ||
|
|
cea315a52c | ||
|
|
5b166d6db8 | ||
|
|
edcc43a6ee | ||
|
|
9723854ddc | ||
|
|
7501817b76 | ||
|
|
4affd4aaec | ||
|
|
6b3db72a14 | ||
|
|
58b69f0d6c | ||
|
|
c62102e993 | ||
|
|
2e66e5a555 | ||
|
|
ce525318d8 | ||
|
|
aac2d520a6 | ||
|
|
e761ee02ba | ||
|
|
c53f87b4a9 | ||
|
|
a656f4e57f | ||
|
|
0b50f2cf0b | ||
|
|
e48c7bbadd | ||
|
|
727fcc8186 | ||
|
|
dc196d53f5 | ||
|
|
f0379e5d19 | ||
|
|
fd94842647 | ||
|
|
ef6be8c6ec | ||
|
|
767dc2fcee | ||
|
|
52305987c5 | ||
|
|
6f14da152a | ||
|
|
bb291b211c | ||
|
|
88f245d476 | ||
|
|
5bc78df918 | ||
|
|
c586afb97d | ||
|
|
d9150c2556 | ||
|
|
cd0635e94f | ||
|
|
443c7850d7 | ||
|
|
d24136ecb6 | ||
|
|
55507446cc | ||
|
|
925ea8c3ce | ||
|
|
14c5210931 | ||
|
|
cc29ddaf57 | ||
|
|
1e8979b641 | ||
|
|
7ba1229a4e | ||
|
|
4c2a715324 | ||
|
|
678ba216f1 | ||
|
|
07d15f5dca | ||
|
|
c84a091469 | ||
|
|
3c171cfb8f | ||
|
|
47fd13692f | ||
|
|
2ec9519b7d | ||
|
|
24606190e0 | ||
|
|
ed98d14b37 | ||
|
|
b882612dfa | ||
|
|
32291620b4 | ||
|
|
9b368c5f11 | ||
|
|
e167ef5a13 | ||
|
|
2f3df00967 | ||
|
|
215156d316 | ||
|
|
47d75db690 | ||
|
|
82768e0415 | ||
|
|
e44187fe4b | ||
|
|
72af32436e | ||
|
|
e1f64a38de | ||
|
|
82ed48761d | ||
|
|
a81c342d2a | ||
|
|
68d630262d | ||
|
|
9c72a55aff | ||
|
|
92ffc76075 | ||
|
|
ce3860f73b | ||
|
|
d8b10a2133 | ||
|
|
1581304dcb | ||
|
|
60ddf474e0 | ||
|
|
52ae328e2e | ||
|
|
aa0fad2ecf | ||
|
|
dab9071d1e | ||
|
|
189a90ba31 | ||
|
|
8509ae8f9a | ||
|
|
a6ebfdcd7d | ||
|
|
5f7655baaf | ||
|
|
bca2dcc9bd | ||
|
|
546a4da043 |
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
@@ -1,6 +1,7 @@
|
|||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
|
pull_request:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@@ -20,9 +21,12 @@ jobs:
|
|||||||
node-version: 16
|
node-version: 16
|
||||||
- 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
|
||||||
|
run: pnpm run build
|
||||||
- name: Test
|
- name: Test
|
||||||
run: pnpm run test
|
run: pnpm run test
|
||||||
- name: Release
|
- name: Release
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"preset": "angular",
|
"preset": "angular",
|
||||||
"releaseRules": [
|
"releaseRules": [
|
||||||
{"type": "chore", "scope": "classes", "release": "patch"},
|
{"type": "chore", "scope": "classes", "release": "patch"},
|
||||||
|
{"type": "docs", "scope": "steamclient", "release": "patch"},
|
||||||
{"type": "*", "scope": "docs", "release": false}
|
{"type": "*", "scope": "docs", "release": false}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
406
CHANGELOG.md
406
CHANGELOG.md
@@ -1,3 +1,409 @@
|
|||||||
|
## [3.24.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.24.1...v3.24.2) (2024-01-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **navigation:** Fix on chromium 109 ([#100](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/100)) ([ebf496b](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/ebf496bf61cffa1a5205b4a094fd2279011bffa9))
|
||||||
|
|
||||||
|
## [3.24.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.24.0...v3.24.1) (2023-12-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **utils/react:** support react 18, add getReactRoot ([11dd82b](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/11dd82bbb1814ac4d2fa9d381372e325daba2558))
|
||||||
|
|
||||||
|
# [3.24.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.23.1...v3.24.0) (2023-12-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **static-classes:** add BasicAppDetailsSectionStylerClasses ([#99](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/99)) ([e27b638](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/e27b638d26e41332b1554dbd55ca0c55a1821138))
|
||||||
|
|
||||||
|
## [3.23.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.23.0...v3.23.1) (2023-11-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **webpack:** don't break if a module fails to load ([5203ce3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/5203ce348afd727da0c8c52f6d8f8a16712f88d2))
|
||||||
|
|
||||||
|
# [3.23.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.22.1...v3.23.0) (2023-10-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **static-classes:** add more css classes ([#94](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/94)) ([30e3194](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/30e319425bd4b0ee481dd7bd3245dacd90806afb))
|
||||||
|
|
||||||
|
## [3.22.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.22.0...v3.22.1) (2023-10-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **useQuickAccessVisible:** use the "Page Visibility API" instead of focus/blur ([4c4fda4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/4c4fda47e3d9fd936b493c5965634a0ff443014f))
|
||||||
|
|
||||||
|
# [3.22.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.8...v3.22.0) (2023-08-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add patch indicator to prevent crashes ([3170779](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/3170779c6b3d02ea17f7b6c1fbd57e00498ffe4f))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add components found while working on tabmaster ([4f8f65d](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/4f8f65d42979149cc80b4a86545d3d0d9bf14bf3))
|
||||||
|
* add components found while working on tabmaster ([fd0d011](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/fd0d011cbf05790c5a1078970b5be72f9267402c))
|
||||||
|
|
||||||
|
## [3.21.8](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.7...v3.21.8) (2023-06-27)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* the typescript compiler was eating the enum ([c9b5839](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/c9b583945c1cb5267b41a821743590a841572abe))
|
||||||
|
|
||||||
|
## [3.21.7](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.6...v3.21.7) (2023-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add patch indicator to prevent crashes ([#88](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/88)) ([9128c1e](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/9128c1e7dadb98a8926d3dba9907a01cc78d90cf))
|
||||||
|
|
||||||
|
## [3.21.6](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.5...v3.21.6) (2023-06-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* reposition parameter for file picker V2 ([ee51dc5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/ee51dc5fc0dd5bdc2b0b9e10aa27607fbe51f491))
|
||||||
|
|
||||||
|
## [3.21.5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.4...v3.21.5) (2023-06-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* missing parameter ([8b54ee9](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/8b54ee990ee4d9b51174737979c35ab7ad92ed7a))
|
||||||
|
|
||||||
|
## [3.21.4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.3...v3.21.4) (2023-06-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* move the new file picker api as v2 ([8bfeae4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/8bfeae4b3593b2efa0aa075a0d9e0b5926cdf169))
|
||||||
|
|
||||||
|
## [3.21.3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.2...v3.21.3) (2023-06-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* total is not needed as a return value to plugins ([979a630](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/979a630f2b02ac4a1ac19e38002244f9dfe97177))
|
||||||
|
|
||||||
|
## [3.21.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.1...v3.21.2) (2023-06-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **SidebarNavigation:** allow ReactNode for page title ([44d9b90](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/44d9b90cdcfb9e6441fdb1e4b21fe844f1f29fd5))
|
||||||
|
|
||||||
|
## [3.21.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.21.0...v3.21.1) (2023-05-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **reorderable-list:** open label type from string to ReactNode ([fb5f043](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/fb5f043ba9eeed0209960c8ae4ae597c2831b8c8))
|
||||||
|
|
||||||
|
# [3.21.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.7...v3.21.0) (2023-05-19)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Utils:** return null when SP not found ([18d341f](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/18d341f82acf843ff830d1bf3d44678f3f2eda52))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **StaticClasses:** add new GamepadUI classes ([3ca8c43](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/3ca8c43a542b1049c4e203ad186e555401fbfbfe))
|
||||||
|
|
||||||
|
## [3.20.7](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.6...v3.20.7) (2023-05-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **decky:** fix decky on latest beta ([74a7cba](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/74a7cbaf94538c68a01f5fa707935c4d21570c5f))
|
||||||
|
|
||||||
|
## [3.20.6](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.5...v3.20.6) (2023-04-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **QuickAccessTab:** set decky tab ID to 999 ([5d5cb31](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/5d5cb31638070deae9970a93c587b447d5e56559))
|
||||||
|
|
||||||
|
## [3.20.5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.4...v3.20.5) (2023-04-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* reorderable list no longer toggles on backout ([7e1182a](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/7e1182a83f7fafbec6fe115a72f8b64b71c119a4))
|
||||||
|
|
||||||
|
## [3.20.4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.3...v3.20.4) (2023-04-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **SteamSpinner:** oh apparently the class was moved outside the component for some reason?????? ([b8ddf3d](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/b8ddf3d927401d04c0fde8ebc8960639369b8ad3))
|
||||||
|
|
||||||
|
## [3.20.3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.2...v3.20.3) (2023-04-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **SteamSpinner:** fix the fix ([79d229b](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/79d229be50d26e2510af0ea16cdf6644371a5967))
|
||||||
|
|
||||||
|
## [3.20.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.1...v3.20.2) (2023-04-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **SteamSpinner:** dont error on latest desktop beta ([19819b7](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/19819b7a5bc9434fa802f4e8dca4f4cb6921df07))
|
||||||
|
|
||||||
|
## [3.20.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.20.0...v3.20.1) (2023-04-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **useQuickAccessVisible:** make it work again ([7dacb23](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/7dacb23e8be7b1f076cdd0869a4e3a3902b07ec5))
|
||||||
|
|
||||||
|
# [3.20.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.19.2...v3.20.0) (2023-04-03)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Field:** remove style ([53faf55](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/53faf55df1484204e276cd21a32703c2d7809332))
|
||||||
|
* fixed missing export ([b480d39](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/b480d397c4251f42c1f24ff5e74322d22e313f05))
|
||||||
|
* list didn't update on prop change ([b146eab](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/b146eab8d7e1338afa54a168a2fd895e716c2bb2))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* added doc comments ([dfcb3be](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/dfcb3bec19900e099ae3766771e120dbd4f229f5))
|
||||||
|
* added reorderable list and updated fieldProps ([3c171cf](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/3c171cfb8ff18ed02eeb569a183c9d43fd0b4f57))
|
||||||
|
* changed ReorderableList to working version ([5b166d6](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/5b166d6db879200b049e872cba327957ba5fb705))
|
||||||
|
* made requested changes and ran prettier ([b1b2f4f](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/b1b2f4fa2da755efd65b82b15b52196f89fb09c0))
|
||||||
|
* refactoring mostly complete ([cea315a](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/cea315a52c285b31ad4e5d0a03104c674ae4f7f5))
|
||||||
|
* reorderable list now saves on backout ([b1591f8](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/b1591f86bbd36e160818626760e0717ee50878e0))
|
||||||
|
* **ReorderableList:** add animations, clean up ([26fae13](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/26fae13c8ebd3f11f134c3bc0edfc971afd42fff))
|
||||||
|
* support for non-interactable reordering ([dbd01b1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/dbd01b11cafe9b102cc371b9812f99aec718d106))
|
||||||
|
* support for user specified icon ([47a6fdd](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/47a6fddc89b8f9110252c5e19a6e95152c367dbf))
|
||||||
|
|
||||||
|
## [3.19.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.19.1...v3.19.2) (2023-03-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Item:** add highlightOnFocus prop ([c53f87b](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/c53f87b4a9273b377853bfff1d27474ebd6e564a))
|
||||||
|
|
||||||
|
## [3.19.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.19.0...v3.19.1) (2023-02-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* refactoring to fix for feb 22 2023 beta ([0b6dc24](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/0b6dc24c0da2d7644e185425e975787657f8bba1))
|
||||||
|
|
||||||
|
# [3.19.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.11...v3.19.0) (2023-02-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* added reorderable list and updated fieldProps ([#57](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/57)) ([5a074b5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/5a074b5bb68c675c484a7b693f67a67488be9bcf))
|
||||||
|
|
||||||
|
## [3.18.11](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.10...v3.18.11) (2023-02-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Navigation:** fix NavigateToExternalWeb ([82214fe](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/82214fef4c0a383776631fbb754550fe69f9000d))
|
||||||
|
* **Navigation:** fix NavigateToExternalWeb ([c53d7f8](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/c53d7f8448d8aad76dc699f1f309bdd547ee14df))
|
||||||
|
|
||||||
|
## [3.18.10](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.9...v3.18.10) (2023-01-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **SuspensefulImage:** fix changing src ([9723854](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/9723854ddca53d7708e1effbddec9e5ead22d5de))
|
||||||
|
|
||||||
|
## [3.18.9](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.8...v3.18.9) (2023-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Navigation:** fix on stable ([4affd4a](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/4affd4aaec088f01d0f30af48cb4daa34acf26b1))
|
||||||
|
|
||||||
|
## [3.18.8](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.7...v3.18.8) (2023-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Navigation:** fix timing issue in decky-loader ([58b69f0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/58b69f0d6c43356c4f0ed183802d5bf7fb80e978))
|
||||||
|
|
||||||
|
## [3.18.7](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.6...v3.18.7) (2023-01-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* un-break navigation on stable ([2e66e5a](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/2e66e5a555f44009d24e332eca82453ba930baf7))
|
||||||
|
|
||||||
|
## [3.18.6](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.5...v3.18.6) (2023-01-13)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Router:** fix Navigation for the millionth time ([aac2d52](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/aac2d520a68b1074ba1ae988d6c92f7881a296d7))
|
||||||
|
|
||||||
|
## [3.18.5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.4...v3.18.5) (2022-12-21)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* fixed prop interfaces ([#70](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/70)) ([0b50f2c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/0b50f2cf0baa76fc00aa0a41a8435d7a512bff19))
|
||||||
|
|
||||||
|
## [3.18.4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.3...v3.18.4) (2022-12-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **modals:** fix ModalRoot again ([fd94842](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/fd94842647e51dd9a104e170e0c5ee2bebce12d6))
|
||||||
|
|
||||||
|
## [3.18.3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.2...v3.18.3) (2022-12-12)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Router:** update Router interface to SteamOS3.4 and add Navigation ([#52](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/52)) ([f0379e5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/f0379e5d19279863b571e66918bc9107efedb612))
|
||||||
|
|
||||||
|
## [3.18.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.1...v3.18.2) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **useQuickAccessVisible:** remove invalid prop access ([#66](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/66)) ([767dc2f](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/767dc2fcee97d8b6c2d331ae29704d9b469de51a))
|
||||||
|
|
||||||
|
## [3.18.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.18.0...v3.18.1) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **findSP:** fallback to last active context ([#53](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/53)) ([6f14da1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/6f14da152acc4757b814844f1b77bf83dd98d77e))
|
||||||
|
|
||||||
|
# [3.18.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.17.0...v3.18.0) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **DialogCheckbox:** Add DialogCheckbox component ([#58](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/58)) ([88f245d](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/88f245d476a6477e9fc0cd35e9b675961ecbc26c))
|
||||||
|
|
||||||
|
# [3.17.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.16.2...v3.17.0) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **ControlsList:** Add ControlsList component ([#61](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/61)) ([c586afb](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/c586afb97d59928ecb703b5a254ed1b9405e2c7e))
|
||||||
|
|
||||||
|
## [3.16.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.16.1...v3.16.2) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Marquee:** replace default export with named export ([cd0635e](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/cd0635e94f98499f9f5fc24a7fd4b93efe7dfc38))
|
||||||
|
|
||||||
|
## [3.16.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.16.0...v3.16.1) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **FooterLegend:** change description types to ReactNode ([#62](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/62)) ([d24136e](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/d24136ecb6b0c5239b68723e8f92a4822aa7b590))
|
||||||
|
|
||||||
|
# [3.16.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.15.0...v3.16.0) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Marquee:** Add Marquee component ([#63](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/63)) ([925ea8c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/925ea8c3ceaaf6ff2f79b8808908a9b144a4fcff))
|
||||||
|
|
||||||
|
# [3.15.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.14.0...v3.15.0) (2022-12-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Focusable:** add noFocusRing prop type ([#65](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/65)) ([cc29dda](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/cc29ddaf578e21ab2abe1cd266f1d15debee0637))
|
||||||
|
|
||||||
|
# [3.14.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.13.0...v3.14.0) (2022-12-10)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **toast:** add showToast/playSound to ToastData ([#64](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/64)) ([7ba1229](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/7ba1229a4e24fea587b96dc8b078200faf45ddee))
|
||||||
|
|
||||||
|
# [3.13.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.12.0...v3.13.0) (2022-11-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Menu:** add more missing props ([#60](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/60)) [CI SKIP] ([678ba21](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/678ba216f1e194986b0c391398e6f73536cd0102))
|
||||||
|
|
||||||
|
# [3.12.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.11.1...v3.12.0) (2022-11-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **MenuItem:** add missing props ([#59](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/59)) ([c84a091](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/c84a09146935f0942265b7a1e4aadc40e8cf22dc))
|
||||||
|
|
||||||
|
## [3.11.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.11.0...v3.11.1) (2022-11-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Footer:** add types for ActionDescriptionMap ([2ec9519](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/2ec9519b7d6d1cc0d232853ce05a773953b37c5a))
|
||||||
|
|
||||||
|
# [3.11.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.10.0...v3.11.0) (2022-11-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **classes:** add "appDetailsClasses" ([#55](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/55)) ([ed98d14](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/ed98d14b37cf09500afd88e7c8e9c03749119b38))
|
||||||
|
|
||||||
|
# [3.10.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.9.0...v3.10.0) (2022-11-18)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **classes:** add appDetailsHeaderClasses ([#54](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/54)) ([3229162](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/32291620b403f8b65cf378343454a3f2668fb6ee))
|
||||||
|
|
||||||
|
# [3.9.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.8.0...v3.9.0) (2022-11-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **Dialog:** add "focusable" button prop ([#51](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/51)) ([e167ef5](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/e167ef5a138a3edc004db2365334f8455c177132))
|
||||||
|
|
||||||
|
# [3.8.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.7.14...v3.8.0) (2022-11-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **routerhook:** add global components support ([215156d](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/215156d31688faac9028627379e5a3ac4d64ec46))
|
||||||
|
|
||||||
|
## [3.7.14](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.7.13...v3.7.14) (2022-11-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **Menu:** fix on Steam beta ([82768e0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/82768e0415d084deb2af39beb3f9273a83e819de))
|
||||||
|
* **Modal:** fix on Steam beta ([e44187f](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/e44187fe4b9d3e3c9e94490669591599dc5246ba))
|
||||||
|
|
||||||
|
## [3.7.13](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.7.12...v3.7.13) (2022-11-02)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **useQuickAccessVisible:** make it work in beta ([#49](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/49)) ([e1f64a3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/e1f64a38de85073e5cea74ecea4b9cde9a783ecc))
|
||||||
|
|
||||||
## [3.7.12](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.7.11...v3.7.12) (2022-10-29)
|
## [3.7.12](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v3.7.11...v3.7.12) (2022-10-29)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
Library used to develop plugins used for use with [decky-loader](https://github.com/SteamDeckHomebrew/decky-loader).
|
Library used to develop plugins used for use with [decky-loader](https://github.com/SteamDeckHomebrew/decky-loader).
|
||||||
|
|
||||||
## Decky Loader Discord [](https://discord.gg/ZU74G2NJzk)
|
## Decky Loader Discord [](https://deckbrew.xyz/discord)
|
||||||
|
|
||||||
Please contact the developers here for questions and support that cannot be addressed via a Github issue.
|
Please [contact the developers here](https://deckbrew.xyz/discord) for questions and support that cannot be addressed via a Github issue.
|
||||||
|
|
||||||
## Developers and Contributors
|
## Developers and Contributors
|
||||||
|
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "decky-frontend-lib",
|
"name": "decky-frontend-lib",
|
||||||
"version": "3.7.12",
|
"version": "3.24.2",
|
||||||
"description": "A library for building decky plugins",
|
"description": "A library for building decky plugins",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
@@ -9,8 +9,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "shx rm -rf dist && tsc -b",
|
"build": "shx rm -rf dist && tsc -b",
|
||||||
"dev": "tsc -b -w",
|
"dev": "tsc -b -w",
|
||||||
"docs": "typedoc --tsconfig ./tsconfig.json src/**/*",
|
"docs": "typedoc --theme wiki-js --tsconfig ./tsconfig.json src/**/*",
|
||||||
"prepack": "npm run build",
|
|
||||||
"test": "echo 'No tests for now!'",
|
"test": "echo 'No tests for now!'",
|
||||||
"prepare": "husky install",
|
"prepare": "husky install",
|
||||||
"commit": "git-cz"
|
"commit": "git-cz"
|
||||||
@@ -60,11 +59,11 @@
|
|||||||
"semantic-release": "^19.0.3",
|
"semantic-release": "^19.0.3",
|
||||||
"shx": "^0.3.4",
|
"shx": "^0.3.4",
|
||||||
"ts-jest": "^27.1.4",
|
"ts-jest": "^27.1.4",
|
||||||
"typedoc": "^0.23.15",
|
"typedoc": "^0.23.24",
|
||||||
"typedoc-plugin-markdown": "^3.13.6",
|
|
||||||
"typedoc-plugin-mdn-links": "^2.0.0",
|
"typedoc-plugin-mdn-links": "^2.0.0",
|
||||||
"typedoc-plugin-missing-exports": "^1.0.0",
|
"typedoc-plugin-missing-exports": "^1.0.0",
|
||||||
"typescript": "^4.6.3"
|
"typedoc-wikijs-theme": "^1.0.5",
|
||||||
|
"typescript": "^4.9.5"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"peerDependencyRules": {
|
"peerDependencyRules": {
|
||||||
|
|||||||
3151
pnpm-lock.yaml
generated
Executable file → Normal file
3151
pnpm-lock.yaml
generated
Executable file → Normal file
File diff suppressed because it is too large
Load Diff
183
src/custom-components/ReorderableList.tsx
Normal file
183
src/custom-components/ReorderableList.tsx
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
import { Fragment, JSXElementConstructor, ReactElement, ReactNode, useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import { Field, FieldProps, Focusable, GamepadButton } from '../deck-components';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ReorderableList entry of type <T>.
|
||||||
|
* @param label The name of this entry in the list.
|
||||||
|
* @param data Optional data to connect to this entry.
|
||||||
|
* @param position The position of this entry in the list.
|
||||||
|
*/
|
||||||
|
export type ReorderableEntry<T> = {
|
||||||
|
label: ReactNode;
|
||||||
|
data?: T;
|
||||||
|
position: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for a ReorderableList component of type <T>.
|
||||||
|
*
|
||||||
|
* @param animate If the list should animate. @default true
|
||||||
|
*/
|
||||||
|
export type ReorderableListProps<T> = {
|
||||||
|
entries: ReorderableEntry<T>[];
|
||||||
|
onSave: (entries: ReorderableEntry<T>[]) => void;
|
||||||
|
interactables?: JSXElementConstructor<{ entry: ReorderableEntry<T> }>;
|
||||||
|
fieldProps?: FieldProps;
|
||||||
|
animate?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component for creating reorderable lists.
|
||||||
|
*
|
||||||
|
* See an example implementation {@linkplain https://github.com/Tormak9970/Component-Testing-Plugin/blob/main/src/testing-window/ReorderableListTest.tsx here}.
|
||||||
|
*/
|
||||||
|
export function ReorderableList<T>(props: ReorderableListProps<T>) {
|
||||||
|
if (props.animate === undefined) props.animate = true;
|
||||||
|
const [entryList, setEntryList] = useState<ReorderableEntry<T>[]>(
|
||||||
|
props.entries.sort((a: ReorderableEntry<T>, b: ReorderableEntry<T>) => a.position - b.position),
|
||||||
|
);
|
||||||
|
const [reorderEnabled, setReorderEnabled] = useState<boolean>(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setEntryList(props.entries.sort((a: ReorderableEntry<T>, b: ReorderableEntry<T>) => a.position - b.position));
|
||||||
|
}, [props.entries]);
|
||||||
|
|
||||||
|
function toggleReorderEnabled(): void {
|
||||||
|
let newReorderValue = !reorderEnabled;
|
||||||
|
setReorderEnabled(newReorderValue);
|
||||||
|
|
||||||
|
if (!newReorderValue) {
|
||||||
|
props.onSave(entryList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveOnBackout(e: Event) {
|
||||||
|
const event = e as CustomEvent;
|
||||||
|
if (event.detail.button == GamepadButton.CANCEL && reorderEnabled) {
|
||||||
|
setReorderEnabled(!reorderEnabled);
|
||||||
|
props.onSave(entryList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Fragment>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
width: 'inherit',
|
||||||
|
height: 'inherit',
|
||||||
|
flex: '1 1 1px',
|
||||||
|
scrollPadding: '48px 0px',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
alignContent: 'stretch',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Focusable
|
||||||
|
onSecondaryButton={toggleReorderEnabled}
|
||||||
|
onSecondaryActionDescription={reorderEnabled ? 'Save Order' : 'Reorder'}
|
||||||
|
onClick={toggleReorderEnabled}
|
||||||
|
onButtonDown={saveOnBackout}
|
||||||
|
>
|
||||||
|
{entryList.map((entry: ReorderableEntry<T>) => (
|
||||||
|
<ReorderableItem
|
||||||
|
animate={props.animate!}
|
||||||
|
listData={entryList}
|
||||||
|
entryData={entry}
|
||||||
|
reorderEntryFunc={setEntryList}
|
||||||
|
reorderEnabled={reorderEnabled}
|
||||||
|
fieldProps={props.fieldProps}
|
||||||
|
>
|
||||||
|
{props.interactables ? <props.interactables entry={entry} /> : null}
|
||||||
|
</ReorderableItem>
|
||||||
|
))}
|
||||||
|
</Focusable>
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properties for a ReorderableItem component of type <T>
|
||||||
|
*/
|
||||||
|
export type ReorderableListEntryProps<T> = {
|
||||||
|
fieldProps?: FieldProps;
|
||||||
|
listData: ReorderableEntry<T>[];
|
||||||
|
entryData: ReorderableEntry<T>;
|
||||||
|
reorderEntryFunc: CallableFunction;
|
||||||
|
reorderEnabled: boolean;
|
||||||
|
animate: boolean;
|
||||||
|
children: ReactElement | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
function ReorderableItem<T>(props: ReorderableListEntryProps<T>) {
|
||||||
|
const [isSelected, _setIsSelected] = useState<boolean>(false);
|
||||||
|
const [isSelectedLastFrame, setIsSelectedLastFrame] = useState<boolean>(false);
|
||||||
|
const listEntries = props.listData;
|
||||||
|
|
||||||
|
function onReorder(e: Event): void {
|
||||||
|
if (!props.reorderEnabled) return;
|
||||||
|
|
||||||
|
const event = e as CustomEvent;
|
||||||
|
const currentIdx = listEntries.findIndex((entryData: ReorderableEntry<T>) => entryData === props.entryData);
|
||||||
|
const currentIdxValue = listEntries[currentIdx];
|
||||||
|
if (currentIdx < 0) return;
|
||||||
|
|
||||||
|
let targetPosition: number = -1;
|
||||||
|
if (event.detail.button == GamepadButton.DIR_DOWN) {
|
||||||
|
targetPosition = currentIdxValue.position + 1;
|
||||||
|
} else if (event.detail.button == GamepadButton.DIR_UP) {
|
||||||
|
targetPosition = currentIdxValue.position - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetPosition >= listEntries.length || targetPosition < 0) return;
|
||||||
|
|
||||||
|
let otherToUpdate = listEntries.find((entryData: ReorderableEntry<T>) => entryData.position === targetPosition);
|
||||||
|
if (!otherToUpdate) return;
|
||||||
|
|
||||||
|
let currentPosition = currentIdxValue.position;
|
||||||
|
|
||||||
|
currentIdxValue.position = otherToUpdate.position;
|
||||||
|
otherToUpdate.position = currentPosition;
|
||||||
|
|
||||||
|
props.reorderEntryFunc(
|
||||||
|
[...listEntries].sort((a: ReorderableEntry<T>, b: ReorderableEntry<T>) => a.position - b.position),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setIsSelected(val: boolean) {
|
||||||
|
_setIsSelected(val);
|
||||||
|
// Wait 3 frames, then set. I have no idea why, but if you dont wait long enough it doesn't work.
|
||||||
|
for (let i = 0; i < 3; i++) await new Promise((res) => requestAnimationFrame(res));
|
||||||
|
setIsSelectedLastFrame(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={
|
||||||
|
props.animate
|
||||||
|
? {
|
||||||
|
transition:
|
||||||
|
isSelected || isSelectedLastFrame
|
||||||
|
? ''
|
||||||
|
: 'transform 0.3s cubic-bezier(0.25, 1, 0.5, 1), opacity 0.3s cubic-bezier(0.25, 1, 0.5, 1)', // easeOutQuart https://easings.net/#easeOutQuart
|
||||||
|
transform: !props.reorderEnabled || isSelected ? 'scale(1)' : 'scale(0.9)',
|
||||||
|
opacity: !props.reorderEnabled || isSelected ? 1 : 0.7,
|
||||||
|
}
|
||||||
|
: {}
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
label={props.entryData.label}
|
||||||
|
{...props.fieldProps}
|
||||||
|
focusable={!props.children}
|
||||||
|
onButtonDown={onReorder}
|
||||||
|
onGamepadBlur={() => setIsSelected(false)}
|
||||||
|
onGamepadFocus={() => setIsSelected(true)}
|
||||||
|
>
|
||||||
|
<Focusable style={{ display: 'flex', width: '100%', position: 'relative' }}>{props.children}</Focusable>
|
||||||
|
</Field>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -13,6 +13,8 @@ export const SuspensefulImage: FC<SuspensefulImageProps> = (props) => {
|
|||||||
const [error, setError] = useState(false);
|
const [error, setError] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
setLoading(true);
|
||||||
|
setError(false);
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.src = props.src || '';
|
img.src = props.src || '';
|
||||||
img.addEventListener('load', () => {
|
img.addEventListener('load', () => {
|
||||||
@@ -21,7 +23,7 @@ export const SuspensefulImage: FC<SuspensefulImageProps> = (props) => {
|
|||||||
img.addEventListener('error', () => {
|
img.addEventListener('error', () => {
|
||||||
setError(true);
|
setError(true);
|
||||||
});
|
});
|
||||||
}, []);
|
}, [props.src]);
|
||||||
|
|
||||||
return loading ? (
|
return loading ? (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from './SuspensefulImage';
|
export * from './SuspensefulImage';
|
||||||
export * from './ColorPickerModal';
|
export * from './ColorPickerModal';
|
||||||
|
export * from './ReorderableList';
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
export * from './usequickaccessvisible';
|
export * from './useQuickAccessVisible';
|
||||||
|
|||||||
60
src/custom-hooks/useQuickAccessVisible.tsx
Normal file
60
src/custom-hooks/useQuickAccessVisible.tsx
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { getGamepadNavigationTrees } from '../utils';
|
||||||
|
|
||||||
|
function getQuickAccessWindow(): Window | null {
|
||||||
|
const navTrees = getGamepadNavigationTrees();
|
||||||
|
return navTrees.find((tree: any) => tree?.id === 'QuickAccess-NA')?.m_Root?.m_element?.ownerDocument.defaultView ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns state indicating the visibility of quick access menu.
|
||||||
|
*
|
||||||
|
* @returns `true` if quick access menu is visible and `false` otherwise.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* import { VFC, useEffect } from "react";
|
||||||
|
* import { useQuickAccessVisible } from "decky-frontend-lib";
|
||||||
|
*
|
||||||
|
* export const PluginPanelView: VFC<{}> = ({ }) => {
|
||||||
|
* const isVisible = useQuickAccessVisible();
|
||||||
|
*
|
||||||
|
* useEffect(() => {
|
||||||
|
* if (!isVisible) {
|
||||||
|
* return;
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* const interval = setInterval(() => console.log("Hello world!"), 1000);
|
||||||
|
* return () => {
|
||||||
|
* clearInterval(interval);
|
||||||
|
* }
|
||||||
|
* }, [isVisible])
|
||||||
|
*
|
||||||
|
* return (
|
||||||
|
* <div>
|
||||||
|
* {isVisible ? "VISIBLE" : "INVISIBLE"}
|
||||||
|
* </div>
|
||||||
|
* );
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
export function useQuickAccessVisible(): boolean {
|
||||||
|
// By default we say that document is not hidden, unless we know otherwise.
|
||||||
|
// This would cover the cases when Valve breaks something and the quick access window
|
||||||
|
// cannot be accessed anymore - the plugins that use this would continue working somewhat.
|
||||||
|
const [isHidden, setIsHidden] = useState(getQuickAccessWindow()?.document.hidden ?? false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const quickAccessWindow = getQuickAccessWindow();
|
||||||
|
if (quickAccessWindow === null) {
|
||||||
|
console.error('Could not get window of QuickAccess menu!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onVisibilityChange = () => setIsHidden(quickAccessWindow.document.hidden);
|
||||||
|
quickAccessWindow.addEventListener('visibilitychange', onVisibilityChange);
|
||||||
|
return () => {
|
||||||
|
quickAccessWindow.removeEventListener('visibilitychange', onVisibilityChange);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return !isHidden;
|
||||||
|
}
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
declare global {
|
|
||||||
var FocusNavController: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns state indicating the visibility of quick access menu.
|
|
||||||
*
|
|
||||||
* @remarks
|
|
||||||
* During development it is possible to open the quick access menu without giving it
|
|
||||||
* focus in some cases. In such cases, the quick access menu state is invisible.
|
|
||||||
*
|
|
||||||
* This seems to be impossible to replicate when running the deck normally. Even in
|
|
||||||
* the edge cases it always seems to have a focus.
|
|
||||||
*
|
|
||||||
* @returns `true` if quick access menu is visible (focused) and `false` otherwise.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* import { VFC, useEffect } from "react";
|
|
||||||
* import { useQuickAccessVisible } from "decky-frontend-lib";
|
|
||||||
*
|
|
||||||
* export const PluginPanelView: VFC<{}> = ({ }) => {
|
|
||||||
* const isVisible = useQuickAccessVisible();
|
|
||||||
*
|
|
||||||
* useEffect(() => {
|
|
||||||
* if (!isVisible) {
|
|
||||||
* return;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* const interval = setInterval(() => console.log("Hello world!"), 1000);
|
|
||||||
* return () => {
|
|
||||||
* clearInterval(interval);
|
|
||||||
* }
|
|
||||||
* }, [isVisible])
|
|
||||||
*
|
|
||||||
* return (
|
|
||||||
* <div>
|
|
||||||
* {isVisible ? "VISIBLE" : "INVISIBLE"}
|
|
||||||
* </div>
|
|
||||||
* );
|
|
||||||
* };
|
|
||||||
*/
|
|
||||||
export function useQuickAccessVisible(): boolean {
|
|
||||||
// Assuming that the component is rendered in QAM already, so true by default...
|
|
||||||
const [isVisible, setIsVisible] = useState(true);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const quickAccessWindow: Window | null =
|
|
||||||
FocusNavController?.GetGamepadNavTreeByID('QuickAccess-NA')?.m_Root?.m_element?.ownerDocument.defaultView ?? null;
|
|
||||||
if (quickAccessWindow === null) {
|
|
||||||
console.error('Could not get window of QuickAccess menu!');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const onBlur = () => setIsVisible(false);
|
|
||||||
const onFocus = () => setIsVisible(true);
|
|
||||||
|
|
||||||
quickAccessWindow.addEventListener('blur', onBlur);
|
|
||||||
quickAccessWindow.addEventListener('focus', onFocus);
|
|
||||||
return () => {
|
|
||||||
quickAccessWindow.removeEventListener('blur', onBlur);
|
|
||||||
quickAccessWindow.removeEventListener('focus', onFocus);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return isVisible;
|
|
||||||
}
|
|
||||||
@@ -7,9 +7,10 @@ export interface ButtonItemProps extends ItemProps {
|
|||||||
onClick?(e: MouseEvent): void;
|
onClick?(e: MouseEvent): void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
export const ButtonItem =
|
||||||
export const ButtonItem = Object.values(CommonUIModule).find(
|
CommonUIModule.ButtonField ||
|
||||||
(mod: any) =>
|
(Object.values(CommonUIModule).find(
|
||||||
mod?.render?.toString()?.includes('"highlightOnFocus","childrenContainerWidth"') ||
|
(mod: any) =>
|
||||||
mod?.render?.toString()?.includes('childrenContainerWidth:"min"'),
|
mod?.render?.toString()?.includes('"highlightOnFocus","childrenContainerWidth"') ||
|
||||||
) as FC<ButtonItemProps>;
|
mod?.render?.toString()?.includes('childrenContainerWidth:"min"'),
|
||||||
|
) as FC<ButtonItemProps>);
|
||||||
|
|||||||
17
src/deck-components/ControlsList.tsx
Normal file
17
src/deck-components/ControlsList.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { findModuleChild } from '../webpack';
|
||||||
|
import { FC } from 'react';
|
||||||
|
|
||||||
|
export interface ControlsListProps {
|
||||||
|
alignItems?: 'left' | 'right' | 'center';
|
||||||
|
spacing?: 'standard' | 'extra';
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ControlsList: FC<ControlsListProps> = findModuleChild((m) => {
|
||||||
|
if (typeof m !== 'object') return;
|
||||||
|
for (const prop in m) {
|
||||||
|
if (m[prop]?.toString && m[prop].toString().includes('().ControlsListChild') && m[prop].toString().includes('().ControlsListOuterPanel')) {
|
||||||
|
return m[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
});
|
||||||
@@ -9,8 +9,35 @@ export interface DialogCommonProps extends RefAttributes<HTMLDivElement> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface DialogButtonProps extends DialogCommonProps, FooterLegendProps {
|
export interface DialogButtonProps extends DialogCommonProps, FooterLegendProps {
|
||||||
|
/**
|
||||||
|
* Enables/disables the focus around the button.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Default value depends on context, so setting it to `false` will enable it.
|
||||||
|
*/
|
||||||
noFocusRing?: boolean;
|
noFocusRing?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables the button - assigned `on*` methods will not be invoked if clicked.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* Depending on where it is, it might still get focus. In such case it can be
|
||||||
|
* partially disabled separately.
|
||||||
|
*
|
||||||
|
* @see focusable.
|
||||||
|
*/
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables/disables the navigation based focus on button - you won't be able to navigate to
|
||||||
|
* it via the gamepad or keyboard.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* If set to `false`, it still can be clicked and **WILL** become focused until navigated away.
|
||||||
|
* Depending on the context of where the button is, even a disabled button can focused.
|
||||||
|
*/
|
||||||
|
focusable?: boolean;
|
||||||
|
|
||||||
onClick?(e: MouseEvent): void;
|
onClick?(e: MouseEvent): void;
|
||||||
onPointerDown?(e: PointerEvent): void;
|
onPointerDown?(e: PointerEvent): void;
|
||||||
onPointerUp?(e: PointerEvent): void;
|
onPointerUp?(e: PointerEvent): void;
|
||||||
|
|||||||
33
src/deck-components/DialogCheckbox.tsx
Normal file
33
src/deck-components/DialogCheckbox.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { findModule } from '../webpack';
|
||||||
|
import { DialogCommonProps } from './Dialog';
|
||||||
|
import { FooterLegendProps } from './FooterLegend';
|
||||||
|
|
||||||
|
export interface DialogCheckboxProps extends DialogCommonProps, FooterLegendProps {
|
||||||
|
onChange?(checked: boolean): void;
|
||||||
|
label?: ReactNode;
|
||||||
|
description?: ReactNode;
|
||||||
|
disabled?: boolean;
|
||||||
|
tooltip?: string;
|
||||||
|
color?: string;
|
||||||
|
highlightColor?: string;
|
||||||
|
bottomSeparator?: 'standard' | 'thick' | 'none';
|
||||||
|
controlled?: boolean;
|
||||||
|
checked?: boolean;
|
||||||
|
onClick?(evt: Event): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DialogCheckbox = Object.values(findModule((m: any) => {
|
||||||
|
if (typeof m !== 'object') return false;
|
||||||
|
for (const prop in m) {
|
||||||
|
if (m[prop]?.prototype?.GetPanelElementProps) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
})).find((m: any) =>
|
||||||
|
m.contextType &&
|
||||||
|
m.prototype?.render.toString().includes('fallback:') &&
|
||||||
|
m?.prototype?.SetChecked &&
|
||||||
|
m?.prototype?.Toggle &&
|
||||||
|
m?.prototype?.GetPanelElementProps
|
||||||
|
) as FC<DialogCheckboxProps>;
|
||||||
@@ -8,6 +8,7 @@ export interface FocusableProps extends HTMLAttributes<HTMLDivElement>, FooterLe
|
|||||||
'flow-children'?: string;
|
'flow-children'?: string;
|
||||||
focusClassName?: string;
|
focusClassName?: string;
|
||||||
focusWithinClassName?: string;
|
focusWithinClassName?: string;
|
||||||
|
noFocusRing?: boolean;
|
||||||
onActivate?: (e: CustomEvent) => void;
|
onActivate?: (e: CustomEvent) => void;
|
||||||
onCancel?: (e: CustomEvent) => void;
|
onCancel?: (e: CustomEvent) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { ReactNode } from 'react';
|
||||||
|
|
||||||
export enum GamepadButton {
|
export enum GamepadButton {
|
||||||
INVALID,
|
INVALID,
|
||||||
OK,
|
OK,
|
||||||
@@ -29,30 +31,29 @@ export enum GamepadButton {
|
|||||||
STEAM_GUIDE,
|
STEAM_GUIDE,
|
||||||
STEAM_QUICK_MENU,
|
STEAM_QUICK_MENU,
|
||||||
}
|
}
|
||||||
|
export declare enum NavEntryPositionPreferences {
|
||||||
export enum NavEntryPositionPreferences {
|
|
||||||
FIRST,
|
FIRST,
|
||||||
LAST,
|
LAST,
|
||||||
MAINTAIN_X,
|
MAINTAIN_X,
|
||||||
MAINTAIN_Y,
|
MAINTAIN_Y,
|
||||||
PREFERRED_CHILD,
|
PREFERRED_CHILD
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GamepadEventDetail {
|
export interface GamepadEventDetail {
|
||||||
button: number;
|
button: number;
|
||||||
is_repeat?: boolean;
|
is_repeat?: boolean;
|
||||||
source: number;
|
source: number;
|
||||||
}
|
}
|
||||||
|
export declare type ActionDescriptionMap = {
|
||||||
export type GamepadEvent = CustomEvent<GamepadEventDetail>;
|
[key in GamepadButton]?: ReactNode
|
||||||
|
}
|
||||||
|
export declare type GamepadEvent = CustomEvent<GamepadEventDetail>;
|
||||||
export interface FooterLegendProps {
|
export interface FooterLegendProps {
|
||||||
actionDescriptionMap?: unknown;
|
actionDescriptionMap?: ActionDescriptionMap;
|
||||||
onOKActionDescription?: string;
|
onOKActionDescription?: ReactNode;
|
||||||
onCancelActionDescription?: string;
|
onCancelActionDescription?: ReactNode;
|
||||||
onSecondaryActionDescription?: string;
|
onSecondaryActionDescription?: ReactNode;
|
||||||
onOptionsActionDescription?: string;
|
onOptionsActionDescription?: ReactNode;
|
||||||
onMenuActionDescription?: string;
|
onMenuActionDescription?: ReactNode;
|
||||||
onButtonDown?: (evt: GamepadEvent) => void;
|
onButtonDown?: (evt: GamepadEvent) => void;
|
||||||
onButtonUp?: (evt: GamepadEvent) => void;
|
onButtonUp?: (evt: GamepadEvent) => void;
|
||||||
onOKButton?: (evt: GamepadEvent) => void;
|
onOKButton?: (evt: GamepadEvent) => void;
|
||||||
|
|||||||
@@ -8,4 +8,5 @@ export interface ItemProps {
|
|||||||
bottomSeparator?: 'standard' | 'thick' | 'none';
|
bottomSeparator?: 'standard' | 'thick' | 'none';
|
||||||
indentLevel?: number;
|
indentLevel?: number;
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
|
highlightOnFocus?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/deck-components/Marquee.tsx
Normal file
26
src/deck-components/Marquee.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import { CSSProperties, FC } from 'react';
|
||||||
|
|
||||||
|
import { findModuleChild } from '../webpack';
|
||||||
|
|
||||||
|
export interface MarqueeProps {
|
||||||
|
play?: boolean;
|
||||||
|
direction?: 'left' | 'right';
|
||||||
|
speed?: number;
|
||||||
|
delay?: number;
|
||||||
|
fadeLength?: number;
|
||||||
|
center?: boolean;
|
||||||
|
resetOnPause?: boolean;
|
||||||
|
style?: CSSProperties;
|
||||||
|
className?: string;
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Marquee: FC<MarqueeProps> = findModuleChild((m) => {
|
||||||
|
if (typeof m !== 'object') return;
|
||||||
|
for (const prop in m) {
|
||||||
|
if (m[prop]?.toString && m[prop].toString().includes('.Marquee') && m[prop].toString().includes('--fade-length')) {
|
||||||
|
return m[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
});
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
import { FC, ReactNode } from 'react';
|
import { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
|
import { fakeRenderComponent } from '../utils';
|
||||||
import { findModuleChild } from '../webpack';
|
import { findModuleChild } from '../webpack';
|
||||||
|
import { FooterLegendProps } from './FooterLegend';
|
||||||
|
|
||||||
export const showContextMenu: (children: ReactNode, parent?: EventTarget) => void = findModuleChild((m) => {
|
export const showContextMenu: (children: ReactNode, parent?: EventTarget) => void = findModuleChild((m) => {
|
||||||
if (typeof m !== 'object') return undefined;
|
if (typeof m !== 'object') return undefined;
|
||||||
@@ -11,7 +13,7 @@ export const showContextMenu: (children: ReactNode, parent?: EventTarget) => voi
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface MenuProps {
|
export interface MenuProps extends FooterLegendProps {
|
||||||
label: string;
|
label: string;
|
||||||
onCancel?(): void;
|
onCancel?(): void;
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
@@ -38,15 +40,26 @@ export const MenuGroup: FC<MenuGroupProps> = findModuleChild((m) => {
|
|||||||
if (typeof m !== 'object') return undefined;
|
if (typeof m !== 'object') return undefined;
|
||||||
|
|
||||||
for (let prop in m) {
|
for (let prop in m) {
|
||||||
if (m[prop]?.prototype?.RenderSubMenu && m[prop]?.prototype?.ShowSubMenu) {
|
if (
|
||||||
|
(m[prop]?.toString()?.includes?.('bInGamepadUI:') &&
|
||||||
|
fakeRenderComponent(() => m[prop]({overview: {appid: 7}}))?.type?.prototype?.RenderSubMenu) ||
|
||||||
|
(m[prop]?.prototype?.RenderSubMenu && m[prop]?.prototype?.ShowSubMenu)
|
||||||
|
) {
|
||||||
return m[prop];
|
return m[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export interface MenuItemProps {
|
export interface MenuItemProps extends FooterLegendProps {
|
||||||
onSelected?(): void;
|
bInteractableItem?: boolean;
|
||||||
|
onClick?(evt: Event): void;
|
||||||
|
onSelected?(evt: Event): void;
|
||||||
|
onMouseEnter?(evt: MouseEvent): void;
|
||||||
|
onMoveRight?(): void;
|
||||||
|
selected?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
bPlayAudio?: boolean;
|
||||||
|
tone?: 'positive' | 'emphasis' | 'destructive';
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +67,10 @@ export const MenuItem: FC<MenuItemProps> = findModuleChild((m) => {
|
|||||||
if (typeof m !== 'object') return undefined;
|
if (typeof m !== 'object') return undefined;
|
||||||
|
|
||||||
for (let prop in m) {
|
for (let prop in m) {
|
||||||
if (m[prop]?.prototype?.OnOKButton && m[prop]?.prototype?.OnMouseEnter) {
|
if (
|
||||||
|
m[prop]?.render?.toString()?.includes('bPlayAudio:') ||
|
||||||
|
(m[prop]?.prototype?.OnOKButton && m[prop]?.prototype?.OnMouseEnter)
|
||||||
|
) {
|
||||||
return m[prop];
|
return m[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { FC, ReactNode } from 'react';
|
import { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
import { findSP } from '../utils';
|
import { findSP } from '../utils';
|
||||||
import { findModuleChild } from '../webpack';
|
import { findModule, findModuleChild } from '../webpack';
|
||||||
|
|
||||||
// All of the popout options + strTitle are related. Proper usage is not yet known...
|
// All of the popout options + strTitle are related. Proper usage is not yet known...
|
||||||
export interface ShowModalProps {
|
export interface ShowModalProps {
|
||||||
@@ -29,7 +29,30 @@ export interface ShowModalResult {
|
|||||||
Update: (modal: ReactNode) => void;
|
Update: (modal: ReactNode) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const showModalRaw: (modal: ReactNode, parent?: EventTarget, props?: ShowModalProps) => Promise<ShowModalResult> =
|
const showModalRaw:
|
||||||
|
| ((
|
||||||
|
modal: ReactNode,
|
||||||
|
parent?: EventTarget,
|
||||||
|
title?: string,
|
||||||
|
props?: ShowModalProps,
|
||||||
|
unknown1?: unknown,
|
||||||
|
hideActions?: { bHideActions?: boolean },
|
||||||
|
modalManager?: unknown,
|
||||||
|
) => ShowModalResult)
|
||||||
|
| void = findModuleChild((m) => {
|
||||||
|
if (typeof m !== 'object') return undefined;
|
||||||
|
for (let prop in m) {
|
||||||
|
if (
|
||||||
|
typeof m[prop] === 'function' &&
|
||||||
|
m[prop].toString().includes('props.bDisableBackgroundDismiss') &&
|
||||||
|
!m[prop]?.prototype?.Cancel
|
||||||
|
) {
|
||||||
|
return m[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const oldShowModalRaw: ((modal: ReactNode, parent?: EventTarget, props?: ShowModalProps) => ShowModalResult) | void =
|
||||||
findModuleChild((m) => {
|
findModuleChild((m) => {
|
||||||
if (typeof m !== 'object') return undefined;
|
if (typeof m !== 'object') return undefined;
|
||||||
for (let prop in m) {
|
for (let prop in m) {
|
||||||
@@ -39,8 +62,23 @@ const showModalRaw: (modal: ReactNode, parent?: EventTarget, props?: ShowModalPr
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const showModal = (modal: ReactNode, parent?: EventTarget, props?: ShowModalProps): Promise<ShowModalResult> => {
|
export const showModal = (
|
||||||
return showModalRaw(modal, parent || findSP(), props);
|
modal: ReactNode,
|
||||||
|
parent?: EventTarget,
|
||||||
|
props: ShowModalProps = {
|
||||||
|
strTitle: 'Decky Dialog',
|
||||||
|
bHideMainWindowForPopouts: false,
|
||||||
|
},
|
||||||
|
): ShowModalResult => {
|
||||||
|
if (showModalRaw) {
|
||||||
|
return showModalRaw(modal, parent || findSP(), props.strTitle, props, undefined, {
|
||||||
|
bHideActions: props.bHideActionIcons,
|
||||||
|
});
|
||||||
|
} else if (oldShowModalRaw) {
|
||||||
|
return oldShowModalRaw(modal, parent || findSP(), props);
|
||||||
|
} else {
|
||||||
|
throw new Error('[DFL:Modals]: Cannot find showModal function');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ModalRootProps {
|
export interface ModalRootProps {
|
||||||
@@ -79,11 +117,53 @@ export const ConfirmModal = findModuleChild((m) => {
|
|||||||
}
|
}
|
||||||
}) as FC<ConfirmModalProps>;
|
}) as FC<ConfirmModalProps>;
|
||||||
|
|
||||||
export const ModalRoot = findModuleChild((m) => {
|
// new as of december 2022 on beta
|
||||||
if (typeof m !== 'object') return undefined;
|
export const ModalRoot = (Object.values(
|
||||||
for (let prop in m) {
|
findModule((m: any) => {
|
||||||
if (m[prop]?.prototype?.OK && m[prop]?.prototype?.Cancel && m[prop]?.prototype?.render) {
|
if (typeof m !== 'object') return false;
|
||||||
return m[prop];
|
|
||||||
|
for (let prop in m) {
|
||||||
|
if (m[prop]?.m_mapModalManager && Object.values(m)?.find((x: any) => x?.type)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}) as FC<ModalRootProps>;
|
return false;
|
||||||
|
}) || {},
|
||||||
|
)?.find((x: any) => x?.type?.toString()?.includes('((function(){')) ||
|
||||||
|
// before december 2022 beta
|
||||||
|
Object.values(
|
||||||
|
findModule((m: any) => {
|
||||||
|
if (typeof m !== 'object') return false;
|
||||||
|
|
||||||
|
for (let prop in m) {
|
||||||
|
if (m[prop]?.toString()?.includes('"ModalManager","DialogWrapper"')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}) || {},
|
||||||
|
)?.find((x: any) => x?.type?.toString()?.includes('((function(){')) ||
|
||||||
|
// old
|
||||||
|
findModuleChild((m) => {
|
||||||
|
if (typeof m !== 'object') return undefined;
|
||||||
|
for (let prop in m) {
|
||||||
|
if (m[prop]?.prototype?.OK && m[prop]?.prototype?.Cancel && m[prop]?.prototype?.render) {
|
||||||
|
return m[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})) as FC<ModalRootProps>;
|
||||||
|
|
||||||
|
interface SimpleModalProps{
|
||||||
|
active?: boolean,
|
||||||
|
children: ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const ModalModule = findModule((mod) => {
|
||||||
|
if (typeof mod !== 'object' || !mod.__esModule) return undefined;
|
||||||
|
if (mod.SimpleModal && mod.ModalPosition) return mod;
|
||||||
|
})
|
||||||
|
|
||||||
|
export const SimpleModal = ModalModule.SimpleModal as FC<SimpleModalProps>
|
||||||
|
export const ModalPosition = ModalModule.ModalPosition as FC<SimpleModalProps>
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
import { FC } from 'react';
|
import { FC, ReactNode } from 'react';
|
||||||
|
|
||||||
import { findModuleChild } from '../webpack';
|
import { findModuleChild } from '../webpack';
|
||||||
|
|
||||||
|
export const Panel: FC<{ children?: ReactNode; }> = findModuleChild((mod) => {
|
||||||
|
if (typeof mod !== 'object' || !mod.__esModule) return undefined;
|
||||||
|
return mod.Panel;
|
||||||
|
})
|
||||||
|
|
||||||
export interface PanelSectionProps {
|
export interface PanelSectionProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
spinner?: boolean;
|
spinner?: boolean;
|
||||||
|
children?: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [panelSection, mod] = findModuleChild((mod: any) => {
|
const [panelSection, mod] = findModuleChild((mod: any) => {
|
||||||
@@ -18,6 +24,10 @@ const [panelSection, mod] = findModuleChild((mod: any) => {
|
|||||||
|
|
||||||
export const PanelSection = panelSection as FC<PanelSectionProps>;
|
export const PanelSection = panelSection as FC<PanelSectionProps>;
|
||||||
|
|
||||||
export const PanelSectionRow = Object.values(mod).filter(
|
export interface PanelSectionRowProps {
|
||||||
(exp: any) => !exp?.toString()?.includes('.PanelSection'),
|
children?: ReactNode;
|
||||||
)[0] as FC;
|
}
|
||||||
|
// New as of Feb 22 2023 Beta || Old
|
||||||
|
export const PanelSectionRow =
|
||||||
|
mod.PanelSectionRow ||
|
||||||
|
(Object.values(mod).filter((exp: any) => !exp?.toString()?.includes('.PanelSection'))[0] as FC<PanelSectionRowProps>);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { sleep } from '../utils';
|
||||||
import { Module, findModuleChild } from '../webpack';
|
import { Module, findModuleChild } from '../webpack';
|
||||||
|
|
||||||
export enum SideMenu {
|
export enum SideMenu {
|
||||||
@@ -14,7 +15,8 @@ export enum QuickAccessTab {
|
|||||||
Settings,
|
Settings,
|
||||||
Perf,
|
Perf,
|
||||||
Help,
|
Help,
|
||||||
Decky,
|
Music,
|
||||||
|
Decky = 999,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DisplayStatus {
|
export enum DisplayStatus {
|
||||||
@@ -63,28 +65,37 @@ export type AppOverview = {
|
|||||||
sort_as: string;
|
sort_as: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Router {
|
export interface MenuStore {
|
||||||
CloseSideMenus(): void;
|
|
||||||
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
|
|
||||||
GetQuickAccessTab(): QuickAccessTab;
|
|
||||||
Navigate(path: string): void;
|
|
||||||
NavigateBackOrOpenMenu(): void;
|
|
||||||
NavigateToAppProperties(): void;
|
|
||||||
NavigateToBugForum(): void;
|
|
||||||
NavigateToExternalWeb(url: string): void;
|
|
||||||
NavigateToHelp(): void;
|
|
||||||
NavigateToInvites(): void;
|
|
||||||
NavigateToRunningApp(replace?: boolean): void;
|
|
||||||
NavigateToStorage(): void;
|
|
||||||
NavigateToStore(): void;
|
|
||||||
NavigateToStoreApp(appId: number | string): void;
|
|
||||||
NavigateToStoreFreeToPlay(): void;
|
|
||||||
NavigateToStoreManual(): void;
|
|
||||||
NavigateToStoreNewReleases(): void;
|
|
||||||
NavigateToStoreOnSale(): void;
|
|
||||||
ToggleSideMenu(sideMenu: SideMenu): void;
|
|
||||||
CloseSideMenus(): void;
|
|
||||||
OpenSideMenu(sideMenu: SideMenu): void;
|
OpenSideMenu(sideMenu: SideMenu): void;
|
||||||
|
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
|
||||||
|
OpenMainMenu(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WindowRouter {
|
||||||
|
BrowserWindow: Window;
|
||||||
|
MenuStore: MenuStore;
|
||||||
|
Navigate(path: string): void;
|
||||||
|
NavigateToChat(): void;
|
||||||
|
NavigateToSteamWeb(url: string): void;
|
||||||
|
NavigateBack(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WindowStore {
|
||||||
|
GamepadUIMainWindowInstance?: WindowRouter; // Current
|
||||||
|
SteamUIWindows: WindowRouter[];
|
||||||
|
OverlayWindows: WindowRouter[]; // Used by desktop GamepadUI
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Router {
|
||||||
|
WindowStore?: WindowStore;
|
||||||
|
CloseSideMenus(): void;
|
||||||
|
Navigate(path: string): void;
|
||||||
|
NavigateToAppProperties(): void;
|
||||||
|
NavigateToExternalWeb(url: string): void;
|
||||||
|
NavigateToInvites(): void;
|
||||||
|
NavigateToChat(): void;
|
||||||
|
NavigateToLibraryTab(): void;
|
||||||
|
NavigateToLayoutPreview(e: unknown): void;
|
||||||
OpenPowerMenu(unknown?: any): void;
|
OpenPowerMenu(unknown?: any): void;
|
||||||
get RunningApps(): AppOverview[];
|
get RunningApps(): AppOverview[];
|
||||||
get MainRunningApp(): AppOverview | undefined;
|
get MainRunningApp(): AppOverview | undefined;
|
||||||
@@ -96,3 +107,80 @@ export const Router = findModuleChild((m: Module) => {
|
|||||||
if (m[prop]?.Navigate && m[prop]?.NavigationManager) return m[prop];
|
if (m[prop]?.Navigate && m[prop]?.NavigationManager) return m[prop];
|
||||||
}
|
}
|
||||||
}) as Router;
|
}) as Router;
|
||||||
|
|
||||||
|
export interface Navigation {
|
||||||
|
Navigate(path: string): void;
|
||||||
|
NavigateBack(): void;
|
||||||
|
NavigateToAppProperties(): void;
|
||||||
|
NavigateToExternalWeb(url: string): void;
|
||||||
|
NavigateToInvites(): void;
|
||||||
|
NavigateToChat(): void;
|
||||||
|
NavigateToLibraryTab(): void;
|
||||||
|
NavigateToLayoutPreview(e: unknown): void;
|
||||||
|
NavigateToSteamWeb(url: string): void;
|
||||||
|
OpenSideMenu(sideMenu: SideMenu): void;
|
||||||
|
OpenQuickAccessMenu(quickAccessTab?: QuickAccessTab): void;
|
||||||
|
OpenMainMenu(): void;
|
||||||
|
OpenPowerMenu(unknown?: any): void;
|
||||||
|
CloseSideMenus(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let Navigation = {} as Navigation;
|
||||||
|
|
||||||
|
try {
|
||||||
|
(async () => {
|
||||||
|
let InternalNavigators: any = {};
|
||||||
|
if (!Router.NavigateToAppProperties || (Router as unknown as any).deckyShim) {
|
||||||
|
function initInternalNavigators() {
|
||||||
|
try {
|
||||||
|
InternalNavigators = findModuleChild((m: any) => {
|
||||||
|
if (typeof m !== 'object') return undefined;
|
||||||
|
for (let prop in m) {
|
||||||
|
if (m[prop]?.GetNavigator && m[prop]?.SetNavigator) {
|
||||||
|
return m[prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})?.GetNavigator();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[DFL:Router]: Failed to init internal navigators, trying again');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initInternalNavigators();
|
||||||
|
while (!InternalNavigators?.AppProperties) {
|
||||||
|
console.log('[DFL:Router]: Trying to init internal navigators again');
|
||||||
|
await sleep(100);
|
||||||
|
initInternalNavigators();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const newNavigation = {
|
||||||
|
Navigate: Router.Navigate?.bind(Router),
|
||||||
|
NavigateBack: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateBack?.bind(
|
||||||
|
Router.WindowStore.GamepadUIMainWindowInstance,
|
||||||
|
),
|
||||||
|
NavigateToAppProperties: InternalNavigators?.AppProperties || Router.NavigateToAppProperties?.bind(Router),
|
||||||
|
NavigateToExternalWeb: InternalNavigators?.ExternalWeb || Router.NavigateToExternalWeb?.bind(Router),
|
||||||
|
NavigateToInvites: InternalNavigators?.Invites || Router.NavigateToInvites?.bind(Router),
|
||||||
|
NavigateToChat: InternalNavigators?.Chat || Router.NavigateToChat?.bind(Router),
|
||||||
|
NavigateToLibraryTab: InternalNavigators?.LibraryTab || Router.NavigateToLibraryTab?.bind(Router),
|
||||||
|
NavigateToLayoutPreview: Router.NavigateToLayoutPreview?.bind(Router),
|
||||||
|
NavigateToSteamWeb: Router.WindowStore?.GamepadUIMainWindowInstance?.NavigateToSteamWeb?.bind(
|
||||||
|
Router.WindowStore.GamepadUIMainWindowInstance,
|
||||||
|
),
|
||||||
|
OpenSideMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenSideMenu?.bind(
|
||||||
|
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
|
||||||
|
),
|
||||||
|
OpenQuickAccessMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenQuickAccessMenu?.bind(
|
||||||
|
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
|
||||||
|
),
|
||||||
|
OpenMainMenu: Router.WindowStore?.GamepadUIMainWindowInstance?.MenuStore.OpenMainMenu?.bind(
|
||||||
|
Router.WindowStore.GamepadUIMainWindowInstance.MenuStore,
|
||||||
|
),
|
||||||
|
CloseSideMenus: Router.CloseSideMenus?.bind(Router),
|
||||||
|
OpenPowerMenu: Router.OpenPowerMenu?.bind(Router),
|
||||||
|
} as Navigation;
|
||||||
|
|
||||||
|
Object.assign(Navigation, newNavigation);
|
||||||
|
})();
|
||||||
|
} catch (e) {
|
||||||
|
console.error('[DFL:Router]: Error initializing Navigation interface', e);
|
||||||
|
}
|
||||||
|
|||||||
14
src/deck-components/Scroll.tsx
Normal file
14
src/deck-components/Scroll.tsx
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import { FC, ReactNode } from "react";
|
||||||
|
import { findModuleChild, findModule } from "../webpack";
|
||||||
|
|
||||||
|
const ScrollingModule = findModule((mod) => {
|
||||||
|
if (typeof mod !== 'object' || !mod.__esModule) return undefined;
|
||||||
|
if (mod.ScrollPanel) return mod;
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ScrollPanel: FC<{ children?: ReactNode; }> = ScrollingModule.ScrollPanel;
|
||||||
|
|
||||||
|
export const ScrollPanelGroup: FC<{ children?: ReactNode; }> = findModuleChild((mod) => {
|
||||||
|
if (typeof mod !== 'object' || !mod.__esModule) return undefined;
|
||||||
|
return mod.ScrollPanelGroup;
|
||||||
|
})
|
||||||
@@ -3,7 +3,7 @@ import { ReactNode, VFC } from 'react';
|
|||||||
import { Module, findModuleChild } from '../webpack';
|
import { Module, findModuleChild } from '../webpack';
|
||||||
|
|
||||||
export interface SidebarNavigationPage {
|
export interface SidebarNavigationPage {
|
||||||
title: string;
|
title: ReactNode;
|
||||||
content: ReactNode;
|
content: ReactNode;
|
||||||
icon?: ReactNode;
|
icon?: ReactNode;
|
||||||
visible?: boolean;
|
visible?: boolean;
|
||||||
@@ -16,7 +16,7 @@ export interface SidebarNavigationPage {
|
|||||||
|
|
||||||
export interface SidebarNavigationProps {
|
export interface SidebarNavigationProps {
|
||||||
title?: string;
|
title?: string;
|
||||||
pages: SidebarNavigationPage[];
|
pages: (SidebarNavigationPage | 'separator')[];
|
||||||
showTitle?: boolean;
|
showTitle?: boolean;
|
||||||
disableRouteReporting?: boolean;
|
disableRouteReporting?: boolean;
|
||||||
page?: string;
|
page?: string;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export interface SliderFieldProps extends ItemProps {
|
|||||||
valueSuffix?: string;
|
valueSuffix?: string;
|
||||||
minimumDpadGranularity?: number;
|
minimumDpadGranularity?: number;
|
||||||
onChange?(value: number): void;
|
onChange?(value: number): void;
|
||||||
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SliderField = Object.values(CommonUIModule).find((mod: any) =>
|
export const SliderField = Object.values(CommonUIModule).find((mod: any) =>
|
||||||
|
|||||||
317
src/deck-components/SteamClient.ts
Normal file
317
src/deck-components/SteamClient.ts
Normal file
@@ -0,0 +1,317 @@
|
|||||||
|
export interface Apps {
|
||||||
|
RegisterForAppOverviewChanges: any;
|
||||||
|
RegisterForAppDetails: any;
|
||||||
|
RegisterForLocalizationChanges: any;
|
||||||
|
RegisterForWorkshopChanges: any;
|
||||||
|
RegisterForWorkshopItemDownloads: any;
|
||||||
|
GetLibraryBootstrapData: any;
|
||||||
|
RegisterForAchievementChanges: any;
|
||||||
|
GetFriendAchievementsForApp: any;
|
||||||
|
GetMyAchievementsForApp: any;
|
||||||
|
AddUserTagToApps: any;
|
||||||
|
RemoveUserTagFromApps: any;
|
||||||
|
ClearUserTagsOnApps: any;
|
||||||
|
ClearAndSetUserTagsOnApp: any;
|
||||||
|
SetAppHidden: any;
|
||||||
|
ResetHiddenState: any;
|
||||||
|
SetAppLaunchOptions: any;
|
||||||
|
SetAppResolutionOverride: any;
|
||||||
|
SetAppCurrentLanguage: any;
|
||||||
|
SetAppAutoUpdateBehavior: any;
|
||||||
|
SetAppBackgroundDownloadsBehavior: any;
|
||||||
|
ToggleAppFamilyBlockedState: any;
|
||||||
|
ToggleAppSteamCloudEnabled: any;
|
||||||
|
ToggleAppSteamCloudSyncOnSuspendEnabled: any;
|
||||||
|
ToggleOverrideResolutionForInternalDisplay: any;
|
||||||
|
ToggleEnableSteamOverlayForApp: any;
|
||||||
|
ToggleEnableDesktopTheatreForApp: any;
|
||||||
|
BrowseLocalFilesForApp: any;
|
||||||
|
BrowseScreenshotsForApp: any;
|
||||||
|
BrowseScreenshotForApp: any;
|
||||||
|
BackupFilesForApp: any;
|
||||||
|
VerifyFilesForApp: any;
|
||||||
|
CreateDesktopShortcutForApp: any;
|
||||||
|
JoinAppContentBeta: any;
|
||||||
|
JoinAppContentBetaByPassword: any;
|
||||||
|
GetAchievementsInTimeRange: any;
|
||||||
|
GetSubscribedWorkshopItems: any;
|
||||||
|
SubscribeWorkshopItem: any;
|
||||||
|
GetDownloadedWorkshopItems: any;
|
||||||
|
DownloadWorkshopItem: any;
|
||||||
|
SetLocalScreenshotCaption: any;
|
||||||
|
SetLocalScreenshotSpoiler: any;
|
||||||
|
GetDetailsForScreenshotUpload: any;
|
||||||
|
UploadLocalScreenshot: any;
|
||||||
|
DeleteLocalScreenshot: any;
|
||||||
|
GetScreenshotsInTimeRange: any;
|
||||||
|
GetFriendsWhoPlay: any;
|
||||||
|
RequestLegacyCDKeysForApp: any;
|
||||||
|
GetSoundtrackDetails: any;
|
||||||
|
GetStoreTagLocalization: any;
|
||||||
|
GetLaunchOptionsForApp: any;
|
||||||
|
GetResolutionOverrideForApp: any;
|
||||||
|
ScanForShortcuts: any;
|
||||||
|
GetAllShortcuts: any;
|
||||||
|
GetShortcutData: any;
|
||||||
|
AddShortcut: any;
|
||||||
|
RemoveShortcut: any;
|
||||||
|
InstallFlatpakAppAndCreateShortcut: any;
|
||||||
|
ListFlatpakApps: any;
|
||||||
|
UninstallFlatpakApp: any;
|
||||||
|
ShowControllerConfigurator: any;
|
||||||
|
SetThirdPartyControllerConfiguration: any;
|
||||||
|
ToggleAllowDesktopConfiguration: any;
|
||||||
|
SetControllerRumblePreference: any;
|
||||||
|
GetCachedAppDetails: any;
|
||||||
|
SetCachedAppDetails: any;
|
||||||
|
ReportLibraryAssetCacheMiss: any;
|
||||||
|
SaveAchievementProgressCache: any;
|
||||||
|
SetStreamingClientForApp: any;
|
||||||
|
SetCustomArtworkForApp: any;
|
||||||
|
ClearCustomArtworkForApp: any;
|
||||||
|
SetCustomLogoPositionForApp: any;
|
||||||
|
ClearCustomLogoPositionForApp: any;
|
||||||
|
RequestIconDataForApp: any;
|
||||||
|
SpecifyCompatTool: any;
|
||||||
|
GetAvailableCompatTools: any;
|
||||||
|
SetShortcutName: any;
|
||||||
|
SetShortcutExe: any;
|
||||||
|
SetShortcutStartDir: any;
|
||||||
|
SetShortcutLaunchOptions: any;
|
||||||
|
SetShortcutIsVR: any;
|
||||||
|
PromptToChangeShortcut: any;
|
||||||
|
PromptToSelectShortcutIcon: any;
|
||||||
|
InstallApp: any;
|
||||||
|
RunGame: any;
|
||||||
|
VerifyApp: any;
|
||||||
|
StreamGame: any;
|
||||||
|
CancelLaunch: any;
|
||||||
|
TerminateApp: any;
|
||||||
|
UninstallApps: any;
|
||||||
|
ShowStore: any;
|
||||||
|
SetDLCEnabled: any;
|
||||||
|
ContinueGameAction: any;
|
||||||
|
CancelGameAction: any;
|
||||||
|
GetActiveGameActions: any;
|
||||||
|
GetGameActionDetails: any;
|
||||||
|
GetGameActionForApp: any;
|
||||||
|
SkipShaderProcessing: any;
|
||||||
|
MarkEulaAccepted: any;
|
||||||
|
MarkEulaRejected: any;
|
||||||
|
LoadEula: any;
|
||||||
|
GetConflictingFileTimestamps: any;
|
||||||
|
GetCloudPendingRemoteOperations: any;
|
||||||
|
ClearProton: any;
|
||||||
|
RegisterForMarketingMessages: any;
|
||||||
|
FetchMarketingMessages: any;
|
||||||
|
MarkMarketingMessageSeen: any;
|
||||||
|
ReportMarketingMessageSeen: any;
|
||||||
|
RegisterForGameActionStart: any;
|
||||||
|
RegisterForGameActionEnd: any;
|
||||||
|
RegisterForGameActionTaskChange: any;
|
||||||
|
RegisterForGameActionUserRequest: any;
|
||||||
|
RegisterForGameActionShowError: any;
|
||||||
|
RegisterForGameActionShowUI: any;
|
||||||
|
OpenAppSettingsDialog: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Window {
|
||||||
|
RegisterForExternalDisplayChanged: any;
|
||||||
|
SetManualDisplayScaleFactor: any;
|
||||||
|
SetAutoDisplayScale: any;
|
||||||
|
Minimize: any;
|
||||||
|
ProcessShuttingDown: any;
|
||||||
|
ToggleMaximize: any;
|
||||||
|
MoveTo: any;
|
||||||
|
ResizeTo: any;
|
||||||
|
SetMinSize: any;
|
||||||
|
SetResizeGrip: any;
|
||||||
|
SetComposition: any;
|
||||||
|
GamescopeBlur: any;
|
||||||
|
BringToFront: any;
|
||||||
|
SetForegroundWindow: any;
|
||||||
|
SetKeyFocus: any;
|
||||||
|
FlashWindow: any;
|
||||||
|
StopFlashWindow: any;
|
||||||
|
ShowWindow: any;
|
||||||
|
HideWindow: any;
|
||||||
|
SetWindowIcon: any;
|
||||||
|
GetWindowDimensions: any;
|
||||||
|
GetWindowRestoreDetails: any;
|
||||||
|
PositionWindowRelative: any;
|
||||||
|
GetMousePositionDetails: any;
|
||||||
|
IsWindowMinimized: any;
|
||||||
|
GetBrowserID: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamClient {
|
||||||
|
Apps: Apps;
|
||||||
|
Browser: any;
|
||||||
|
BrowserView: any;
|
||||||
|
ClientNotifications: any;
|
||||||
|
Cloud: any;
|
||||||
|
Console: any;
|
||||||
|
Downloads: any;
|
||||||
|
FamilySharing: any;
|
||||||
|
FriendSettings: any;
|
||||||
|
Friends: any;
|
||||||
|
GameSessions: any;
|
||||||
|
Input: any;
|
||||||
|
InstallFolder: any;
|
||||||
|
Installs: any;
|
||||||
|
MachineStorage: any;
|
||||||
|
Messaging: any;
|
||||||
|
Notifications: any;
|
||||||
|
OpenVR: any;
|
||||||
|
Overlay: any;
|
||||||
|
Parental: any;
|
||||||
|
RegisterIFrameNavigatedCallback: any;
|
||||||
|
RemotePlay: any;
|
||||||
|
RoamingStorage: any;
|
||||||
|
Screenshots: any;
|
||||||
|
Settings: any;
|
||||||
|
SharedConnection: any;
|
||||||
|
Stats: any;
|
||||||
|
Storage: any;
|
||||||
|
Streaming: any;
|
||||||
|
System: any;
|
||||||
|
UI: any;
|
||||||
|
URL: any;
|
||||||
|
Updates: any;
|
||||||
|
User: any;
|
||||||
|
WebChat: any;
|
||||||
|
Window: Window;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamShortcut {
|
||||||
|
appid: number;
|
||||||
|
data: {
|
||||||
|
bIsApplication: boolean;
|
||||||
|
strAppName: string;
|
||||||
|
strExePath: string;
|
||||||
|
strArguments: string;
|
||||||
|
strShortcutPath: string;
|
||||||
|
strSortAs: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @prop unAppID is not properly set by Steam for non-steam game shortcuts, so it defaults to 0 for them
|
||||||
|
*/
|
||||||
|
export interface LifetimeNotification {
|
||||||
|
unAppID: number;
|
||||||
|
nInstanceID: number;
|
||||||
|
bRunning: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AppAchievements = {
|
||||||
|
nAchieved: number;
|
||||||
|
nTotal: number;
|
||||||
|
vecAchievedHidden: any[];
|
||||||
|
vecHighlight: any[];
|
||||||
|
vecUnachieved: any[];
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AppLanguages = {
|
||||||
|
strDisplayName: string;
|
||||||
|
strShortName: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogoPinPositions = 'BottomLeft' | 'UpperLeft' | 'CenterCenter' | 'UpperCenter' | 'BottomCenter';
|
||||||
|
|
||||||
|
export interface LogoPosition {
|
||||||
|
pinnedPosition: LogoPinPositions;
|
||||||
|
nWidthPct: number;
|
||||||
|
nHeightPct: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface AppDetails {
|
||||||
|
achievements: AppAchievements;
|
||||||
|
bCanMoveInstallFolder: boolean;
|
||||||
|
bCloudAvailable: boolean;
|
||||||
|
bCloudEnabledForAccount: boolean;
|
||||||
|
bCloudEnabledForApp: boolean;
|
||||||
|
bCloudSyncOnSuspendAvailable: boolean;
|
||||||
|
bCloudSyncOnSuspendEnabled: boolean;
|
||||||
|
bCommunityMarketPresence: boolean;
|
||||||
|
bEnableAllowDesktopConfiguration: boolean;
|
||||||
|
bFreeRemovableLicense: boolean;
|
||||||
|
bHasAllLegacyCDKeys: boolean;
|
||||||
|
bHasAnyLocalContent: boolean;
|
||||||
|
bHasLockedPrivateBetas: boolean;
|
||||||
|
bIsExcludedFromSharing: boolean;
|
||||||
|
bIsSubscribedTo: boolean;
|
||||||
|
bOverlayEnabled: boolean;
|
||||||
|
bOverrideInternalResolution: boolean;
|
||||||
|
bRequiresLegacyCDKey: boolean;
|
||||||
|
bShortcutIsVR: boolean;
|
||||||
|
bShowCDKeyInMenus: boolean;
|
||||||
|
bShowControllerConfig: boolean;
|
||||||
|
bSupportsCDKeyCopyToClipboard: boolean;
|
||||||
|
bVRGameTheatreEnabled: boolean;
|
||||||
|
bWorkshopVisible: boolean;
|
||||||
|
eAppOwnershipFlags: number;
|
||||||
|
eAutoUpdateValue: number;
|
||||||
|
eBackgroundDownloads: number;
|
||||||
|
eCloudSync: number;
|
||||||
|
eControllerRumblePreference: number;
|
||||||
|
eDisplayStatus: number;
|
||||||
|
eEnableThirdPartyControllerConfiguration: number;
|
||||||
|
eSteamInputControllerMask: number;
|
||||||
|
iInstallFolder: number;
|
||||||
|
lDiskUsageBytes: number;
|
||||||
|
lDlcUsageBytes: number;
|
||||||
|
nBuildID: number;
|
||||||
|
nCompatToolPriority: number;
|
||||||
|
nPlaytimeForever: number;
|
||||||
|
nScreenshots: number;
|
||||||
|
rtLastTimePlayed: number;
|
||||||
|
rtLastUpdated: number;
|
||||||
|
rtPurchased: number;
|
||||||
|
selectedLanguage: {
|
||||||
|
strDisplayName: string;
|
||||||
|
strShortName: string;
|
||||||
|
};
|
||||||
|
strCloudBytesAvailable: string;
|
||||||
|
strCloudBytesUsed: string;
|
||||||
|
strCompatToolDisplayName: string;
|
||||||
|
strCompatToolName: string;
|
||||||
|
strDeveloperName: string;
|
||||||
|
strDeveloperURL: string;
|
||||||
|
strDisplayName: string;
|
||||||
|
strExternalSubscriptionURL: string;
|
||||||
|
strFlatpakAppID: string;
|
||||||
|
strHomepageURL: string;
|
||||||
|
strLaunchOptions: string;
|
||||||
|
strManualURL: string;
|
||||||
|
strOwnerSteamID: string;
|
||||||
|
strResolutionOverride: string;
|
||||||
|
strSelectedBeta: string;
|
||||||
|
strShortcutExe: string;
|
||||||
|
strShortcutLaunchOptions: string;
|
||||||
|
strShortcutStartDir: string;
|
||||||
|
strSteamDeckBlogURL: string;
|
||||||
|
unAppID: number;
|
||||||
|
vecBetas: any[];
|
||||||
|
vecDLC: any[];
|
||||||
|
vecDeckCompatTestResults: any[];
|
||||||
|
vecLanguages: AppLanguages[];
|
||||||
|
vecLegacyCDKeys: any[];
|
||||||
|
vecMusicAlbums: any[];
|
||||||
|
vecPlatforms: string[];
|
||||||
|
vecScreenShots: any[];
|
||||||
|
libraryAssets?: {
|
||||||
|
logoPosition?: LogoPosition;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SteamAppOverview {
|
||||||
|
display_name: string;
|
||||||
|
gameid: string;
|
||||||
|
appid: number;
|
||||||
|
icon_hash: string;
|
||||||
|
third_party_mod?: boolean;
|
||||||
|
selected_clientid?: string;
|
||||||
|
BIsModOrShortcut: () => boolean;
|
||||||
|
BIsShortcut: () => boolean;
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@ import { findModuleChild } from '../webpack';
|
|||||||
export const SteamSpinner = findModuleChild((m) => {
|
export const SteamSpinner = findModuleChild((m) => {
|
||||||
if (typeof m !== 'object') return undefined;
|
if (typeof m !== 'object') return undefined;
|
||||||
for (let prop in m) {
|
for (let prop in m) {
|
||||||
if (m[prop]?.toString()?.includes('Steam Spinner') && m[prop].toString().includes('PreloadThrobber'))
|
if (
|
||||||
|
m[prop]?.toString?.()?.includes('Steam Spinner') && m[prop]?.toString?.()?.includes('src')
|
||||||
|
)
|
||||||
return m[prop];
|
return m[prop];
|
||||||
}
|
}
|
||||||
}) as FC<SVGAttributes<SVGElement>>;
|
}) as FC<SVGAttributes<SVGElement>>;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { CommonUIModule } from '../webpack';
|
|||||||
import { ItemProps } from './Item';
|
import { ItemProps } from './Item';
|
||||||
|
|
||||||
export interface ToggleFieldProps extends ItemProps {
|
export interface ToggleFieldProps extends ItemProps {
|
||||||
|
highlightOnFocus?: boolean;
|
||||||
checked: boolean;
|
checked: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
onChange?(checked: boolean): void;
|
onChange?(checked: boolean): void;
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
export * from './Button';
|
export * from './Button';
|
||||||
export * from './ButtonItem';
|
export * from './ButtonItem';
|
||||||
export * from './Carousel';
|
export * from './Carousel';
|
||||||
|
export * from './ControlsList';
|
||||||
export * from './Dialog';
|
export * from './Dialog';
|
||||||
|
export * from './DialogCheckbox';
|
||||||
export * from './Dropdown';
|
export * from './Dropdown';
|
||||||
export * from './Field';
|
export * from './Field';
|
||||||
export * from './Focusable';
|
export * from './Focusable';
|
||||||
export * from './FocusRing';
|
export * from './FocusRing';
|
||||||
export * from './FooterLegend';
|
export * from './FooterLegend';
|
||||||
|
export * from './Marquee';
|
||||||
export * from './Menu';
|
export * from './Menu';
|
||||||
export * from './Modal';
|
export * from './Modal';
|
||||||
export * from './Panel';
|
export * from './Panel';
|
||||||
@@ -21,3 +24,59 @@ export * from './Tabs';
|
|||||||
export * from './TextField';
|
export * from './TextField';
|
||||||
export * from './Toggle';
|
export * from './Toggle';
|
||||||
export * from './ToggleField';
|
export * from './ToggleField';
|
||||||
|
export * from './SteamClient';
|
||||||
|
export * from './Scroll';
|
||||||
|
|
||||||
|
import { AppDetails, LogoPosition, SteamAppOverview, SteamClient } from './SteamClient';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var SteamClient: SteamClient;
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
LocalizationManager: {
|
||||||
|
m_mapTokens: Map<string, string>;
|
||||||
|
m_mapFallbackTokens: Map<string, string>;
|
||||||
|
m_rgLocalesToUse: string[];
|
||||||
|
};
|
||||||
|
App: {
|
||||||
|
m_CurrentUser: {
|
||||||
|
bIsLimited: boolean;
|
||||||
|
bIsOfflineMode: boolean;
|
||||||
|
bSupportAlertActive: boolean;
|
||||||
|
bCanInviteFriends: boolean;
|
||||||
|
NotificationCounts: {
|
||||||
|
comments: number;
|
||||||
|
inventory_items: number;
|
||||||
|
invites: number;
|
||||||
|
gifts: number;
|
||||||
|
offline_messages: number;
|
||||||
|
trade_offers: number;
|
||||||
|
async_game_updates: number;
|
||||||
|
moderator_messages: number;
|
||||||
|
help_request_replies: number;
|
||||||
|
};
|
||||||
|
strAccountBalance: string;
|
||||||
|
strAccountName: string;
|
||||||
|
strSteamID: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
appStore: {
|
||||||
|
GetAppOverviewByAppID: (appId: number) => SteamAppOverview | null;
|
||||||
|
GetCustomVerticalCapsuleURLs: (app: SteamAppOverview) => string[];
|
||||||
|
GetCustomLandcapeImageURLs: (app: SteamAppOverview) => string[];
|
||||||
|
GetCustomHeroImageURLs: (app: SteamAppOverview) => string[];
|
||||||
|
GetCustomLogoImageURLs: (app: SteamAppOverview) => string[];
|
||||||
|
GetLandscapeImageURLForApp: (app: SteamAppOverview) => string;
|
||||||
|
GetVerticalCapsuleURLForApp: (app: SteamAppOverview) => string;
|
||||||
|
GetCachedLandscapeImageURLForApp: (app: SteamAppOverview) => string;
|
||||||
|
GetCachedVerticalImageURLForApp: (app: SteamAppOverview) => string;
|
||||||
|
GetPregeneratedVerticalCapsuleForApp: (app: SteamAppOverview) => string;
|
||||||
|
GetIconURLForApp: (app: SteamAppOverview) => string;
|
||||||
|
};
|
||||||
|
appDetailsStore: {
|
||||||
|
GetAppDetails: (appId: number) => AppDetails | null;
|
||||||
|
GetCustomLogoPosition: (app: SteamAppOverview) => LogoPosition | null;
|
||||||
|
SaveCustomLogoPosition: (app: SteamAppOverview, logoPositions: LogoPosition) => any;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -349,6 +349,350 @@ type GamepadSliderClasses = Record<
|
|||||||
string
|
string
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
type AppDetailsHeaderClasses = Record<
|
||||||
|
| 'AddBoxSizer'
|
||||||
|
| 'Background'
|
||||||
|
| 'Bottom'
|
||||||
|
| 'BottomCenter'
|
||||||
|
| 'BottomLeft'
|
||||||
|
| 'BottomRight'
|
||||||
|
| 'BoxSizer'
|
||||||
|
| 'BoxSizerButtonContainer'
|
||||||
|
| 'BoxSizerContainer'
|
||||||
|
| 'BoxSizerDelete'
|
||||||
|
| 'BoxSizerDragBox'
|
||||||
|
| 'BoxSizerEdge'
|
||||||
|
| 'BoxSizerGridBox'
|
||||||
|
| 'BoxSizerInfo'
|
||||||
|
| 'BoxSizerSettings'
|
||||||
|
| 'BoxSizerValidRegion'
|
||||||
|
| 'CenterCenter'
|
||||||
|
| 'DialogButton'
|
||||||
|
| 'EdgeDown'
|
||||||
|
| 'FallbackArt'
|
||||||
|
| 'Features'
|
||||||
|
| 'FullscreenEnterActive'
|
||||||
|
| 'FullscreenEnterDone'
|
||||||
|
| 'FullscreenEnterStart'
|
||||||
|
| 'FullscreenExitActive'
|
||||||
|
| 'FullscreenExitDone'
|
||||||
|
| 'FullscreenExitStart'
|
||||||
|
| 'HeaderBackgroundImage'
|
||||||
|
| 'ImgBlur'
|
||||||
|
| 'ImgBlurBackdrop'
|
||||||
|
| 'ImgContainer'
|
||||||
|
| 'ImgSrc'
|
||||||
|
| 'Left'
|
||||||
|
| 'Loaded'
|
||||||
|
| 'Middle'
|
||||||
|
| 'NoArt'
|
||||||
|
| 'PinBox'
|
||||||
|
| 'Right'
|
||||||
|
| 'SVGTitle'
|
||||||
|
| 'SaveBoxSizer'
|
||||||
|
| 'TextNameSpace'
|
||||||
|
| 'TitleImageContainer'
|
||||||
|
| 'TitleLogo'
|
||||||
|
| 'TitleSection'
|
||||||
|
| 'Top'
|
||||||
|
| 'TopCapsule'
|
||||||
|
| 'TopGradient'
|
||||||
|
| 'TopLeft'
|
||||||
|
| 'TopRight'
|
||||||
|
| 'UpperCenter'
|
||||||
|
| 'UpperLeft'
|
||||||
|
| 'duration-app-launch',
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type AppDetailsClasses = Record<
|
||||||
|
| 'BreakNarrow'
|
||||||
|
| 'BreakShort'
|
||||||
|
| 'BreakTall'
|
||||||
|
| 'BreakUltraWide'
|
||||||
|
| 'BreakWide'
|
||||||
|
| 'Container'
|
||||||
|
| 'GamepadUIBreakNarrow'
|
||||||
|
| 'GamepadUIBreakShort'
|
||||||
|
| 'GamepadUIBreakWide'
|
||||||
|
| 'Glassy'
|
||||||
|
| 'Header'
|
||||||
|
| 'HeaderLoaded'
|
||||||
|
| 'InnerContainer'
|
||||||
|
| 'ItemFocusAnim-darkGrey'
|
||||||
|
| 'ItemFocusAnim-darkerGrey'
|
||||||
|
| 'ItemFocusAnim-darkerGrey-nocolor'
|
||||||
|
| 'ItemFocusAnim-green'
|
||||||
|
| 'ItemFocusAnim-grey'
|
||||||
|
| 'ItemFocusAnimBorder-darkGrey'
|
||||||
|
| 'PlayBar'
|
||||||
|
| 'PreventScrolling'
|
||||||
|
| 'RightBreakNarrow'
|
||||||
|
| 'RightBreakUltraNarrow'
|
||||||
|
| 'RightBreakUltraWide'
|
||||||
|
| 'RightBreakWide'
|
||||||
|
| 'ScrollContainer'
|
||||||
|
| 'ShowPlayBar'
|
||||||
|
| 'Throbber'
|
||||||
|
| 'duration-app-launch'
|
||||||
|
| 'fadein'
|
||||||
|
| 'focusAnimation'
|
||||||
|
| 'hoverAnimation',
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type GamepadUIClasses = Record<
|
||||||
|
| 'duration-app-launch'
|
||||||
|
| 'TransitionMenuDelay'
|
||||||
|
| 'PanelSection'
|
||||||
|
| 'PanelSectionTitle'
|
||||||
|
| 'Text'
|
||||||
|
| 'PanelSectionRow'
|
||||||
|
| 'Label'
|
||||||
|
| 'ComingSoon'
|
||||||
|
| 'LowBattery'
|
||||||
|
| 'ReallyLow'
|
||||||
|
| 'LowBatteryGauge'
|
||||||
|
| 'Remaining'
|
||||||
|
| 'EmptyNotifications'
|
||||||
|
| 'BatterySectionContainer'
|
||||||
|
| 'BatteryIcon'
|
||||||
|
| 'BatteryPercentageLabel'
|
||||||
|
| 'BatteryDetailsLabels'
|
||||||
|
| 'BatteryProjectedValue'
|
||||||
|
| 'BatteryProjectedLabel'
|
||||||
|
| 'ViewPlaceholder'
|
||||||
|
| 'FullHeight'
|
||||||
|
| 'Title'
|
||||||
|
| 'Container'
|
||||||
|
| 'Open'
|
||||||
|
| 'QuickAccessMenu'
|
||||||
|
| 'HeaderContainer'
|
||||||
|
| 'Menu'
|
||||||
|
| 'HeaderAndFooterVisible'
|
||||||
|
| 'TabContentColumn'
|
||||||
|
| 'Tabs'
|
||||||
|
| 'Tab'
|
||||||
|
| 'Selected'
|
||||||
|
| 'ItemFocusAnim-darkerGrey'
|
||||||
|
| 'ItemFocusAnim-darkerGrey-nocolor'
|
||||||
|
| 'VoiceTab'
|
||||||
|
| 'ItemFocusAnim-green'
|
||||||
|
| 'Blocked'
|
||||||
|
| 'TabPanelHidden'
|
||||||
|
| 'FriendsTitle'
|
||||||
|
| 'FriendsListTabPanel'
|
||||||
|
| 'PanelOuterNav'
|
||||||
|
| 'PanelExitAnchor'
|
||||||
|
| 'TabGroupPanel'
|
||||||
|
| 'FooterBoxShadow'
|
||||||
|
| 'AllTabContents'
|
||||||
|
| 'ContentTransition'
|
||||||
|
| 'ActiveTab'
|
||||||
|
| 'Up'
|
||||||
|
| 'Enter'
|
||||||
|
| 'EnterActive'
|
||||||
|
| 'Exit'
|
||||||
|
| 'ExitActive'
|
||||||
|
| 'Down'
|
||||||
|
| 'KeyboardButton'
|
||||||
|
| 'ItemFocusAnim-darkGrey'
|
||||||
|
| 'ItemFocusAnim-grey'
|
||||||
|
| 'ItemFocusAnimBorder-darkGrey'
|
||||||
|
| 'focusAnimation'
|
||||||
|
| 'hoverAnimation',
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type GamepadTabbedPageClasses = Record<
|
||||||
|
| 'duration-app-launch'
|
||||||
|
| 'headerHeight'
|
||||||
|
| 'contentPadding'
|
||||||
|
| 'GamepadTabbedPage'
|
||||||
|
| 'TabHeaderRowWrapper'
|
||||||
|
| 'Floating'
|
||||||
|
| 'TabRow'
|
||||||
|
| 'TabRowTabs'
|
||||||
|
| 'BleedGlyphs'
|
||||||
|
| 'TabsRowScroll'
|
||||||
|
| 'FixCenterAlignScroll'
|
||||||
|
| 'Tab'
|
||||||
|
| 'Selected'
|
||||||
|
| 'HasAddon'
|
||||||
|
| 'RightAddon'
|
||||||
|
| 'TabTitle'
|
||||||
|
| 'LeftAddon'
|
||||||
|
| 'TabCount'
|
||||||
|
| 'Active'
|
||||||
|
| 'TabBadge'
|
||||||
|
| 'TabCountBadge'
|
||||||
|
| 'TabRowSpacer'
|
||||||
|
| 'Glyphs'
|
||||||
|
| 'Show'
|
||||||
|
| 'TabContents'
|
||||||
|
| 'ContentTransition'
|
||||||
|
| 'TabContentsScroll'
|
||||||
|
| 'Right'
|
||||||
|
| 'Enter'
|
||||||
|
| 'EnterActive'
|
||||||
|
| 'Exit'
|
||||||
|
| 'ExitActive'
|
||||||
|
| 'Left'
|
||||||
|
| 'TabIcon',
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type GamepadContextMenuClasses = Record<
|
||||||
|
| "duration-app-launch"
|
||||||
|
| "BasicContextMenuModal"
|
||||||
|
| "BasicContextMenuHeader"
|
||||||
|
| "BasicContextMenuHeaderShrinkableSpacing"
|
||||||
|
| "BasicContextMenuContainer"
|
||||||
|
| "slideInAnimation"
|
||||||
|
| "contextMenu"
|
||||||
|
| "contextMenuContents"
|
||||||
|
| "hasSubMenu"
|
||||||
|
| "contextMenuFade"
|
||||||
|
| "contextMenuItem"
|
||||||
|
| "active"
|
||||||
|
| "Selected"
|
||||||
|
| "Focused"
|
||||||
|
| "Positive"
|
||||||
|
| "Emphasis"
|
||||||
|
| "Destructive"
|
||||||
|
| "Capitalized"
|
||||||
|
| "MenuSectionHeader"
|
||||||
|
| "UpperCase"
|
||||||
|
| "SubMenu"
|
||||||
|
| "ContextMenuSeparator"
|
||||||
|
| "Label"
|
||||||
|
| "Arrow"
|
||||||
|
| "ItemFocusAnim-darkerGrey-nocolor"
|
||||||
|
| "ItemFocusAnim-darkerGrey"
|
||||||
|
| "ItemFocusAnim-darkGrey"
|
||||||
|
| "ItemFocusAnim-grey"
|
||||||
|
| "ItemFocusAnimBorder-darkGrey"
|
||||||
|
| "ItemFocusAnim-green"
|
||||||
|
| "focusAnimation"
|
||||||
|
| "hoverAnimation",
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type AchievementClasses = Record<
|
||||||
|
| "nAchievementHeight"
|
||||||
|
| "nGlobalAchievementHeight"
|
||||||
|
| "nAchievementsListTitleHeight"
|
||||||
|
| "nAchievementGap"
|
||||||
|
| "AchievementList"
|
||||||
|
| "ListTitle"
|
||||||
|
| "AchievementListItemBase"
|
||||||
|
| "Container"
|
||||||
|
| "Content"
|
||||||
|
| "Right"
|
||||||
|
| "Footer"
|
||||||
|
| "AchievementTitle"
|
||||||
|
| "AchievementDescription"
|
||||||
|
| "AchievementGlobalPercentage"
|
||||||
|
| "InBody"
|
||||||
|
| "VerticalContent"
|
||||||
|
| "UnlockDate"
|
||||||
|
| "AlignEnd"
|
||||||
|
| "ProgressBar"
|
||||||
|
| "ProgressCount"
|
||||||
|
| "AchievementContent"
|
||||||
|
| "HiddenAchievementContent"
|
||||||
|
| "FriendAchievementFooter"
|
||||||
|
| "GlobalPercentage"
|
||||||
|
| "UserUnlockDateTime"
|
||||||
|
| "GlobalAchievementsListHeader"
|
||||||
|
| "SearchField"
|
||||||
|
| "Avatar"
|
||||||
|
| "HeaderText"
|
||||||
|
| "GlobalAchievementListItem"
|
||||||
|
| "UnlockContainer"
|
||||||
|
| "Info"
|
||||||
|
| "Title"
|
||||||
|
| "Description"
|
||||||
|
| "Percent"
|
||||||
|
| "ImageContainer"
|
||||||
|
| "ProgressFill"
|
||||||
|
| "SpoilerWarning"
|
||||||
|
| "Hidden"
|
||||||
|
| "ComparisonAchieverColumn"
|
||||||
|
| "ComparisonAchieverInfo"
|
||||||
|
| "ProgressContainer"
|
||||||
|
| "ProgressLabel"
|
||||||
|
| "Secondary"
|
||||||
|
| "AvatarContainer"
|
||||||
|
| "Unachieved",
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type MainMenuAppRunningClasses = Record<
|
||||||
|
| "duration-app-launch"
|
||||||
|
| "ScrollMask"
|
||||||
|
| "HideMask"
|
||||||
|
| "MainMenuAppRunning"
|
||||||
|
| "MenuOpen"
|
||||||
|
| "NavigationColumn"
|
||||||
|
| "ControllerColumnFocused"
|
||||||
|
| "NavColumnFocused"
|
||||||
|
| "NavigationBox"
|
||||||
|
| "NavigationMenuItem"
|
||||||
|
| "ItemFocusAnim-darkerGrey"
|
||||||
|
| "Active"
|
||||||
|
| "Disabled"
|
||||||
|
| "SwitchAppsTitle"
|
||||||
|
| "SelectableAppWindow"
|
||||||
|
| "ActiveDot"
|
||||||
|
| "NavigationMenuItemSeparator"
|
||||||
|
| "AppColumn"
|
||||||
|
| "FocusedColumn"
|
||||||
|
| "AppColumnContent"
|
||||||
|
| "ActiveContent"
|
||||||
|
| "CurrentGameBackground"
|
||||||
|
| "CurrentGameLogo"
|
||||||
|
| "OverlayAchievements"
|
||||||
|
| "Container"
|
||||||
|
| "OverlayGuides"
|
||||||
|
| "OverlayNotes"
|
||||||
|
| "OverlayInplaceBrowser"
|
||||||
|
| "ItemFocusAnim-darkerGrey-nocolor"
|
||||||
|
| "ItemFocusAnim-darkGrey"
|
||||||
|
| "ItemFocusAnim-grey"
|
||||||
|
| "ItemFocusAnimBorder-darkGrey"
|
||||||
|
| "ItemFocusAnim-green"
|
||||||
|
| "focusAnimation"
|
||||||
|
| "hoverAnimation",
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
|
type BasicAppDetailsSectionStylerClasses = Record<
|
||||||
|
| "duration-app-launch"
|
||||||
|
| "headerPadding"
|
||||||
|
| "Header"
|
||||||
|
| "AppDetailsContent"
|
||||||
|
| "AppDetailsContainer"
|
||||||
|
| "AppDetailsRoot"
|
||||||
|
| "GameInfoContainer"
|
||||||
|
| "GameInfoQuickLinks"
|
||||||
|
| "GameInfoCollections"
|
||||||
|
| "CollectionsHeader"
|
||||||
|
| "PlaySection"
|
||||||
|
| "ActionRow"
|
||||||
|
| "AppDetailSectionList"
|
||||||
|
| "AppActionButton"
|
||||||
|
| "ActionButtonAndStatusPanel"
|
||||||
|
| "AppButtons"
|
||||||
|
| "InvertFocusedIcon"
|
||||||
|
| "DeckVerifiedFeedbackContainer"
|
||||||
|
| "DeckVerifiedFeedbackConfirmationContainer"
|
||||||
|
| "DeckVerifiedFeedbackButton"
|
||||||
|
| "DeckVerifiedFeedbackQuestion"
|
||||||
|
| "DeckVerifiedFeedbackConfirmation",
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
|
||||||
export const quickAccessMenuClasses: QuickAccessMenuClasses = findModule(
|
export const quickAccessMenuClasses: QuickAccessMenuClasses = findModule(
|
||||||
(mod) => typeof mod === 'object' && mod?.Title?.includes('quickaccessmenu'),
|
(mod) => typeof mod === 'object' && mod?.Title?.includes('quickaccessmenu'),
|
||||||
);
|
);
|
||||||
@@ -367,7 +711,7 @@ export const gamepadDialogClasses: GamepadDialogClasses = findModule(
|
|||||||
(mod) => typeof mod === 'object' && mod?.GamepadDialogContent?.includes('gamepaddialog'),
|
(mod) => typeof mod === 'object' && mod?.GamepadDialogContent?.includes('gamepaddialog'),
|
||||||
);
|
);
|
||||||
export const quickAccessControlsClasses: QuickAccessControlsClasses = findModule(
|
export const quickAccessControlsClasses: QuickAccessControlsClasses = findModule(
|
||||||
(mod) => typeof mod === 'object' && mod?.PanelSection?.includes('quickaccesscontrols'),
|
(mod) => typeof mod === 'object' && typeof mod?.PanelSection === 'string' && mod?.PanelSection?.includes('quickaccesscontrols'),
|
||||||
);
|
);
|
||||||
export const updaterFieldClasses: UpdaterFieldClasses = findModule(
|
export const updaterFieldClasses: UpdaterFieldClasses = findModule(
|
||||||
(mod) => typeof mod === 'object' && mod?.OOBEUpdateStatusContainer?.includes('updaterfield'),
|
(mod) => typeof mod === 'object' && mod?.OOBEUpdateStatusContainer?.includes('updaterfield'),
|
||||||
@@ -378,3 +722,27 @@ export const playSectionClasses: PlaySectionClasses = findModule(
|
|||||||
export const gamepadSliderClasses: GamepadSliderClasses = findModule(
|
export const gamepadSliderClasses: GamepadSliderClasses = findModule(
|
||||||
(mod) => typeof mod === 'object' && mod?.SliderControlPanelGroup?.includes('gamepadslider'),
|
(mod) => typeof mod === 'object' && mod?.SliderControlPanelGroup?.includes('gamepadslider'),
|
||||||
);
|
);
|
||||||
|
export const appDetailsHeaderClasses: AppDetailsHeaderClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.TopCapsule?.includes('sharedappdetailsheader'),
|
||||||
|
);
|
||||||
|
export const appDetailsClasses: AppDetailsClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.HeaderLoaded?.includes('appdetails_'),
|
||||||
|
);
|
||||||
|
export const gamepadUIClasses: GamepadUIClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.BasicUiRoot?.includes('gamepadui_'),
|
||||||
|
);
|
||||||
|
export const gamepadTabbedPageClasses: GamepadTabbedPageClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.GamepadTabbedPage?.includes('gamepadtabbedpage_')
|
||||||
|
);
|
||||||
|
export const gamepadContextMenuClasses: GamepadContextMenuClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.BasicContextMenuModal?.includes('gamepadcontextmenu')
|
||||||
|
);
|
||||||
|
export const achievementClasses: AchievementClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.AchievementListItemBase?.includes('achievementslist')
|
||||||
|
);
|
||||||
|
export const mainMenuAppRunningClasses: MainMenuAppRunningClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.MainMenuAppRunning?.includes('mainmenuapprunning')
|
||||||
|
);
|
||||||
|
export const basicAppDetailsSectionStylerClasses: BasicAppDetailsSectionStylerClasses = findModule(
|
||||||
|
(mod) => typeof mod === 'object' && mod?.AppDetailsRoot?.includes('basicappdetailssectionstyler_')
|
||||||
|
);
|
||||||
|
|||||||
@@ -26,8 +26,10 @@ export type RoutePatch = (route: RouteProps) => RouteProps;
|
|||||||
export interface RouterHook {
|
export interface RouterHook {
|
||||||
addRoute(path: string, component: ComponentType, props?: Omit<RouteProps, 'path' | 'children'>): void;
|
addRoute(path: string, component: ComponentType, props?: Omit<RouteProps, 'path' | 'children'>): void;
|
||||||
addPatch(path: string, patch: RoutePatch): RoutePatch;
|
addPatch(path: string, patch: RoutePatch): RoutePatch;
|
||||||
removePatch(path: string, patch: RoutePatch): void;
|
addGlobalComponent(name: string, component: ComponentType): void;
|
||||||
removeRoute(path: string): void;
|
removeRoute(path: string): void;
|
||||||
|
removePatch(path: string, patch: RoutePatch): void;
|
||||||
|
removeGlobalComponent(name: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ToastData {
|
export interface ToastData {
|
||||||
@@ -40,6 +42,10 @@ export interface ToastData {
|
|||||||
contentClassName?: string;
|
contentClassName?: string;
|
||||||
duration?: number;
|
duration?: number;
|
||||||
critical?: boolean;
|
critical?: boolean;
|
||||||
|
eType?: number;
|
||||||
|
sound?: number;
|
||||||
|
playSound?: boolean;
|
||||||
|
showToast?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Toaster {
|
export interface Toaster {
|
||||||
@@ -51,10 +57,26 @@ export interface FilePickerRes {
|
|||||||
realpath: string;
|
realpath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum FileSelectionType {
|
||||||
|
FILE,
|
||||||
|
FOLDER,
|
||||||
|
}
|
||||||
|
|
||||||
export interface ServerAPI {
|
export interface ServerAPI {
|
||||||
routerHook: RouterHook;
|
routerHook: RouterHook;
|
||||||
toaster: Toaster;
|
toaster: Toaster;
|
||||||
openFilePicker(startPath: string, includeFiles?: boolean, regex?: RegExp): Promise<FilePickerRes>;
|
openFilePicker(startPath: string, includeFiles?: boolean, regex?: RegExp): Promise<FilePickerRes>;
|
||||||
|
openFilePickerV2(
|
||||||
|
select: FileSelectionType,
|
||||||
|
startPath: string,
|
||||||
|
includeFiles?: boolean,
|
||||||
|
includeFolders?: boolean,
|
||||||
|
filter?: RegExp | ((file: File) => boolean),
|
||||||
|
extensions?: string[],
|
||||||
|
showHiddenFiles?: boolean,
|
||||||
|
allowAllFiles?: boolean,
|
||||||
|
max?: number,
|
||||||
|
): Promise<FilePickerRes>;
|
||||||
callPluginMethod<TArgs = {}, TRes = {}>(methodName: string, args: TArgs): Promise<ServerResponse<TRes>>;
|
callPluginMethod<TArgs = {}, TRes = {}>(methodName: string, args: TArgs): Promise<ServerResponse<TRes>>;
|
||||||
callServerMethod<TArgs = {}, TRes = {}>(methodName: string, args: TArgs): Promise<ServerResponse<TRes>>;
|
callServerMethod<TArgs = {}, TRes = {}>(methodName: string, args: TArgs): Promise<ServerResponse<TRes>>;
|
||||||
fetchNoCors<TRes = {}>(url: RequestInfo, request?: RequestInit): Promise<ServerResponse<TRes>>;
|
fetchNoCors<TRes = {}>(url: RequestInfo, request?: RequestInit): Promise<ServerResponse<TRes>>;
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
export * from './patcher';
|
export * from './patcher';
|
||||||
export * from './react';
|
export * from './react';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var FocusNavController: any;
|
||||||
|
var GamepadNavTree: any;
|
||||||
|
}
|
||||||
|
|
||||||
export function joinClassNames(...classes: string[]): string {
|
export function joinClassNames(...classes: string[]): string {
|
||||||
return classes.join(' ');
|
return classes.join(' ');
|
||||||
}
|
}
|
||||||
@@ -16,6 +21,22 @@ export function findSP(): Window {
|
|||||||
// old (SP as host)
|
// old (SP as host)
|
||||||
if (document.title == 'SP') return window;
|
if (document.title == 'SP') return window;
|
||||||
// new (SP as popup)
|
// new (SP as popup)
|
||||||
return FocusNavController.m_ActiveContext.m_rgGamepadNavigationTrees.find((x: any) => x.m_ID == 'root_1_').Root
|
const navTrees = getGamepadNavigationTrees();
|
||||||
.Element.ownerDocument.defaultView;
|
return navTrees?.find((x: any) => x.m_ID == 'root_1_').Root.Element.ownerDocument.defaultView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the correct FocusNavController, as the Feb 22 2023 beta has two for some reason.
|
||||||
|
*/
|
||||||
|
export function getFocusNavController(): any {
|
||||||
|
return window.GamepadNavTree?.m_context?.m_controller || window.FocusNavController;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the gamepad navigation trees as Valve seems to be moving them.
|
||||||
|
*/
|
||||||
|
export function getGamepadNavigationTrees(): any {
|
||||||
|
const focusNav = getFocusNavController();
|
||||||
|
const context = focusNav.m_ActiveContext || focusNav.m_LastActiveContext;
|
||||||
|
return context?.m_rgGamepadNavigationTrees;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,17 +46,37 @@ export function fakeRenderComponent(fun: Function, customHooks: any = {}): any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function wrapReactType(node: any, prop: any = 'type') {
|
export function wrapReactType(node: any, prop: any = 'type') {
|
||||||
return (node[prop] = { ...node[prop] });
|
if (node[prop]?.__DECKY_WRAPPED) {
|
||||||
|
return node[prop];
|
||||||
|
} else {
|
||||||
|
return (node[prop] = { ...node[prop], __DECKY_WRAPPED: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function wrapReactClass(node: any, prop: any = 'type') {
|
export function wrapReactClass(node: any, prop: any = 'type') {
|
||||||
const cls = node[prop];
|
if (node[prop]?.__DECKY_WRAPPED) {
|
||||||
const wrappedCls = class extends cls {};
|
return node[prop];
|
||||||
return (node[prop] = wrappedCls);
|
} else {
|
||||||
|
const cls = node[prop];
|
||||||
|
const wrappedCls = class extends cls {
|
||||||
|
static __DECKY_WRAPPED = true;
|
||||||
|
};
|
||||||
|
return (node[prop] = wrappedCls);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getReactRoot(o: HTMLElement | Element | Node) {
|
||||||
|
return (
|
||||||
|
o[Object.keys(o).find((k) => k.startsWith('__reactContainer$')) as string] ||
|
||||||
|
o['_reactRootContainer']?._internalRoot?.current
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getReactInstance(o: HTMLElement | Element | Node) {
|
export function getReactInstance(o: HTMLElement | Element | Node) {
|
||||||
return o[Object.keys(o).find((k) => k.startsWith('__reactInternalInstance')) as string];
|
return (
|
||||||
|
o[Object.keys(o).find((k) => k.startsWith('__reactFiber')) as string] ||
|
||||||
|
o[Object.keys(o).find((k) => k.startsWith('__reactInternalInstance')) as string]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Based on https://github.com/GooseMod/GooseMod/blob/9ef146515a9e59ed4e25665ed365fd72fc0dcf23/src/util/react.js#L20
|
// Based on https://github.com/GooseMod/GooseMod/blob/9ef146515a9e59ed4e25665ed365fd72fc0dcf23/src/util/react.js#L20
|
||||||
|
|||||||
@@ -37,7 +37,11 @@ if (window.webpackJsonp && !window.webpackJsonp.deckyShimmed) {
|
|||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
for (let i of Object.keys(initReq.m)) {
|
for (let i of Object.keys(initReq.m)) {
|
||||||
webpackCache[i] = initReq(i);
|
try {
|
||||||
|
webpackCache[i] = initReq(i);
|
||||||
|
} catch (e) {
|
||||||
|
console.debug("[DFL:Webpack]: Ignoring require error for module", i, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"githubPages": false,
|
|
||||||
"categorizeByGroup": false,
|
"categorizeByGroup": false,
|
||||||
"excludeExternals": true
|
"excludeExternals": true
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user