discourse/plugins/chat/assets/javascripts/discourse/services/emoji-picker-scroll-observer.js
2024-03-06 18:05:11 +01:00

71 lines
1.8 KiB
JavaScript

import { tracked } from "@glimmer/tracking";
import Service, { service } from "@ember/service";
import { bind } from "discourse-common/utils/decorators";
export default class EmojiPickerScrollObserver extends Service {
@service chatEmojiPickerManager;
@tracked enabled = true;
direction = "up";
prevYPosition = 0;
@bind
_observerCallback(event) {
if (!this.enabled) {
return;
}
this._setScrollDirection(event.target);
const visibleSections = [
...document.querySelectorAll(".chat-emoji-picker__section"),
].filter((sectionElement) =>
this._isSectionVisibleInPicker(sectionElement, event.target)
);
if (visibleSections?.length) {
let sectionElement;
if (this.direction === "up" || this.prevYPosition < 50) {
sectionElement = visibleSections.firstObject;
} else {
sectionElement = visibleSections.lastObject;
}
this.chatEmojiPickerManager.lastVisibleSection =
sectionElement.dataset.section;
this.chatEmojiPickerManager.addVisibleSections(
visibleSections.map((s) => s.dataset.section)
);
}
}
observe(element) {
element.addEventListener("scroll", this._observerCallback);
}
unobserve(element) {
element.removeEventListener("scroll", this._observerCallback);
}
_setScrollDirection(target) {
if (target.scrollTop > this.prevYPosition) {
this.direction = "down";
} else {
this.direction = "up";
}
this.prevYPosition = target.scrollTop;
}
_isSectionVisibleInPicker(section, picker) {
const { bottom, height, top } = section.getBoundingClientRect();
const containerRect = picker.getBoundingClientRect();
return top <= containerRect.top
? containerRect.top - top <= height
: bottom - containerRect.bottom <= height;
}
}