2020-10-02 15:10:00 +00:00
|
|
|
import {dom, IDomArgs, Observable, styled} from 'grainjs';
|
|
|
|
|
|
|
|
// Shadow css settings for member scroll top and bottom.
|
2023-09-21 16:57:58 +00:00
|
|
|
const SHADOW_TOP = 'inset 0 4px 6px 0 var(--grist-theme-scroll-shadow, rgba(217,217,217,0.4))';
|
|
|
|
const SHADOW_BTM = 'inset 0 -4px 6px 0 var(--grist-theme-scroll-shadow, rgba(217,217,217,0.4))';
|
2020-10-02 15:10:00 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates a scroll div used in the UserManager and moveDoc menus to display
|
|
|
|
* shadows at the top and bottom of a list of scrollable items.
|
|
|
|
*/
|
|
|
|
export function shadowScroll(...args: IDomArgs<HTMLDivElement>) {
|
|
|
|
// Observables to indicate the scroll position.
|
|
|
|
const scrollTop = Observable.create(null, true);
|
|
|
|
const scrollBtm = Observable.create(null, true);
|
|
|
|
return cssScrollMenu(
|
|
|
|
dom.autoDispose(scrollTop),
|
|
|
|
dom.autoDispose(scrollBtm),
|
|
|
|
// Update scroll positions on init and on scroll.
|
|
|
|
(elem) => { setTimeout(() => scrollBtm.set(isAtScrollBtm(elem)), 0); },
|
|
|
|
dom.on('scroll', (_, elem) => {
|
|
|
|
scrollTop.set(isAtScrollTop(elem));
|
|
|
|
scrollBtm.set(isAtScrollBtm(elem));
|
|
|
|
}),
|
|
|
|
// Add shadows on the top/bottom if the list is scrolled away from either.
|
|
|
|
dom.style('box-shadow', (use) => {
|
|
|
|
const shadows = [use(scrollTop) ? null : SHADOW_TOP, use(scrollBtm) ? null : SHADOW_BTM];
|
|
|
|
return shadows.filter(css => css).join(', ');
|
|
|
|
}),
|
|
|
|
...args
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indicates that an element is currently scrolled such that the top of the element is visible.
|
|
|
|
function isAtScrollTop(elem: Element): boolean {
|
|
|
|
return elem.scrollTop === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indicates that an element is currently scrolled such that the bottom of the element is visible.
|
|
|
|
// It is expected that the elem arg has the offsetHeight property set.
|
|
|
|
function isAtScrollBtm(elem: HTMLElement): boolean {
|
2024-08-13 23:21:48 +00:00
|
|
|
// Check we're within a threshold of 1 pixel, to account for possible rounding.
|
|
|
|
return (elem.scrollHeight - elem.offsetHeight - elem.scrollTop) < 1;
|
2020-10-02 15:10:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const cssScrollMenu = styled('div', `
|
|
|
|
flex: 1 1 0;
|
|
|
|
width: 100%;
|
|
|
|
overflow-y: auto;
|
|
|
|
`);
|