(window as any).global = window; import cx from "classnames"; import throttle from "lodash.throttle"; import React, { useCallback, useEffect, useRef, useState } from "react"; import { DndProvider, useDrop } from "react-dnd"; import { HTML5Backend } from "react-dnd-html5-backend"; import "./App.css"; import { ChatHeading, ChatMessageList, QuotedMessage, UserInput, UserList, UsersTyping, } from "./features"; import { ChatProvider, DrawerProvider, useChat, useDrawer } from "./hooks"; const SCROLL_CANCEL_THRESHOLD = 500; const WINDOW_RESIZE_THROTTLE_WAIT = 250; export function App() { return ( ); } function AppInner() { const [_, dropRef] = useDrop({ accept: "drawer", }); const { open, config } = useDrawer(); const contentWrapper = useRef(null); const initiallyScrolledDown = useRef(false); const { messages, quote, userToDm, updateUserToDm } = useChat(); const [focused, setFocused] = useState(false); const toggleFocus = useCallback(() => { setTimeout(() => { setFocused(prev => !prev); }, 0); }, []); // See: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ useEffect(() => { const updateViewportHeightUnit = () => { const vh = window.innerHeight * 0.01; document.documentElement.style.setProperty("--vh", `${vh}px`); }; const throttledResizeHandler = throttle( updateViewportHeightUnit, WINDOW_RESIZE_THROTTLE_WAIT ); throttledResizeHandler(); window.addEventListener("resize", throttledResizeHandler); return () => { window.removeEventListener("resize", throttledResizeHandler); }; }, []); useEffect(() => { if (messages.length > 0) { if (initiallyScrolledDown.current) { /* We only want to scroll back down on a new message if the user is not scrolled up looking at previous messages. */ const scrollableDistance = contentWrapper.current.scrollHeight - contentWrapper.current.clientHeight; const scrolledDistance = contentWrapper.current.scrollTop; const hasScrolledEnough = scrollableDistance - scrolledDistance >= SCROLL_CANCEL_THRESHOLD; if (hasScrolledEnough) { return; } } else { // Always scroll to the bottom on first load. initiallyScrolledDown.current = true; } contentWrapper.current.scrollTop = contentWrapper.current.scrollHeight; } }, [messages]); useEffect(() => { if (!open) { // Scroll to the bottom after any drawer closes. contentWrapper.current.scrollTop = contentWrapper.current.scrollHeight; } }, [open]); return (
v{process.env.VERSION}
{open ? (
{config.content}
) : ( )}
{quote && (
)} {userToDm && (
Directly messaging @{userToDm.username}
)}
); }