@cloudflare/realtimekit-ui 1.1.0-staging.7 → 1.1.0-staging.9

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.
@@ -79,12 +79,18 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
79
79
  * @param {DataNode} node - The data node to add to the beginning of the list
80
80
  */
81
81
  async onNewNode(node) {
82
- // if there are no pages, load the first page
82
+ // if there are no pages, append to the first page
83
83
  if (this.pages.length < 1) {
84
- this.oldTS = node.timeMs + 1;
85
- this.loadPrevPage();
84
+ this.oldTS = node.timeMs;
85
+ this.pages.unshift([node]);
86
+ this.newTS = node.timeMs;
87
+ this.maxTS = node.timeMs;
88
+ this.rerender();
89
+ if (this.autoScroll)
90
+ this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
86
91
  }
87
- else {
92
+ else if (this.maxTS === this.newTS) {
93
+ this.maxTS = node.timeMs;
88
94
  // append messages to the page if page has not reached full capacity
89
95
  if (this.pages[0].length < this.pageSize) {
90
96
  this.pages[0].unshift(node);
@@ -93,14 +99,25 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
93
99
  }
94
100
  else {
95
101
  // if page is at full capacity, load next page
96
- this.loadNextPage();
102
+ this.pages.unshift([node]);
103
+ this.newTS = node.timeMs;
104
+ // remove pages if out of bounds
105
+ if (this.pages.length > this.pagesAllowed)
106
+ this.pages.pop();
107
+ // update timestamps
108
+ const lastPage = this.pages[this.pages.length - 1];
109
+ this.oldTS = lastPage[lastPage.length - 1].timeMs;
110
+ this.newTS = this.pages[0][0].timeMs;
111
+ this.rerender();
97
112
  }
113
+ if (this.autoScroll)
114
+ this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
98
115
  }
99
- // If autoscroll is enabled, scroll to the bottom
100
- if (this.autoScroll) {
101
- this.shouldScrollToBottom = true;
102
- this.scrollToBottom();
116
+ else {
117
+ if (this.autoScroll)
118
+ this.scrollToBottom();
103
119
  }
120
+ this.pendingScrollAnchor = null;
104
121
  }
105
122
  /**
106
123
  * Deletes a node anywhere from the list
@@ -108,7 +125,6 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
108
125
  * */
109
126
  async onNodeDelete(id) {
110
127
  var _a, _b;
111
- let didDelete = false;
112
128
  for (let i = this.pages.length - 1; i >= 0; i--) {
113
129
  const index = this.pages[i].findIndex((node) => node.id === id);
114
130
  // if message not found, move on
@@ -119,24 +135,35 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
119
135
  // if page is empty, delete it
120
136
  if (this.pages[i].length === 0)
121
137
  this.pages.splice(i, 1);
122
- didDelete = true;
138
+ // update timestamps
139
+ const firstPage = this.pages[0];
140
+ const lastPage = this.pages[this.pages.length - 1];
141
+ this.newTS = (_a = firstPage === null || firstPage === void 0 ? void 0 : firstPage[0]) === null || _a === void 0 ? void 0 : _a.timeMs;
142
+ this.oldTS = (_b = lastPage === null || lastPage === void 0 ? void 0 : lastPage[lastPage.length - 1]) === null || _b === void 0 ? void 0 : _b.timeMs;
143
+ // if I have deleted the latest message, update maxTS
144
+ if (index === 0 && i === 0)
145
+ this.maxTS = this.newTS;
146
+ this.rerender();
123
147
  break;
124
148
  }
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();
133
149
  }
134
150
  /**
135
151
  * Updates a new node anywhere in the list
136
- * @param {string} _id - The id of the node to update
137
- * @param {DataNode} _node - The updated data node
152
+ * @param {string} id - The id of the node to update
153
+ * @param {DataNode} node - The updated data node
138
154
  * */
139
- async onNodeUpdate(_id, _node) { }
155
+ async onNodeUpdate(id, node) {
156
+ for (let i = this.pages.length - 1; i >= 0; i--) {
157
+ const index = this.pages[i].findIndex((node) => node.id === id);
158
+ // if message not found, move on
159
+ if (index === -1)
160
+ continue;
161
+ // edit message
162
+ this.pages[i][index] = node;
163
+ this.rerender();
164
+ break;
165
+ }
166
+ }
140
167
  connectedCallback() {
141
168
  this.rerender = debounce(this.rerender.bind(this), 50, { maxWait: 200 });
142
169
  }
@@ -145,6 +172,10 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
145
172
  this.loadPrevPage();
146
173
  if (this.$containerRef) {
147
174
  this.$containerRef.onscrollend = async () => {
175
+ // do not do anything if we are scrolling to bottom
176
+ if (this.shouldScrollToBottom)
177
+ return;
178
+ // handle top and bottom scroll
148
179
  if (this.isInView(this.$bottomRef)) {
149
180
  await this.loadNextPage();
150
181
  }
@@ -187,6 +218,8 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
187
218
  const lastPage = this.pages[this.pages.length - 1];
188
219
  this.oldTS = lastPage[lastPage.length - 1].timeMs;
189
220
  this.newTS = this.pages[0][0].timeMs;
221
+ if (!this.maxTS)
222
+ this.maxTS = this.newTS;
190
223
  this.rerender();
191
224
  // fix scroll position
192
225
  if (scrollAnchor)
@@ -194,53 +227,47 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
194
227
  }
195
228
  async loadNextPage() {
196
229
  if (this.isLoading)
197
- return;
230
+ return [];
198
231
  // Do nothing. New timestamp needs to be assigned by loadPrevPage method
199
232
  if (!this.newTS) {
200
233
  this.showNewMessagesCTR = false;
201
- this.shouldScrollToBottom = false;
202
- return;
234
+ return [];
203
235
  }
204
- // for autoscroll or scroll to bottom button
205
- const maxAutoLoads = 200;
206
- let loads = 0;
207
- let prevNewTS = this.newTS;
208
236
  this.isLoading = true;
209
237
  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
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++;
238
+ const scrollAnchor = this.getScrollAnchor('bottom');
239
+ const data = await this.fetchData(this.newTS + 1, this.pageSize, false);
240
+ this.isLoading = false;
241
+ this.isLoadingBottom = false;
242
+ // no more new messages to load
243
+ if (!data.length) {
244
+ this.maxTS = this.newTS;
245
+ this.showNewMessagesCTR = false;
246
+ return [];
243
247
  }
248
+ // load new messages and append to the start
249
+ const incoming = [...data].reverse();
250
+ if (this.pages.length === 0)
251
+ this.pages.unshift([]);
252
+ const firstPage = this.pages[0];
253
+ const spaceInFirstPage = this.pageSize - firstPage.length;
254
+ if (spaceInFirstPage > 0) {
255
+ const toFill = incoming.splice(0, spaceInFirstPage);
256
+ firstPage.unshift(...toFill);
257
+ }
258
+ while (incoming.length > 0) {
259
+ this.pages.unshift(incoming.splice(0, this.pageSize));
260
+ }
261
+ // remove pages if out of bounds
262
+ if (this.pages.length > this.pagesAllowed)
263
+ this.pages.pop();
264
+ // update timestamps
265
+ const lastPage = this.pages[this.pages.length - 1];
266
+ this.oldTS = lastPage[lastPage.length - 1].timeMs;
267
+ this.newTS = this.pages[0][0].timeMs;
268
+ this.rerender();
269
+ this.pendingScrollAnchor = scrollAnchor;
270
+ return data;
244
271
  }
245
272
  // Find the element that is closest to the top/bottom of the container
246
273
  getScrollAnchor(edge = 'top') {
@@ -296,11 +323,14 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
296
323
  }
297
324
  }
298
325
  // 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()));
326
+ async scrollToBottom() {
327
+ this.shouldScrollToBottom = true;
328
+ while (this.shouldScrollToBottom) {
329
+ const response = await this.loadNextPage();
330
+ this.$bottomRef.scrollIntoView({ behavior: 'smooth' });
331
+ if (response.length === 0)
332
+ this.shouldScrollToBottom = false;
333
+ }
304
334
  }
305
335
  rerender() {
306
336
  this.rerenderBoolean = !this.rerenderBoolean;
@@ -309,10 +339,9 @@ const RtkPaginatedList = /*@__PURE__*/ proxyCustomElement(class RtkPaginatedList
309
339
  /**
310
340
  * div.container is flex=column-reversewhich is why div#bottom-scroll comes before div#top-scroll
311
341
  */
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: () => {
313
- this.shouldScrollToBottom = true;
342
+ return (h(Host, { key: '3e7a77a4254ea0c75513edeaf72a5a77cee0e913' }, h("div", { key: 'f61e72e7a447048fe17ed8321a077841f991bfc5', class: "scrollbar container", part: "container", ref: (el) => (this.$containerRef = el) }, h("div", { key: '9efd0543b48b5ad5e147a763d258f7ef1a5024c5', class: { 'show-new-messages-ctr': true, active: this.showNewMessagesCTR } }, h("rtk-button", { key: '4b9bfda38538ceb89f31f317ddcb15d24f75ae8e', class: "show-new-messages", kind: "icon", variant: "secondary", part: "show-new-messages", onClick: () => {
314
343
  this.scrollToBottom();
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) }))));
344
+ } }, h("rtk-icon", { key: 'fbcbc895940c8046916a2382806fb403e83a0a53', icon: this.iconPack.chevron_down }))), h("div", { key: 'fe2e51385216cba1905c75db783f037953e4831e', class: "smallest-dom-element", id: "bottom-scroll", ref: (el) => (this.$bottomRef = el) }), this.isLoadingBottom && this.pages.length > 0 && h("rtk-spinner", { key: '548899e797bbf139526208df3c7696b5859cc884', size: "sm" }), this.isLoading && this.pages.length < 1 && h("rtk-spinner", { key: '6353d5970e284369c274c28fc3c774d03fd555cc', 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: 'ff7b4e80f27610c0b73b63ea32fa5331b0cf4630', size: "sm" }), h("div", { key: '8729bf082cde39f7b154fa5816a70b6fb2c7f7df', class: "smallest-dom-element", id: "top-scroll", ref: (el) => (this.$topRef = el) }))));
316
345
  }
