Fix mobile AI chat keyboard overlap and keep input focused
This commit is contained in:
27
ai-chat.js
27
ai-chat.js
@@ -76,7 +76,9 @@
|
||||
const messages = chatRoot.querySelector(".ai-chat__messages");
|
||||
const form = chatRoot.querySelector(".ai-chat__form");
|
||||
const input = chatRoot.querySelector(".ai-chat__input");
|
||||
const sendBtn = chatRoot.querySelector(".ai-chat__send");
|
||||
const backToTop = document.getElementById("back-to-top");
|
||||
const viewport = window.visualViewport;
|
||||
|
||||
function addMessage(text, fromUser) {
|
||||
const bubble = document.createElement("p");
|
||||
@@ -96,12 +98,14 @@
|
||||
addMessage(introMessage, false);
|
||||
}
|
||||
input.focus();
|
||||
syncKeyboardOffset();
|
||||
}
|
||||
|
||||
function closeChat() {
|
||||
panel.classList.remove("is-open");
|
||||
panel.setAttribute("aria-hidden", "true");
|
||||
fab.setAttribute("aria-expanded", "false");
|
||||
syncKeyboardOffset();
|
||||
}
|
||||
|
||||
function randomItem(items) {
|
||||
@@ -123,6 +127,18 @@
|
||||
);
|
||||
}
|
||||
|
||||
function syncKeyboardOffset() {
|
||||
if (!viewport) {
|
||||
chatRoot.style.setProperty("--ai-chat-keyboard-offset", "0px");
|
||||
return;
|
||||
}
|
||||
const offset = Math.max(
|
||||
0,
|
||||
Math.round(window.innerHeight - viewport.height - viewport.offsetTop),
|
||||
);
|
||||
chatRoot.style.setProperty("--ai-chat-keyboard-offset", `${offset}px`);
|
||||
}
|
||||
|
||||
fab.addEventListener("click", () => {
|
||||
if (panel.classList.contains("is-open")) {
|
||||
closeChat();
|
||||
@@ -132,6 +148,10 @@
|
||||
});
|
||||
|
||||
closeBtn.addEventListener("click", closeChat);
|
||||
sendBtn.addEventListener("pointerdown", (event) => {
|
||||
// Keep focus on the input so mobile keyboards stay open after sending.
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
@@ -142,6 +162,7 @@
|
||||
addMessage(text, true);
|
||||
addMessage(buildReply(), false);
|
||||
input.value = "";
|
||||
input.focus({ preventScroll: true });
|
||||
});
|
||||
|
||||
if (backToTop) {
|
||||
@@ -152,5 +173,11 @@
|
||||
});
|
||||
window.addEventListener("resize", syncChatPosition);
|
||||
}
|
||||
if (viewport) {
|
||||
viewport.addEventListener("resize", syncKeyboardOffset);
|
||||
viewport.addEventListener("scroll", syncKeyboardOffset);
|
||||
}
|
||||
window.addEventListener("resize", syncKeyboardOffset);
|
||||
syncChatPosition();
|
||||
syncKeyboardOffset();
|
||||
})();
|
||||
|
||||
15
styles.css
15
styles.css
@@ -881,7 +881,7 @@ li a span {
|
||||
.ai-chat {
|
||||
position: fixed;
|
||||
right: 24px;
|
||||
bottom: 24px;
|
||||
bottom: calc(24px + var(--ai-chat-keyboard-offset, 0px));
|
||||
z-index: 1100;
|
||||
transition: bottom 0.25s ease;
|
||||
font-family:
|
||||
@@ -896,7 +896,7 @@ li a span {
|
||||
}
|
||||
|
||||
.ai-chat.ai-chat--raised {
|
||||
bottom: 96px;
|
||||
bottom: calc(96px + var(--ai-chat-keyboard-offset, 0px));
|
||||
}
|
||||
|
||||
.ai-chat__fab {
|
||||
@@ -1012,21 +1012,22 @@ li a span {
|
||||
@media (max-width: 600px) {
|
||||
.ai-chat {
|
||||
right: 14px;
|
||||
bottom: 14px;
|
||||
bottom: calc(14px + var(--ai-chat-keyboard-offset, 0px));
|
||||
}
|
||||
|
||||
.ai-chat.ai-chat--raised {
|
||||
bottom: 82px;
|
||||
bottom: calc(82px + var(--ai-chat-keyboard-offset, 0px));
|
||||
}
|
||||
|
||||
.ai-chat__panel {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: var(--ai-chat-keyboard-offset, 0px);
|
||||
width: 100vw;
|
||||
max-width: none;
|
||||
border-radius: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.ai-chat__panel.is-open {
|
||||
|
||||
Reference in New Issue
Block a user