diff --git a/plugins/server-drawer/src/lib/createElementIntercept.ts b/plugins/server-drawer/src/lib/createElementIntercept.ts index 30c942b..5ff938b 100644 --- a/plugins/server-drawer/src/lib/createElementIntercept.ts +++ b/plugins/server-drawer/src/lib/createElementIntercept.ts @@ -216,7 +216,7 @@ function resolveReplacement(type: any, props: any, rest: any[]): { type: any; pr if (effectiveProps) { for (const { predicate, transform } of propsTransforms) { try { - if (predicate(effectiveProps, type)) { + if (predicate(effectiveProps, type, rest)) { effectiveProps = transform(effectiveProps); } } catch { @@ -228,7 +228,7 @@ function resolveReplacement(type: any, props: any, rest: any[]): { type: any; pr if (effectiveProps) { for (const { predicate, replacement } of propsIntercepts) { try { - if (predicate(effectiveProps, type)) { + if (predicate(effectiveProps, type, rest)) { return replacement ? { type: replacement, props: effectiveProps } : null; } } catch { @@ -333,7 +333,7 @@ export function patchCreateElement(cleanups: (() => void)[]) { // This is synchronous because the race we're fixing is specifically the first QuestDock render: // an async scan completes too late and the element is created through an unpatched runtime. const initialRuntimes = rawFindAll( - (m: any) => typeof m?.jsx === "function" && typeof m?.jsxs === "function", + (m: any) => typeof m?.jsx === "function" || typeof m?.jsxs === "function" || typeof m?.jsxDEV === "function", ); for (const runtime of initialRuntimes) { patchRuntime(runtime); @@ -344,7 +344,7 @@ export function patchCreateElement(cleanups: (() => void)[]) { scanning = true; rawFindAllAsync( - (m: any) => typeof m?.jsx === "function" && typeof m?.jsxs === "function", + (m: any) => typeof m?.jsx === "function" || typeof m?.jsxs === "function" || typeof m?.jsxDEV === "function", ).then((runtimes) => { for (const runtime of runtimes) { patchRuntime(runtime); diff --git a/plugins/server-drawer/src/patches/contentPatch.tsx b/plugins/server-drawer/src/patches/contentPatch.tsx index fc094e1..8a12a16 100644 --- a/plugins/server-drawer/src/patches/contentPatch.tsx +++ b/plugins/server-drawer/src/patches/contentPatch.tsx @@ -37,6 +37,18 @@ function isQuestDock(type: any): boolean { return QUEST_DOCK_NAMES.some((name) => isNamed(name)(type)); } +const SD_DRAWER_TEST_ID = "ServerDrawer"; + +function hasChildWithTestID(children: any, rest: any[], testID: string): boolean { + const inspect = (child: any) => child != null && typeof child === "object" && child.props?.testID === testID; + if (children != null) { + if (Array.isArray(children)) { if (children.some(inspect)) return true; } + else if (inspect(children)) return true; + } + for (const child of rest) if (inspect(child)) return true; + return false; +} + function ServerDrawerSheetWrapper() { return ; } @@ -63,7 +75,9 @@ export function patchExpanded(cleanups: (() => void)[]): boolean { // Make the quest dock's wrapper(s) transparent - the ServerDrawerSheet content still renders on // top, but the panel/drawer background that used to be behind the quest menu is removed. registerPropsTransform( - (_props: any, type: any) => questDockTypes.has(type), + (props: any, type: any, rest: any[]) => + questDockTypes.has(type) || + hasChildWithTestID(props?.children, rest, SD_DRAWER_TEST_ID), (props: any) => ({ ...props, style: [props?.style, { backgroundColor: "transparent" }] }), ); @@ -73,7 +87,7 @@ export function patchExpanded(cleanups: (() => void)[]): boolean { }, { persistent: true }); registerTypeDetector("ServerDrawer.Expanded", isNamed("QuestDockContentExpanded"), (real) => { - registerIntercept(real, ServerDrawerSheetWrapper); + registerIntercept(real, ServerDrawerSheetWrapper, { testID: SD_DRAWER_TEST_ID }); console.log(TAG, "PATCH: QuestDockContentExpanded replaced (type detector)"); }, { persistent: true }); @@ -84,7 +98,7 @@ export function patchExpanded(cleanups: (() => void)[]): boolean { } const orig = mod.type; - registerIntercept(orig, ServerDrawerSheetWrapper); + registerIntercept(orig, ServerDrawerSheetWrapper, { testID: SD_DRAWER_TEST_ID }); mod.type = ServerDrawerSheetWrapper; cleanups.push(() => { mod.type = orig; }); console.log(TAG, "PATCH: QuestDockContentExpanded replaced (module mutation)"); diff --git a/plugins/server-drawer/src/patches/hideGuildsBar.tsx b/plugins/server-drawer/src/patches/hideGuildsBar.tsx index e3c2289..0166257 100644 --- a/plugins/server-drawer/src/patches/hideGuildsBar.tsx +++ b/plugins/server-drawer/src/patches/hideGuildsBar.tsx @@ -1,9 +1,10 @@ import React from "react"; import { View } from "react-native"; -import { registerTypeDetector, registerIntercept } from "../lib/createElementIntercept"; +import { registerPropsTransform, registerTypeDetector, registerIntercept } from "../lib/createElementIntercept"; import { captureFiberRef } from "../lib/fiberCapture"; const TAG = "[ServerDrawer]"; +const SD_NOTHING_TEST_ID = "ServerDrawerNothing"; // Whether this capture point actually mounts depends entirely on whether the intercept below // fires (unverified independently of it - see lib/fiberCapture.ts for the primary, confirmed @@ -64,12 +65,30 @@ function isGuildsBar(type: any): boolean { * so every future creation of it - which happens on every re-render of GuildsBar's parent, i.e. * whenever the rail would normally repaint - renders nothing instead. */ +function hasChildWithTestID(children: any, rest: any[], testID: string): boolean { + const inspect = (child: any) => child != null && typeof child === "object" && child.props?.testID === testID; + if (children != null) { + if (Array.isArray(children)) { if (children.some(inspect)) return true; } + else if (inspect(children)) return true; + } + for (const child of rest) if (inspect(child)) return true; + return false; +} + export function patchHideGuildsBar(cleanups: (() => void)[]): boolean { + // Hard-enforce the GuildsBar parent's visibility by detecting the hidden Nothing child and + // applying display: none to the rail wrapper itself. + registerPropsTransform( + (props: any, _type: any, rest: any[]) => + hasChildWithTestID(props?.children, rest, SD_NOTHING_TEST_ID), + (props: any) => ({ ...props, style: [props?.style, { display: "none" }] }), + ); + // Use a stable string key so duplicate registrations from retry loops are deduped correctly. registerTypeDetector("ServerDrawer.HideGuildsBar", isGuildsBar, (realGuildsBar) => { // Ask createElementIntercept to collapse a few ancestor levels as well so wrapper // containers around the rail don't leave a leftover gap. - registerIntercept(realGuildsBar, Nothing, undefined, { collapseAncestors: 6 }); + registerIntercept(realGuildsBar, Nothing, { testID: SD_NOTHING_TEST_ID }, { collapseAncestors: 6 }); console.log(TAG, "PATCH: found a real GuildsBar reference, now rendering nothing"); }, { persistent: true }); cleanups.push(() => {