improve message input box
This commit is contained in:
parent
17a7aaafdd
commit
97847288fc
3 changed files with 39 additions and 8 deletions
|
@ -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 }">
|
||||||
|
|
|
@ -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)');
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
Loading…
Reference in a new issue