317
346
  static get style() { return RtkPaginatedListStyle0; }
318
347
  }, [1, "rtk-paginated-list", {
@@ -1,4 +1,4 @@
1
- import { R as RtkChatMessagesUiPaginated$1, d as defineCustomElement$1 } from './p-7be71567.js';
1
+ import { R as RtkChatMessagesUiPaginated$1, d as defineCustomElement$1 } from './p-c0db1a83.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-7f8d9afc.js';
14
+ import { d as defineCustomElement$4 } from './p-fbc02b1f.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
 
@@ -1,4 +1,4 @@
1
- import { R as RtkChat$1, d as defineCustomElement$1 } from './p-1d16490e.js';
1
+ import { R as RtkChat$1, d as defineCustomElement$1 } from './p-b64798ac.js';
2
2
 
3
3
  const RtkChat = RtkChat$1;
4
4
  const defineCustomElement = defineCustomElement$1;
@@ -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-1d16490e.js';
11
+ import { d as defineCustomElement$l } from './p-b64798ac.js';
12
12
  import { d as defineCustomElement$k } from './p-28170a8d.js';
13
- import { d as defineCustomElement$j } from './p-7be71567.js';
13
+ import { d as defineCustomElement$j } from './p-c0db1a83.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-7f8d9afc.js';
26
+ import { d as defineCustomElement$6 } from './p-fbc02b1f.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';
@@ -1,4 +1,4 @@
1
- import { R as RtkPaginatedList$1, d as defineCustomElement$1 } from './p-7f8d9afc.js';
1
+ import { R as RtkPaginatedList$1, d as defineCustomElement$1 } from './p-fbc02b1f.js';
2
2
 
3
3
  const RtkPaginatedList = RtkPaginatedList$1;
4
4
  const defineCustomElement = defineCustomElement$1;
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-01-20T04:51:21",
2
+ "timestamp": "2026-01-21T08:07:19",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.27.2",
@@ -50500,6 +50500,26 @@
50500
50500
  "docs": "Event emitted when a message is deleted",
50501
50501
  "docsTags": []
50502
50502
  },
50503
+ {
50504
+ "event": "editMessage",
50505
+ "detail": "CustomMessage | FileMessage | ImageMessage | TextMessage",
50506
+ "bubbles": true,
50507
+ "complexType": {
50508
+ "original": "Message",
50509
+ "resolved": "CustomMessage | FileMessage | ImageMessage | TextMessage",
50510
+ "references": {
50511
+ "Message": {
50512
+ "location": "import",
50513
+ "path": "@cloudflare/realtimekit",
50514
+ "id": "node_modules::Message"
50515
+ }
50516
+ }
50517
+ },
50518
+ "cancelable": true,
50519
+ "composed": true,
50520
+ "docs": "Event emitted when a message is edited",
50521
+ "docsTags": []
50522
+ },
50503
50523
  {
50504
50524
  "event": "editMessageInit",
50505
50525
  "detail": "{ payload: TextMessage; flags: { isReply?: boolean; isEdit?: boolean; }; }",
@@ -151082,15 +151102,15 @@
151082
151102
  "docs": ""
151083
151103
  },
151084
151104
  "complexType": {
151085
- "signature": "(_id: string, _node: DataNode) => Promise<void>",
151105
+ "signature": "(id: string, node: DataNode) => Promise<void>",
151086
151106
  "parameters": [
151087
151107
  {
151088
- "name": "_id",
151108
+ "name": "id",
151089
151109
  "type": "string",
151090
151110
  "docs": "- The id of the node to update"
151091
151111
  },
151092
151112
  {
151093
- "name": "_node",
151113
+ "name": "node",
151094
151114
  "type": "DataNode",
151095
151115
  "docs": "- The updated data node"
151096
151116
  }
@@ -151108,15 +151128,15 @@
151108
151128
  },
151109
151129
  "return": "Promise<void>"
151110
151130
  },
151111
- "signature": "onNodeUpdate(_id: string, _node: DataNode) => Promise<void>",
151131
+ "signature": "onNodeUpdate(id: string, node: DataNode) => Promise<void>",
151112
151132
  "parameters": [
151113
151133
  {
151114
- "name": "_id",
151134
+ "name": "id",
151115
151135
  "type": "string",
151116
151136
  "docs": "- The id of the node to update"
151117
151137
  },
151118
151138
  {
151119
- "name": "_node",
151139
+ "name": "node",
151120
151140
  "type": "DataNode",
151121
151141
  "docs": "- The updated data node"
151122
151142
  }
@@ -151125,11 +151145,11 @@
151125
151145
  "docsTags": [
151126
151146
  {
151127
151147
  "name": "param",
151128
- "text": "_id - The id of the node to update"
151148
+ "text": "id - The id of the node to update"
151129
151149
  },
151130
151150
  {
151131
151151
  "name": "param",
151132
- "text": "_node - The updated data node"
151152
+ "text": "node - The updated data node"
151133
151153
  }
151134
151154
  ]
151135
151155
  }