@cloudflare/realtimekit-ui 1.1.0-staging.5 → 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 +186 -175
- package/dist/cjs/rtk-chat-toggle.cjs.entry.js +2 -2
- 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 +2 -2
- package/dist/collection/components/rtk-notifications/rtk-notifications.js +4 -1
- package/dist/collection/components/rtk-paginated-list/rtk-paginated-list.js +184 -173
- package/dist/components/{p-32c6e86d.js → p-1d16490e.js} +2 -2
- package/dist/components/{p-ae376177.js → p-7be71567.js} +3 -3
- package/dist/components/{p-0d472019.js → p-7f8d9afc.js} +184 -173
- 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 +2 -2
- 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 +191 -177
- package/dist/esm/rtk-avatar_24.entry.js +186 -175
- package/dist/esm/rtk-chat-toggle.entry.js +2 -2
- 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-f457ae6f.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-83db4de1.entry.js +0 -1
- package/dist/realtimekit-ui/p-a859d883.entry.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { p as proxyCustomElement, H,
|
|
1
|
+
import { p as proxyCustomElement, H, h, e as Host } from './p-c3592601.js';
|
|
2
2
|
import { e as defaultIconPack, i as useLanguage } from './p-e847fee9.js';
|
|
3
3
|
import { S as SyncWithStore } from './p-6f7c46d2.js';
|
|
4
4
|
import { d as defineCustomElement$3 } from './p-1391bef0.js';
|
|
@@ -10,32 +10,30 @@ const rtkPaginatedListCss = ".scrollbar{scrollbar-width:thin;scrollbar-color:var
|
|
|
10
10
|
const RtkPaginatedListStyle0 = rtkPaginatedListCss;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* NOTE(ikabra): INFINITE SCROLL IMPLEMENTATION:
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Uses scrollend listener for 2way scrolling.
|
|
16
|
+
* Empty divs ($topRef, $bottomRef) act as scroll triggers to fetch new messages.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* UPWARD SCROLLING:
|
|
19
|
+
* - Fetch top anchor (element currently visible to the user near top)
|
|
20
|
+
* - Fetch older messages, push to end of 2D array
|
|
21
|
+
* - When exceeding pagesAllowed, delete pages and scroll back to anchor
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
* DOWNWARD SCROLLING:
|
|
24
|
+
* - Fetch bottom anchor (element currently visible to the user near bottom)
|
|
25
|
+
* - Fetch new page, insert at the start
|
|
26
|
+
* - Update timestamps & firstEmptyIndex, then rerender
|
|
27
|
+
* - When exceeding pagesAllowed, delete pages and scroll back to anchor
|
|
24
28
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* if length exceeds pagesAllowed, we free up the pages and keep the first empty index in memory (firstEmptyIndex).
|
|
29
|
+
* ADDING NEW NODES:
|
|
30
|
+
* - If no pages exist, load old page
|
|
31
|
+
* - If on 1st page, append messages till page size is full and then load new page
|
|
29
32
|
*
|
|
30
|
-
*
|
|
31
|
-
* If
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* If we have exceeded our page allowance we delete old pages.
|
|
35
|
-
*
|
|
36
|
-
* In this case deleting pages is okay as we are not relying on the index of dom elements to detect page end.
|
|
37
|
-
*
|
|
38
|
-
* This also simplifies the code because when a user scrolls up we do not need to manage a lastEmptyIndex.
|
|
33
|
+
* DELETE NODE:
|
|
34
|
+
* - If deleting the only available node, reset to initial state
|
|
35
|
+
* - If page is empty, delete it
|
|
36
|
+
* - Update timestamp curors
|
|
39
37
|
*/
|
|
40
38
|
var __decorate = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
|
|
41
39
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -52,43 +50,27 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
|
|
|
52
50
|
super();
|
|
53
51
|
this.__registerHost();
|
|
54
52
|
this.__attachShadow();
|
|
55
|
-
/**
|
|
56
|
-
* when scrolling up, we can't remove pages as intersectionObserver relies on
|
|
57
|
-
* the index of dom elements to stay stable.
|
|
58
|
-
* So, instead we free up the pages and keep the last empty index in memory.
|
|
59
|
-
*/
|
|
60
|
-
this.firstEmptyIndex = -1;
|
|
61
|
-
this.maxTS = 0;
|
|
62
53
|
// the length of pages will always be pageSize + 2
|
|
63
54
|
this.pages = [];
|
|
55
|
+
// Controls whether to keep auto-scrolling when a new page load.
|
|
56
|
+
this.shouldScrollToBottom = false;
|
|
57
|
+
// Shows "scroll to bottom" button when new nodes arrive and autoscroll is off.
|
|
58
|
+
this.showNewMessagesCTR = false;
|
|
64
59
|
/** label to show when empty */
|
|
65
60
|
this.emptyListLabel = null;
|
|
66
|
-
this.rerenderBoolean = false;
|
|
67
|
-
this.showEmptyListLabel = false;
|
|
68
61
|
/** Icon pack */
|
|
69
62
|
this.iconPack = defaultIconPack;
|
|
70
63
|
/** Language */
|
|
71
64
|
this.t = useLanguage();
|
|
65
|
+
this.rerenderBoolean = false;
|
|
66
|
+
this.showEmptyListLabel = false;
|
|
72
67
|
this.isLoading = false;
|
|
73
68
|
this.isLoadingTop = false;
|
|
74
69
|
this.isLoadingBottom = false;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
* */
|
|
80
|
-
this.shouldScrollToBottom = false;
|
|
81
|
-
/** UI Indicator for the "scroll to bottom" button.
|
|
82
|
-
* Toggles on when a new node is added and autoscroll is disabled.
|
|
83
|
-
* Toggles off when all nodes are loaded */
|
|
84
|
-
this.showNewMessagesCTR = false;
|
|
85
|
-
this.observe = (el) => {
|
|
86
|
-
if (!el)
|
|
87
|
-
return;
|
|
88
|
-
this.intersectionObserver.observe(el);
|
|
89
|
-
};
|
|
90
|
-
this.isAtBottom = () => {
|
|
91
|
-
const rect = this.$bottomRef.getBoundingClientRect();
|
|
70
|
+
// Tells us if we need to scroll to a specific anchor after a rerender
|
|
71
|
+
this.pendingScrollAnchor = null;
|
|
72
|
+
this.isInView = (el) => {
|
|
73
|
+
const rect = el.getBoundingClientRect();
|
|
92
74
|
return rect.top >= 0 && rect.bottom <= window.innerHeight;
|
|
93
75
|
};
|
|
94
76
|
}
|
|
@@ -97,10 +79,12 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
|
|
|
97
79
|
* @param {DataNode} node - The data node to add to the beginning of the list
|
|
98
80
|
*/
|
|
99
81
|
async onNewNode(node) {
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
82
|
+
// if there are no pages, load the first page
|
|
83
|
+
if (this.pages.length < 1) {
|
|
84
|
+
this.oldTS = node.timeMs + 1;
|
|
85
|
+
this.loadPrevPage();
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
104
88
|
// append messages to the page if page has not reached full capacity
|
|
105
89
|
if (this.pages[0].length < this.pageSize) {
|
|
106
90
|
this.pages[0].unshift(node);
|
|
@@ -112,49 +96,40 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
|
|
|
112
96
|
this.loadNextPage();
|
|
113
97
|
}
|
|
114
98
|
}
|
|
115
|
-
// If autoscroll is enabled,
|
|
99
|
+
// If autoscroll is enabled, scroll to the bottom
|
|
116
100
|
if (this.autoScroll) {
|
|
117
101
|
this.shouldScrollToBottom = true;
|
|
118
102
|
this.scrollToBottom();
|
|
119
103
|
}
|
|
120
|
-
else {
|
|
121
|
-
this.showNewMessagesCTR = true;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
// this method is called recursively based on shouldScrollToBottom (see scrollEnd listener)
|
|
125
|
-
scrollToBottom() {
|
|
126
|
-
this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
|
|
127
104
|
}
|
|
128
105
|
/**
|
|
129
106
|
* Deletes a node anywhere from the list
|
|
130
107
|
* @param {string} id - The id of the node to delete
|
|
131
108
|
* */
|
|
132
109
|
async onNodeDelete(id) {
|
|
133
|
-
|
|
134
|
-
|
|
110
|
+
var _a, _b;
|
|
111
|
+
let didDelete = false;
|
|
112
|
+
for (let i = this.pages.length - 1; i >= 0; i--) {
|
|
135
113
|
const index = this.pages[i].findIndex((node) => node.id === id);
|
|
136
|
-
// message
|
|
137
|
-
if (index
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
else if (i === this.firstEmptyIndex + this.pagesAllowed) {
|
|
148
|
-
// if oldest page is empty, remove it
|
|
149
|
-
if (this.pages[i].length === 0)
|
|
150
|
-
this.pages.pop();
|
|
151
|
-
// update timestamp
|
|
152
|
-
const lastPage = this.pages[this.firstEmptyIndex + this.pagesAllowed];
|
|
153
|
-
this.oldTS = lastPage[lastPage.length - 1].timeMs;
|
|
154
|
-
}
|
|
155
|
-
this.rerender();
|
|
156
|
-
}
|
|
114
|
+
// if message not found, move on
|
|
115
|
+
if (index === -1)
|
|
116
|
+
continue;
|
|
117
|
+
// delete message
|
|
118
|
+
this.pages[i].splice(index, 1);
|
|
119
|
+
// if page is empty, delete it
|
|
120
|
+
if (this.pages[i].length === 0)
|
|
121
|
+
this.pages.splice(i, 1);
|
|
122
|
+
didDelete = true;
|
|
123
|
+
break;
|
|
157
124
|
}
|
|
125
|
+
if (!didDelete)
|
|
126
|
+
return;
|
|
127
|
+
// update timestamps
|
|
128
|
+
const firstPage = this.pages[0];
|
|
129
|
+
const lastPage = this.pages[this.pages.length - 1];
|
|
130
|
+
this.newTS = (_a = firstPage === null || firstPage === void 0 ? void 0 : firstPage[0]) === null || _a === void 0 ? void 0 : _a.timeMs;
|
|
131
|
+
this.oldTS = (_b = lastPage === null || lastPage === void 0 ? void 0 : lastPage[lastPage.length - 1]) === null || _b === void 0 ? void 0 : _b.timeMs;
|
|
132
|
+
this.rerender();
|
|
158
133
|
}
|
|
159
134
|
/**
|
|
160
135
|
* Updates a new node anywhere in the list
|
|
@@ -162,146 +137,182 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
|
|
|
162
137
|
* @param {DataNode} _node - The updated data node
|
|
163
138
|
* */
|
|
164
139
|
async onNodeUpdate(_id, _node) { }
|
|
165
|
-
rerender() {
|
|
166
|
-
this.rerenderBoolean = !this.rerenderBoolean;
|
|
167
|
-
}
|
|
168
140
|
connectedCallback() {
|
|
169
141
|
this.rerender = debounce(this.rerender.bind(this), 50, { maxWait: 200 });
|
|
170
|
-
this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
171
|
-
writeTask(async () => {
|
|
172
|
-
for (const entry of entries) {
|
|
173
|
-
if (entry.target.id === 'top-scroll' && entry.isIntersecting) {
|
|
174
|
-
this.isLoadingTop = true;
|
|
175
|
-
await this.loadPrevPage();
|
|
176
|
-
this.isLoadingTop = false;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
142
|
}
|
|
182
143
|
componentDidLoad() {
|
|
183
|
-
|
|
144
|
+
// initial load
|
|
145
|
+
this.loadPrevPage();
|
|
184
146
|
if (this.$containerRef) {
|
|
185
147
|
this.$containerRef.onscrollend = async () => {
|
|
186
|
-
|
|
187
|
-
* Load new page if:
|
|
188
|
-
* if there are nodes to load at the bottom (maxTS > newTS)
|
|
189
|
-
* or if there are pages to fill at the bottom (firstEmptyIndex > -1)
|
|
190
|
-
*/
|
|
191
|
-
if (this.isAtBottom() && (this.maxTS > this.newTS || this.firstEmptyIndex > -1)) {
|
|
192
|
-
this.isLoadingBottom = true;
|
|
148
|
+
if (this.isInView(this.$bottomRef)) {
|
|
193
149
|
await this.loadNextPage();
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
150
|
+
}
|
|
151
|
+
else if (this.isInView(this.$topRef)) {
|
|
152
|
+
this.showNewMessagesCTR = true;
|
|
153
|
+
await this.loadPrevPage();
|
|
197
154
|
}
|
|
198
155
|
};
|
|
199
156
|
}
|
|
200
157
|
}
|
|
158
|
+
componentDidRender() {
|
|
159
|
+
if (!this.pendingScrollAnchor)
|
|
160
|
+
return;
|
|
161
|
+
const anchor = this.pendingScrollAnchor;
|
|
162
|
+
this.pendingScrollAnchor = null;
|
|
163
|
+
this.restoreScrollToAnchor(anchor);
|
|
164
|
+
}
|
|
201
165
|
async loadPrevPage() {
|
|
202
166
|
if (this.isLoading)
|
|
203
167
|
return;
|
|
204
|
-
|
|
205
|
-
* NOTE(ikabra): this case also runs on initial load
|
|
206
|
-
* if scrolling up ->
|
|
207
|
-
* fetch older messages and push to the end of the array
|
|
208
|
-
* cleanup 1st non empty page from the array if length exceeds pagesAllowed
|
|
209
|
-
*/
|
|
168
|
+
const scrollAnchor = this.getScrollAnchor('top');
|
|
210
169
|
// if no old timestamp, it means we are at initial state
|
|
211
170
|
if (!this.oldTS)
|
|
212
171
|
this.oldTS = new Date().getTime();
|
|
213
172
|
// load data
|
|
214
173
|
this.isLoading = true;
|
|
174
|
+
this.isLoadingTop = true;
|
|
215
175
|
const data = await this.fetchData(this.oldTS - 1, this.pageSize, true);
|
|
216
176
|
this.isLoading = false;
|
|
177
|
+
this.isLoadingTop = false;
|
|
217
178
|
// no more old messages to show, we are at the top of the page
|
|
218
179
|
if (!data.length)
|
|
219
180
|
return;
|
|
220
181
|
// add old data to the end of the array
|
|
221
182
|
this.pages.push(data);
|
|
222
183
|
// clear old pages when we reach the limit
|
|
223
|
-
if (this.pages.length > this.pagesAllowed)
|
|
224
|
-
this.pages
|
|
225
|
-
|
|
226
|
-
* find last non empty page in range (this.pages.length, this.firstEmptyIndex)
|
|
227
|
-
* we are doing this because any of the middle pages in the currently rendered pages
|
|
228
|
-
* could be empty as we allow deleting messages.
|
|
229
|
-
* This helps us set the first empty index correctly.
|
|
230
|
-
*/
|
|
231
|
-
for (let i = this.firstEmptyIndex + 1; i < this.pages.length; i++) {
|
|
232
|
-
if (this.pages[i].length > 0)
|
|
233
|
-
break;
|
|
234
|
-
this.firstEmptyIndex = i;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
// update the old timestamp
|
|
184
|
+
if (this.pages.length > this.pagesAllowed)
|
|
185
|
+
this.pages.shift();
|
|
186
|
+
// update timestamps
|
|
238
187
|
const lastPage = this.pages[this.pages.length - 1];
|
|
239
188
|
this.oldTS = lastPage[lastPage.length - 1].timeMs;
|
|
240
|
-
|
|
241
|
-
this.newTS = this.pages[this.firstEmptyIndex + 1][0].timeMs;
|
|
189
|
+
this.newTS = this.pages[0][0].timeMs;
|
|
242
190
|
this.rerender();
|
|
191
|
+
// fix scroll position
|
|
192
|
+
if (scrollAnchor)
|
|
193
|
+
this.pendingScrollAnchor = scrollAnchor;
|
|
243
194
|
}
|
|
244
195
|
async loadNextPage() {
|
|
245
196
|
if (this.isLoading)
|
|
246
197
|
return;
|
|
247
|
-
//
|
|
198
|
+
// Do nothing. New timestamp needs to be assigned by loadPrevPage method
|
|
248
199
|
if (!this.newTS) {
|
|
249
200
|
this.showNewMessagesCTR = false;
|
|
250
201
|
this.shouldScrollToBottom = false;
|
|
251
202
|
return;
|
|
252
203
|
}
|
|
253
|
-
//
|
|
204
|
+
// for autoscroll or scroll to bottom button
|
|
205
|
+
const maxAutoLoads = 200;
|
|
206
|
+
let loads = 0;
|
|
207
|
+
let prevNewTS = this.newTS;
|
|
254
208
|
this.isLoading = true;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
this.
|
|
260
|
-
this.
|
|
261
|
-
//
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
this.pages[this.firstEmptyIndex] = data.reverse();
|
|
269
|
-
}
|
|
270
|
-
else {
|
|
271
|
-
// when already at the bottom and loading messages in realtime
|
|
209
|
+
this.isLoadingBottom = true;
|
|
210
|
+
while (loads < maxAutoLoads) {
|
|
211
|
+
const scrollAnchor = this.getScrollAnchor('bottom');
|
|
212
|
+
const data = await this.fetchData(this.newTS + 1, this.pageSize, false);
|
|
213
|
+
this.isLoading = false;
|
|
214
|
+
this.isLoadingBottom = false;
|
|
215
|
+
// no more new messages to load
|
|
216
|
+
if (!data.length) {
|
|
217
|
+
this.showNewMessagesCTR = false;
|
|
218
|
+
this.shouldScrollToBottom = false;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
// load new messages and append to the start
|
|
272
222
|
this.pages.unshift(data.reverse());
|
|
223
|
+
// remove pages if out of bounds
|
|
224
|
+
if (this.pages.length > this.pagesAllowed)
|
|
225
|
+
this.pages.pop();
|
|
226
|
+
// update timestamps
|
|
227
|
+
const lastPage = this.pages[this.pages.length - 1];
|
|
228
|
+
this.oldTS = lastPage[lastPage.length - 1].timeMs;
|
|
229
|
+
this.newTS = this.pages[0][0].timeMs;
|
|
230
|
+
this.rerender();
|
|
231
|
+
this.pendingScrollAnchor = scrollAnchor;
|
|
232
|
+
if (!this.shouldScrollToBottom)
|
|
233
|
+
break;
|
|
234
|
+
// if should scroll to bottom then retrigger
|
|
235
|
+
await this.waitForNextFrame();
|
|
236
|
+
this.scrollToBottom();
|
|
237
|
+
await this.waitForNextFrame();
|
|
238
|
+
// if no new messages, break
|
|
239
|
+
if (this.newTS === prevNewTS)
|
|
240
|
+
break;
|
|
241
|
+
prevNewTS = this.newTS;
|
|
242
|
+
loads++;
|
|
273
243
|
}
|
|
274
|
-
|
|
275
|
-
|
|
244
|
+
}
|
|
245
|
+
// Find the element that is closest to the top/bottom of the container
|
|
246
|
+
getScrollAnchor(edge = 'top') {
|
|
247
|
+
if (!this.$containerRef)
|
|
248
|
+
return null;
|
|
249
|
+
const containerRect = this.$containerRef.getBoundingClientRect();
|
|
250
|
+
const candidates = Array.from(this.$containerRef.querySelectorAll('[id]')).filter((el) => el.id !== 'top-scroll' && el.id !== 'bottom-scroll');
|
|
251
|
+
let best = null;
|
|
252
|
+
for (const el of candidates) {
|
|
253
|
+
const rect = el.getBoundingClientRect();
|
|
254
|
+
const isVisibleInContainer = rect.bottom > containerRect.top && rect.top < containerRect.bottom;
|
|
255
|
+
if (!isVisibleInContainer)
|
|
256
|
+
continue;
|
|
257
|
+
if (edge === 'top') {
|
|
258
|
+
const offsetTop = rect.top - containerRect.top;
|
|
259
|
+
if (best == null || (best.edge === 'top' && offsetTop < best.offsetTop)) {
|
|
260
|
+
best = { id: el.id, edge: 'top', offsetTop };
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
const offsetBottom = containerRect.bottom - rect.bottom;
|
|
265
|
+
if (best == null || (best.edge === 'bottom' && offsetBottom < best.offsetBottom)) {
|
|
266
|
+
best = { id: el.id, edge: 'bottom', offsetBottom };
|
|
267
|
+
}
|
|
268
|
+
}
|
|
276
269
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
270
|
+
return best;
|
|
271
|
+
}
|
|
272
|
+
//instant scroll to anchor to make sure we are at the same position after a rerender
|
|
273
|
+
restoreScrollToAnchor(anchor) {
|
|
274
|
+
if (!this.$containerRef)
|
|
275
|
+
return;
|
|
276
|
+
// make element id safe to use inside a CSS selector
|
|
277
|
+
const escapeId = (id) => {
|
|
278
|
+
var _a;
|
|
279
|
+
const cssEscape = (_a = globalThis.CSS) === null || _a === void 0 ? void 0 : _a.escape;
|
|
280
|
+
return typeof cssEscape === 'function'
|
|
281
|
+
? cssEscape(id)
|
|
282
|
+
: id.replace(/[^a-zA-Z0-9_-]/g, '\\$&');
|
|
283
|
+
};
|
|
284
|
+
const el = this.$containerRef.querySelector(`#${escapeId(anchor.id)}`);
|
|
285
|
+
if (!el)
|
|
286
|
+
return;
|
|
287
|
+
const containerRect = this.$containerRef.getBoundingClientRect();
|
|
288
|
+
const rect = el.getBoundingClientRect();
|
|
289
|
+
if (anchor.edge === 'top') {
|
|
290
|
+
const newOffsetTop = rect.top - containerRect.top;
|
|
291
|
+
this.$containerRef.scrollTop += newOffsetTop - anchor.offsetTop;
|
|
285
292
|
}
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
this.
|
|
294
|
-
|
|
293
|
+
else {
|
|
294
|
+
const newOffsetBottom = containerRect.bottom - rect.bottom;
|
|
295
|
+
this.$containerRef.scrollTop += anchor.offsetBottom - newOffsetBottom;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// this method is called recursively based on shouldScrollToBottom (see loadNextPage)
|
|
299
|
+
scrollToBottom() {
|
|
300
|
+
this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
|
|
301
|
+
}
|
|
302
|
+
waitForNextFrame() {
|
|
303
|
+
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
304
|
+
}
|
|
305
|
+
rerender() {
|
|
306
|
+
this.rerenderBoolean = !this.rerenderBoolean;
|
|
295
307
|
}
|
|
296
308
|
render() {
|
|
297
309
|
/**
|
|
298
|
-
* div.container is flex=column-
|
|
299
|
-
* which is why div#bottom-scroll comes before div#top-scroll
|
|
310
|
+
* div.container is flex=column-reversewhich is why div#bottom-scroll comes before div#top-scroll
|
|
300
311
|
*/
|
|
301
|
-
return (h(Host, { key: '
|
|
312
|
+
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: () => {
|
|
302
313
|
this.shouldScrollToBottom = true;
|
|
303
314
|
this.scrollToBottom();
|
|
304
|
-
} }, h("rtk-icon", { key: '
|
|
315
|
+
} }, 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) }))));
|
|
305
316
|
}
|
|
306
317
|
static get style() { return RtkPaginatedListStyle0; }
|
|
307
318
|
}, [1, "rtk-paginated-list", {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as RtkChatMessagesUiPaginated$1, d as defineCustomElement$1 } from './p-
|
|
1
|
+
import { R as RtkChatMessagesUiPaginated$1, d as defineCustomElement$1 } from './p-7be71567.js';
|
|
2
2
|
|
|
3
3
|
const RtkChatMessagesUiPaginated = RtkChatMessagesUiPaginated$1;
|
|
4
4
|
const defineCustomElement = defineCustomElement$1;
|
|
@@ -11,7 +11,7 @@ import { d as defineCustomElement$8 } from './p-fa476519.js';
|
|
|
11
11
|
import { d as defineCustomElement$7 } from './p-2447a26f.js';
|
|
12
12
|
import { d as defineCustomElement$6 } from './p-819cb785.js';
|
|
13
13
|
import { d as defineCustomElement$5 } from './p-7148ec6a.js';
|
|
14
|
-
import { d as defineCustomElement$4 } from './p-
|
|
14
|
+
import { d as defineCustomElement$4 } from './p-7f8d9afc.js';
|
|
15
15
|
import { d as defineCustomElement$3 } from './p-4ebf9684.js';
|
|
16
16
|
import { d as defineCustomElement$2 } from './p-46d99dd9.js';
|
|
17
17
|
|
|
@@ -95,9 +95,9 @@ const RtkChatToggle$1 = /*@__PURE__*/ proxyCustomElement(class RtkChatToggle ext
|
|
|
95
95
|
const { messages } = await chat.getMessages(new Date().getTime(), this.pageSize, true);
|
|
96
96
|
const meetingStartedTimeMs = (_b = (_a = this.meeting.meta) === null || _a === void 0 ? void 0 : _a.meetingStartedTimestamp.getTime()) !== null && _b !== void 0 ? _b : 0;
|
|
97
97
|
const newMessages = messages.filter((m) => m.timeMs > meetingStartedTimeMs);
|
|
98
|
-
if (newMessages.length ===
|
|
98
|
+
if (newMessages.length === this.pageSize && newMessages.length > 0) {
|
|
99
99
|
// all messages are new, so we can't know the exact count, but we know there are at least pageSize - 1 new messages
|
|
100
|
-
this.unreadMessageCount =
|
|
100
|
+
this.unreadMessageCount = newMessages.length;
|
|
101
101
|
}
|
|
102
102
|
else {
|
|
103
103
|
this.unreadMessageCount = newMessages.length;
|
|
@@ -8,9 +8,9 @@ import { i as index } from './p-f47d4fe8.js';
|
|
|
8
8
|
import { d as defineCustomElement$o } from './p-241a8245.js';
|
|
9
9
|
import { d as defineCustomElement$n } from './p-1391bef0.js';
|
|
10
10
|
import { d as defineCustomElement$m } from './p-a73665b4.js';
|
|
11
|
-
import { d as defineCustomElement$l } from './p-
|
|
11
|
+
import { d as defineCustomElement$l } from './p-1d16490e.js';
|
|
12
12
|
import { d as defineCustomElement$k } from './p-28170a8d.js';
|
|
13
|
-
import { d as defineCustomElement$j } from './p-
|
|
13
|
+
import { d as defineCustomElement$j } from './p-7be71567.js';
|
|
14
14
|
import { d as defineCustomElement$i } from './p-1f5a4682.js';
|
|
15
15
|
import { d as defineCustomElement$h } from './p-598dc3f2.js';
|
|
16
16
|
import { d as defineCustomElement$g } from './p-0e5cc539.js';
|
|
@@ -23,7 +23,7 @@ import { d as defineCustomElement$a } from './p-2447a26f.js';
|
|
|
23
23
|
import { d as defineCustomElement$9 } from './p-819cb785.js';
|
|
24
24
|
import { d as defineCustomElement$8 } from './p-7148ec6a.js';
|
|
25
25
|
import { d as defineCustomElement$7 } from './p-0f2de0f8.js';
|
|
26
|
-
import { d as defineCustomElement$6 } from './p-
|
|
26
|
+
import { d as defineCustomElement$6 } from './p-7f8d9afc.js';
|
|
27
27
|
import { d as defineCustomElement$5 } from './p-4ebf9684.js';
|
|
28
28
|
import { d as defineCustomElement$4 } from './p-4902c5cf.js';
|
|
29
29
|
import { d as defineCustomElement$3 } from './p-6739a399.js';
|
|
@@ -233,7 +233,10 @@ const RtkNotifications$1 = /*@__PURE__*/ proxyCustomElement(class RtkNotificatio
|
|
|
233
233
|
this.waitlistedParticipantLeftListener = (participant) => {
|
|
234
234
|
this.remove(`${participant.id}-joined-waitlist`);
|
|
235
235
|
};
|
|
236
|
-
this.chatUpdateListener = ({ message }) => {
|
|
236
|
+
this.chatUpdateListener = ({ message, action }) => {
|
|
237
|
+
// NOTE(ikabra): we only want notifications for new messages
|
|
238
|
+
if (action !== 'add')
|
|
239
|
+
return;
|
|
237
240
|
const parsedMessage = parseMessageForTarget(message);
|
|
238
241
|
if (parsedMessage != null) {
|
|
239
242
|
if (parsedMessage.userId === meeting.self.userId) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { R as RtkPaginatedList$1, d as defineCustomElement$1 } from './p-
|
|
1
|
+
import { R as RtkPaginatedList$1, d as defineCustomElement$1 } from './p-7f8d9afc.js';
|
|
2
2
|
|
|
3
3
|
const RtkPaginatedList = RtkPaginatedList$1;
|
|
4
4
|
const defineCustomElement = defineCustomElement$1;
|