-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy pathoverflow-controller.ts
91 lines (76 loc) · 2.62 KB
/
overflow-controller.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import type { ReactiveController, ReactiveControllerHost } from 'lit';
import { isElementInView } from '@patternfly/pfe-core/functions/isElementInView.js';
export interface Options {
hideOverflowButtons?: boolean;
}
export class OverflowController implements ReactiveController {
/** Overflow container */
#container?: HTMLElement;
/** Children that can overflow */
#items: HTMLElement[] = [];
#scrollTimeoutDelay = 0;
#scrollTimeout?: number;
/** Default state */
#hideOverflowButtons = false;
showScrollButtons = false;
overflowLeft = false;
overflowRight = false;
get firstItem(): HTMLElement | undefined {
return this.#items.at(0);
}
get lastItem(): HTMLElement | undefined {
return this.#items.at(-1);
}
constructor(public host: ReactiveControllerHost & Element, private options?: Options) {
this.host.addController(this);
if (options?.hideOverflowButtons) {
this.#hideOverflowButtons = options?.hideOverflowButtons;
}
}
#setOverflowState(): void {
if (!this.firstItem || !this.lastItem || !this.#container) {
return;
}
this.overflowLeft = !this.#hideOverflowButtons && !isElementInView(this.#container, this.firstItem);
this.overflowRight = !this.#hideOverflowButtons && !isElementInView(this.#container, this.lastItem);
let scrollButtonsWidth = 0;
if (this.overflowLeft || this.overflowRight) {
scrollButtonsWidth = (this.#container.parentElement?.querySelector('button')?.getBoundingClientRect().width || 0) * 2;
}
this.showScrollButtons = !this.#hideOverflowButtons &&
this.#container.scrollWidth > (this.#container.clientWidth + scrollButtonsWidth);
this.host.requestUpdate();
}
init(container: HTMLElement, items: HTMLElement[]) {
this.#container = container;
// convert HTMLCollection to HTMLElement[]
this.#items = items;
}
onScroll = () => {
clearTimeout(this.#scrollTimeout);
this.#scrollTimeout = window.setTimeout(() => this.#setOverflowState(), this.#scrollTimeoutDelay);
};
scrollLeft() {
if (!this.#container) {
return;
}
const leftScroll = this.#container.scrollLeft - this.#container.clientWidth;
this.#container.scroll({ left: leftScroll, behavior: 'smooth' });
this.#setOverflowState();
}
scrollRight() {
if (!this.#container) {
return;
}
const leftScroll = this.#container.scrollLeft + this.#container.clientWidth;
this.#container.scroll({ left: leftScroll, behavior: 'smooth' });
this.#setOverflowState();
}
update() {
this.#setOverflowState();
}
hostConnected(): void {
this.onScroll();
this.#setOverflowState();
}
}