mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-17 09:48:42 +00:00
[Glitch] Don't reset scroll when using hotkeys to focus columns, add hotkey 0 to scroll to top
Port 9334bd9ede to glitch-soc
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
@@ -1,16 +1,30 @@
|
||||
interface FocusColumnOptions {
|
||||
index?: number;
|
||||
focusItem?: 'first' | 'first-visible';
|
||||
/**
|
||||
* Out of a list of elements, return the first one whose top edge
|
||||
* is inside of the viewport, and return the element and its BoundingClientRect.
|
||||
*/
|
||||
function findFirstVisibleWithRect(
|
||||
items: HTMLElement[],
|
||||
): { item: HTMLElement; rect: DOMRect } | null {
|
||||
const viewportHeight =
|
||||
window.innerHeight || document.documentElement.clientHeight;
|
||||
|
||||
for (const item of items) {
|
||||
const rect = item.getBoundingClientRect();
|
||||
const isVisible = rect.top >= 0 && rect.top < viewportHeight;
|
||||
|
||||
if (isVisible) {
|
||||
return { item, rect };
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Move focus to the column of the passed index (1-based).
|
||||
* Can either focus the topmost item or the first one in the viewport
|
||||
* Focus is placed on the topmost visible item
|
||||
*/
|
||||
export function focusColumn({
|
||||
index = 1,
|
||||
focusItem = 'first',
|
||||
}: FocusColumnOptions = {}) {
|
||||
export function focusColumn(index = 1) {
|
||||
// Skip the leftmost drawer in multi-column mode
|
||||
const isMultiColumnLayout = !!document.querySelector(
|
||||
'body.layout-multiple-columns',
|
||||
@@ -27,33 +41,28 @@ export function focusColumn({
|
||||
|
||||
if (!container) return;
|
||||
|
||||
let itemToFocus: HTMLElement | null = null;
|
||||
const focusableItems = Array.from(
|
||||
container.querySelectorAll<HTMLElement>(
|
||||
'.focusable:not(.status__quote .focusable)',
|
||||
),
|
||||
);
|
||||
|
||||
if (focusItem === 'first-visible') {
|
||||
const focusableItems = Array.from(
|
||||
container.querySelectorAll<HTMLElement>(
|
||||
'.focusable:not(.status__quote .focusable)',
|
||||
),
|
||||
);
|
||||
|
||||
const viewportHeight =
|
||||
window.innerHeight || document.documentElement.clientHeight;
|
||||
|
||||
// Find first item visible in the viewport
|
||||
itemToFocus =
|
||||
focusableItems.find((item) => {
|
||||
const { top } = item.getBoundingClientRect();
|
||||
return top >= 0 && top < viewportHeight;
|
||||
}) ?? null;
|
||||
} else {
|
||||
itemToFocus = container.querySelector('.focusable');
|
||||
}
|
||||
// Find first item visible in the viewport
|
||||
const itemToFocus = findFirstVisibleWithRect(focusableItems);
|
||||
|
||||
if (itemToFocus) {
|
||||
if (container.scrollTop > itemToFocus.offsetTop) {
|
||||
itemToFocus.scrollIntoView(true);
|
||||
const viewportWidth =
|
||||
window.innerWidth || document.documentElement.clientWidth;
|
||||
const { item, rect } = itemToFocus;
|
||||
|
||||
if (
|
||||
container.scrollTop > item.offsetTop ||
|
||||
rect.right > viewportWidth ||
|
||||
rect.left < 0
|
||||
) {
|
||||
itemToFocus.item.scrollIntoView(true);
|
||||
}
|
||||
itemToFocus.focus();
|
||||
itemToFocus.item.focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +80,26 @@ export function getFocusedItemIndex() {
|
||||
return items.indexOf(focusedItem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the topmost item of the column that currently has focus,
|
||||
* or the first column if none
|
||||
*/
|
||||
export function focusFirstItem() {
|
||||
const focusedElement = document.activeElement;
|
||||
const container =
|
||||
focusedElement?.closest('.scrollable') ??
|
||||
document.querySelector('.scrollable');
|
||||
|
||||
if (!container) return;
|
||||
|
||||
const itemToFocus = container.querySelector<HTMLElement>('.focusable');
|
||||
|
||||
if (itemToFocus) {
|
||||
container.scrollTo(0, 0);
|
||||
itemToFocus.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Focus the item next to the one with the provided index
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user