From 835b31271480af0b6c0a6c56dbc301598d47edfc Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Sun, 14 Apr 2024 21:09:32 +0200 Subject: [PATCH 01/15] scrolling fixes (#15914) * scrolling fixes * initial scroll fixing * more scrolling * typo * use a local ref * fixes chat pushing too many messages on init * integrating changes from TG to test * cleanup * fix a Ui crash on BodyRecords --- tgui/packages/tgui-panel/chat/renderer.jsx | 2 +- tgui/packages/tgui/components/Autofocus.tsx | 18 ++- tgui/packages/tgui/components/Section.tsx | 136 +++++++++--------- tgui/packages/tgui/components/Tabs.tsx | 9 ++ tgui/packages/tgui/events.ts | 8 ++ .../packages/tgui/interfaces/BodyDesigner.jsx | 18 +-- .../tgui/layouts/{Layout.jsx => Layout.tsx} | 47 ++++-- 7 files changed, 147 insertions(+), 91 deletions(-) rename tgui/packages/tgui/layouts/{Layout.jsx => Layout.tsx} (56%) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index 1dc17bc8971..1461491b4f5 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -216,7 +216,7 @@ class ChatRenderer { this.scrollToBottom(); }); // Flush the queue - this.tryFlushQueue(true); + this.tryFlushQueue(); } onStateLoaded() { diff --git a/tgui/packages/tgui/components/Autofocus.tsx b/tgui/packages/tgui/components/Autofocus.tsx index a0b3f6f7659..403dbe2e965 100644 --- a/tgui/packages/tgui/components/Autofocus.tsx +++ b/tgui/packages/tgui/components/Autofocus.tsx @@ -1,17 +1,23 @@ -import { createRef, PropsWithChildren, useEffect } from 'react'; +import { PropsWithChildren, useEffect, useRef } from 'react'; -export const Autofocus = (props: PropsWithChildren) => { - const ref = createRef(); +/** Used to force the window to steal focus on load. Children optional */ +export function Autofocus(props: PropsWithChildren) { + const { children } = props; + const ref = useRef(null); useEffect(() => { - setTimeout(() => { + const timer = setTimeout(() => { ref.current?.focus(); }, 1); + + return () => { + clearTimeout(timer); + }; }, []); return (
- {props.children} + {children}
); -}; +} diff --git a/tgui/packages/tgui/components/Section.tsx b/tgui/packages/tgui/components/Section.tsx index e18cb7e76a8..f85e96a05ea 100644 --- a/tgui/packages/tgui/components/Section.tsx +++ b/tgui/packages/tgui/components/Section.tsx @@ -5,7 +5,7 @@ */ import { canRender, classes } from 'common/react'; -import { forwardRef, ReactNode, RefObject, useEffect } from 'react'; +import { ReactNode, useEffect, useRef } from 'react'; import { addScrollableNode, removeScrollableNode } from '../events'; import { BoxProps, computeBoxClassName, computeBoxProps } from './Box'; @@ -23,6 +23,8 @@ type Props = Partial<{ scrollableHorizontal: boolean; /** Title of the section. */ title: ReactNode; + /** id to assosiate with the parent div element used by this section, for uses with procs like getElementByID */ + container_id: string; /** @member Callback function for the `scroll` event */ onScroll: ((this: GlobalEventHandlers, ev: Event) => any) | null; @@ -59,75 +61,77 @@ type Props = Partial<{ * * ``` */ -export const Section = forwardRef( - (props: Props, forwardedRef: RefObject) => { - const { - buttons, - children, - className, - fill, - fitted, - onScroll, - scrollable, - scrollableHorizontal, - title, - flexGrow, // VOREStation Addition - noTopPadding, // VOREStation Addition - stretchContents, // VOREStation Addition - ...rest - } = props; +export const Section = (props: Props) => { + const { + buttons, + children, + className, + fill, + fitted, + onScroll, + scrollable, + scrollableHorizontal, + title, + container_id, + flexGrow, // VOREStation Addition + noTopPadding, // VOREStation Addition + stretchContents, // VOREStation Addition + ...rest + } = props; + const node = useRef(null); - const hasTitle = canRender(title) || canRender(buttons); + const hasTitle = canRender(title) || canRender(buttons); - /** We want to be able to scroll on hover, but using focus will steal it from inputs */ - useEffect(() => { - if (!forwardedRef?.current) return; - if (!scrollable && !scrollableHorizontal) return; + /** We want to be able to scroll on hover, but using focus will steal it from inputs */ + useEffect(() => { + if (!node?.current) return; + if (!scrollable && !scrollableHorizontal) return; + const self = node.current; - addScrollableNode(forwardedRef.current); + addScrollableNode(self); - return () => { - if (!forwardedRef?.current) return; - removeScrollableNode(forwardedRef.current!); - }; - }, []); + return () => { + if (!self) return; + removeScrollableNode(self!); + }; + }, []); - return ( -
- {hasTitle && ( -
- {title} -
{buttons}
-
- )} -
-
- {children} -
+ return ( +
+ {hasTitle && ( +
+ {title} +
{buttons}
+
+ )} +
+
+ {children}
- ); - }, -); +
+ ); +}; diff --git a/tgui/packages/tgui/components/Tabs.tsx b/tgui/packages/tgui/components/Tabs.tsx index 84779bcf748..ba2b4e93c31 100644 --- a/tgui/packages/tgui/components/Tabs.tsx +++ b/tgui/packages/tgui/components/Tabs.tsx @@ -60,9 +60,17 @@ const Tab = (props: TabProps) => { leftSlot, rightSlot, children, + onClick, ...rest } = props; + const handleClick = (e) => { + if (onClick) { + onClick(e); + e.target.blur(); + } + }; + return (
{ className, computeBoxClassName(rest), ])} + onClick={handleClick} {...computeBoxProps(rest)} > {(canRender(leftSlot) &&
{leftSlot}
) || diff --git a/tgui/packages/tgui/events.ts b/tgui/packages/tgui/events.ts index cc53d31bfab..f7e14c13e13 100644 --- a/tgui/packages/tgui/events.ts +++ b/tgui/packages/tgui/events.ts @@ -106,6 +106,14 @@ const focusNearestTrackedParent = (node: HTMLElement | null) => { }; window.addEventListener('mousemove', (e) => { + const node = e.target as HTMLElement; + if (node !== lastVisitedNode && trackedNodes.length < 2) { + lastVisitedNode = node; + focusNearestTrackedParent(node); + } +}); + +window.addEventListener('click', (e) => { const node = e.target as HTMLElement; if (node !== lastVisitedNode) { lastVisitedNode = node; diff --git a/tgui/packages/tgui/interfaces/BodyDesigner.jsx b/tgui/packages/tgui/interfaces/BodyDesigner.jsx index 059cf61700b..e22a8c14c90 100644 --- a/tgui/packages/tgui/interfaces/BodyDesigner.jsx +++ b/tgui/packages/tgui/interfaces/BodyDesigner.jsx @@ -81,14 +81,16 @@ const BodyDesignerBodyRecords = (props) => { /> } > - {bodyrecords.map((record) => ( -