fix(FN-695): portalize QuickEntryBox model selection modal to fix z-index clipping

- Render ModelSelectionModal via createPortal to document.body so it is no longer clipped behind the board on mobile
- Add SSR guard (typeof document check) around the portal call
- Update QuickEntryBox test to assert the modal is portaled outside the component container
- Add changeset for the patch fix
This commit is contained in:
gsxdsm
2026-04-01 09:29:21 -07:00
parent f6ba388536
commit 8bd2fdf5e1
3 changed files with 29 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
import { useState, useCallback, useRef, useEffect } from "react";
import { createPortal } from "react-dom";
import type { ToastType } from "../hooks/useToast";
import type { Task, TaskCreateInput } from "@fusion/core";
import type { ModelInfo, RefinementType } from "../api";
@@ -648,18 +649,23 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
</div>
)}
<ModelSelectionModal
isOpen={isModelModalOpen}
onClose={() => setIsModelModalOpen(false)}
models={loadedModels}
executorValue={executorSelectionValue}
validatorValue={validatorSelectionValue}
onExecutorChange={handleExecutorChange}
onValidatorChange={handleValidatorChange}
modelsLoading={modelsLoading}
modelsError={modelsError}
onRetry={loadModels}
/>
{typeof document !== "undefined"
? createPortal(
<ModelSelectionModal
isOpen={isModelModalOpen}
onClose={() => setIsModelModalOpen(false)}
models={loadedModels}
executorValue={executorSelectionValue}
validatorValue={validatorSelectionValue}
onExecutorChange={handleExecutorChange}
onValidatorChange={handleValidatorChange}
modelsLoading={modelsLoading}
modelsError={modelsError}
onRetry={loadModels}
/>,
document.body,
)
: null}
</div>
);
}

View File

@@ -560,7 +560,7 @@ describe("QuickEntryBox", () => {
it("opens model modal when clicking models button", () => {
renderQuickEntryBox();
const { container } = renderQuickEntryBox();
expandQuickEntry();
const textarea = screen.getByTestId("quick-entry-input");
@@ -573,8 +573,11 @@ describe("QuickEntryBox", () => {
// Click the models button
fireEvent.click(screen.getByTestId("quick-entry-models-button"));
// Modal should now be visible
expect(screen.getByTestId("model-selection-modal")).toBeTruthy();
// Modal should now be visible via portal outside the component container
const modal = screen.getByTestId("model-selection-modal");
expect(modal).toBeTruthy();
expect(container.contains(modal)).toBe(false);
expect(document.body.contains(modal)).toBe(true);
});
it("modal receives correct props (models, loading state, etc.)", () => {