improve message input box

This commit is contained in:
hippoz 2023-07-23 18:58:53 +03:00
parent 17a7aaafdd
commit 97847288fc
Signed by: hippoz
GPG key ID: 56C4E02A85F2FBED
3 changed files with 39 additions and 8 deletions

View file

@ -1,7 +1,7 @@
<script> <script>
import { onDestroy, onMount } from "svelte"; import { onDestroy, onMount } from "svelte";
import { getItem } from "../storage"; import { getItem } from "../storage";
import { selectedChannel, sendMessageAction, setMessageInputEvent, smallViewport, typingStore, userInfoStore } from "../stores"; import { overlayStore, selectedChannel, sendMessageAction, setMessageInputEvent, smallViewport, typingStore, userInfoStore, usesKeyboardNavigation } from "../stores";
export let channel; export let channel;
let messageInput = ""; let messageInput = "";
@ -65,14 +65,21 @@
const unsubscribers = []; const unsubscribers = [];
// Focus the text area when the component first loads, or when the user selects another channel const handleDocumentKeydown = () => {
const focusTextarea = () => { if (document.activeElement && (["input", "textarea"]).includes(document.activeElement.tagName.toLowerCase())) {
if (messageTextarea && getItem("ui:useragent:formFactor") !== "touch") { return;
messageTextarea.focus();
} }
if (overlayStore.isOverlayPresent()) {
return;
}
messageTextarea.focus();
}; };
onMount(focusTextarea);
unsubscribers.push(selectedChannel.on(focusTextarea)); onMount(() => {
document.addEventListener("keydown", handleDocumentKeydown);
return () => document.removeEventListener("keydown", handleDocumentKeydown);
});
// Handle the setMessageInput event // Handle the setMessageInput event
unsubscribers.push(setMessageInputEvent.on((value) => { unsubscribers.push(setMessageInputEvent.on((value) => {
@ -121,7 +128,11 @@
contain: strict; contain: strict;
} }
/* TODO: is this good? */
.message-input:focus-visible { .message-input:focus-visible {
outline: none;
}
.message-input.keyboard-nav:focus-visible {
outline: 2px solid var(--purple-2); outline: 2px solid var(--purple-2);
} }
@ -179,6 +190,7 @@
bind:value={ messageInput } bind:value={ messageInput }
bind:this={ messageTextarea } bind:this={ messageTextarea }
class:small={ $smallViewport || getItem("ui:alwaysUseMobileChatBar") } class:small={ $smallViewport || getItem("ui:alwaysUseMobileChatBar") }
class:keyboard-nav={ $usesKeyboardNavigation }
/> />
{#if $smallViewport || getItem("ui:alwaysUseMobileChatBar")} {#if $smallViewport || getItem("ui:alwaysUseMobileChatBar")}
<button class="icon-button send-button material-icons-outlined" on:click="{ sendMessage }"> <button class="icon-button send-button material-icons-outlined" on:click="{ sendMessage }">

View file

@ -1,5 +1,5 @@
import { getItem } from "./storage"; import { getItem } from "./storage";
import { showSidebar, smallViewport, theme } from "./stores"; import { showSidebar, smallViewport, theme, usesKeyboardNavigation } from "./stores";
function initViewportSizeHandler() { function initViewportSizeHandler() {
const root = document.querySelector(':root'); const root = document.querySelector(':root');
@ -33,8 +33,22 @@ function updateTheme(themeName) {
classes.add(`theme--${themeName}`); classes.add(`theme--${themeName}`);
} }
function initKeyboardNavigationDetection() {
document.addEventListener("keydown", ({ key }) => {
if (key === "Tab") {
usesKeyboardNavigation.set(true);
}
});
document.addEventListener("click", e => {
// screenX and screenY are 0 when a user presses enter for navigation
usesKeyboardNavigation.set(!e.screenX && !e.screenY);
});
}
export function initResponsiveHandlers() { export function initResponsiveHandlers() {
initViewportSizeHandler(); initViewportSizeHandler();
initKeyboardNavigationDetection();
const mediaQuery = window.matchMedia('(min-width: 768px)'); const mediaQuery = window.matchMedia('(min-width: 768px)');

View file

@ -410,6 +410,10 @@ class OverlayStore extends Store {
super([], "OverlayStore"); super([], "OverlayStore");
} }
isOverlayPresent() {
return !!this.value.length;
}
push(type, props={}) { push(type, props={}) {
const id = Math.floor(Math.random() * 9999999); const id = Math.floor(Math.random() * 9999999);
@ -840,6 +844,7 @@ export const selectedChannel = new SelectedChannelStore();
export const showSidebar = new Store(true, "showSidebar"); export const showSidebar = new Store(true, "showSidebar");
export const showPresenceSidebar = new Store(false, "showPresenceSidebar"); export const showPresenceSidebar = new Store(false, "showPresenceSidebar");
export const smallViewport = new Store(false, "smallViewport"); export const smallViewport = new Store(false, "smallViewport");
export const usesKeyboardNavigation = new Store(false, "usesKeyboardNavigation");
export const showChannelView = new Store(true, "showChannelView"); export const showChannelView = new Store(true, "showChannelView");
export const theme = new StorageItemStore("ui:theme"); export const theme = new StorageItemStore("ui:theme");
export const sendTypingUpdatesItemStore = new StorageItemStore("ui:online:sendTypingUpdates"); export const sendTypingUpdatesItemStore = new StorageItemStore("ui:online:sendTypingUpdates");