Skip to content

Commit 6d6b903

Browse files
committedMar 14, 2025··
More examples converted
1 parent bb0402e commit 6d6b903

18 files changed

+203
-54
lines changed
 

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/context.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ The example below has a header component that accesses the `loading` flag from t
1818

1919
```tsx live
2020
import { VirtuosoMessageList, VirtuosoMessageListProps, VirtuosoMessageListLicense } from '@virtuoso.dev/message-list'
21-
import React, { useState } from 'react'
21+
import { useState } from 'react'
2222

2323
interface MessageListContext {
2424
loading: boolean

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/01-messaging.md

+119-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The example below is a simplified version of the final result of the tutorial -
2222
```tsx live
2323
import * as React from 'react'
2424
import { VirtuosoMessageList, VirtuosoMessageListProps, VirtuosoMessageListMethods, ListScrollLocation, VirtuosoMessageListLicense } from '@virtuoso.dev/message-list'
25-
import { ChatChannel, ChatMessage } from './ChatChannel'
25+
import { rand, randFullName, randSentence, randPhrase, randNumber } from "@ngneat/falso";
2626

2727
interface MessageListContext {
2828
loadingNewer: boolean
@@ -131,7 +131,7 @@ export default function App() {
131131
)
132132

133133
return (
134-
<div className="tall-example" style={{ height: 800, display: 'flex', flexDirection: 'column', fontSize: '70%' }}>
134+
<div className="tall-example" style={{ height: '100%', display: 'flex', flexDirection: 'column', fontSize: '70%' }}>
135135
<VirtuosoMessageListLicense licenseKey="">
136136
<VirtuosoMessageList<ChatMessage, MessageListContext>
137137
key={channel.name}
@@ -181,5 +181,122 @@ export default function App() {
181181
</div>
182182
)
183183
}
184+
185+
type GetMessageParams = { limit?: number } | { before: number; limit?: number };
186+
187+
export class ChatChannel {
188+
public users: ChatUser[];
189+
private localIdCounter = 0;
190+
public messages: ChatMessage[] = [];
191+
192+
public onNewMessages = (messages: ChatMessage[]) => {
193+
void messages;
194+
};
195+
public currentUser: ChatUser;
196+
private otherUser: ChatUser;
197+
private loading = false;
198+
public loaded = false;
199+
200+
constructor(
201+
public name: string,
202+
private totalMessages: number,
203+
) {
204+
this.users = Array.from({ length: 2 }, (_, i) => new ChatUser(i));
205+
this.currentUser = this.users[0];
206+
this.otherUser = this.users[1];
207+
if (this.totalMessages === 0) {
208+
this.loaded = true;
209+
}
210+
}
211+
212+
async getMessages(params: GetMessageParams) {
213+
if (this.loading) {
214+
return null;
215+
}
216+
217+
this.loading = true;
218+
219+
await new Promise((r) => setTimeout(r, 1000));
220+
const { limit = 10 } = params;
221+
this.loading = false;
222+
223+
if (!this.loaded) {
224+
this.loaded = true;
225+
}
226+
227+
if (this.messages.length >= this.totalMessages) {
228+
return [];
229+
}
230+
231+
// prepending messages, simplified for the sake of the example
232+
if ("before" in params) {
233+
if (this.messages.length >= this.totalMessages) {
234+
return [];
235+
}
236+
237+
const offset = this.totalMessages - this.messages.length - limit;
238+
239+
const newMessages = Array.from({ length: limit }, (_, i) => {
240+
const id = offset + i;
241+
return new ChatMessage(id, rand(this.users));
242+
});
243+
this.messages = newMessages.concat(this.messages);
244+
return newMessages;
245+
} else {
246+
// initial load
247+
this.messages = Array.from({ length: limit }, (_, i) => {
248+
const id = this.totalMessages - limit + i;
249+
return new ChatMessage(id, rand(this.users));
250+
});
251+
return this.messages;
252+
}
253+
}
254+
255+
createNewMessageFromAnotherUser() {
256+
const newMessage = new ChatMessage(this.messages.length, this.otherUser);
257+
this.messages.push(newMessage);
258+
this.onNewMessages([newMessage]);
259+
}
260+
261+
sendOwnMessage() {
262+
const tempMessage = new ChatMessage(null, this.currentUser);
263+
tempMessage.localId = ++this.localIdCounter;
264+
tempMessage.delivered = false;
265+
266+
setTimeout(() => {
267+
const deliveredMessage = new ChatMessage(
268+
this.messages.length,
269+
this.currentUser,
270+
tempMessage.message,
271+
);
272+
deliveredMessage.localId = tempMessage.localId;
273+
this.messages.push(deliveredMessage);
274+
this.onNewMessages([deliveredMessage]);
275+
}, 1000);
276+
277+
return tempMessage;
278+
}
279+
}
280+
281+
export class ChatUser {
282+
constructor(
283+
public id: number | null,
284+
public name = randFullName(),
285+
public avatar = `https://i.pravatar.cc/30?u=${encodeURIComponent(name)}`,
286+
) {}
287+
}
288+
289+
// a ChatMessage class with a random message
290+
export class ChatMessage {
291+
public delivered = true;
292+
public localId: number | null = null;
293+
constructor(
294+
public id: number | null,
295+
public user: ChatUser,
296+
public message = randSentence({
297+
length: randNumber({ min: 1, max: 5 }),
298+
}).join(" "),
299+
) {}
300+
}
184301

185302
```

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/02-ai-chatbot.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The example below simulates a conversation with a chatbot. Shortly after the que
2222
```tsx live
2323
import * as React from 'react'
2424
import { VirtuosoMessageList, VirtuosoMessageListProps, VirtuosoMessageListMethods, VirtuosoMessageListLicense } from '@virtuoso.dev/message-list'
25-
import { randTextRange, randPhrase } from './helpers'
25+
import { randTextRange, randPhrase } from '@ngneat/falso'
2626

2727
interface Message {
2828
key: string

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/03-gemini.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
VirtuosoMessageListMethods,
2727
VirtuosoMessageListProps,
2828
} from "@virtuoso.dev/message-list";
29-
import { randTextRange, randPhrase } from './helpers';
29+
import { randTextRange, randPhrase } from '@ngneat/falso';
3030

3131
interface Message {
3232
key: string;

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/04-reactions.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ The approach above is not exclusive to reactions - the same principle should be
1717
```tsx live
1818
import { VirtuosoMessageList, VirtuosoMessageListLicense, useVirtuosoMethods, VirtuosoMessageListProps, VirtuosoMessageListMethods } from '@virtuoso.dev/message-list'
1919
import * as React from 'react'
20-
import { randTextRange, rand } from './helpers'
20+
import { randTextRange, rand } from '@ngneat/falso'
2121

2222
interface Message {
2323
key: string
@@ -81,18 +81,16 @@ export default function App() {
8181
const virtuoso = React.useRef<VirtuosoMessageListMethods<Message>>(null)
8282

8383
return (
84-
<div class="tall-example" style={{fontSize: '70%'}}>
8584
<VirtuosoMessageListLicense licenseKey="">
8685
<VirtuosoMessageList<Message, null>
8786
ref={virtuoso}
8887
initialData={messages}
89-
style={{ height: 800 }}
88+
style={{ height: '100%' }}
9089
computeItemKey={({ data }) => data.key}
9190
initialLocation={{ index: 'LAST', align: 'end' }}
9291
ItemContent={ItemContent}
9392
/>
9493
</VirtuosoMessageListLicense>
95-
</div>
9694
)
9795
}
9896

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/05-date-separators.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ The example below demonstrates how to implement date separators in a message lis
2121
```tsx live
2222
import * as React from 'react'
2323
import { VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListProps, useCurrentlyRenderedData } from '@virtuoso.dev/message-list'
24-
import { randTextRange, rand } from './helpers'
24+
import { randTextRange, rand } from '@ngneat/falso'
2525

2626
interface Message {
2727
key: string

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/06-scroll-to-reply.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This example showcases a chat with a message that replies to another message. Cl
1515
```tsx live
1616
import * as React from 'react'
1717
import { VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListProps, VirtuosoMessageListMethods, useVirtuosoMethods } from '@virtuoso.dev/message-list'
18-
import { randPhrase } from './helpers'
18+
import { randPhrase } from '@ngneat/falso'
1919

2020
interface Message {
2121
key: string

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/examples/07-grouped-messages.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ You can use similar approach to render the users' avatars only once per group, o
1515
```tsx live
1616
import * as React from 'react'
1717
import { VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListProps, VirtuosoMessageListMethods } from '@virtuoso.dev/message-list'
18-
import { randTextRange } from './helpers'
18+
import { randTextRange } from '@ngneat/falso'
1919

2020
interface Message {
2121
key: string

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/headers-footers.md

+8
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ If you need to access certain changing values inside the custom components, use
2020
The example below features a basic list with Header and Footer specified.
2121

2222
```tsx live
23+
import { VirtuosoMessageListProps, VirtuosoMessageList, useVirtuosoMethods, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
24+
2325
const Header: VirtuosoMessageListProps<number, null>['Header'] = () => <div style={{ height: 30, background: 'lightblue' }}>Header</div>
2426
const Footer: VirtuosoMessageListProps<number, null>['Footer'] = () => <div style={{ height: 30, background: 'lightblue' }}>Footer</div>
2527

@@ -45,6 +47,8 @@ export default function App() {
4547
Unlike the regular ones, the sticky custom components are persistently visible in the viewport, making them suitable for displaying custom UI (like pinned messages, for example). Their size is getting measured, so that the first/last messages are not obscured by them.
4648

4749
```tsx live
50+
import { VirtuosoMessageListProps, VirtuosoMessageList, useVirtuosoMethods, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
51+
4852
const StickyHeader: VirtuosoMessageListProps<number, null>['StickyHeader'] = () => <div style={{ height: 30, background: 'lightblue' }}>Header</div>
4953
const StickyFooter: VirtuosoMessageListProps<number, null>['StickyFooter'] = () => <div style={{ height: 30, background: 'lightblue' }}>Footer</div>
5054

@@ -70,6 +74,8 @@ export default function App() {
7074
By default, the sticky header and footer will offset the list content. In some cases, we would like to avoid that - for example, the scroll to bottom button should not leave space below the messages. To achieve that, we can wrap the content with a `position: absolute` container.
7175

7276
```tsx live
77+
import { VirtuosoMessageListProps, VirtuosoMessageList, useVirtuosoMethods, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
78+
7379
const StickyHeader: VirtuosoMessageListProps<number, null>['StickyHeader'] = () => {
7480
return (
7581
<div style={{ position: 'absolute', right: 0, top: 0, background: 'lightblue' }}>Header</div>
@@ -104,6 +110,8 @@ export default function App() {
104110
If needed, you can combine sticky and regular components. The sticky ones will be always visible, while the regular ones will scroll with the content.
105111

106112
```tsx live
113+
import { VirtuosoMessageListProps, VirtuosoMessageList, useVirtuosoMethods, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
114+
107115
const StickyHeader: VirtuosoMessageListProps<number, null>['StickyHeader'] = () => <div style={{ height: 30, background: 'lightblue' }}>Sticky Header</div>
108116
const StickyFooter: VirtuosoMessageListProps<number, null>['StickyFooter'] = () => <div style={{ height: 30, background: 'lightblue' }}>Sticky Footer</div>
109117
const Header: VirtuosoMessageListProps<number, null>['Header'] = () => <div style={{ height: 30, background: 'lightgreen' }}>Header</div>

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/overview.md

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ Apart from the structural styling necessary for the virtualized rendering, the c
1717
## Live Example
1818

1919
```tsx live
20+
import { VirtuosoMessageListProps, VirtuosoMessageListLicense, VirtuosoMessageList } from '@virtuoso.dev/message-list'
21+
import { randTextRange } from '@ngneat/falso'
2022

2123
interface Message {
2224
key: string
@@ -123,6 +125,8 @@ npm install @virtuoso.dev/message-list
123125
Then, add the component along with your license to your application.
124126

125127
```tsx live
128+
import { VirtuosoMessageListLicense, VirtuosoMessageList } from '@virtuoso.dev/message-list'
129+
126130
// const licenseKey = 'your-license-key'
127131
const licenseKey = ''
128132

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/smooth-scrolling.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ In addition to the default `'smooth'` and `'auto'` scroll behavior values, the c
1212

1313
```tsx live
1414
import { VirtuosoMessageList, VirtuosoMessageListProps, VirtuosoMessageListMethods, VirtuosoMessageListLicense } from '@virtuoso.dev/message-list'
15-
import React from 'react'
15+
import {useRef} from 'react'
16+
import {randTextRange, randPhrase} from '@ngneat/falso'
1617

1718
/**
1819
* Bounce easing function - https://easings.net/#easeOutBounce. This is just an example, you can use any easing function.
@@ -44,7 +45,7 @@ function customSmoothScroll(currentTop: number, targetTop: number) {
4445
}
4546

4647
export default function App() {
47-
const virtuoso = React.useRef<VirtuosoMessageListMethods<Message>>(null);
48+
const virtuoso = useRef<VirtuosoMessageListMethods<Message>>(null);
4849

4950
return (
5051
<div

‎apps/virtuoso.dev/docs/guides/virtuoso-message-list/working-with-data.md

+11
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ The Message List component exposes an imperative API to interact with the list d
1515
Use this method when you need to add additional messages before the current ones, for example when loading older messages. The component will automatically adjust the scroll position to keep the previous messages in view.
1616

1717
```tsx live
18+
import { VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
19+
1820
export default function App() {
1921
const ref = React.useRef<VirtuosoMessageListMethods>(null);
2022
const offset = React.useRef(0);
@@ -66,6 +68,8 @@ The function should return:
6668
Experiment with the live example below to see how the scroll behavior changes when appending new items.
6769

6870
```tsx live
71+
import { VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
72+
6973
export default function App() {
7074
const ref = React.useRef<VirtuosoMessageListMethods>(null);
7175
const offset = React.useRef(100);
@@ -112,6 +116,8 @@ To see a `data.map` example usage, visit the [Reactions example](/virtuoso-messa
112116
The `data.findAndDelete(predicate: (item: Data) => boolean)` method lets you remove a message from the list. The predicate function receives the data item and should return a boolean value indicating whether the item should be removed. The example below adds a button next to each item that removes it.
113117

114118
```tsx live
119+
import { VirtuosoMessageList, useVirtuosoMethods, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
120+
115121
function ItemContent({ data }) {
116122
const virtuosoMethods = useVirtuosoMethods();
117123
return (
@@ -146,6 +152,9 @@ export default function App() {
146152
You can remove multiple items at once with the `data.deleteRange` method.
147153

148154
```tsx live
155+
import { VirtuosoMessageList, useVirtuosoMethods, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
156+
import {useRef} from 'react'
157+
149158
function ItemContent({ data }) {
150159
const virtuosoMethods = useVirtuosoMethods();
151160
return <div>Item {data}</div>;
@@ -179,6 +188,8 @@ In case you're building a chat application with multiple channels, you might wan
179188
The method accepts `data` and, optionally, an `options: { initalLocation: ItemLocation, purgeItemSizes?: boolean }` to specify the initial scroll position and weather to clear the cached item sizes. Purging the item sizes is useful when the new data has different item sizes than the previous data.
180189

181190
```tsx live
191+
import { VirtuosoMessageList, VirtuosoMessageListLicense, VirtuosoMessageListMethods} from '@virtuoso.dev/message-list'
192+
182193
export default function App() {
183194
const ref = React.useRef<VirtuosoMessageListMethods>(null);
184195

‎apps/virtuoso.dev/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
"@radix-ui/react-icons": "^1.3.2",
3434
"@radix-ui/themes": "^3.2.0",
3535
"@tanstack/react-table": "^8.15.0",
36-
"@virtuoso.dev/message-list": "^1.9.6",
36+
"@virtuoso.dev/message-list": "^1.9.15",
3737
"clsx": "^2.0.0",
3838
"css-loader": "^7.1.2",
3939
"docusaurus-plugin-typedoc": "^1.2.3",

‎apps/virtuoso.dev/src/theme/CodeBlock/LiveCodeBlock/esmTransform.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export async function transformToFunctionBody(code: string) {
1111
esBuildInitializePromise = new Promise<void>((resolve, reject) => {
1212
esbuild
1313
.initialize({
14-
wasmURL: 'https://unpkg.com/esbuild-wasm/esbuild.wasm',
14+
wasmURL: 'https://unpkg.com/esbuild-wasm@0.25.0/esbuild.wasm',
1515
})
1616
.then(() => resolve())
1717
.catch(() => reject())

0 commit comments

Comments
 (0)
Please sign in to comment.