chat-layout 1.1.0-2 → 1.1.0-4
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/example/chat.ts +166 -29
- package/index.d.mts +50 -12
- package/index.mjs +548 -35
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/example/chat.ts
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
type Context,
|
|
14
14
|
type DynValue,
|
|
15
15
|
type HitTest,
|
|
16
|
+
type InlineSpan,
|
|
16
17
|
type Node,
|
|
17
18
|
type RenderFeedback,
|
|
18
19
|
} from "chat-layout";
|
|
@@ -131,18 +132,66 @@ if (context == null) {
|
|
|
131
132
|
const ctx: C = context;
|
|
132
133
|
ctx.scale(devicePixelRatio, devicePixelRatio);
|
|
133
134
|
|
|
134
|
-
type
|
|
135
|
+
type ReplyPreview = {
|
|
136
|
+
sender: string;
|
|
137
|
+
content: string | InlineSpan<C>[];
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
type BaseChatItem = {
|
|
141
|
+
id: number;
|
|
135
142
|
sender: string;
|
|
136
|
-
content: string;
|
|
137
|
-
reply?: {
|
|
138
|
-
sender: string;
|
|
139
|
-
content: string;
|
|
140
|
-
};
|
|
141
143
|
};
|
|
142
144
|
|
|
145
|
+
type MessageItem = BaseChatItem & {
|
|
146
|
+
kind: "message";
|
|
147
|
+
content: string | InlineSpan<C>[];
|
|
148
|
+
reply?: ReplyPreview;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
type RevokedItem = BaseChatItem & {
|
|
152
|
+
kind: "revoked";
|
|
153
|
+
original: MessageItem;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
type ChatItem = MessageItem | RevokedItem;
|
|
157
|
+
|
|
158
|
+
const richTextMessage: InlineSpan<C>[] = [
|
|
159
|
+
{ text: "现在这个 chat example 可以直接展示 " },
|
|
160
|
+
{ text: "rich text", font: "700 16px system-ui", style: "#0f766e" },
|
|
161
|
+
{ text: " 了,支持 " },
|
|
162
|
+
{ text: "颜色", style: "#2563eb" },
|
|
163
|
+
{ text: "、" },
|
|
164
|
+
{ text: "粗体", font: "700 16px system-ui", style: "#b91c1c" },
|
|
165
|
+
{ text: ",以及 " },
|
|
166
|
+
{ text: "inline code", font: "15px ui-monospace, SFMono-Regular, Consolas, monospace", style: "#7c3aed" },
|
|
167
|
+
{ text: " 这样的片段混排。" },
|
|
168
|
+
];
|
|
169
|
+
|
|
170
|
+
const richReplyPreview: InlineSpan<C>[] = [
|
|
171
|
+
{ text: "回复预览里也能用 " },
|
|
172
|
+
{ text: "rich text", font: "700 13px system-ui", style: "#0f766e" },
|
|
173
|
+
{ text: ",比如 " },
|
|
174
|
+
{ text: "关键词高亮", style: "#2563eb" },
|
|
175
|
+
{ text: " 和 " },
|
|
176
|
+
{ text: "code()", font: "12px ui-monospace, SFMono-Regular, Consolas, monospace", style: "#7c3aed" },
|
|
177
|
+
{
|
|
178
|
+
text: ",超长内容仍然会按原来的两行省略规则收起,不需要额外处理。",
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
|
|
143
182
|
let currentHover: ChatItem | undefined;
|
|
183
|
+
const REPLACE_ANIMATION_DURATION = 320;
|
|
184
|
+
|
|
185
|
+
function revokeMessage(item: MessageItem): RevokedItem {
|
|
186
|
+
return {
|
|
187
|
+
id: item.id,
|
|
188
|
+
sender: item.sender,
|
|
189
|
+
kind: "revoked",
|
|
190
|
+
original: item,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
144
193
|
|
|
145
|
-
class
|
|
194
|
+
class ItemDetector extends Wrapper<C> {
|
|
146
195
|
constructor(
|
|
147
196
|
inner: Node<C>,
|
|
148
197
|
readonly item: ChatItem,
|
|
@@ -150,21 +199,65 @@ class HoverDetector extends Wrapper<C> {
|
|
|
150
199
|
super(inner);
|
|
151
200
|
}
|
|
152
201
|
|
|
153
|
-
hittest(_ctx: Context<C>,
|
|
202
|
+
hittest(_ctx: Context<C>, test: HitTest): boolean {
|
|
154
203
|
currentHover = this.item;
|
|
204
|
+
if (test.type === "click") {
|
|
205
|
+
const index = list.items.indexOf(this.item);
|
|
206
|
+
if (index < 0) {
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
const nextItem = this.item.kind === "revoked" ? this.item.original : revokeMessage(this.item);
|
|
210
|
+
currentHover = nextItem;
|
|
211
|
+
list.replace(index, nextItem, {
|
|
212
|
+
duration: REPLACE_ANIMATION_DURATION,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
155
215
|
return true;
|
|
156
216
|
}
|
|
157
217
|
}
|
|
158
218
|
|
|
159
219
|
const renderItem = memoRenderItem((item: ChatItem): Node<C> => {
|
|
220
|
+
if (item.kind === "revoked") {
|
|
221
|
+
return new ItemDetector(
|
|
222
|
+
new Place(
|
|
223
|
+
new PaddingBox(
|
|
224
|
+
new RoundedBox(
|
|
225
|
+
new Text(`${item.sender}已撤回一条消息`, {
|
|
226
|
+
lineHeight: 18,
|
|
227
|
+
font: "14px system-ui",
|
|
228
|
+
style: () => (currentHover?.id === item.id ? "#525252" : "#666"),
|
|
229
|
+
overflow: "ellipsis",
|
|
230
|
+
}),
|
|
231
|
+
{
|
|
232
|
+
top: 10,
|
|
233
|
+
bottom: 10,
|
|
234
|
+
left: 12,
|
|
235
|
+
right: 12,
|
|
236
|
+
radii: 999,
|
|
237
|
+
fill: () => (currentHover?.id === item.id ? "#d9d9d9" : "#ececec"),
|
|
238
|
+
stroke: () => (currentHover?.id === item.id ? "#bcbcbc" : "#d3d3d3"),
|
|
239
|
+
},
|
|
240
|
+
),
|
|
241
|
+
{
|
|
242
|
+
top: 8,
|
|
243
|
+
bottom: 8,
|
|
244
|
+
left: 4,
|
|
245
|
+
right: 4,
|
|
246
|
+
},
|
|
247
|
+
),
|
|
248
|
+
{
|
|
249
|
+
align: item.sender === "A" ? "end" : "start",
|
|
250
|
+
},
|
|
251
|
+
),
|
|
252
|
+
item,
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
160
256
|
const senderLine = new Flex<C>(
|
|
161
257
|
[
|
|
162
|
-
new
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}),
|
|
166
|
-
item,
|
|
167
|
-
),
|
|
258
|
+
new Circle(15, {
|
|
259
|
+
fill: "blue",
|
|
260
|
+
}),
|
|
168
261
|
new RoundedBox(
|
|
169
262
|
new Text(item.sender, {
|
|
170
263
|
lineHeight: 15,
|
|
@@ -177,7 +270,7 @@ const renderItem = memoRenderItem((item: ChatItem): Node<C> => {
|
|
|
177
270
|
left: 0,
|
|
178
271
|
right: 0,
|
|
179
272
|
radii: 2,
|
|
180
|
-
fill: () => (currentHover === item ? "red" : "transparent"),
|
|
273
|
+
fill: () => (currentHover?.id === item.id ? "red" : "transparent"),
|
|
181
274
|
},
|
|
182
275
|
),
|
|
183
276
|
],
|
|
@@ -209,12 +302,12 @@ const renderItem = memoRenderItem((item: ChatItem): Node<C> => {
|
|
|
209
302
|
new Text(item.reply.sender, {
|
|
210
303
|
lineHeight: 14,
|
|
211
304
|
font: "11px system-ui",
|
|
212
|
-
style: () => (currentHover === item ? "#4d4d4d" : "#666"),
|
|
305
|
+
style: () => (currentHover?.id === item.id ? "#4d4d4d" : "#666"),
|
|
213
306
|
}),
|
|
214
307
|
new MultilineText(item.reply.content, {
|
|
215
308
|
lineHeight: 16,
|
|
216
309
|
font: "13px system-ui",
|
|
217
|
-
style: () => (currentHover === item ? "#222" : "#444"),
|
|
310
|
+
style: () => (currentHover?.id === item.id ? "#222" : "#444"),
|
|
218
311
|
align: "start",
|
|
219
312
|
overflow: "ellipsis",
|
|
220
313
|
overflowWrap: "anywhere",
|
|
@@ -233,7 +326,7 @@ const renderItem = memoRenderItem((item: ChatItem): Node<C> => {
|
|
|
233
326
|
left: 8,
|
|
234
327
|
right: 8,
|
|
235
328
|
radii: 6,
|
|
236
|
-
fill: () => (currentHover === item ? "#c2c2c2" : "#e2e2e2"),
|
|
329
|
+
fill: () => (currentHover?.id === item.id ? "#c2c2c2" : "#e2e2e2"),
|
|
237
330
|
},
|
|
238
331
|
),
|
|
239
332
|
{ alignSelf: "stretch" },
|
|
@@ -255,7 +348,7 @@ const renderItem = memoRenderItem((item: ChatItem): Node<C> => {
|
|
|
255
348
|
left: 10,
|
|
256
349
|
right: 10,
|
|
257
350
|
radii: 8,
|
|
258
|
-
fill: () => (currentHover === item ? "#aaa" : "#ccc"),
|
|
351
|
+
fill: () => (currentHover?.id === item.id ? "#aaa" : "#ccc"),
|
|
259
352
|
});
|
|
260
353
|
|
|
261
354
|
const body = new Flex<C>([senderLine, content], {
|
|
@@ -289,34 +382,45 @@ const renderItem = memoRenderItem((item: ChatItem): Node<C> => {
|
|
|
289
382
|
right: 4,
|
|
290
383
|
});
|
|
291
384
|
|
|
292
|
-
return new
|
|
293
|
-
|
|
294
|
-
|
|
385
|
+
return new ItemDetector(
|
|
386
|
+
new Place(padded, {
|
|
387
|
+
align: item.sender === "A" ? "end" : "start",
|
|
388
|
+
}),
|
|
389
|
+
item,
|
|
390
|
+
);
|
|
295
391
|
});
|
|
296
392
|
|
|
297
393
|
const list = new ListState<ChatItem>([
|
|
298
394
|
{
|
|
395
|
+
id: 1,
|
|
396
|
+
kind: "message",
|
|
299
397
|
sender: "A",
|
|
300
398
|
content:
|
|
301
399
|
"hello world chat layout message render bubble timeline virtualized canvas",
|
|
302
400
|
},
|
|
303
401
|
{
|
|
402
|
+
id: 2,
|
|
403
|
+
kind: "message",
|
|
304
404
|
sender: "B",
|
|
305
|
-
content:
|
|
405
|
+
content: richTextMessage,
|
|
306
406
|
reply: {
|
|
307
407
|
sender: "A",
|
|
308
408
|
content: "hello world chat layout message render",
|
|
309
409
|
},
|
|
310
410
|
},
|
|
311
|
-
{ sender: "B", content: "aaaabbb" },
|
|
312
|
-
{ sender: "B", content: "测试中文" },
|
|
411
|
+
{ id: 3, kind: "message", sender: "B", content: "aaaabbb" },
|
|
412
|
+
{ id: 4, kind: "message", sender: "B", content: "测试中文" },
|
|
313
413
|
{
|
|
414
|
+
id: 5,
|
|
415
|
+
kind: "message",
|
|
314
416
|
sender: "A",
|
|
315
417
|
content:
|
|
316
418
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
317
419
|
},
|
|
318
|
-
{ sender: "B", content: "测试aa中文aaa" },
|
|
420
|
+
{ id: 6, kind: "message", sender: "B", content: "测试aa中文aaa" },
|
|
319
421
|
{
|
|
422
|
+
id: 7,
|
|
423
|
+
kind: "message",
|
|
320
424
|
sender: "A",
|
|
321
425
|
content: randomText(8),
|
|
322
426
|
reply: {
|
|
@@ -326,20 +430,22 @@ const list = new ListState<ChatItem>([
|
|
|
326
430
|
},
|
|
327
431
|
},
|
|
328
432
|
{
|
|
433
|
+
id: 8,
|
|
434
|
+
kind: "message",
|
|
329
435
|
sender: "B",
|
|
330
436
|
content: "这里是一条会展示回复预览省略效果的消息。",
|
|
331
437
|
reply: {
|
|
332
438
|
sender: "A",
|
|
333
|
-
content:
|
|
334
|
-
"这是一条非常长的回复预览,用来演示 MultilineText 在 chat example 里的末尾 ellipsis 能力。它应该被限制在两行之内,而不是把整个气泡一路撑到天花板。",
|
|
439
|
+
content: richReplyPreview,
|
|
335
440
|
},
|
|
336
441
|
},
|
|
337
|
-
{ sender: "B", content: randomText(5) },
|
|
442
|
+
{ id: 9, kind: "message", sender: "B", content: randomText(5) },
|
|
338
443
|
]);
|
|
339
444
|
const renderer = new ChatRenderer(ctx, {
|
|
340
445
|
renderItem,
|
|
341
446
|
list,
|
|
342
447
|
});
|
|
448
|
+
let nextMessageId = list.items.length + 1;
|
|
343
449
|
|
|
344
450
|
function drawFrame(): void {
|
|
345
451
|
const feedback: RenderFeedback = {
|
|
@@ -383,6 +489,22 @@ canvas.addEventListener("pointermove", (e) => {
|
|
|
383
489
|
}
|
|
384
490
|
});
|
|
385
491
|
|
|
492
|
+
canvas.addEventListener("pointerleave", () => {
|
|
493
|
+
currentHover = undefined;
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
canvas.addEventListener("click", (e) => {
|
|
497
|
+
const { top, left } = canvas.getBoundingClientRect();
|
|
498
|
+
const result = renderer.hittest({
|
|
499
|
+
x: e.clientX - left,
|
|
500
|
+
y: e.clientY - top,
|
|
501
|
+
type: "click",
|
|
502
|
+
});
|
|
503
|
+
if (!result) {
|
|
504
|
+
currentHover = undefined;
|
|
505
|
+
}
|
|
506
|
+
});
|
|
507
|
+
|
|
386
508
|
function randomText(words: number): string {
|
|
387
509
|
const out: string[] = [];
|
|
388
510
|
for (let i = 0; i < words; i += 1) {
|
|
@@ -393,6 +515,8 @@ function randomText(words: number): string {
|
|
|
393
515
|
|
|
394
516
|
button("unshift", () => {
|
|
395
517
|
list.unshift({
|
|
518
|
+
id: nextMessageId++,
|
|
519
|
+
kind: "message",
|
|
396
520
|
sender: Math.random() < 0.5 ? "A" : "B",
|
|
397
521
|
content: randomText(10 + Math.floor(200 * Math.random())),
|
|
398
522
|
});
|
|
@@ -400,6 +524,8 @@ button("unshift", () => {
|
|
|
400
524
|
|
|
401
525
|
button("push", () => {
|
|
402
526
|
list.push({
|
|
527
|
+
id: nextMessageId++,
|
|
528
|
+
kind: "message",
|
|
403
529
|
sender: Math.random() < 0.5 ? "A" : "B",
|
|
404
530
|
content: randomText(10 + Math.floor(200 * Math.random())),
|
|
405
531
|
});
|
|
@@ -420,3 +546,14 @@ button("jump latest (no anim)", () => {
|
|
|
420
546
|
animated: false,
|
|
421
547
|
});
|
|
422
548
|
});
|
|
549
|
+
|
|
550
|
+
button("revoke first", () => {
|
|
551
|
+
const item = list.items.find((entry): entry is MessageItem => entry.kind === "message");
|
|
552
|
+
if (item == null) {
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
const index = list.items.indexOf(item);
|
|
556
|
+
list.replace(index, revokeMessage(item), {
|
|
557
|
+
duration: REPLACE_ANIMATION_DURATION,
|
|
558
|
+
});
|
|
559
|
+
});
|
package/index.d.mts
CHANGED
|
@@ -81,6 +81,21 @@ interface TextStyleOptions<C extends CanvasRenderingContext2D> {
|
|
|
81
81
|
/** Default: break-word; use anywhere when min-content should honor grapheme break opportunities. */
|
|
82
82
|
overflowWrap?: TextOverflowWrapMode;
|
|
83
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* A span-like inline text fragment used by rich multi-line text.
|
|
86
|
+
*/
|
|
87
|
+
interface InlineSpan<C extends CanvasRenderingContext2D> {
|
|
88
|
+
/** Source text contained in this inline fragment. */
|
|
89
|
+
text: string;
|
|
90
|
+
/** Canvas font string override for this fragment. Falls back to the node-level font. */
|
|
91
|
+
font?: string;
|
|
92
|
+
/** Fill style override for this fragment. Falls back to the node-level style. */
|
|
93
|
+
style?: DynValue<C, string>;
|
|
94
|
+
/** Optional break hint forwarded to pretext rich-inline layout. */
|
|
95
|
+
break?: "normal" | "never";
|
|
96
|
+
/** Optional extra occupied width forwarded to pretext rich-inline layout. */
|
|
97
|
+
extraWidth?: number;
|
|
98
|
+
}
|
|
84
99
|
/**
|
|
85
100
|
* Options for multi-line text nodes.
|
|
86
101
|
*/
|
|
@@ -352,15 +367,16 @@ declare class Place<C extends CanvasRenderingContext2D> extends Wrapper<C> {
|
|
|
352
367
|
//#region src/nodes/text.d.ts
|
|
353
368
|
/**
|
|
354
369
|
* Draws wrapped text using the configured line height and alignment.
|
|
370
|
+
* Accepts either a plain string or an array of `InlineSpan` items for mixed inline styles.
|
|
355
371
|
*/
|
|
356
372
|
declare class MultilineText<C extends CanvasRenderingContext2D> implements Node<C> {
|
|
357
|
-
readonly text: string;
|
|
373
|
+
readonly text: string | InlineSpan<C>[];
|
|
358
374
|
readonly options: MultilineTextOptions<C>;
|
|
359
375
|
/**
|
|
360
|
-
* @param text Source text to measure and draw.
|
|
376
|
+
* @param text Source text to measure and draw. Pass an `InlineSpan[]` for mixed inline styles.
|
|
361
377
|
* @param options Text layout and drawing options.
|
|
362
378
|
*/
|
|
363
|
-
constructor(text: string, options: MultilineTextOptions<C>);
|
|
379
|
+
constructor(text: string | InlineSpan<C>[], options: MultilineTextOptions<C>);
|
|
364
380
|
measure(ctx: Context<C>): Box;
|
|
365
381
|
measureMinContent(ctx: Context<C>): Box;
|
|
366
382
|
draw(ctx: Context<C>, x: number, y: number): boolean;
|
|
@@ -448,13 +464,20 @@ declare class DebugRenderer<C extends CanvasRenderingContext2D> extends BaseRend
|
|
|
448
464
|
/**
|
|
449
465
|
* Mutable list state shared with virtualized renderers.
|
|
450
466
|
*/
|
|
467
|
+
interface ReplaceListItemAnimationOptions {
|
|
468
|
+
/** Animation duration in milliseconds. */
|
|
469
|
+
duration?: number;
|
|
470
|
+
}
|
|
451
471
|
declare class ListState<T extends {}> {
|
|
472
|
+
#private;
|
|
452
473
|
/** Pixel offset from the anchored item edge. */
|
|
453
474
|
offset: number;
|
|
454
475
|
/** Anchor item index, or `undefined` to use the renderer default. */
|
|
455
476
|
position: number | undefined;
|
|
456
477
|
/** Items currently managed by the renderer. */
|
|
457
|
-
items: T[];
|
|
478
|
+
get items(): T[];
|
|
479
|
+
/** Replaces the full item collection while preserving scroll state. */
|
|
480
|
+
set items(value: T[]);
|
|
458
481
|
/**
|
|
459
482
|
* @param items Initial list items.
|
|
460
483
|
*/
|
|
@@ -467,6 +490,10 @@ declare class ListState<T extends {}> {
|
|
|
467
490
|
push(...items: T[]): void;
|
|
468
491
|
/** Appends an array of items. */
|
|
469
492
|
pushAll(items: T[]): void;
|
|
493
|
+
/**
|
|
494
|
+
* Replaces an existing item by index.
|
|
495
|
+
*/
|
|
496
|
+
replace(index: number, item: T, animation?: ReplaceListItemAnimationOptions): void;
|
|
470
497
|
/**
|
|
471
498
|
* Sets the current anchor item and pixel offset.
|
|
472
499
|
*/
|
|
@@ -530,6 +557,10 @@ interface JumpToOptions {
|
|
|
530
557
|
/** Called after the jump completes or finishes animating. */
|
|
531
558
|
onComplete?: () => void;
|
|
532
559
|
}
|
|
560
|
+
type VirtualizedResolvedItem<C extends CanvasRenderingContext2D> = {
|
|
561
|
+
draw: (y: number) => boolean;
|
|
562
|
+
hittest: (test: HitTest, y: number) => boolean;
|
|
563
|
+
};
|
|
533
564
|
/**
|
|
534
565
|
* Shared base class for virtualized list renderers.
|
|
535
566
|
*/
|
|
@@ -541,6 +572,10 @@ declare abstract class VirtualizedRenderer<C extends CanvasRenderingContext2D, T
|
|
|
541
572
|
static readonly MIN_JUMP_DURATION = 160;
|
|
542
573
|
static readonly MAX_JUMP_DURATION = 420;
|
|
543
574
|
static readonly JUMP_DURATION_PER_ITEM = 28;
|
|
575
|
+
constructor(graphics: C, options: {
|
|
576
|
+
renderItem: (item: T) => Node<C>;
|
|
577
|
+
list: ListState<T>;
|
|
578
|
+
});
|
|
544
579
|
/** Current anchor item index. */
|
|
545
580
|
get position(): number | undefined;
|
|
546
581
|
/** Updates the current anchor item index. */
|
|
@@ -569,23 +604,24 @@ declare abstract class VirtualizedRenderer<C extends CanvasRenderingContext2D, T
|
|
|
569
604
|
jumpTo(index: number, options?: JumpToOptions): void;
|
|
570
605
|
protected _resetRenderFeedback(feedback?: RenderFeedback): void;
|
|
571
606
|
protected _accumulateRenderFeedback(feedback: RenderFeedback, idx: number, top: number, height: number): void;
|
|
572
|
-
protected _renderDrawList(list: VisibleWindow<
|
|
573
|
-
protected _renderVisibleWindow(window: VisibleWindow<
|
|
574
|
-
protected _hittestVisibleWindow(window: VisibleWindow<
|
|
575
|
-
x: number;
|
|
576
|
-
y: number;
|
|
577
|
-
type: "click" | "auxclick" | "hover";
|
|
578
|
-
}): boolean;
|
|
607
|
+
protected _renderDrawList(list: VisibleWindow<VirtualizedResolvedItem<C>>["drawList"], shift: number, feedback?: RenderFeedback): boolean;
|
|
608
|
+
protected _renderVisibleWindow(window: VisibleWindow<VirtualizedResolvedItem<C>>, feedback?: RenderFeedback): boolean;
|
|
609
|
+
protected _hittestVisibleWindow(window: VisibleWindow<VirtualizedResolvedItem<C>>, test: HitTest): boolean;
|
|
579
610
|
protected _prepareRender(): boolean;
|
|
580
611
|
protected _finishRender(requestRedraw: boolean): boolean;
|
|
581
612
|
protected _clampItemIndex(index: number): number;
|
|
582
613
|
protected _getItemHeight(index: number): number;
|
|
614
|
+
protected _resolveItem(item: T, index: number, now: number): {
|
|
615
|
+
value: VirtualizedResolvedItem<C>;
|
|
616
|
+
height: number;
|
|
617
|
+
};
|
|
583
618
|
protected _getAnchorAtOffset(index: number, offset: number): number;
|
|
584
619
|
protected abstract _normalizeListState(state: VisibleListState): NormalizedListState;
|
|
585
620
|
protected abstract _readAnchor(state: NormalizedListState): number;
|
|
586
621
|
protected abstract _applyAnchor(anchor: number): void;
|
|
587
622
|
protected abstract _getDefaultJumpBlock(): NonNullable<JumpToOptions["block"]>;
|
|
588
623
|
protected abstract _getTargetAnchor(index: number, block: NonNullable<JumpToOptions["block"]>): number;
|
|
624
|
+
protected abstract _getAnimatedLayerOffset(slotHeight: number, nodeHeight: number): number;
|
|
589
625
|
}
|
|
590
626
|
//#endregion
|
|
591
627
|
//#region src/renderer/virtualized/chat.d.ts
|
|
@@ -599,6 +635,7 @@ declare class ChatRenderer<C extends CanvasRenderingContext2D, T extends {}> ext
|
|
|
599
635
|
protected _readAnchor(state: NormalizedListState): number;
|
|
600
636
|
protected _applyAnchor(anchor: number): void;
|
|
601
637
|
protected _getTargetAnchor(index: number, block: NonNullable<JumpToOptions["block"]>): number;
|
|
638
|
+
protected _getAnimatedLayerOffset(slotHeight: number, nodeHeight: number): number;
|
|
602
639
|
render(feedback?: RenderFeedback): boolean;
|
|
603
640
|
hittest(test: HitTest): boolean;
|
|
604
641
|
}
|
|
@@ -614,9 +651,10 @@ declare class TimelineRenderer<C extends CanvasRenderingContext2D, T extends {}>
|
|
|
614
651
|
protected _readAnchor(state: NormalizedListState): number;
|
|
615
652
|
protected _applyAnchor(anchor: number): void;
|
|
616
653
|
protected _getTargetAnchor(index: number, block: NonNullable<JumpToOptions["block"]>): number;
|
|
654
|
+
protected _getAnimatedLayerOffset(_slotHeight: number, _nodeHeight: number): number;
|
|
617
655
|
render(feedback?: RenderFeedback): boolean;
|
|
618
656
|
hittest(test: HitTest): boolean;
|
|
619
657
|
}
|
|
620
658
|
//#endregion
|
|
621
|
-
export { Axis, BaseRenderer, Box, ChatRenderer, ChildLayoutResult, Context, CrossAxisAlignment, DebugRenderer, DynValue, Fixed, Flex, FlexContainerOptions, FlexItem, FlexItemOptions, FlexLayoutResult, Group, HitTest, JumpToOptions, LayoutConstraints, LayoutRect, ListState, MainAxisAlignment, MainAxisSize, MultilineText, MultilineTextOptions, Node, PaddingBox, PhysicalTextAlign, Place, RenderFeedback, RendererOptions, Text, TextAlign, TextEllipsisPosition, TextOptions, TextOverflowMode, TextOverflowWrapMode, TextStyleOptions, TextWhiteSpaceMode, TextWordBreakMode, TimelineRenderer, VirtualizedRenderer, Wrapper, memoRenderItem, memoRenderItemBy };
|
|
659
|
+
export { Axis, BaseRenderer, Box, ChatRenderer, ChildLayoutResult, Context, CrossAxisAlignment, DebugRenderer, DynValue, Fixed, Flex, FlexContainerOptions, FlexItem, FlexItemOptions, FlexLayoutResult, Group, HitTest, InlineSpan, JumpToOptions, LayoutConstraints, LayoutRect, ListState, MainAxisAlignment, MainAxisSize, MultilineText, MultilineTextOptions, Node, PaddingBox, PhysicalTextAlign, Place, RenderFeedback, RendererOptions, ReplaceListItemAnimationOptions, Text, TextAlign, TextEllipsisPosition, TextOptions, TextOverflowMode, TextOverflowWrapMode, TextStyleOptions, TextWhiteSpaceMode, TextWordBreakMode, TimelineRenderer, VirtualizedRenderer, Wrapper, memoRenderItem, memoRenderItemBy };
|
|
622
660
|
//# sourceMappingURL=index.d.mts.map
|