mirror of
https://github.com/MeshCore-Beacon/beacon-web.git
synced 2026-10-16 00:39:55 +00:00
fix(layout): keep region picker right-anchored on desktop (#47)
This commit is contained in:
@@ -114,7 +114,7 @@ function RegionSelector() {
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
align="left"
|
||||
align="left-below-md"
|
||||
width="w-60"
|
||||
renderTrigger={({ toggle }) => (
|
||||
<button
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { useState, useRef, useCallback, useEffect, type ReactNode } from "react";
|
||||
import { useClickOutside } from "../hooks/useClickOutside";
|
||||
|
||||
const ALIGN_CLASS = { left: "left-0", right: "right-0", "left-below-md": "left-0 md:left-auto md:right-0" } as const;
|
||||
|
||||
export function Dropdown({ renderTrigger, align = "right", width = "w-48", fullWidth = false, children }: {
|
||||
renderTrigger: (props: { open: boolean; toggle: () => void }) => ReactNode;
|
||||
align?: "left" | "right";
|
||||
// left-below-md: the trigger sits at the left edge of a phone row but mid-row on desktop
|
||||
align?: "left" | "right" | "left-below-md";
|
||||
width?: string;
|
||||
// stretch + render the panel inline (accordion) for the mobile filter sheet
|
||||
fullWidth?: boolean;
|
||||
@@ -33,7 +36,7 @@ export function Dropdown({ renderTrigger, align = "right", width = "w-48", fullW
|
||||
<div className={
|
||||
fullWidth
|
||||
? "mt-1 w-full bg-bg-raised border border-border rounded-md py-1 max-h-72 overflow-y-auto"
|
||||
: `absolute top-full mt-1 ${align === "left" ? "left-0" : "right-0"} ${width} max-w-[calc(100vw-1.5rem)] bg-bg-raised border border-border rounded-md shadow-lg z-50 py-1 max-h-80 overflow-y-auto`
|
||||
: `absolute top-full mt-1 ${ALIGN_CLASS[align]} ${width} max-w-[calc(100vw-1.5rem)] bg-bg-raised border border-border rounded-md shadow-lg z-50 py-1 max-h-80 overflow-y-auto`
|
||||
}>
|
||||
{children(close)}
|
||||
</div>
|
||||
|
||||
@@ -260,3 +260,14 @@ describe("rate limit badge", () => {
|
||||
expect(screen.queryByText(/RATE LIMITED/)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("AppShell region picker alignment", () => {
|
||||
it("opens rightward only below md so the desktop row's controls stay visible", async () => {
|
||||
vi.mocked(getIatas).mockResolvedValue([]);
|
||||
renderShell();
|
||||
fireEvent.click(screen.getByRole("button", { name: /REGION/ }));
|
||||
const panel = screen.getByPlaceholderText("Filter IATA or name…").closest(".absolute")!;
|
||||
expect(panel.className).toContain("left-0");
|
||||
expect(panel.className).toContain("md:right-0");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,3 +45,18 @@ describe("Dropdown", () => {
|
||||
expect(onClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Dropdown align", () => {
|
||||
it("left-below-md anchors left on phones and flips to right at md", () => {
|
||||
render(
|
||||
<Dropdown align="left-below-md" renderTrigger={({ toggle }) => <button type="button" onClick={toggle}>trigger</button>}>
|
||||
{() => <div data-testid="dropdown-panel">option</div>}
|
||||
</Dropdown>,
|
||||
);
|
||||
fireEvent.click(screen.getByText("trigger"));
|
||||
const panel = screen.getByTestId("dropdown-panel").parentElement!;
|
||||
expect(panel.className).toContain("left-0");
|
||||
expect(panel.className).toContain("md:left-auto");
|
||||
expect(panel.className).toContain("md:right-0");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user