@cloudflare/realtimekit-ui 1.1.0-staging.6 → 1.1.0-staging.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.js +1 -1
- package/dist/cjs/rtk-avatar_24.cjs.entry.js +193 -195
- package/dist/cjs/rtk-chat-toggle.cjs.entry.js +1 -1
- package/dist/cjs/rtk-notifications.cjs.entry.js +4 -1
- package/dist/collection/components/rtk-chat-messages-ui-paginated/rtk-chat-messages-ui-paginated.js +2 -2
- package/dist/collection/components/rtk-chat-toggle/rtk-chat-toggle.js +1 -1
- package/dist/collection/components/rtk-notifications/rtk-notifications.js +4 -1
- package/dist/collection/components/rtk-paginated-list/rtk-paginated-list.js +191 -193
- package/dist/components/{p-85872241.js → p-1d16490e.js} +2 -2
- package/dist/components/{p-b6781e91.js → p-7be71567.js} +3 -3
- package/dist/components/{p-e7e2156a.js → p-7f8d9afc.js} +191 -193
- package/dist/components/rtk-chat-messages-ui-paginated.js +1 -1
- package/dist/components/rtk-chat-search-results.js +1 -1
- package/dist/components/rtk-chat-toggle.js +1 -1
- package/dist/components/rtk-chat.js +1 -1
- package/dist/components/rtk-meeting.js +3 -3
- package/dist/components/rtk-notifications.js +4 -1
- package/dist/components/rtk-paginated-list.js +1 -1
- package/dist/docs/docs-components.json +1 -1
- package/dist/esm/loader.js +197 -196
- package/dist/esm/rtk-avatar_24.entry.js +193 -195
- package/dist/esm/rtk-chat-toggle.entry.js +1 -1
- package/dist/esm/rtk-notifications.entry.js +4 -1
- package/dist/realtimekit-ui/p-25c13ff8.entry.js +1 -0
- package/dist/realtimekit-ui/p-342b4926.entry.js +1 -0
- package/dist/realtimekit-ui/{p-421e4c6f.entry.js → p-ec5ed8a4.entry.js} +1 -1
- package/dist/realtimekit-ui/realtimekit-ui.esm.js +1 -1
- package/dist/types/components/rtk-paginated-list/rtk-paginated-list.d.ts +32 -46
- package/package.json +1 -1
- package/dist/realtimekit-ui/p-19587963.entry.js +0 -1
- package/dist/realtimekit-ui/p-a859d883.entry.js +0 -1
package/dist/esm/loader.js
CHANGED
|
@@ -11586,7 +11586,7 @@ const RtkChatMessagesUiPaginated = class {
|
|
|
11586
11586
|
}
|
|
11587
11587
|
const isSelf = message.userId === this.meeting.self.userId;
|
|
11588
11588
|
const viewType = isSelf ? 'outgoing' : 'incoming';
|
|
11589
|
-
return (h("div", null, h("div", { class: "message-wrapper" }, h("rtk-message-view", { pinned: message.pinned, time: message.time, actions: this.getMessageActions(message), authorName: message.displayName, isSelf: isSelf, avatarUrl: displayPicture, hideAuthorName: isContinued, viewType: viewType, variant: "bubble", onAction: (event) => this.onMessageActionHandler(event.detail, message) }, h("div", null, h("div", { class: "body" }, message.type === 'text' && (h("rtk-text-message-view", { text: message.message, isMarkdown: true })), message.type === 'file' && (h("rtk-file-message-view", { name: message.name, url: message.link, size: message.size })), message.type === 'image' && (h("rtk-image-message-view", { url: message.link, onPreview: () => {
|
|
11589
|
+
return (h("div", null, h("div", { class: "message-wrapper", id: message.id }, h("rtk-message-view", { pinned: message.pinned, time: message.time, actions: this.getMessageActions(message), authorName: message.displayName, isSelf: isSelf, avatarUrl: displayPicture, hideAuthorName: isContinued, viewType: viewType, variant: "bubble", onAction: (event) => this.onMessageActionHandler(event.detail, message) }, h("div", null, h("div", { class: "body" }, message.type === 'text' && (h("rtk-text-message-view", { text: message.message, isMarkdown: true })), message.type === 'file' && (h("rtk-file-message-view", { name: message.name, url: message.link, size: message.size })), message.type === 'image' && (h("rtk-image-message-view", { url: message.link, onPreview: () => {
|
|
11590
11590
|
this.stateUpdate.emit({ image: message });
|
|
11591
11591
|
} }))))))));
|
|
11592
11592
|
};
|
|
@@ -11634,7 +11634,7 @@ const RtkChatMessagesUiPaginated = class {
|
|
|
11634
11634
|
this.lastReadMessageIndex = -1;
|
|
11635
11635
|
}
|
|
11636
11636
|
render() {
|
|
11637
|
-
return (h(Host, { key: '
|
|
11637
|
+
return (h(Host, { key: 'c710da6e2fda420146905a2ed75d3444dd6d2c0b' }, h("rtk-paginated-list", { key: '51a36437e38e9c0242cca34bfda39f6d8309bee3', ref: (el) => (this.$paginatedListRef = el), pageSize: this.pageSize, pagesAllowed: 3, fetchData: this.getChatMessages, createNodes: this.createChatNodes, selectedItemId: this.selectedChannelId, emptyListLabel: this.t('chat.empty_channel') }, h("slot", { key: '69b54a41263510b425ce3e39af055321c4e2deb8' }))));
|
|
11638
11638
|
}
|
|
11639
11639
|
get host() { return getElement(this); }
|
|
11640
11640
|
static get watchers() { return {
|
|
@@ -12590,32 +12590,30 @@ const rtkPaginatedListCss = ".scrollbar{scrollbar-width:thin;scrollbar-color:var
|
|
|
12590
12590
|
const RtkPaginatedListStyle0 = rtkPaginatedListCss;
|
|
12591
12591
|
|
|
12592
12592
|
/**
|
|
12593
|
-
*
|
|
12593
|
+
* NOTE(ikabra): INFINITE SCROLL IMPLEMENTATION:
|
|
12594
12594
|
*
|
|
12595
|
-
*
|
|
12596
|
-
*
|
|
12595
|
+
* Uses scrollend listener for 2way scrolling.
|
|
12596
|
+
* Empty divs ($topRef, $bottomRef) act as scroll triggers to fetch new messages.
|
|
12597
12597
|
*
|
|
12598
|
-
*
|
|
12599
|
-
*
|
|
12600
|
-
*
|
|
12598
|
+
* UPWARD SCROLLING:
|
|
12599
|
+
* - Fetch top anchor (element currently visible to the user near top)
|
|
12600
|
+
* - Fetch older messages, push to end of 2D array
|
|
12601
|
+
* - When exceeding pagesAllowed, delete pages and scroll back to anchor
|
|
12601
12602
|
*
|
|
12602
|
-
*
|
|
12603
|
-
*
|
|
12603
|
+
* DOWNWARD SCROLLING:
|
|
12604
|
+
* - Fetch bottom anchor (element currently visible to the user near bottom)
|
|
12605
|
+
* - Fetch new page, insert at the start
|
|
12606
|
+
* - Update timestamps & firstEmptyIndex, then rerender
|
|
12607
|
+
* - When exceeding pagesAllowed, delete pages and scroll back to anchor
|
|
12604
12608
|
*
|
|
12605
|
-
*
|
|
12606
|
-
*
|
|
12607
|
-
*
|
|
12608
|
-
* if length exceeds pagesAllowed, we free up the pages and keep the first empty index in memory (firstEmptyIndex).
|
|
12609
|
+
* ADDING NEW NODES:
|
|
12610
|
+
* - If no pages exist, load old page
|
|
12611
|
+
* - If on 1st page, append messages till page size is full and then load new page
|
|
12609
12612
|
*
|
|
12610
|
-
*
|
|
12611
|
-
* If
|
|
12612
|
-
*
|
|
12613
|
-
*
|
|
12614
|
-
* If we have exceeded our page allowance we delete old pages.
|
|
12615
|
-
*
|
|
12616
|
-
* In this case deleting pages is okay as we are not relying on the index of dom elements to detect page end.
|
|
12617
|
-
*
|
|
12618
|
-
* This also simplifies the code because when a user scrolls up we do not need to manage a lastEmptyIndex.
|
|
12613
|
+
* DELETE NODE:
|
|
12614
|
+
* - If deleting the only available node, reset to initial state
|
|
12615
|
+
* - If page is empty, delete it
|
|
12616
|
+
* - Update timestamp curors
|
|
12619
12617
|
*/
|
|
12620
12618
|
var __decorate$2$8 = function (decorators, target, key, desc) {
|
|
12621
12619
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -12630,43 +12628,27 @@ var __decorate$2$8 = function (decorators, target, key, desc) {
|
|
|
12630
12628
|
const RtkPaginatedList = class {
|
|
12631
12629
|
constructor(hostRef) {
|
|
12632
12630
|
registerInstance(this, hostRef);
|
|
12633
|
-
/**
|
|
12634
|
-
* when scrolling up, we can't remove pages as intersectionObserver relies on
|
|
12635
|
-
* the index of dom elements to stay stable.
|
|
12636
|
-
* So, instead we free up the pages and keep the last empty index in memory.
|
|
12637
|
-
*/
|
|
12638
|
-
this.firstEmptyIndex = -1;
|
|
12639
|
-
this.maxTS = 0;
|
|
12640
12631
|
// the length of pages will always be pageSize + 2
|
|
12641
12632
|
this.pages = [];
|
|
12633
|
+
// Controls whether to keep auto-scrolling when a new page load.
|
|
12634
|
+
this.shouldScrollToBottom = false;
|
|
12635
|
+
// Shows "scroll to bottom" button when new nodes arrive and autoscroll is off.
|
|
12636
|
+
this.showNewMessagesCTR = false;
|
|
12642
12637
|
/** label to show when empty */
|
|
12643
12638
|
this.emptyListLabel = null;
|
|
12644
|
-
this.rerenderBoolean = false;
|
|
12645
|
-
this.showEmptyListLabel = false;
|
|
12646
12639
|
/** Icon pack */
|
|
12647
12640
|
this.iconPack = defaultIconPack;
|
|
12648
12641
|
/** Language */
|
|
12649
12642
|
this.t = useLanguage();
|
|
12643
|
+
this.rerenderBoolean = false;
|
|
12644
|
+
this.showEmptyListLabel = false;
|
|
12650
12645
|
this.isLoading = false;
|
|
12651
12646
|
this.isLoadingTop = false;
|
|
12652
12647
|
this.isLoadingBottom = false;
|
|
12653
|
-
|
|
12654
|
-
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
* */
|
|
12658
|
-
this.shouldScrollToBottom = false;
|
|
12659
|
-
/** UI Indicator for the "scroll to bottom" button.
|
|
12660
|
-
* Toggles on when a new node is added and autoscroll is disabled.
|
|
12661
|
-
* Toggles off when all nodes are loaded */
|
|
12662
|
-
this.showNewMessagesCTR = false;
|
|
12663
|
-
this.observe = (el) => {
|
|
12664
|
-
if (!el)
|
|
12665
|
-
return;
|
|
12666
|
-
this.intersectionObserver.observe(el);
|
|
12667
|
-
};
|
|
12668
|
-
this.isAtBottom = () => {
|
|
12669
|
-
const rect = this.$bottomRef.getBoundingClientRect();
|
|
12648
|
+
// Tells us if we need to scroll to a specific anchor after a rerender
|
|
12649
|
+
this.pendingScrollAnchor = null;
|
|
12650
|
+
this.isInView = (el) => {
|
|
12651
|
+
const rect = el.getBoundingClientRect();
|
|
12670
12652
|
return rect.top >= 0 && rect.bottom <= window.innerHeight;
|
|
12671
12653
|
};
|
|
12672
12654
|
}
|
|
@@ -12675,77 +12657,57 @@ const RtkPaginatedList = class {
|
|
|
12675
12657
|
* @param {DataNode} node - The data node to add to the beginning of the list
|
|
12676
12658
|
*/
|
|
12677
12659
|
async onNewNode(node) {
|
|
12678
|
-
//
|
|
12679
|
-
|
|
12680
|
-
|
|
12681
|
-
|
|
12682
|
-
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12686
|
-
this.
|
|
12660
|
+
// if there are no pages, load the first page
|
|
12661
|
+
if (this.pages.length < 1) {
|
|
12662
|
+
this.oldTS = node.timeMs + 1;
|
|
12663
|
+
this.loadPrevPage();
|
|
12664
|
+
}
|
|
12665
|
+
else {
|
|
12666
|
+
// append messages to the page if page has not reached full capacity
|
|
12667
|
+
if (this.pages[0].length < this.pageSize) {
|
|
12668
|
+
this.pages[0].unshift(node);
|
|
12669
|
+
this.newTS = node.timeMs;
|
|
12670
|
+
this.rerender();
|
|
12687
12671
|
}
|
|
12688
12672
|
else {
|
|
12689
|
-
//
|
|
12690
|
-
|
|
12691
|
-
this.pages[0].unshift(node);
|
|
12692
|
-
this.newTS = node.timeMs;
|
|
12693
|
-
this.rerender();
|
|
12694
|
-
}
|
|
12695
|
-
else {
|
|
12696
|
-
// if page is at full capacity, load next page
|
|
12697
|
-
this.loadNextPage();
|
|
12698
|
-
}
|
|
12673
|
+
// if page is at full capacity, load next page
|
|
12674
|
+
this.loadNextPage();
|
|
12699
12675
|
}
|
|
12700
12676
|
}
|
|
12701
|
-
// If autoscroll is enabled,
|
|
12677
|
+
// If autoscroll is enabled, scroll to the bottom
|
|
12702
12678
|
if (this.autoScroll) {
|
|
12703
12679
|
this.shouldScrollToBottom = true;
|
|
12704
12680
|
this.scrollToBottom();
|
|
12705
12681
|
}
|
|
12706
|
-
else {
|
|
12707
|
-
this.showNewMessagesCTR = true;
|
|
12708
|
-
}
|
|
12709
|
-
}
|
|
12710
|
-
// this method is called recursively based on shouldScrollToBottom (see scrollEnd listener)
|
|
12711
|
-
scrollToBottom() {
|
|
12712
|
-
this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
|
|
12713
12682
|
}
|
|
12714
12683
|
/**
|
|
12715
12684
|
* Deletes a node anywhere from the list
|
|
12716
12685
|
* @param {string} id - The id of the node to delete
|
|
12717
12686
|
* */
|
|
12718
12687
|
async onNodeDelete(id) {
|
|
12719
|
-
|
|
12720
|
-
|
|
12688
|
+
var _a, _b;
|
|
12689
|
+
let didDelete = false;
|
|
12690
|
+
for (let i = this.pages.length - 1; i >= 0; i--) {
|
|
12721
12691
|
const index = this.pages[i].findIndex((node) => node.id === id);
|
|
12722
|
-
// message
|
|
12723
|
-
if (index
|
|
12724
|
-
|
|
12725
|
-
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
// if newest page is empty, update first empty index
|
|
12733
|
-
if (this.pages[i].length === 0)
|
|
12734
|
-
this.firstEmptyIndex++;
|
|
12735
|
-
// update timestamp, first empty index could be -1, so we need to cap it at 0
|
|
12736
|
-
this.newTS = this.pages[Math.max(this.firstEmptyIndex, 0)][0].timeMs;
|
|
12737
|
-
}
|
|
12738
|
-
else if (i === this.firstEmptyIndex + this.pagesAllowed) {
|
|
12739
|
-
// if oldest page is empty, remove it
|
|
12740
|
-
if (this.pages[i].length === 0)
|
|
12741
|
-
this.pages.pop();
|
|
12742
|
-
// update timestamp
|
|
12743
|
-
const lastPage = this.pages[this.firstEmptyIndex + this.pagesAllowed];
|
|
12744
|
-
this.oldTS = lastPage[lastPage.length - 1].timeMs;
|
|
12745
|
-
}
|
|
12746
|
-
this.rerender();
|
|
12747
|
-
}
|
|
12692
|
+
// if message not found, move on
|
|
12693
|
+
if (index === -1)
|
|
12694
|
+
continue;
|
|
12695
|
+
// delete message
|
|
12696
|
+
this.pages[i].splice(index, 1);
|
|
12697
|
+
// if page is empty, delete it
|
|
12698
|
+
if (this.pages[i].length === 0)
|
|
12699
|
+
this.pages.splice(i, 1);
|
|
12700
|
+
didDelete = true;
|
|
12701
|
+
break;
|
|
12748
12702
|
}
|
|
12703
|
+
if (!didDelete)
|
|
12704
|
+
return;
|
|
12705
|
+
// update timestamps
|
|
12706
|
+
const firstPage = this.pages[0];
|
|
12707
|
+
const lastPage = this.pages[this.pages.length - 1];
|
|
12708
|
+
this.newTS = (_a = firstPage === null || firstPage === void 0 ? void 0 : firstPage[0]) === null || _a === void 0 ? void 0 : _a.timeMs;
|
|
12709
|
+
this.oldTS = (_b = lastPage === null || lastPage === void 0 ? void 0 : lastPage[lastPage.length - 1]) === null || _b === void 0 ? void 0 : _b.timeMs;
|
|
12710
|
+
this.rerender();
|
|
12749
12711
|
}
|
|
12750
12712
|
/**
|
|
12751
12713
|
* Updates a new node anywhere in the list
|
|
@@ -12753,146 +12715,182 @@ const RtkPaginatedList = class {
|
|
|
12753
12715
|
* @param {DataNode} _node - The updated data node
|
|
12754
12716
|
* */
|
|
12755
12717
|
async onNodeUpdate(_id, _node) { }
|
|
12756
|
-
rerender() {
|
|
12757
|
-
this.rerenderBoolean = !this.rerenderBoolean;
|
|
12758
|
-
}
|
|
12759
12718
|
connectedCallback() {
|
|
12760
12719
|
this.rerender = debounce$1(this.rerender.bind(this), 50, { maxWait: 200 });
|
|
12761
|
-
this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
12762
|
-
writeTask(async () => {
|
|
12763
|
-
for (const entry of entries) {
|
|
12764
|
-
if (entry.target.id === 'top-scroll' && entry.isIntersecting) {
|
|
12765
|
-
this.isLoadingTop = true;
|
|
12766
|
-
await this.loadPrevPage();
|
|
12767
|
-
this.isLoadingTop = false;
|
|
12768
|
-
}
|
|
12769
|
-
}
|
|
12770
|
-
});
|
|
12771
|
-
});
|
|
12772
12720
|
}
|
|
12773
12721
|
componentDidLoad() {
|
|
12774
|
-
|
|
12722
|
+
// initial load
|
|
12723
|
+
this.loadPrevPage();
|
|
12775
12724
|
if (this.$containerRef) {
|
|
12776
12725
|
this.$containerRef.onscrollend = async () => {
|
|
12777
|
-
|
|
12778
|
-
* Load new page if:
|
|
12779
|
-
* if there are nodes to load at the bottom (maxTS > newTS)
|
|
12780
|
-
* or if there are pages to fill at the bottom (firstEmptyIndex > -1)
|
|
12781
|
-
*/
|
|
12782
|
-
if (this.isAtBottom() && (this.maxTS > this.newTS || this.firstEmptyIndex > -1)) {
|
|
12783
|
-
this.isLoadingBottom = true;
|
|
12726
|
+
if (this.isInView(this.$bottomRef)) {
|
|
12784
12727
|
await this.loadNextPage();
|
|
12785
|
-
|
|
12786
|
-
|
|
12787
|
-
|
|
12728
|
+
}
|
|
12729
|
+
else if (this.isInView(this.$topRef)) {
|
|
12730
|
+
this.showNewMessagesCTR = true;
|
|
12731
|
+
await this.loadPrevPage();
|
|
12788
12732
|
}
|
|
12789
12733
|
};
|
|
12790
12734
|
}
|
|
12791
12735
|
}
|
|
12736
|
+
componentDidRender() {
|
|
12737
|
+
if (!this.pendingScrollAnchor)
|
|
12738
|
+
return;
|
|
12739
|
+
const anchor = this.pendingScrollAnchor;
|
|
12740
|
+
this.pendingScrollAnchor = null;
|
|
12741
|
+
this.restoreScrollToAnchor(anchor);
|
|
12742
|
+
}
|
|
12792
12743
|
async loadPrevPage() {
|
|
12793
12744
|
if (this.isLoading)
|
|
12794
12745
|
return;
|
|
12795
|
-
|
|
12796
|
-
* NOTE(ikabra): this case also runs on initial load
|
|
12797
|
-
* if scrolling up ->
|
|
12798
|
-
* fetch older messages and push to the end of the array
|
|
12799
|
-
* cleanup 1st non empty page from the array if length exceeds pagesAllowed
|
|
12800
|
-
*/
|
|
12746
|
+
const scrollAnchor = this.getScrollAnchor('top');
|
|
12801
12747
|
// if no old timestamp, it means we are at initial state
|
|
12802
12748
|
if (!this.oldTS)
|
|
12803
12749
|
this.oldTS = new Date().getTime();
|
|
12804
12750
|
// load data
|
|
12805
12751
|
this.isLoading = true;
|
|
12752
|
+
this.isLoadingTop = true;
|
|
12806
12753
|
const data = await this.fetchData(this.oldTS - 1, this.pageSize, true);
|
|
12807
12754
|
this.isLoading = false;
|
|
12755
|
+
this.isLoadingTop = false;
|
|
12808
12756
|
// no more old messages to show, we are at the top of the page
|
|
12809
12757
|
if (!data.length)
|
|
12810
12758
|
return;
|
|
12811
12759
|
// add old data to the end of the array
|
|
12812
12760
|
this.pages.push(data);
|
|
12813
12761
|
// clear old pages when we reach the limit
|
|
12814
|
-
if (this.pages.length > this.pagesAllowed)
|
|
12815
|
-
this.pages
|
|
12816
|
-
|
|
12817
|
-
* find last non empty page in range (this.pages.length, this.firstEmptyIndex)
|
|
12818
|
-
* we are doing this because any of the middle pages in the currently rendered pages
|
|
12819
|
-
* could be empty as we allow deleting messages.
|
|
12820
|
-
* This helps us set the first empty index correctly.
|
|
12821
|
-
*/
|
|
12822
|
-
for (let i = this.firstEmptyIndex + 1; i < this.pages.length; i++) {
|
|
12823
|
-
if (this.pages[i].length > 0)
|
|
12824
|
-
break;
|
|
12825
|
-
this.firstEmptyIndex = i;
|
|
12826
|
-
}
|
|
12827
|
-
}
|
|
12828
|
-
// update the old timestamp
|
|
12762
|
+
if (this.pages.length > this.pagesAllowed)
|
|
12763
|
+
this.pages.shift();
|
|
12764
|
+
// update timestamps
|
|
12829
12765
|
const lastPage = this.pages[this.pages.length - 1];
|
|
12830
12766
|
this.oldTS = lastPage[lastPage.length - 1].timeMs;
|
|
12831
|
-
|
|
12832
|
-
this.newTS = this.pages[this.firstEmptyIndex + 1][0].timeMs;
|
|
12767
|
+
this.newTS = this.pages[0][0].timeMs;
|
|
12833
12768
|
this.rerender();
|
|
12769
|
+
// fix scroll position
|
|
12770
|
+
if (scrollAnchor)
|
|
12771
|
+
this.pendingScrollAnchor = scrollAnchor;
|
|
12834
12772
|
}
|
|
12835
12773
|
async loadNextPage() {
|
|
12836
12774
|
if (this.isLoading)
|
|
12837
12775
|
return;
|
|
12838
|
-
//
|
|
12776
|
+
// Do nothing. New timestamp needs to be assigned by loadPrevPage method
|
|
12839
12777
|
if (!this.newTS) {
|
|
12840
12778
|
this.showNewMessagesCTR = false;
|
|
12841
12779
|
this.shouldScrollToBottom = false;
|
|
12842
12780
|
return;
|
|
12843
12781
|
}
|
|
12844
|
-
//
|
|
12782
|
+
// for autoscroll or scroll to bottom button
|
|
12783
|
+
const maxAutoLoads = 200;
|
|
12784
|
+
let loads = 0;
|
|
12785
|
+
let prevNewTS = this.newTS;
|
|
12845
12786
|
this.isLoading = true;
|
|
12846
|
-
|
|
12847
|
-
|
|
12848
|
-
|
|
12849
|
-
|
|
12850
|
-
this.
|
|
12851
|
-
this.
|
|
12852
|
-
//
|
|
12853
|
-
|
|
12854
|
-
|
|
12855
|
-
|
|
12856
|
-
|
|
12857
|
-
|
|
12858
|
-
|
|
12859
|
-
this.pages[this.firstEmptyIndex] = data.reverse();
|
|
12860
|
-
}
|
|
12861
|
-
else {
|
|
12862
|
-
// when already at the bottom and loading messages in realtime
|
|
12787
|
+
this.isLoadingBottom = true;
|
|
12788
|
+
while (loads < maxAutoLoads) {
|
|
12789
|
+
const scrollAnchor = this.getScrollAnchor('bottom');
|
|
12790
|
+
const data = await this.fetchData(this.newTS + 1, this.pageSize, false);
|
|
12791
|
+
this.isLoading = false;
|
|
12792
|
+
this.isLoadingBottom = false;
|
|
12793
|
+
// no more new messages to load
|
|
12794
|
+
if (!data.length) {
|
|
12795
|
+
this.showNewMessagesCTR = false;
|
|
12796
|
+
this.shouldScrollToBottom = false;
|
|
12797
|
+
break;
|
|
12798
|
+
}
|
|
12799
|
+
// load new messages and append to the start
|
|
12863
12800
|
this.pages.unshift(data.reverse());
|
|
12801
|
+
// remove pages if out of bounds
|
|
12802
|
+
if (this.pages.length > this.pagesAllowed)
|
|
12803
|
+
this.pages.pop();
|
|
12804
|
+
// update timestamps
|
|
12805
|
+
const lastPage = this.pages[this.pages.length - 1];
|
|
12806
|
+
this.oldTS = lastPage[lastPage.length - 1].timeMs;
|
|
12807
|
+
this.newTS = this.pages[0][0].timeMs;
|
|
12808
|
+
this.rerender();
|
|
12809
|
+
this.pendingScrollAnchor = scrollAnchor;
|
|
12810
|
+
if (!this.shouldScrollToBottom)
|
|
12811
|
+
break;
|
|
12812
|
+
// if should scroll to bottom then retrigger
|
|
12813
|
+
await this.waitForNextFrame();
|
|
12814
|
+
this.scrollToBottom();
|
|
12815
|
+
await this.waitForNextFrame();
|
|
12816
|
+
// if no new messages, break
|
|
12817
|
+
if (this.newTS === prevNewTS)
|
|
12818
|
+
break;
|
|
12819
|
+
prevNewTS = this.newTS;
|
|
12820
|
+
loads++;
|
|
12821
|
+
}
|
|
12822
|
+
}
|
|
12823
|
+
// Find the element that is closest to the top/bottom of the container
|
|
12824
|
+
getScrollAnchor(edge = 'top') {
|
|
12825
|
+
if (!this.$containerRef)
|
|
12826
|
+
return null;
|
|
12827
|
+
const containerRect = this.$containerRef.getBoundingClientRect();
|
|
12828
|
+
const candidates = Array.from(this.$containerRef.querySelectorAll('[id]')).filter((el) => el.id !== 'top-scroll' && el.id !== 'bottom-scroll');
|
|
12829
|
+
let best = null;
|
|
12830
|
+
for (const el of candidates) {
|
|
12831
|
+
const rect = el.getBoundingClientRect();
|
|
12832
|
+
const isVisibleInContainer = rect.bottom > containerRect.top && rect.top < containerRect.bottom;
|
|
12833
|
+
if (!isVisibleInContainer)
|
|
12834
|
+
continue;
|
|
12835
|
+
if (edge === 'top') {
|
|
12836
|
+
const offsetTop = rect.top - containerRect.top;
|
|
12837
|
+
if (best == null || (best.edge === 'top' && offsetTop < best.offsetTop)) {
|
|
12838
|
+
best = { id: el.id, edge: 'top', offsetTop };
|
|
12839
|
+
}
|
|
12840
|
+
}
|
|
12841
|
+
else {
|
|
12842
|
+
const offsetBottom = containerRect.bottom - rect.bottom;
|
|
12843
|
+
if (best == null || (best.edge === 'bottom' && offsetBottom < best.offsetBottom)) {
|
|
12844
|
+
best = { id: el.id, edge: 'bottom', offsetBottom };
|
|
12845
|
+
}
|
|
12846
|
+
}
|
|
12864
12847
|
}
|
|
12865
|
-
|
|
12866
|
-
|
|
12848
|
+
return best;
|
|
12849
|
+
}
|
|
12850
|
+
//instant scroll to anchor to make sure we are at the same position after a rerender
|
|
12851
|
+
restoreScrollToAnchor(anchor) {
|
|
12852
|
+
if (!this.$containerRef)
|
|
12853
|
+
return;
|
|
12854
|
+
// make element id safe to use inside a CSS selector
|
|
12855
|
+
const escapeId = (id) => {
|
|
12856
|
+
var _a;
|
|
12857
|
+
const cssEscape = (_a = globalThis.CSS) === null || _a === void 0 ? void 0 : _a.escape;
|
|
12858
|
+
return typeof cssEscape === 'function'
|
|
12859
|
+
? cssEscape(id)
|
|
12860
|
+
: id.replace(/[^a-zA-Z0-9_-]/g, '\\$&');
|
|
12861
|
+
};
|
|
12862
|
+
const el = this.$containerRef.querySelector(`#${escapeId(anchor.id)}`);
|
|
12863
|
+
if (!el)
|
|
12864
|
+
return;
|
|
12865
|
+
const containerRect = this.$containerRef.getBoundingClientRect();
|
|
12866
|
+
const rect = el.getBoundingClientRect();
|
|
12867
|
+
if (anchor.edge === 'top') {
|
|
12868
|
+
const newOffsetTop = rect.top - containerRect.top;
|
|
12869
|
+
this.$containerRef.scrollTop += newOffsetTop - anchor.offsetTop;
|
|
12867
12870
|
}
|
|
12868
|
-
|
|
12869
|
-
|
|
12870
|
-
|
|
12871
|
-
for (let i = this.pages.length - 1; i > this.firstEmptyIndex; i--) {
|
|
12872
|
-
if (this.pages[i].length > 0)
|
|
12873
|
-
break;
|
|
12874
|
-
// if page is empty, remove it
|
|
12875
|
-
this.pages.pop();
|
|
12871
|
+
else {
|
|
12872
|
+
const newOffsetBottom = containerRect.bottom - rect.bottom;
|
|
12873
|
+
this.$containerRef.scrollTop += anchor.offsetBottom - newOffsetBottom;
|
|
12876
12874
|
}
|
|
12877
|
-
|
|
12878
|
-
|
|
12879
|
-
|
|
12880
|
-
|
|
12881
|
-
|
|
12882
|
-
|
|
12883
|
-
|
|
12884
|
-
|
|
12885
|
-
|
|
12875
|
+
}
|
|
12876
|
+
// this method is called recursively based on shouldScrollToBottom (see loadNextPage)
|
|
12877
|
+
scrollToBottom() {
|
|
12878
|
+
this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
|
|
12879
|
+
}
|
|
12880
|
+
waitForNextFrame() {
|
|
12881
|
+
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
12882
|
+
}
|
|
12883
|
+
rerender() {
|
|
12884
|
+
this.rerenderBoolean = !this.rerenderBoolean;
|
|
12886
12885
|
}
|
|
12887
12886
|
render() {
|
|
12888
12887
|
/**
|
|
12889
|
-
* div.container is flex=column-
|
|
12890
|
-
* which is why div#bottom-scroll comes before div#top-scroll
|
|
12888
|
+
* div.container is flex=column-reversewhich is why div#bottom-scroll comes before div#top-scroll
|
|
12891
12889
|
*/
|
|
12892
|
-
return (h(Host, { key: '
|
|
12890
|
+
return (h(Host, { key: 'e0f806cccdcba162d0c834476863b34630cb1a1e' }, h("div", { key: '6d54d50ed703a59df8d26399499533e3cb0d70fe', class: "scrollbar container", part: "container", ref: (el) => (this.$containerRef = el) }, h("div", { key: '4e9fcbed725fb55d9fbb67eca94b0e770662d51b', class: { 'show-new-messages-ctr': true, active: this.showNewMessagesCTR } }, h("rtk-button", { key: '7db0236d35db3fb9856fea7a4f62c1fbd421829e', class: "show-new-messages", kind: "icon", variant: "secondary", part: "show-new-messages", onClick: () => {
|
|
12893
12891
|
this.shouldScrollToBottom = true;
|
|
12894
12892
|
this.scrollToBottom();
|
|
12895
|
-
} }, h("rtk-icon", { key: '
|
|
12893
|
+
} }, h("rtk-icon", { key: '6e247e86029560601080e0b4d6dcfccbd90fcdd6', icon: this.iconPack.chevron_down }))), h("div", { key: '01d1ba7eacc67ece70b805fb2dfb493cdf1c9d23', class: "smallest-dom-element", id: "bottom-scroll", ref: (el) => (this.$bottomRef = el) }), this.isLoadingBottom && this.pages.length > 0 && h("rtk-spinner", { key: '24391bfc34914675cbfd0c287332bfdf3f5f5000', size: "sm" }), this.isLoading && this.pages.length < 1 && h("rtk-spinner", { key: 'e6c2cb44fce52ca54c9f1e543d91a29648745408', size: "lg" }), !this.isLoading && this.pages.flat().length === 0 ? (h("div", { class: "empty-list" }, this.t('list.empty'))) : (h("div", { class: "page-wrapper" }, this.pages.map((page, pageIndex) => (h("div", { class: "page", "data-page-index": pageIndex }, this.createNodes([...page].reverse())))))), this.isLoadingTop && this.pages.length > 0 && h("rtk-spinner", { key: 'd90a15494bcd7ec6c9c7ffc5e9a55054252a4258', size: "sm" }), h("div", { key: '2a65f98c3c4e6f2510c6cf1b4e2bcf1e607a7552', class: "smallest-dom-element", id: "top-scroll", ref: (el) => (this.$topRef = el) }))));
|
|
12896
12894
|
}
|
|
12897
12895
|
};
|
|
12898
12896
|
__decorate$2$8([
|
|
@@ -15418,7 +15416,7 @@ const RtkChatToggle = class {
|
|
|
15418
15416
|
const newMessages = messages.filter((m) => m.timeMs > meetingStartedTimeMs);
|
|
15419
15417
|
if (newMessages.length === this.pageSize && newMessages.length > 0) {
|
|
15420
15418
|
// all messages are new, so we can't know the exact count, but we know there are at least pageSize - 1 new messages
|
|
15421
|
-
this.unreadMessageCount =
|
|
15419
|
+
this.unreadMessageCount = newMessages.length;
|
|
15422
15420
|
}
|
|
15423
15421
|
else {
|
|
15424
15422
|
this.unreadMessageCount = newMessages.length;
|
|
@@ -18708,7 +18706,10 @@ const RtkNotifications = class {
|
|
|
18708
18706
|
this.waitlistedParticipantLeftListener = (participant) => {
|
|
18709
18707
|
this.remove(`${participant.id}-joined-waitlist`);
|
|
18710
18708
|
};
|
|
18711
|
-
this.chatUpdateListener = ({ message }) => {
|
|
18709
|
+
this.chatUpdateListener = ({ message, action }) => {
|
|
18710
|
+
// NOTE(ikabra): we only want notifications for new messages
|
|
18711
|
+
if (action !== 'add')
|
|
18712
|
+
return;
|
|
18712
18713
|
const parsedMessage = parseMessageForTarget(message);
|
|
18713
18714
|
if (parsedMessage != null) {
|
|
18714
18715
|
if (parsedMessage.userId === meeting.self.userId) {
|