~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
54 lines · 1.9 KB Raw History
import type { Attachment } from 'svelte/attachments';

/**
 * A row of tabs or chips that scrolls sideways when it is wider than the
 * screen: the one picked brought into view, `at` naming it so a new pick
 * brings that one, and the row marked `more-start` or `more-end` while
 * there is more past either edge, which app.css fades.
 */
export function scrollRow(at: unknown): Attachment<HTMLElement> {
	return (row) => {
		void at;
		const edges = () => {
			row.classList.toggle('more-start', row.scrollLeft > 1);
			row.classList.toggle('more-end', row.scrollLeft + row.clientWidth < row.scrollWidth - 1);
		};
		const picked = row.querySelector<HTMLElement>('[aria-current]');
		if (picked && row.scrollWidth > row.clientWidth) {
			const box = row.getBoundingClientRect();
			const it = picked.getBoundingClientRect();
			row.scrollLeft += it.left - box.left - (box.width - it.width) / 2;
		}
		edges();
		row.addEventListener('scroll', edges, { passive: true });
		const sized = new ResizeObserver(edges);
		sized.observe(row);
		return () => {
			row.removeEventListener('scroll', edges);
			sized.disconnect();
		};
	};
}

/**
 * A list that scrolls within a box of its own, as a dialog's: marked
 * `more-above` or `more-below` while there is more past its top or its
 * bottom, which app.css fades, and again as what it holds changes.
 */
export const scrollFades: Attachment<HTMLElement> = (list) => {
	const edges = () => {
		list.classList.toggle('more-above', list.scrollTop > 1);
		list.classList.toggle('more-below', list.scrollTop + list.clientHeight < list.scrollHeight - 1);
	};
	edges();
	list.addEventListener('scroll', edges, { passive: true });
	const sized = new ResizeObserver(edges);
	sized.observe(list);
	const changed = new MutationObserver(edges);
	changed.observe(list, { childList: true, subtree: true });
	return () => {
		list.removeEventListener('scroll', edges);
		sized.disconnect();
		changed.disconnect();
	};
};