mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 08:22:20 +02:00
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work. > - The new task dialog lets an operator assign work on a phone. > - The mobile picker used fixed coordinates inside the Radix wrapper. > - iOS Safari already makes fixed coordinates relative to the visual viewport. > - The old code added the visual viewport offset a second time. > - This pull request removes the second offset and gives the mobile wrapper full viewport geometry. > - The benefit is a visible picker and search field when the iOS keyboard opens. ## Linked Issues or Issue Description **What happened?** The assignee and project pickers could move outside the visible screen in the new task dialog on iOS. **What did you expect to happen?** The picker and its search field must stay visible above the bottom edge and the software keyboard. **Steps to reproduce** Open the new task dialog on an iPhone. Select Assignee or Project. The picker can move outside the visual viewport when Safari pans the page. **Paperclip version or commit** The problem exists after the change in PR #13343. **Deployment mode** The problem affects the board UI in local and authenticated modes. Refs #13343 ## What Changed - Use visual viewport local coordinates for the new task dialog. - Give the mobile Radix popper wrapper full viewport geometry. - Render both shared selector components as large, titled mobile modals. - Keep desktop selectors as anchored popovers. - Cover the new-task assignee, new-task project, composer assignee, and generic searchable selector in Storybook. - Add iPhone-sized Storybook states for the assignee and project pickers. - Update viewport tests for the corrected coordinate model. ## Verification - `pnpm --filter @paperclipai/ui exec vitest run src/components/NewIssueDialog.test.tsx src/components/InlineEntitySelector.test.tsx` - `pnpm check:token-gates` - Playwright used the iPhone 14 device profile. All mobile modals were inside the 390 by 664 CSS viewport. - Each mobile modal was `x=16, y=16, width=358, height=632`. - A desktop check kept the anchored popover at `width=320, height=211`. ## Risks - Low risk. The CSS only changes narrow mobile viewports. - The full-screen popper wrapper does not receive pointer events. The picker still receives pointer events. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. See `CONTRIBUTING.md`. ## Model Used - OpenAI GPT-5.6, Codex agent with tool use and code execution. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change and contains no internal task ID - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant Storybook documentation to reflect my changes - [x] I have considered and documented any risks above - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Paperclip <noreply@paperclip.ing>
40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import { useEffect, useState, type CSSProperties } from "react";
|
|
|
|
export type MobileEntityPickerViewportStyle = CSSProperties & {
|
|
"--mobile-entity-picker-visual-viewport-height"?: string;
|
|
};
|
|
|
|
function readVisualViewportHeight() {
|
|
const height = window.visualViewport?.height;
|
|
return typeof height === "number" && Number.isFinite(height) && height > 0
|
|
? height
|
|
: null;
|
|
}
|
|
|
|
/** Keeps mobile picker sheets inside the live viewport when a keyboard opens. */
|
|
export function useMobileEntityPickerViewportStyle(): MobileEntityPickerViewportStyle {
|
|
const [height, setHeight] = useState<number | null>(() =>
|
|
typeof window === "undefined" ? null : readVisualViewportHeight(),
|
|
);
|
|
|
|
useEffect(() => {
|
|
const viewport = window.visualViewport;
|
|
if (!viewport) return;
|
|
const update = () => {
|
|
const next = readVisualViewportHeight();
|
|
if (next !== null) setHeight(next);
|
|
};
|
|
update();
|
|
viewport.addEventListener("resize", update);
|
|
viewport.addEventListener("scroll", update);
|
|
return () => {
|
|
viewport.removeEventListener("resize", update);
|
|
viewport.removeEventListener("scroll", update);
|
|
};
|
|
}, []);
|
|
|
|
return height === null
|
|
? {}
|
|
: { "--mobile-entity-picker-visual-viewport-height": `${height}px` };
|
|
}
|