From 2f31d20184d00508ec3669332f80ce3719660161 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 16:31:18 -0400 Subject: [PATCH 1/9] possibly fixes chat scrolling? --- tgui/packages/tgui-panel/chat/renderer.jsx | 8 +++++++- tgui/packages/tgui-panel/{panelFocus.js => panelFocus.ts} | 7 +++++-- 2 files changed, 12 insertions(+), 3 deletions(-) rename tgui/packages/tgui-panel/{panelFocus.js => panelFocus.ts} (85%) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index 9af2daebbcf4..fefab6cdcfb5 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -129,12 +129,14 @@ class ChatRenderer { /** @type {HTMLElement} */ this.scrollNode = null; this.scrollTracking = true; + this.lastScrollHeight = 0; this.handleScroll = (type) => { const node = this.scrollNode; const height = node.scrollHeight; const bottom = node.scrollTop + node.offsetHeight; const scrollTracking = - Math.abs(height - bottom) < SCROLL_TRACKING_TOLERANCE; + Math.abs(height - bottom) < SCROLL_TRACKING_TOLERANCE || + this.lastScrollHeight === 0; if (scrollTracking !== this.scrollTracking) { this.scrollTracking = scrollTracking; this.events.emit('scrollTrackingChanged', scrollTracking); @@ -342,6 +344,10 @@ class ChatRenderer { } return; } + // Store last scroll position + if (this.scrollNode) { + this.lastScrollHeight = this.scrollNode.scrollHeight; + } // Insert messages const fragment = document.createDocumentFragment(); const countByType = {}; diff --git a/tgui/packages/tgui-panel/panelFocus.js b/tgui/packages/tgui-panel/panelFocus.ts similarity index 85% rename from tgui/packages/tgui-panel/panelFocus.js rename to tgui/packages/tgui-panel/panelFocus.ts index 8cff4a361b3e..966e4898d9d5 100644 --- a/tgui/packages/tgui-panel/panelFocus.js +++ b/tgui/packages/tgui-panel/panelFocus.ts @@ -19,9 +19,9 @@ const deferredFocusMap = () => setTimeout(() => focusMap()); export const setupPanelFocusHacks = () => { let focusStolen = false; - let clickStartPos = null; + let clickStartPos: number[] | null = null; window.addEventListener('focusin', (e) => { - focusStolen = canStealFocus(e.target); + focusStolen = canStealFocus(e.target as HTMLElement); }); window.addEventListener('mousedown', (e) => { clickStartPos = [e.screenX, e.screenY]; @@ -33,6 +33,9 @@ export const setupPanelFocusHacks = () => { if (dist >= MIN_SELECTION_DISTANCE) { focusStolen = true; } + if (document.activeElement?.className.includes('Button')) { + focusStolen = true; + } } if (!focusStolen) { deferredFocusMap(); From 7f797f12dd439308e74f0e4badc49483d8e976f0 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 16:41:23 -0400 Subject: [PATCH 2/9] port the SCSS stuff --- tgui/packages/tgui/styles/functions.scss | 11 ----------- tgui/packages/tgui/styles/interfaces/Mecha.scss | 6 ++++-- .../tgui/styles/interfaces/NuclearBomb.scss | 17 +++++++++++------ tgui/packages/tgui/styles/layouts/Window.scss | 2 +- 4 files changed, 16 insertions(+), 20 deletions(-) diff --git a/tgui/packages/tgui/styles/functions.scss b/tgui/packages/tgui/styles/functions.scss index 1c8d65e3a175..fc1aca9b3bc8 100644 --- a/tgui/packages/tgui/styles/functions.scss +++ b/tgui/packages/tgui/styles/functions.scss @@ -26,17 +26,6 @@ // Color // -------------------------------------------------------- -// Increases perceptual color lightness. -@function lighten($color, $percent) { - $scaled: hsl( - color.hue($color), - color.saturation($color), - color.lightness($color) * (1 + num($percent)) - ); - $mixed: color.mix(#ffffff, $color, 100% * num($percent)); - @return color.mix($scaled, $mixed, 75%); -} - // Returns the NTSC luminance of `$color` as a float (between 0 and 1). // 1 is pure white, 0 is pure black. @function luminance($color) { diff --git a/tgui/packages/tgui/styles/interfaces/Mecha.scss b/tgui/packages/tgui/styles/interfaces/Mecha.scss index 8795c8cb69da..99488ed610f4 100644 --- a/tgui/packages/tgui/styles/interfaces/Mecha.scss +++ b/tgui/packages/tgui/styles/interfaces/Mecha.scss @@ -1,3 +1,5 @@ +@use 'sass:color'; + @use '../base.scss'; @use '../colors.scss'; @use '../functions.scss' as *; @@ -37,7 +39,7 @@ $color-danger: #c92020 !default; padding-left: 0 !important; padding-right: 0 !important; &:hover { - background-color: lighten($color-danger, 15%) !important; - border-color: lighten($color-danger, 15%) !important; + background-color: color.adjust($color-danger, $lightness: 15%) !important; + border-color: color.adjust($color-danger, $lightness: 15%) !important; } } diff --git a/tgui/packages/tgui/styles/interfaces/NuclearBomb.scss b/tgui/packages/tgui/styles/interfaces/NuclearBomb.scss index 615a3f696afa..f2bbfeed8649 100644 --- a/tgui/packages/tgui/styles/interfaces/NuclearBomb.scss +++ b/tgui/packages/tgui/styles/interfaces/NuclearBomb.scss @@ -1,3 +1,5 @@ +@use 'sass:color'; + @use '../base.scss'; @use '../colors.scss'; @use '../functions.scss' as *; @@ -27,8 +29,11 @@ $background-beige: #e8e4c9; background-color: $background-beige; border-color: $background-beige; &:hover { - background-color: lighten($background-beige, 15%) !important; - border-color: lighten($background-beige, 15%) !important; + background-color: color.adjust( + $background-beige, + $lightness: 15% + ) !important; + border-color: color.adjust($background-beige, $lightness: 15%) !important; } } @@ -42,8 +47,8 @@ $background-beige: #e8e4c9; background-color: $color-caution !important; border-color: $color-caution !important; &:hover { - background-color: lighten($color-caution, 15%) !important; - border-color: lighten($color-caution, 15%) !important; + background-color: color.adjust($color-caution, $lightness: 15%) !important; + border-color: color.adjust($color-caution, $lightness: 15%) !important; } } @@ -51,8 +56,8 @@ $background-beige: #e8e4c9; background-color: $color-danger !important; border-color: $color-danger !important; &:hover { - background-color: lighten($color-danger, 15%) !important; - border-color: lighten($color-danger, 15%) !important; + background-color: color.adjust($color-danger, $lightness: 15%) !important; + border-color: color.adjust($color-danger, $lightness: 15%) !important; } } diff --git a/tgui/packages/tgui/styles/layouts/Window.scss b/tgui/packages/tgui/styles/layouts/Window.scss index 232dd8396bbf..452ce1a609e6 100644 --- a/tgui/packages/tgui/styles/layouts/Window.scss +++ b/tgui/packages/tgui/styles/layouts/Window.scss @@ -67,7 +67,7 @@ bottom: 0; left: 0; right: 0; - background-color: rgba(lighten(base.$color-bg, 30%), 0.25); + background-color: rgba(color.adjust(base.$color-bg, $lightness: 30%), 0.25); pointer-events: none; } From 953662f45e61c96da5174e140581810b52c96eff Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 16:59:10 -0400 Subject: [PATCH 3/9] just scroll the bottom shortly after init --- tgui/packages/tgui-panel/chat/renderer.jsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index fefab6cdcfb5..1efb66d0919b 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -29,6 +29,8 @@ const logger = createLogger('chatRenderer'); // We consider this as the smallest possible scroll offset // that is still trackable. const SCROLL_TRACKING_TOLERANCE = 24; +// How long after init to reset scrolling to fix it. +const SCROLL_FIX_TIMEOUT = 500; // List of injectable component names to the actual type export const TGUI_CHAT_COMPONENTS = { @@ -148,6 +150,11 @@ class ChatRenderer { this.scrollToBottom(); } }; + setTimeout(() => { + logger.debug('fixing tracking'); + this.scrollTracking = true; + this.scrollToBottom(); + }, SCROLL_FIX_TIMEOUT); // Periodic message pruning setInterval(() => this.pruneMessages(), MESSAGE_PRUNE_INTERVAL); } From cd8ff9cbf9def1db8fda4f71f8ce407b7cee6621 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 18:48:22 -0400 Subject: [PATCH 4/9] Revert "just scroll the bottom shortly after init" This reverts commit 953662f45e61c96da5174e140581810b52c96eff. --- tgui/packages/tgui-panel/chat/renderer.jsx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index 1efb66d0919b..fefab6cdcfb5 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -29,8 +29,6 @@ const logger = createLogger('chatRenderer'); // We consider this as the smallest possible scroll offset // that is still trackable. const SCROLL_TRACKING_TOLERANCE = 24; -// How long after init to reset scrolling to fix it. -const SCROLL_FIX_TIMEOUT = 500; // List of injectable component names to the actual type export const TGUI_CHAT_COMPONENTS = { @@ -150,11 +148,6 @@ class ChatRenderer { this.scrollToBottom(); } }; - setTimeout(() => { - logger.debug('fixing tracking'); - this.scrollTracking = true; - this.scrollToBottom(); - }, SCROLL_FIX_TIMEOUT); // Periodic message pruning setInterval(() => this.pruneMessages(), MESSAGE_PRUNE_INTERVAL); } From f3e6c658d245d8ed839d1dd3631aeb1c784a9d09 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 19:17:52 -0400 Subject: [PATCH 5/9] current state --- tgui/packages/tgui-panel/chat/renderer.jsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index fefab6cdcfb5..ea4b0e5ac793 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -168,9 +168,6 @@ class ChatRenderer { // Find scrollable parent this.scrollNode = findNearestScrollableParent(this.rootNode); this.scrollNode.addEventListener('scroll', this.handleScroll); - setTimeout(() => { - this.scrollToBottom(); - }); // Flush the queue this.tryFlushQueue(); } @@ -178,6 +175,9 @@ class ChatRenderer { onStateLoaded() { this.loaded = true; this.tryFlushQueue(); + setTimeout(() => { + this.scrollToBottom(); + }, 250); } tryFlushQueue() { From c3788e698ea1d2ab078a8cb09a9114a5a557b022 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 19:25:33 -0400 Subject: [PATCH 6/9] add a check that tg has and we don't --- tgui/packages/tgui-panel/chat/renderer.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index ea4b0e5ac793..a5e899b0155e 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -132,6 +132,9 @@ class ChatRenderer { this.lastScrollHeight = 0; this.handleScroll = (type) => { const node = this.scrollNode; + if (!node) { + return; + } const height = node.scrollHeight; const bottom = node.scrollTop + node.offsetHeight; const scrollTracking = From e54bceceddadcfe8d307147436f8831949621f11 Mon Sep 17 00:00:00 2001 From: Lucy Date: Tue, 1 Apr 2025 21:46:39 -0400 Subject: [PATCH 7/9] better fix, seemingly --- tgui/packages/tgui-panel/chat/renderer.jsx | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index a5e899b0155e..ee11741778ed 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -168,9 +168,6 @@ class ChatRenderer { else { this.rootNode = node; } - // Find scrollable parent - this.scrollNode = findNearestScrollableParent(this.rootNode); - this.scrollNode.addEventListener('scroll', this.handleScroll); // Flush the queue this.tryFlushQueue(); } @@ -178,15 +175,13 @@ class ChatRenderer { onStateLoaded() { this.loaded = true; this.tryFlushQueue(); - setTimeout(() => { - this.scrollToBottom(); - }, 250); } - tryFlushQueue() { + tryFlushQueue(doArchive = false) { if (this.isReady() && this.queue.length > 0) { - this.processBatch(this.queue); + this.processBatch(this.queue, { doArchive: doArchive }); this.queue = []; + this.scrollToBottom(); } } @@ -286,6 +281,7 @@ class ChatRenderer { } scrollToBottom() { + this.tryFindScrollable(); // scrollHeight is always bigger than scrollTop and is // automatically clamped to the valid range. this.scrollNode.scrollTop = this.scrollNode.scrollHeight; @@ -335,6 +331,17 @@ class ChatRenderer { return null; } + tryFindScrollable() { + // Find scrollable parent + if (this.rootNode) { + if (!this.scrollNode || this.scrollNode.scrollHeight === undefined) { + this.scrollNode = findNearestScrollableParent(this.rootNode); + this.scrollNode.addEventListener('scroll', this.handleScroll); + logger.debug(`reset scrollNode to ${this.scrollNode}`); + } + } + } + processBatch(batch, options = {}) { const { prepend, notifyListeners = true } = options; const now = Date.now(); From eaba97e206802eb22c49eb3d8377ef27ed19c338 Mon Sep 17 00:00:00 2001 From: Lucy Date: Wed, 2 Apr 2025 04:13:16 -0400 Subject: [PATCH 8/9] get rid of doArchive var --- tgui/packages/tgui-panel/chat/renderer.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tgui/packages/tgui-panel/chat/renderer.jsx b/tgui/packages/tgui-panel/chat/renderer.jsx index ee11741778ed..14dd9fc64cf1 100644 --- a/tgui/packages/tgui-panel/chat/renderer.jsx +++ b/tgui/packages/tgui-panel/chat/renderer.jsx @@ -177,9 +177,9 @@ class ChatRenderer { this.tryFlushQueue(); } - tryFlushQueue(doArchive = false) { + tryFlushQueue() { if (this.isReady() && this.queue.length > 0) { - this.processBatch(this.queue, { doArchive: doArchive }); + this.processBatch(this.queue); this.queue = []; this.scrollToBottom(); } From c879f07c1a980201187770295df8609f052874fe Mon Sep 17 00:00:00 2001 From: Lucy Date: Wed, 2 Apr 2025 13:07:57 -0400 Subject: [PATCH 9/9] eeee --- tgui/packages/tgui-panel/panelFocus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui-panel/panelFocus.ts b/tgui/packages/tgui-panel/panelFocus.ts index 966e4898d9d5..0f5d509667f5 100644 --- a/tgui/packages/tgui-panel/panelFocus.ts +++ b/tgui/packages/tgui-panel/panelFocus.ts @@ -33,7 +33,7 @@ export const setupPanelFocusHacks = () => { if (dist >= MIN_SELECTION_DISTANCE) { focusStolen = true; } - if (document.activeElement?.className.includes('Button')) { + if (document.activeElement?.className?.includes('Button')) { focusStolen = true; } }