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 messages = chatRoot.querySelector(".ai-chat__messages");
|
||||||
const form = chatRoot.querySelector(".ai-chat__form");
|
const form = chatRoot.querySelector(".ai-chat__form");
|
||||||
const input = chatRoot.querySelector(".ai-chat__input");
|
const input = chatRoot.querySelector(".ai-chat__input");
|
||||||
|
const sendBtn = chatRoot.querySelector(".ai-chat__send");
|
||||||
const backToTop = document.getElementById("back-to-top");
|
const backToTop = document.getElementById("back-to-top");
|
||||||
|
const viewport = window.visualViewport;
|
||||||
|
|
||||||
function addMessage(text, fromUser) {
|
function addMessage(text, fromUser) {
|
||||||
const bubble = document.createElement("p");
|
const bubble = document.createElement("p");
|
||||||
@@ -96,12 +98,14 @@
|
|||||||
addMessage(introMessage, false);
|
addMessage(introMessage, false);
|
||||||
}
|
}
|
||||||
input.focus();
|
input.focus();
|
||||||
|
syncKeyboardOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeChat() {
|
function closeChat() {
|
||||||
panel.classList.remove("is-open");
|
panel.classList.remove("is-open");
|
||||||
panel.setAttribute("aria-hidden", "true");
|
panel.setAttribute("aria-hidden", "true");
|
||||||
fab.setAttribute("aria-expanded", "false");
|
fab.setAttribute("aria-expanded", "false");
|
||||||
|
syncKeyboardOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
function randomItem(items) {
|
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", () => {
|
fab.addEventListener("click", () => {
|
||||||
if (panel.classList.contains("is-open")) {
|
if (panel.classList.contains("is-open")) {
|
||||||
closeChat();
|
closeChat();
|
||||||
@@ -132,6 +148,10 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
closeBtn.addEventListener("click", closeChat);
|
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) => {
|
form.addEventListener("submit", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -142,6 +162,7 @@
|
|||||||
addMessage(text, true);
|
addMessage(text, true);
|
||||||
addMessage(buildReply(), false);
|
addMessage(buildReply(), false);
|
||||||
input.value = "";
|
input.value = "";
|
||||||
|
input.focus({ preventScroll: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
if (backToTop) {
|
if (backToTop) {
|
||||||
@@ -152,5 +173,11 @@
|
|||||||
});
|
});
|
||||||
window.addEventListener("resize", syncChatPosition);
|
window.addEventListener("resize", syncChatPosition);
|
||||||
}
|
}
|
||||||
|
if (viewport) {
|
||||||
|
viewport.addEventListener("resize", syncKeyboardOffset);
|
||||||
|
viewport.addEventListener("scroll", syncKeyboardOffset);
|
||||||
|
}
|
||||||
|
window.addEventListener("resize", syncKeyboardOffset);
|
||||||
syncChatPosition();
|
syncChatPosition();
|
||||||
|
syncKeyboardOffset();
|
||||||
})();
|
})();
|
||||||
|
|||||||
15
styles.css
15
styles.css
@@ -881,7 +881,7 @@ li a span {
|
|||||||
.ai-chat {
|
.ai-chat {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 24px;
|
right: 24px;
|
||||||
bottom: 24px;
|
bottom: calc(24px + var(--ai-chat-keyboard-offset, 0px));
|
||||||
z-index: 1100;
|
z-index: 1100;
|
||||||
transition: bottom 0.25s ease;
|
transition: bottom 0.25s ease;
|
||||||
font-family:
|
font-family:
|
||||||
@@ -896,7 +896,7 @@ li a span {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.ai-chat.ai-chat--raised {
|
.ai-chat.ai-chat--raised {
|
||||||
bottom: 96px;
|
bottom: calc(96px + var(--ai-chat-keyboard-offset, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-chat__fab {
|
.ai-chat__fab {
|
||||||
@@ -1012,21 +1012,22 @@ li a span {
|
|||||||
@media (max-width: 600px) {
|
@media (max-width: 600px) {
|
||||||
.ai-chat {
|
.ai-chat {
|
||||||
right: 14px;
|
right: 14px;
|
||||||
bottom: 14px;
|
bottom: calc(14px + var(--ai-chat-keyboard-offset, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-chat.ai-chat--raised {
|
.ai-chat.ai-chat--raised {
|
||||||
bottom: 82px;
|
bottom: calc(82px + var(--ai-chat-keyboard-offset, 0px));
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-chat__panel {
|
.ai-chat__panel {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
inset: 0;
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
bottom: var(--ai-chat-keyboard-offset, 0px);
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
max-width: none;
|
max-width: none;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.ai-chat__panel.is-open {
|
.ai-chat__panel.is-open {
|
||||||
|
|||||||
Reference in New Issue
Block a user