mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-10-27 21:18:30 -05:00
Hide mobile nav while typing and fix searchable select keyboard on iOS
This commit is contained in:
@@ -11,11 +11,6 @@
|
||||
background: none;
|
||||
color: inherit;
|
||||
z-index: 19;
|
||||
|
||||
--mobile-nav-height: calc(
|
||||
var(--layout-nav-height) +
|
||||
env(safe-area-inset-bottom)
|
||||
);
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) {
|
||||
@@ -25,7 +20,7 @@
|
||||
}
|
||||
|
||||
.tabBar {
|
||||
display: flex;
|
||||
display: var(--mobile-tab-bar-display);
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
height: var(--mobile-nav-height);
|
||||
|
||||
@@ -69,6 +69,15 @@ describe("SendouSelect", () => {
|
||||
.not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("focuses the search input within the opening click", async () => {
|
||||
const screen = await render(<GroupedSelect search={{}} />);
|
||||
const trigger = screen.getByRole("button").element() as HTMLButtonElement;
|
||||
|
||||
trigger.click();
|
||||
|
||||
expect(document.activeElement).toBe(screen.getByRole("combobox").element());
|
||||
});
|
||||
|
||||
test("shows the empty state when nothing matches the search", async () => {
|
||||
const screen = await render(<GroupedSelect search={{}} />);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import clsx from "clsx";
|
||||
import { ChevronsUpDown, Search, X } from "lucide-react";
|
||||
import * as React from "react";
|
||||
import { flushSync } from "react-dom";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { SendouBottomTexts } from "~/components/elements/BottomTexts";
|
||||
import { SendouButton } from "~/components/elements/Button";
|
||||
@@ -299,6 +300,14 @@ export function SendouSelect<T extends object>({
|
||||
scrollIntoView(targetKey);
|
||||
};
|
||||
|
||||
// iOS only brings up the keyboard for a focus inside the tap itself, but the native
|
||||
// open is redone a frame later (useShowPopoverOnOpen), so a searchable select opens here
|
||||
const onTriggerClick = (event: React.MouseEvent) => {
|
||||
if (!search || open) return;
|
||||
event.preventDefault();
|
||||
flushSync(() => setOpen(true));
|
||||
};
|
||||
|
||||
const onTriggerKeyDown = (event: React.KeyboardEvent) => {
|
||||
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
||||
event.preventDefault();
|
||||
@@ -535,6 +544,7 @@ export function SendouSelect<T extends object>({
|
||||
}
|
||||
data-required={isRequired || undefined}
|
||||
{...popoverTriggerProps}
|
||||
onClick={onTriggerClick}
|
||||
onKeyDown={onTriggerKeyDown}
|
||||
>
|
||||
<span
|
||||
|
||||
@@ -670,19 +670,39 @@
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
/* iOS can't pin the tab bar on top of the virtual keyboard, so it gets out of the way while typing */
|
||||
@media (pointer: coarse) {
|
||||
body:has(
|
||||
:is(
|
||||
input:is(
|
||||
:not([type]),
|
||||
[type="text"],
|
||||
[type="search"],
|
||||
[type="email"],
|
||||
[type="url"],
|
||||
[type="tel"],
|
||||
[type="password"],
|
||||
[type="number"]
|
||||
),
|
||||
textarea,
|
||||
[contenteditable]:not([contenteditable="false"])
|
||||
):not([readonly], [inputmode="none"]):focus
|
||||
) {
|
||||
--mobile-nav-height: 0px;
|
||||
--mobile-tab-bar-display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 599px) {
|
||||
body:not(:has(.planner)) .publift-widget-sticky_footer-container {
|
||||
bottom: calc(
|
||||
var(--layout-nav-height) +
|
||||
env(safe-area-inset-bottom)
|
||||
) !important;
|
||||
bottom: var(--mobile-nav-height) !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* the consent dialog is drawn outside the top layer, where the tab bar would cover its buttons */
|
||||
@media screen and (max-width: 599px) {
|
||||
body:not(:has(.planner)) #qc-cmp2-container .qc-cmp-cleanslate {
|
||||
bottom: calc(var(--layout-nav-height) + env(safe-area-inset-bottom));
|
||||
bottom: var(--mobile-nav-height);
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -318,6 +318,11 @@ html,
|
||||
to the document scroll, for a smooth transition between sticking and un-sticking
|
||||
*/
|
||||
--layout-nav-height: 55px;
|
||||
--mobile-nav-height: calc(
|
||||
var(--layout-nav-height) +
|
||||
env(safe-area-inset-bottom)
|
||||
);
|
||||
--mobile-tab-bar-display: flex;
|
||||
--layout-sidenav-width: 250px;
|
||||
--layout-fuse-bottom-height: 90px;
|
||||
--layout-main-padding: var(--s-3);
|
||||
|
||||
4
changelog/2026-10-11-mobile-nav-hides-while-typing.md
Normal file
4
changelog/2026-10-11-mobile-nav-hides-while-typing.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
type: bug
|
||||
---
|
||||
Bottom navigation bar on mobile no longer floats awkwardly above the keyboard, it now hides while typing
|
||||
4
changelog/2026-10-11-searchable-select-keyboard.md
Normal file
4
changelog/2026-10-11-searchable-select-keyboard.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
type: bug
|
||||
---
|
||||
Searchable dropdowns like the weapon picker now bring up the keyboard right away on iPhone
|
||||
Reference in New Issue
Block a user