diff options
| author | AAGaming <aagaming@riseup.net> | 2025-10-15 00:31:12 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-15 00:31:12 -0400 |
| commit | 44bb023b804b0ab360214360a3947935fb41c86c (patch) | |
| tree | f1313a32a16297fcaadecc3ba3eb2e21dec4ddb7 /frontend/src | |
| parent | 86b5567d4eac84399245c9a71270d6142ee54ded (diff) | |
| download | decky-loader-44bb023b804b0ab360214360a3947935fb41c86c.tar.gz decky-loader-44bb023b804b0ab360214360a3947935fb41c86c.zip | |
React 19 support (#818)v3.2.0-pre1v3.2.0
Diffstat (limited to 'frontend/src')
| -rw-r--r-- | frontend/src/components/QuickAccessVisibleState.tsx | 4 | ||||
| -rw-r--r-- | frontend/src/components/WithSuspense.tsx | 2 | ||||
| -rw-r--r-- | frontend/src/components/modals/filepicker/FilePickerError.tsx | 2 | ||||
| -rw-r--r-- | frontend/src/index.ts | 18 | ||||
| -rw-r--r-- | frontend/src/plugin-loader.tsx | 22 | ||||
| -rw-r--r-- | frontend/src/plugin.ts | 1 | ||||
| -rw-r--r-- | frontend/src/router-hook.tsx | 10 |
7 files changed, 23 insertions, 36 deletions
diff --git a/frontend/src/components/QuickAccessVisibleState.tsx b/frontend/src/components/QuickAccessVisibleState.tsx index f5c05061..f90c24b4 100644 --- a/frontend/src/components/QuickAccessVisibleState.tsx +++ b/frontend/src/components/QuickAccessVisibleState.tsx @@ -1,10 +1,10 @@ -import { FC, ReactNode, createContext, useContext, useState } from 'react'; +import { FC, PropsWithChildren, createContext, useContext, useState } from 'react'; const QuickAccessVisibleState = createContext<boolean>(false); export const useQuickAccessVisible = () => useContext(QuickAccessVisibleState); -export const QuickAccessVisibleStateProvider: FC<{ tab: any; children: ReactNode }> = ({ children, tab }) => { +export const QuickAccessVisibleStateProvider: FC<PropsWithChildren<{ tab: any }>> = ({ children, tab }) => { const initial = tab.initialVisibility; const [visible, setVisible] = useState<boolean>(initial); // HACK but i can't think of a better way to do this diff --git a/frontend/src/components/WithSuspense.tsx b/frontend/src/components/WithSuspense.tsx index 153bec8d..d6281e3e 100644 --- a/frontend/src/components/WithSuspense.tsx +++ b/frontend/src/components/WithSuspense.tsx @@ -10,7 +10,7 @@ interface WithSuspenseProps { const WithSuspense: FunctionComponent<WithSuspenseProps> = (props) => { const propsCopy = { ...props }; delete propsCopy.children; - (props.children as ReactElement)?.props && Object.assign((props.children as ReactElement).props, propsCopy); // There is probably a better way to do this but valve does it this way so ¯\_(ツ)_/¯ + (props.children as ReactElement<any>)?.props && Object.assign((props.children as ReactElement<any>).props, propsCopy); // There is probably a better way to do this but valve does it this way so ¯\_(ツ)_/¯ return ( <Suspense fallback={ diff --git a/frontend/src/components/modals/filepicker/FilePickerError.tsx b/frontend/src/components/modals/filepicker/FilePickerError.tsx index f2330b9a..ac672226 100644 --- a/frontend/src/components/modals/filepicker/FilePickerError.tsx +++ b/frontend/src/components/modals/filepicker/FilePickerError.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect, useState } from 'react'; +import { FC, JSX, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { IconContext } from 'react-icons'; import { FaExclamationTriangle, FaQuestionCircle, FaUserSlash } from 'react-icons/fa'; diff --git a/frontend/src/index.ts b/frontend/src/index.ts index 2ee018e0..4f4ff4f7 100644 --- a/frontend/src/index.ts +++ b/frontend/src/index.ts @@ -1,8 +1,4 @@ // Sets up DFL, then loads start.ts which starts up the loader -interface Window { - // Shut up TS - SP_REACTDOM: any; -} (async () => { console.debug('[Decky:Boot] Frontend init'); @@ -21,7 +17,19 @@ interface Window { // deliberate partial import const DFLWebpack = await import('@decky/ui/dist/webpack'); window.SP_REACT = DFLWebpack.findModule((m) => m.Component && m.PureComponent && m.useLayoutEffect); - window.SP_REACTDOM = DFLWebpack.findModule((m) => m.createPortal && m.createRoot); + window.SP_REACTDOM = + DFLWebpack.findModule((m) => m.createPortal && m.createRoot) || + DFLWebpack.findModule((m) => m.createPortal && m.__DOM_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE); + + console.debug('[Decky:Boot] Setting up JSX internals...'); + const jsx = DFLWebpack.findModule((m) => m.jsx && Object.keys(m).length == 1)?.jsx; + if (jsx) { + window.SP_JSX = { + jsx, + jsxs: jsx, + Fragment: window.SP_REACT.Fragment, + }; + } } console.debug('[Decky:Boot] Setting up @decky/ui...'); window.DFL = await import('@decky/ui'); diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx index df0a6956..2bdfcec1 100644 --- a/frontend/src/plugin-loader.tsx +++ b/frontend/src/plugin-loader.tsx @@ -120,28 +120,6 @@ class PluginLoader extends Logger { <DeckyStateContextProvider deckyState={this.deckyState}> <FaPlug /> <TabBadge /> - <style> - {` - /* fixes random overscrolling in QAM */ - .${quickAccessMenuClasses?.TabContentColumn} { - flex-grow: 1 !important; - margin-top: 0 !important; - margin-bottom: 0 !important; - justify-content: center !important; - } - .${quickAccessMenuClasses?.Tab} { - flex-grow: 1 !important; - height: unset !important; - --decky-qam-tab-max-height: 64px; /* make things a little easier for themers */ - max-height: var(--decky-qam-tab-max-height) !important; - } - /* they broke the footer a while ago and forgot to update the styles LOL */ - .${quickAccessMenuClasses?.Tabs}.${quickAccessMenuClasses.TabsWithFooter} { - margin-bottom: 0 !important; - padding-bottom: 0 !important; - } - `} - </style> </DeckyStateContextProvider> ), }); diff --git a/frontend/src/plugin.ts b/frontend/src/plugin.ts index 0035990e..f2b99f71 100644 --- a/frontend/src/plugin.ts +++ b/frontend/src/plugin.ts @@ -1,3 +1,4 @@ +import type { JSX } from 'react'; export enum PluginLoadType { LEGACY_EVAL_IIFE = 0, // legacy, uses legacy serverAPI ESMODULE_V1 = 1, // esmodule loading with modern @decky/backend apis diff --git a/frontend/src/router-hook.tsx b/frontend/src/router-hook.tsx index b3355d76..9b5f65dc 100644 --- a/frontend/src/router-hook.tsx +++ b/frontend/src/router-hook.tsx @@ -9,7 +9,7 @@ import { getReactRoot, sleep, } from '@decky/ui'; -import { FC, ReactElement, ReactNode, cloneElement, createElement } from 'react'; +import { FC, JSX, ReactElement, ReactNode, cloneElement, createElement } from 'react'; import type { Route } from 'react-router'; import { @@ -37,7 +37,7 @@ const isPatched = Symbol('is patched'); class RouterHook extends Logger { private routerState: DeckyRouterState = new DeckyRouterState(); private globalComponentsState: DeckyGlobalComponentsState = new DeckyGlobalComponentsState(); - private renderedComponents: ReactElement[] = []; + private renderedComponents: ReactElement<any>[] = []; private Route: any; private DeckyGamepadRouterWrapper = this.gamepadRouterWrapper.bind(this); private DeckyDesktopRouterWrapper = this.desktopRouterWrapper.bind(this); @@ -233,7 +233,7 @@ class RouterHook extends Logger { return <>{this.renderedComponents}</>; } - private gamepadRouterWrapper({ children }: { children: ReactElement }) { + private gamepadRouterWrapper({ children }: { children: ReactElement<any> }) { // Used to store the new replicated routes we create to allow routes to be unpatched. const { routes, routePatches } = useDeckyRouterState(); @@ -251,7 +251,7 @@ class RouterHook extends Logger { return children; } - private desktopRouterWrapper({ children }: { children: ReactElement }) { + private desktopRouterWrapper({ children }: { children: ReactElement<any> }) { // Used to store the new replicated routes we create to allow routes to be unpatched. this.debug('desktop router wrapper render', children); const { routes, routePatches } = useDeckyRouterState(); @@ -287,7 +287,7 @@ class RouterHook extends Logger { if (routes) { if (!routeList[routerIndex - 1]?.length || routeList[routerIndex - 1]?.length !== routes.size) { if (routeList[routerIndex - 1]?.length && routeList[routerIndex - 1].length !== routes.size) routerIndex--; - const newRouterArray: (ReactElement | JSX.Element)[] = []; + const newRouterArray: (ReactElement<any> | JSX.Element)[] = []; routes.forEach(({ component, props }, path) => { newRouterArray.push( <Route path={path} {...props}> |
