mirror of
https://github.com/SteamDeckHomebrew/decky-frontend-lib.git
synced 2026-05-20 10:00:08 +02:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b151bdce8b | ||
|
|
e44664c970 | ||
|
|
ac8da8e9b6 | ||
|
|
b688bc3544 | ||
|
|
3126dd3e04 | ||
|
|
8596294667 | ||
|
|
772a85523b | ||
|
|
aabc522740 | ||
|
|
66e0afccae | ||
|
|
77e6acd828 | ||
|
|
261162c8bc | ||
|
|
f8fda380f1 | ||
|
|
7242c69758 |
7
.github/workflows/release.yaml
vendored
7
.github/workflows/release.yaml
vendored
@@ -6,6 +6,10 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
@@ -18,7 +22,7 @@ jobs:
|
||||
- name: Setup | Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
node-version: 24
|
||||
- name: Setup | Dependencies
|
||||
run: npm i -g pnpm && pnpm i --frozen-lockfile
|
||||
- name: Build
|
||||
@@ -29,5 +33,4 @@ jobs:
|
||||
if: github.event_name != 'pull_request'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN_DECKY_ORG }}
|
||||
run: pnpm exec semantic-release
|
||||
|
||||
@@ -1,4 +1 @@
|
||||
#!/usr/bin/env sh
|
||||
. "$(dirname -- "$0")/_/husky.sh"
|
||||
|
||||
npx --no -- commitlint --edit "${1}"
|
||||
|
||||
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,3 +1,36 @@
|
||||
## [4.11.4](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.11.3...v4.11.4) (2026-05-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **dropdown:** hack to fix styling in dropdownitem ([e44664c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/e44664c9704b3b284284619bc26cf6a910890136))
|
||||
* **Field:** fix filter for field on beta ([ac8da8e](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/ac8da8e9b650cfcabcd3e5752e1475e91e7edf7a))
|
||||
|
||||
## [4.11.3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.11.2...v4.11.3) (2026-03-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **Tabs:** update for latest beta ([#129](https://github.com/SteamDeckHomebrew/decky-frontend-lib/issues/129)) ([3126dd3](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/3126dd3e040eaef00eb0362b69efb143d7e01030))
|
||||
|
||||
## [4.11.2](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.11.1...v4.11.2) (2026-03-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **ci:** microsoft ([aabc522](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/aabc5227400f1660ddcb7917fa8f305ad2fce3d7))
|
||||
* **ci:** microsoft stinks ([66e0afc](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/66e0afccae6803ee57d817621340d09a12ba75d8))
|
||||
* **ci:** update semantic release ([772a855](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/772a85523b8c4bbf80ccd4827a89801e3a51cfd6))
|
||||
* **ci:** use new npm publishing auth ([77e6acd](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/77e6acd828b1d0f0978356292b1c46bfc3b8e422))
|
||||
* **components:** update for latest beta ([261162c](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/261162c8bceecc50afad07d57a78b85b98936fe1))
|
||||
|
||||
## [4.11.1](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.11.0...v4.11.1) (2025-11-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **webpack:** ignore window module (lol), ignore filter errors ([7242c69](https://github.com/SteamDeckHomebrew/decky-frontend-lib/commit/7242c697580f3a6a6d373eaacc4fb83ccff9bd2a))
|
||||
|
||||
# [4.11.0](https://github.com/SteamDeckHomebrew/decky-frontend-lib/compare/v4.10.6...v4.11.0) (2025-10-15)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@decky/ui",
|
||||
"version": "4.11.0",
|
||||
"version": "4.11.4",
|
||||
"description": "A library for interacting with the Steam frontend in Decky plugins and elsewhere.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
@@ -57,7 +57,7 @@
|
||||
"minimist": "^1.2.8",
|
||||
"prettier": "^3.6.2",
|
||||
"prettier-plugin-import-sort": "^0.0.7",
|
||||
"semantic-release": "^24.2.7",
|
||||
"semantic-release": "^25.0.3",
|
||||
"shx": "^0.3.4",
|
||||
"ts-jest": "^29.4.1",
|
||||
"typedoc": "^0.25.13",
|
||||
|
||||
894
pnpm-lock.yaml
generated
894
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -52,8 +52,17 @@ export interface DialogButtonProps extends DialogCommonProps, FooterLegendProps
|
||||
}
|
||||
|
||||
const CommonDialogDivs = Object.values(CommonUIModule).filter(
|
||||
(m: any) => typeof m === 'object' && m?.render?.toString().includes('createElement("div",{...') ||
|
||||
m?.render?.toString().includes('createElement("div",Object.assign({},'),
|
||||
(m: any) => typeof m === 'object' &&
|
||||
// New
|
||||
(
|
||||
m?.render?.toString().includes('jsx)("div",{...') ||
|
||||
m?.render?.toString().includes('jsx)("div",Object.assign({},')
|
||||
) ||
|
||||
// Old
|
||||
(
|
||||
m?.render?.toString().includes('createElement("div",{...') ||
|
||||
m?.render?.toString().includes('createElement("div",Object.assign({},')
|
||||
)
|
||||
);
|
||||
const MappedDialogDivs = new Map(
|
||||
Object.values(CommonDialogDivs).map((m: any) => {
|
||||
|
||||
@@ -42,6 +42,8 @@ export const Dropdown = Object.values(CommonUIModule).find(
|
||||
export interface DropdownItemProps extends DropdownProps, ItemProps {}
|
||||
|
||||
const dropdownItemRegex = createPropListRegex(["dropDownControlRef", "description"], false);
|
||||
export const DropdownItem = Object.values(CommonUIModule).find((mod: any) =>
|
||||
export const DropdownItemInternal = Object.values(CommonUIModule).find((mod: any) =>
|
||||
mod?.toString && dropdownItemRegex.test(mod.toString()),
|
||||
) as FC<DropdownItemProps>;
|
||||
|
||||
export const DropdownItem = ((args: DropdownItemProps) => <DropdownItemInternal childrenContainerWidth="min" {...args}/>) as FC<DropdownItemProps>;
|
||||
@@ -24,6 +24,7 @@ export interface FieldProps extends FooterLegendProps {
|
||||
onClick?: (e: CustomEvent | MouseEvent) => void;
|
||||
}
|
||||
|
||||
export const Field = findModuleExport((e: Export) => e?.render?.toString().includes('"shift-children-below"')) as FC<
|
||||
// new || old
|
||||
export const Field = findModuleExport((e: Export) => (e?.toString()?.includes('().Field') && e?.toString()?.includes('"shift-children-below"')) || e?.render?.toString()?.includes('"shift-children-below"')) as FC<
|
||||
FieldProps & RefAttributes<HTMLDivElement>
|
||||
>;
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface ItemProps {
|
||||
layout?: 'below' | 'inline';
|
||||
icon?: ReactNode;
|
||||
bottomSeparator?: 'standard' | 'thick' | 'none';
|
||||
childrenContainerWidth?: 'min' | 'max' | 'fixed'; // Does not work with layout==='below'
|
||||
indentLevel?: number;
|
||||
tooltip?: string;
|
||||
highlightOnFocus?: boolean;
|
||||
|
||||
@@ -28,7 +28,8 @@ export const ProgressBar = findModuleExport((e: Export) =>
|
||||
) as FC<ProgressBarProps>;
|
||||
|
||||
export const ProgressBarWithInfo = findModuleExport((e: Export) =>
|
||||
e?.toString?.()?.includes('.ProgressBarFieldStatus},'),
|
||||
// new || old
|
||||
e?.toString?.()?.includes('.ProgressBarFieldStatus,children') || e?.toString?.()?.includes('.ProgressBarFieldStatus},'),
|
||||
) as FC<ProgressBarWithInfoProps>;
|
||||
|
||||
const progressBarItemRegex = createPropListRegex(["indeterminate", "nTransitionSec", "nProgress"]);
|
||||
|
||||
@@ -11,5 +11,6 @@ export const ScrollPanel = ScrollingModuleProps.find((prop: any) =>
|
||||
) as FC<{ children?: ReactNode }>;
|
||||
|
||||
export const ScrollPanelGroup: FC<{ children?: ReactNode }> = findModuleExport((e: Export) =>
|
||||
e?.render?.toString().includes('.FocusVisibleChild()),[])'),
|
||||
// new || old
|
||||
e?.render?.toString().includes('.FocusVisibleChild(),[])') || e?.render?.toString().includes('.FocusVisibleChild()),[])'),
|
||||
);
|
||||
|
||||
@@ -3,6 +3,6 @@ import { FC, SVGAttributes } from 'react';
|
||||
import { IconsModule } from '../webpack';
|
||||
|
||||
// TODO type this and other icons?
|
||||
export const Spinner = Object.values(IconsModule)?.find(
|
||||
(mod: any) => mod?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()),
|
||||
export const Spinner = IconsModule && Object.values(IconsModule)?.find(
|
||||
(mod: any) => mod?.toString && /Spinner\),children:\[\(0,\w+\.jsx\)\("path",\{d:"M18 /.test(mod.toString()) || /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(mod.toString()),
|
||||
) as FC<SVGAttributes<SVGElement>>;
|
||||
|
||||
@@ -67,4 +67,4 @@ const tabsModule = findModuleByExport(e => e?.toString?.()?.includes(".TabRowTab
|
||||
/**
|
||||
* Tabs component as used in the library and media tabs. See {@link TabsProps}.
|
||||
*/
|
||||
export const Tabs = tabsModule && Object.values(tabsModule).find((e: any) => e?.type?.toString?.()?.includes("((function()")) as FC<TabsProps>;
|
||||
export const Tabs = tabsModule && Object.values(tabsModule).find((e: any) => e?.type?.toString?.()?.includes("(function()")) as FC<TabsProps>;
|
||||
@@ -42,6 +42,9 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
||||
};
|
||||
component.prototype.isReactComponent = true;
|
||||
let stubsApplied = false;
|
||||
const patchJsx = window.SP_REACTDOM.version.startsWith("19.");
|
||||
let oldJsx = window.SP_JSX?.jsx;
|
||||
let oldJsxs = window.SP_JSX?.jsxs;
|
||||
let oldCreateElement = window.SP_REACT.createElement;
|
||||
|
||||
const applyStubsIfNeeded = () => {
|
||||
@@ -55,6 +58,18 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
||||
loggingEnabled && console.trace("createElement trace");
|
||||
return Object.create(component.prototype);
|
||||
};
|
||||
if (patchJsx) {
|
||||
window.SP_JSX.jsx = () => {
|
||||
loggingEnabled && logger.debug("jsx hook called");
|
||||
loggingEnabled && console.trace("jsx trace");
|
||||
return Object.create(component.prototype);
|
||||
}
|
||||
window.SP_JSX.jsxs = () => {
|
||||
loggingEnabled && logger.debug("jsxs hook called");
|
||||
loggingEnabled && console.trace("jsxs trace");
|
||||
return Object.create(component.prototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +79,10 @@ export function injectFCTrampoline(component: FC, customHooks?: any): FCTrampoli
|
||||
stubsApplied = false;
|
||||
removeHookStubs();
|
||||
window.SP_REACT.createElement = oldCreateElement;
|
||||
if (patchJsx) {
|
||||
window.SP_JSX.jsx = oldJsx;
|
||||
window.SP_JSX.jsxs = oldJsxs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ export let modules = new Map<ModuleID, Module>();
|
||||
function initModuleCache() {
|
||||
const startTime = performance.now();
|
||||
logger.group('Webpack Module Init');
|
||||
// Webpack 5, currently on beta
|
||||
// Webpack 5
|
||||
// Generate a fake module ID
|
||||
const id = Symbol("@decky/ui");
|
||||
let webpackRequire!: ((id: any) => Module) & { m: object };
|
||||
@@ -70,15 +70,22 @@ export const findModuleDetailsByExport = (
|
||||
for (const [id, m] of modules) {
|
||||
if (!m) continue;
|
||||
for (const mod of [m.default, m]) {
|
||||
// special cases
|
||||
if (typeof mod !== 'object') continue;
|
||||
if (mod == window) continue; // wtf
|
||||
if (minExports && Object.keys(mod).length < minExports) continue;
|
||||
|
||||
for (let exportName in mod) {
|
||||
if (mod?.[exportName]) {
|
||||
const filterRes = filter(mod[exportName], exportName);
|
||||
if (filterRes) {
|
||||
return [mod, mod[exportName], exportName, id];
|
||||
} else {
|
||||
continue;
|
||||
try {
|
||||
const filterRes = filter(mod[exportName], exportName);
|
||||
if (filterRes) {
|
||||
return [mod, mod[exportName], exportName, id];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} catch (e) {
|
||||
logger.warn("Webpack filter threw exception: ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,6 +106,7 @@ export const findModuleExport = (filter: ExportFilterFn, minExports?: number) =>
|
||||
* @deprecated use findModuleExport instead
|
||||
*/
|
||||
export const findModuleChild = (filter: FindFn) => {
|
||||
logger.warn("findModuleChild is deprecated and will be removed soon. Use findModuleExport instead. Used in:", new Error().stack?.substring(5))
|
||||
for (const m of modules.values()) {
|
||||
for (const mod of [m.default, m]) {
|
||||
const filterRes = filter(mod);
|
||||
@@ -115,6 +123,7 @@ export const findModuleChild = (filter: FindFn) => {
|
||||
* @deprecated use createModuleMapping instead
|
||||
*/
|
||||
export const findAllModules = (filter: FilterFn) => {
|
||||
logger.warn("findAllModules is deprecated and will be removed soon. Use createModuleMapping instead. Used in:", new Error().stack?.substring(5))
|
||||
const out = [];
|
||||
|
||||
for (const m of modules.values()) {
|
||||
@@ -145,7 +154,7 @@ export const CommonUIModule = findModule((m: Module) => {
|
||||
});
|
||||
|
||||
export const IconsModule = findModuleByExport(
|
||||
(e) => e?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
|
||||
(e) => e?.toString && /Spinner\),children:\[\(0,\w+\.jsx\)\("path",\{d:"M18 /.test(e.toString()) || /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
|
||||
);
|
||||
|
||||
export const ReactRouter = findModuleByExport((e) => e.computeRootMatch);
|
||||
|
||||
Reference in New Issue
Block a user