@mastra/playground-ui 40.0.0-alpha.3 → 40.0.0-alpha.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/components/CodeBlock.cjs.js +1 -1
  3. package/dist/components/CodeBlock.es.js +1 -1
  4. package/dist/components/MessageScroller.cjs.js +538 -0
  5. package/dist/components/MessageScroller.cjs.js.map +1 -0
  6. package/dist/components/MessageScroller.d.ts +2 -0
  7. package/dist/components/MessageScroller.es.js +505 -0
  8. package/dist/components/MessageScroller.es.js.map +1 -0
  9. package/dist/components/Tabs.cjs.js +1 -1
  10. package/dist/components/Tabs.es.js +1 -1
  11. package/dist/components/ThreadRail.cjs.js +432 -0
  12. package/dist/components/ThreadRail.cjs.js.map +1 -0
  13. package/dist/components/ThreadRail.d.ts +2 -0
  14. package/dist/components/ThreadRail.es.js +407 -0
  15. package/dist/components/ThreadRail.es.js.map +1 -0
  16. package/dist/components/Tree.cjs.js +2 -2
  17. package/dist/components/Tree.cjs.js.map +1 -1
  18. package/dist/components/Tree.es.js +1 -1
  19. package/dist/components/Tree.es.js.map +1 -1
  20. package/dist/domains/metrics/components/latency-card-view.cjs.js +64 -42
  21. package/dist/domains/metrics/components/latency-card-view.cjs.js.map +1 -1
  22. package/dist/domains/metrics/components/latency-card-view.es.js +65 -43
  23. package/dist/domains/metrics/components/latency-card-view.es.js.map +1 -1
  24. package/dist/domains/metrics/components/memory-card-view.cjs.js +1 -1
  25. package/dist/domains/metrics/components/memory-card-view.es.js +1 -1
  26. package/dist/domains/metrics/components/scores-card-view.cjs.js +1 -1
  27. package/dist/domains/metrics/components/scores-card-view.es.js +1 -1
  28. package/dist/domains/metrics/components/token-usage-by-agent-card-view.cjs.js +1 -1
  29. package/dist/domains/metrics/components/token-usage-by-agent-card-view.es.js +1 -1
  30. package/dist/domains/metrics/components/token-usage-timeline-card-view.cjs.js +1 -1
  31. package/dist/domains/metrics/components/token-usage-timeline-card-view.es.js +1 -1
  32. package/dist/domains/metrics/components/traces-volume-card-view.cjs.js +1 -1
  33. package/dist/domains/metrics/components/traces-volume-card-view.es.js +1 -1
  34. package/dist/domains/traces/components/span-data-panel-view.cjs.js +1 -1
  35. package/dist/domains/traces/components/span-data-panel-view.es.js +1 -1
  36. package/dist/ee/signals/components/signal-details-page.cjs.js +1 -1
  37. package/dist/ee/signals/components/signal-details-page.es.js +1 -1
  38. package/dist/hooks/use-isomorphic-layout-effect.cjs.js +29 -0
  39. package/dist/hooks/use-isomorphic-layout-effect.cjs.js.map +1 -0
  40. package/dist/hooks/use-isomorphic-layout-effect.d.ts +2 -0
  41. package/dist/hooks/use-isomorphic-layout-effect.es.js +6 -0
  42. package/dist/hooks/use-isomorphic-layout-effect.es.js.map +1 -0
  43. package/dist/hooks/use-measured-auto-height.cjs.js +75 -0
  44. package/dist/hooks/use-measured-auto-height.cjs.js.map +1 -0
  45. package/dist/hooks/use-measured-auto-height.d.ts +2 -0
  46. package/dist/hooks/use-measured-auto-height.es.js +52 -0
  47. package/dist/hooks/use-measured-auto-height.es.js.map +1 -0
  48. package/dist/message-scroller-hooks-CdsHnth6.js +62 -0
  49. package/dist/message-scroller-hooks-CdsHnth6.js.map +1 -0
  50. package/dist/message-scroller-hooks-DdXqrmC2.cjs +98 -0
  51. package/dist/message-scroller-hooks-DdXqrmC2.cjs.map +1 -0
  52. package/dist/src/ds/components/MessageScroller/index.d.ts +2 -0
  53. package/dist/src/ds/components/MessageScroller/message-scroller-context.d.ts +38 -0
  54. package/dist/src/ds/components/MessageScroller/message-scroller-hooks.d.ts +26 -0
  55. package/dist/src/ds/components/MessageScroller/message-scroller.d.ts +44 -0
  56. package/dist/src/ds/components/Tabs/tabs-tab.d.ts +2 -1
  57. package/dist/src/ds/components/ThreadRail/index.d.ts +2 -0
  58. package/dist/src/ds/components/ThreadRail/thread-rail-turns.d.ts +11 -0
  59. package/dist/src/ds/components/ThreadRail/thread-rail.d.ts +12 -0
  60. package/dist/src/hooks/use-isomorphic-layout-effect.d.ts +2 -0
  61. package/dist/src/hooks/use-measured-auto-height.d.ts +8 -0
  62. package/dist/style.css +249 -5
  63. package/dist/{tabs-tab-CaZnZdY8.js → tabs-tab-1KGOybMG.js} +27 -17
  64. package/dist/tabs-tab-1KGOybMG.js.map +1 -0
  65. package/dist/{tabs-tab-BeUPTvaP.cjs → tabs-tab-DkeS2Iv0.cjs} +27 -17
  66. package/dist/tabs-tab-DkeS2Iv0.cjs.map +1 -0
  67. package/package.json +7 -7
  68. package/dist/tabs-tab-BeUPTvaP.cjs.map +0 -1
  69. package/dist/tabs-tab-CaZnZdY8.js.map +0 -1
@@ -0,0 +1,407 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { FileText } from 'lucide-react';
3
+ import * as React from 'react';
4
+ import { k as useOptionalMessageScroller, m as useOptionalMessageScrollerVisibility } from '../message-scroller-hooks-CdsHnth6.js';
5
+ import { S as ScrollArea } from '../scroll-area-COFVK-be.js';
6
+ import { useMeasuredAutoHeight } from '../hooks/use-measured-auto-height.es.js';
7
+ import { c as cn } from '../cn-BakJzhuv.js';
8
+ import { CLIENT_MESSAGE_ID_KEY } from '@mastra/react';
9
+
10
+ const PREVIEW_TRANSITION_DURATION_MS = 360;
11
+ const PREVIEW_CLEANUP_DELAY_MS = PREVIEW_TRANSITION_DURATION_MS + 80;
12
+ const DEFAULT_PREVIEW_STATE = {
13
+ currentTurn: void 0,
14
+ previousTurn: void 0,
15
+ index: null,
16
+ phase: "hidden",
17
+ top: 0,
18
+ transitionKey: 0
19
+ };
20
+ function ThreadRail({
21
+ turns,
22
+ currentAnchorId,
23
+ visibleMessageIds,
24
+ label = "Conversation timeline",
25
+ className,
26
+ maxHeight = "calc(100dvh - 12rem)",
27
+ scrollAreaClassName,
28
+ onSelect
29
+ }) {
30
+ const railRef = React.useRef(null);
31
+ const previewId = React.useId();
32
+ const [previewState, setPreviewState] = React.useState(DEFAULT_PREVIEW_STATE);
33
+ const messageScroller = useOptionalMessageScroller();
34
+ const scrollerVisibility = useOptionalMessageScrollerVisibility();
35
+ const fallbackMessageId = turns.at(-1)?.messageId;
36
+ const activeMessageId = currentAnchorId ?? scrollerVisibility?.currentAnchorId ?? fallbackMessageId;
37
+ const resolvedVisibleMessageIds = visibleMessageIds ?? scrollerVisibility?.visibleMessageIds ?? (activeMessageId ? [activeMessageId] : []);
38
+ const visibleMessageIdSet = new Set(resolvedVisibleMessageIds);
39
+ const previewHoverActive = previewState.phase === "entering" || previewState.phase === "visible";
40
+ const hoveredIndex = previewHoverActive ? previewState.index : null;
41
+ const selectTurn = React.useCallback(
42
+ (turn) => {
43
+ if (onSelect) {
44
+ onSelect(turn);
45
+ return;
46
+ }
47
+ messageScroller?.scrollToMessage(turn.messageId, { behavior: "smooth", align: "start" });
48
+ },
49
+ [messageScroller, onSelect]
50
+ );
51
+ const showPreview = (index, element) => {
52
+ const railTop = railRef.current?.getBoundingClientRect().top ?? 0;
53
+ const itemRect = element.getBoundingClientRect();
54
+ const nextTurn = turns[index];
55
+ if (!nextTurn) return;
56
+ setPreviewState((current) => {
57
+ const nextTop = itemRect.top + itemRect.height / 2 - railTop;
58
+ if (current.index === index && current.phase !== "hidden" && current.phase !== "exiting") {
59
+ return { ...current, top: nextTop };
60
+ }
61
+ const previousTurn = current.currentTurn && current.currentTurn.key !== nextTurn.key && current.phase !== "hidden" ? current.currentTurn : void 0;
62
+ return {
63
+ currentTurn: nextTurn,
64
+ previousTurn,
65
+ index,
66
+ phase: "entering",
67
+ top: nextTop,
68
+ transitionKey: current.transitionKey + 1
69
+ };
70
+ });
71
+ };
72
+ const hidePreview = () => {
73
+ setPreviewState((current) => {
74
+ if (!current.currentTurn || current.phase === "hidden" || current.phase === "exiting") {
75
+ return { ...current, index: null };
76
+ }
77
+ return {
78
+ ...current,
79
+ index: null,
80
+ previousTurn: void 0,
81
+ phase: "exiting",
82
+ transitionKey: current.transitionKey + 1
83
+ };
84
+ });
85
+ };
86
+ React.useEffect(() => {
87
+ if (previewState.phase !== "entering") return;
88
+ const requestFrame = window.requestAnimationFrame ?? window.setTimeout;
89
+ const cancelFrame = window.cancelAnimationFrame ?? window.clearTimeout;
90
+ let settleFrame;
91
+ const startFrame = requestFrame(() => {
92
+ settleFrame = requestFrame(() => {
93
+ setPreviewState(
94
+ (current) => current.transitionKey === previewState.transitionKey && current.phase === "entering" ? { ...current, phase: "visible" } : current
95
+ );
96
+ });
97
+ });
98
+ return () => {
99
+ cancelFrame(startFrame);
100
+ if (settleFrame !== void 0) cancelFrame(settleFrame);
101
+ };
102
+ }, [previewState.phase, previewState.transitionKey]);
103
+ React.useEffect(() => {
104
+ if (previewState.phase !== "visible" || !previewState.previousTurn) return;
105
+ const timeout = window.setTimeout(() => {
106
+ setPreviewState(
107
+ (current) => current.transitionKey === previewState.transitionKey ? { ...current, previousTurn: void 0 } : current
108
+ );
109
+ }, PREVIEW_CLEANUP_DELAY_MS);
110
+ return () => window.clearTimeout(timeout);
111
+ }, [previewState.phase, previewState.previousTurn, previewState.transitionKey]);
112
+ React.useEffect(() => {
113
+ if (previewState.phase !== "exiting") return;
114
+ const timeout = window.setTimeout(() => {
115
+ setPreviewState(
116
+ (current) => current.transitionKey === previewState.transitionKey ? DEFAULT_PREVIEW_STATE : current
117
+ );
118
+ }, PREVIEW_CLEANUP_DELAY_MS);
119
+ return () => window.clearTimeout(timeout);
120
+ }, [previewState.phase, previewState.transitionKey]);
121
+ if (turns.length === 0) return null;
122
+ return /* @__PURE__ */ jsxs(
123
+ "nav",
124
+ {
125
+ ref: railRef,
126
+ "aria-label": label,
127
+ "data-testid": "thread-rail",
128
+ className: cn("relative w-8 py-2", className),
129
+ onMouseLeave: hidePreview,
130
+ onBlur: (event) => {
131
+ const nextFocus = event.relatedTarget;
132
+ if (!(nextFocus instanceof Node) || !event.currentTarget.contains(nextFocus)) hidePreview();
133
+ },
134
+ children: [
135
+ /* @__PURE__ */ jsx(
136
+ ScrollArea,
137
+ {
138
+ "data-testid": "thread-rail-scroll-area",
139
+ maxHeight,
140
+ className: cn("w-8", scrollAreaClassName),
141
+ viewPortClassName: "pr-3",
142
+ children: /* @__PURE__ */ jsx("div", { className: "flex w-4 flex-col items-start gap-2 py-2", children: turns.map((turn, index) => {
143
+ const distance = hoveredIndex === null ? null : Math.abs(index - hoveredIndex);
144
+ const active = turn.messageId === activeMessageId;
145
+ const inView = visibleMessageIdSet.has(turn.messageId);
146
+ const previewActive = hoveredIndex === index;
147
+ return /* @__PURE__ */ jsx(
148
+ ThreadRailItem,
149
+ {
150
+ turn,
151
+ index,
152
+ distance,
153
+ active,
154
+ inView,
155
+ previewId: previewActive ? previewId : void 0,
156
+ onHoverChange: showPreview,
157
+ onSelect: selectTurn
158
+ },
159
+ turn.key
160
+ );
161
+ }) })
162
+ }
163
+ ),
164
+ previewState.currentTurn && /* @__PURE__ */ jsx(
165
+ ThreadRailPreview,
166
+ {
167
+ id: previewId,
168
+ currentTurn: previewState.currentTurn,
169
+ previousTurn: previewState.previousTurn,
170
+ phase: previewState.phase,
171
+ top: previewState.top
172
+ }
173
+ )
174
+ ]
175
+ }
176
+ );
177
+ }
178
+ const getRailItemWidth = (distance) => {
179
+ if (distance === 0) return "w-4";
180
+ if (distance === 1) return "w-3";
181
+ return "w-2";
182
+ };
183
+ const getRailItemTone = ({
184
+ distance,
185
+ active,
186
+ inView
187
+ }) => {
188
+ if (distance === 0 || active) return "bg-neutral6";
189
+ if (inView) return "bg-neutral5";
190
+ if (distance === 1) return "bg-neutral4";
191
+ return "bg-neutral3/60";
192
+ };
193
+ function ThreadRailItem({
194
+ turn,
195
+ index,
196
+ distance,
197
+ active,
198
+ inView,
199
+ previewId,
200
+ onHoverChange,
201
+ onSelect
202
+ }) {
203
+ const size = getRailItemWidth(distance);
204
+ const tone = getRailItemTone({ distance, active, inView });
205
+ return /* @__PURE__ */ jsx(
206
+ "div",
207
+ {
208
+ "data-in-view": inView ? "true" : void 0,
209
+ "data-active": active ? "true" : void 0,
210
+ className: "group/thread-rail-item relative flex items-center",
211
+ children: /* @__PURE__ */ jsx(
212
+ "button",
213
+ {
214
+ type: "button",
215
+ "aria-label": `Jump to ${turn.prompt}`,
216
+ "aria-current": active ? "location" : void 0,
217
+ "aria-describedby": previewId,
218
+ "data-in-view": inView ? "true" : void 0,
219
+ "data-active": active ? "true" : void 0,
220
+ onClick: () => onSelect(turn),
221
+ onMouseEnter: (event) => onHoverChange(index, event.currentTarget),
222
+ onFocus: (event) => onHoverChange(index, event.currentTarget),
223
+ className: cn(
224
+ "relative block h-px cursor-pointer rounded-full transition-[width,background-color] duration-normal ease-out",
225
+ "before:absolute before:-inset-y-1 before:inset-x-0 before:content-['']",
226
+ "focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent1/40",
227
+ size,
228
+ tone
229
+ )
230
+ }
231
+ )
232
+ }
233
+ );
234
+ }
235
+ function ThreadRailPreview({
236
+ id,
237
+ currentTurn,
238
+ previousTurn,
239
+ phase,
240
+ top
241
+ }) {
242
+ const {
243
+ ref: previewSizerRef,
244
+ heightStyle: previewHeightStyle,
245
+ measure: measurePreviewHeight
246
+ } = useMeasuredAutoHeight();
247
+ const containerVisible = phase === "visible" || phase === "entering" && Boolean(previousTurn);
248
+ const hiddenLayerClassName = "scale-95 opacity-0 blur-xs";
249
+ const visibleLayerClassName = "scale-100 opacity-100 blur-none";
250
+ const layerClassName = "absolute inset-x-0 top-0 h-full origin-left transition-[opacity,filter,scale] duration-150 ease-in-out will-change-[opacity,filter,scale] motion-reduce:scale-100 motion-reduce:blur-none motion-reduce:transition-none";
251
+ React.useLayoutEffect(() => {
252
+ measurePreviewHeight();
253
+ }, [currentTurn.key, phase, measurePreviewHeight]);
254
+ return /* @__PURE__ */ jsxs(
255
+ "div",
256
+ {
257
+ id,
258
+ "data-testid": "thread-rail-preview",
259
+ "data-visible": containerVisible ? "true" : void 0,
260
+ className: cn(
261
+ "pointer-events-none absolute left-full top-0 z-30 ml-3 w-72 overflow-hidden rounded-xl border border-border1 bg-surface3 text-left shadow-dialog transition-[height,translate,opacity] duration-360 ease-out-custom will-change-[height,translate,opacity] motion-reduce:transition-none",
262
+ containerVisible ? "opacity-100" : "opacity-0"
263
+ ),
264
+ style: { ...previewHeightStyle, translate: `0 calc(${top}px - 50%)` },
265
+ children: [
266
+ /* @__PURE__ */ jsx("div", { ref: previewSizerRef, "data-testid": "thread-rail-preview-sizer", "aria-hidden": true, className: "invisible grid", children: /* @__PURE__ */ jsx(ThreadRailPreviewContent, { turn: currentTurn, className: "col-start-1 row-start-1 p-3.5" }) }),
267
+ /* @__PURE__ */ jsx("div", { "data-testid": "thread-rail-preview-viewport", className: "absolute inset-0", children: /* @__PURE__ */ jsxs("div", { className: "relative h-full", children: [
268
+ previousTurn && /* @__PURE__ */ jsx(
269
+ "div",
270
+ {
271
+ "data-testid": "thread-rail-preview-previous",
272
+ "aria-hidden": true,
273
+ className: cn(layerClassName, phase === "entering" ? visibleLayerClassName : hiddenLayerClassName),
274
+ children: /* @__PURE__ */ jsx(ThreadRailPreviewContent, { turn: previousTurn, className: "p-3.5" })
275
+ },
276
+ previousTurn.key
277
+ ),
278
+ /* @__PURE__ */ jsx(
279
+ "div",
280
+ {
281
+ "data-testid": "thread-rail-preview-current",
282
+ className: cn(layerClassName, phase === "visible" ? visibleLayerClassName : hiddenLayerClassName),
283
+ children: /* @__PURE__ */ jsx(ThreadRailPreviewContent, { turn: currentTurn, className: "p-3.5" })
284
+ },
285
+ currentTurn.key
286
+ )
287
+ ] }) })
288
+ ]
289
+ }
290
+ );
291
+ }
292
+ function ThreadRailPreviewContent({
293
+ turn,
294
+ className,
295
+ ...props
296
+ }) {
297
+ return /* @__PURE__ */ jsxs("div", { className, ...props, children: [
298
+ /* @__PURE__ */ jsx("div", { className: "truncate text-ui-md font-medium leading-ui-md text-neutral6", children: turn.prompt }),
299
+ turn.reply && /* @__PURE__ */ jsx("p", { className: "mt-1.5 line-clamp-3 text-ui-sm leading-ui-sm text-neutral4", children: turn.reply }),
300
+ (turn.files.length > 0 || turn.hiddenFileCount > 0) && /* @__PURE__ */ jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2 border-t border-border1/60 pt-2.5", children: [
301
+ turn.files.map((file) => /* @__PURE__ */ jsxs("span", { className: "inline-flex max-w-44 items-center gap-1.5 truncate text-ui-sm text-neutral4", children: [
302
+ /* @__PURE__ */ jsx(FileText, { className: "size-3.5 shrink-0 opacity-70", "aria-hidden": true }),
303
+ file
304
+ ] }, file)),
305
+ turn.hiddenFileCount > 0 && /* @__PURE__ */ jsxs("span", { className: "text-ui-sm font-medium text-neutral4", children: [
306
+ "+",
307
+ turn.hiddenFileCount
308
+ ] })
309
+ ] })
310
+ ] });
311
+ }
312
+
313
+ const SUMMARY_MAX_LENGTH = 120;
314
+ const FILE_PREVIEW_LIMIT = 2;
315
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
316
+ const getClientMessageKey = (message) => {
317
+ const metadata = message.content.metadata;
318
+ const clientMessageId = isRecord(metadata) ? metadata[CLIENT_MESSAGE_ID_KEY] : void 0;
319
+ return typeof clientMessageId === "string" && clientMessageId.length > 0 ? clientMessageId : message.id;
320
+ };
321
+ const normalizeSummary = (value, fallback) => {
322
+ const normalized = value.replace(/\s+/g, " ").trim();
323
+ if (normalized.length === 0) return fallback;
324
+ if (normalized.length <= SUMMARY_MAX_LENGTH) return normalized;
325
+ return `${normalized.slice(0, SUMMARY_MAX_LENGTH - 3).trimEnd()}...`;
326
+ };
327
+ const getTextFromParts = (message) => message.content.parts.flatMap((part) => {
328
+ if (!isRecord(part) || part.type !== "text" || typeof part.text !== "string") return [];
329
+ return [part.text];
330
+ }).join("\n");
331
+ const getStringField = (part, keys) => {
332
+ for (const key of keys) {
333
+ const value = part[key];
334
+ if (typeof value === "string" && value.trim().length > 0) return value;
335
+ }
336
+ return void 0;
337
+ };
338
+ const getPathLabel = (value) => {
339
+ if (value.startsWith("data:")) return void 0;
340
+ try {
341
+ const url = new URL(value);
342
+ const candidate = url.pathname.split("/").filter(Boolean).pop();
343
+ return candidate || url.hostname || void 0;
344
+ } catch {
345
+ const candidate = value.split(/[?#]/)[0]?.split("/").filter(Boolean).pop();
346
+ return candidate && !candidate.startsWith("data:") ? candidate : void 0;
347
+ }
348
+ };
349
+ const getFallbackFileLabel = (part) => {
350
+ const mediaType = getStringField(part, ["mimeType", "mediaType"]) ?? "";
351
+ if (part.type === "image" || mediaType.startsWith("image/")) return "Image";
352
+ if (mediaType === "application/pdf") return "PDF";
353
+ if (mediaType.startsWith("video/")) return "Video";
354
+ if (mediaType.startsWith("audio/")) return "Audio";
355
+ return "File";
356
+ };
357
+ const getFileLabelFromPart = (part) => {
358
+ if (!isRecord(part)) return void 0;
359
+ const type = getStringField(part, ["type"]);
360
+ if (type !== "file" && type !== "image") return void 0;
361
+ const explicitLabel = getStringField(part, ["filename", "name"]);
362
+ if (explicitLabel) return explicitLabel;
363
+ const source = getStringField(part, ["url", "image", "data"]);
364
+ const pathLabel = source ? getPathLabel(source) : void 0;
365
+ return pathLabel ?? getFallbackFileLabel(part);
366
+ };
367
+ const getFileLabels = (message) => message.content.parts.map(getFileLabelFromPart).filter((label) => Boolean(label));
368
+ const getSignalType = (message) => {
369
+ const signal = message.content.metadata?.signal;
370
+ const metadataType = isRecord(signal) ? signal.type : void 0;
371
+ return typeof metadataType === "string" ? metadataType : message.type;
372
+ };
373
+ const isDisplayableUserMessage = (message) => {
374
+ if (message.role === "user") return true;
375
+ if (message.role !== "signal") return false;
376
+ const signalType = getSignalType(message);
377
+ return signalType === "user" || signalType === "user-message";
378
+ };
379
+ const getNextAssistantReply = (messages, startIndex) => {
380
+ for (let index = startIndex + 1; index < messages.length; index += 1) {
381
+ const message = messages[index];
382
+ if (!message) continue;
383
+ if (isDisplayableUserMessage(message)) return void 0;
384
+ if (message.role !== "assistant") continue;
385
+ const reply = normalizeSummary(getTextFromParts(message), "");
386
+ if (reply) return reply;
387
+ }
388
+ return void 0;
389
+ };
390
+ const buildThreadRailTurns = (messages) => messages.flatMap((message, index) => {
391
+ if (!isDisplayableUserMessage(message)) return [];
392
+ const files = getFileLabels(message);
393
+ const visibleFiles = files.slice(0, FILE_PREVIEW_LIMIT);
394
+ return [
395
+ {
396
+ key: getClientMessageKey(message),
397
+ messageId: message.id,
398
+ prompt: normalizeSummary(getTextFromParts(message), files.length > 0 ? "Attached file" : "User message"),
399
+ reply: getNextAssistantReply(messages, index),
400
+ files: visibleFiles,
401
+ hiddenFileCount: files.length - visibleFiles.length
402
+ }
403
+ ];
404
+ });
405
+
406
+ export { ThreadRail, buildThreadRailTurns, getClientMessageKey };
407
+ //# sourceMappingURL=ThreadRail.es.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThreadRail.es.js","sources":["../../src/ds/components/ThreadRail/thread-rail.tsx","../../src/ds/components/ThreadRail/thread-rail-turns.ts"],"sourcesContent":["import { FileText } from 'lucide-react';\nimport * as React from 'react';\n\nimport type { ThreadRailTurn } from './thread-rail-turns';\n\nimport { useOptionalMessageScroller, useOptionalMessageScrollerVisibility } from '@/ds/components/MessageScroller';\nimport { ScrollArea } from '@/ds/components/ScrollArea';\nimport { useMeasuredAutoHeight } from '@/hooks/use-measured-auto-height';\nimport { cn } from '@/lib/utils';\n\ntype ThreadRailPreviewPhase = 'hidden' | 'entering' | 'visible' | 'exiting';\n\ntype ThreadRailPreviewState = {\n currentTurn: ThreadRailTurn | undefined;\n previousTurn: ThreadRailTurn | undefined;\n index: number | null;\n phase: ThreadRailPreviewPhase;\n top: number;\n transitionKey: number;\n};\n\nconst PREVIEW_TRANSITION_DURATION_MS = 360;\nconst PREVIEW_CLEANUP_DELAY_MS = PREVIEW_TRANSITION_DURATION_MS + 80;\n\nconst DEFAULT_PREVIEW_STATE: ThreadRailPreviewState = {\n currentTurn: undefined,\n previousTurn: undefined,\n index: null,\n phase: 'hidden',\n top: 0,\n transitionKey: 0,\n};\n\nexport interface ThreadRailProps {\n turns: ThreadRailTurn[];\n currentAnchorId?: string;\n visibleMessageIds?: string[];\n label?: string;\n className?: string;\n maxHeight?: string;\n scrollAreaClassName?: string;\n onSelect?: (turn: ThreadRailTurn) => void;\n}\n\nexport function ThreadRail({\n turns,\n currentAnchorId,\n visibleMessageIds,\n label = 'Conversation timeline',\n className,\n maxHeight = 'calc(100dvh - 12rem)',\n scrollAreaClassName,\n onSelect,\n}: ThreadRailProps) {\n const railRef = React.useRef<HTMLElement>(null);\n const previewId = React.useId();\n const [previewState, setPreviewState] = React.useState<ThreadRailPreviewState>(DEFAULT_PREVIEW_STATE);\n const messageScroller = useOptionalMessageScroller();\n const scrollerVisibility = useOptionalMessageScrollerVisibility();\n\n const fallbackMessageId = turns.at(-1)?.messageId;\n const activeMessageId = currentAnchorId ?? scrollerVisibility?.currentAnchorId ?? fallbackMessageId;\n const resolvedVisibleMessageIds =\n visibleMessageIds ?? scrollerVisibility?.visibleMessageIds ?? (activeMessageId ? [activeMessageId] : []);\n const visibleMessageIdSet = new Set(resolvedVisibleMessageIds);\n const previewHoverActive = previewState.phase === 'entering' || previewState.phase === 'visible';\n const hoveredIndex = previewHoverActive ? previewState.index : null;\n const selectTurn = React.useCallback(\n (turn: ThreadRailTurn) => {\n if (onSelect) {\n onSelect(turn);\n return;\n }\n\n messageScroller?.scrollToMessage(turn.messageId, { behavior: 'smooth', align: 'start' });\n },\n [messageScroller, onSelect],\n );\n\n const showPreview = (index: number, element: HTMLElement) => {\n const railTop = railRef.current?.getBoundingClientRect().top ?? 0;\n const itemRect = element.getBoundingClientRect();\n const nextTurn = turns[index];\n if (!nextTurn) return;\n\n setPreviewState(current => {\n const nextTop = itemRect.top + itemRect.height / 2 - railTop;\n if (current.index === index && current.phase !== 'hidden' && current.phase !== 'exiting') {\n return { ...current, top: nextTop };\n }\n\n const previousTurn =\n current.currentTurn && current.currentTurn.key !== nextTurn.key && current.phase !== 'hidden'\n ? current.currentTurn\n : undefined;\n\n return {\n currentTurn: nextTurn,\n previousTurn,\n index,\n phase: 'entering',\n top: nextTop,\n transitionKey: current.transitionKey + 1,\n };\n });\n };\n\n const hidePreview = () => {\n setPreviewState(current => {\n if (!current.currentTurn || current.phase === 'hidden' || current.phase === 'exiting') {\n return { ...current, index: null };\n }\n\n return {\n ...current,\n index: null,\n previousTurn: undefined,\n phase: 'exiting',\n transitionKey: current.transitionKey + 1,\n };\n });\n };\n\n React.useEffect(() => {\n if (previewState.phase !== 'entering') return;\n\n const requestFrame = window.requestAnimationFrame ?? window.setTimeout;\n const cancelFrame = window.cancelAnimationFrame ?? window.clearTimeout;\n let settleFrame: number | undefined;\n const startFrame = requestFrame(() => {\n settleFrame = requestFrame(() => {\n setPreviewState(current =>\n current.transitionKey === previewState.transitionKey && current.phase === 'entering'\n ? { ...current, phase: 'visible' }\n : current,\n );\n });\n });\n\n return () => {\n cancelFrame(startFrame);\n if (settleFrame !== undefined) cancelFrame(settleFrame);\n };\n }, [previewState.phase, previewState.transitionKey]);\n\n React.useEffect(() => {\n if (previewState.phase !== 'visible' || !previewState.previousTurn) return;\n\n const timeout = window.setTimeout(() => {\n setPreviewState(current =>\n current.transitionKey === previewState.transitionKey ? { ...current, previousTurn: undefined } : current,\n );\n }, PREVIEW_CLEANUP_DELAY_MS);\n\n return () => window.clearTimeout(timeout);\n }, [previewState.phase, previewState.previousTurn, previewState.transitionKey]);\n\n React.useEffect(() => {\n if (previewState.phase !== 'exiting') return;\n\n const timeout = window.setTimeout(() => {\n setPreviewState(current =>\n current.transitionKey === previewState.transitionKey ? DEFAULT_PREVIEW_STATE : current,\n );\n }, PREVIEW_CLEANUP_DELAY_MS);\n\n return () => window.clearTimeout(timeout);\n }, [previewState.phase, previewState.transitionKey]);\n\n if (turns.length === 0) return null;\n\n return (\n <nav\n ref={railRef}\n aria-label={label}\n data-testid=\"thread-rail\"\n className={cn('relative w-8 py-2', className)}\n onMouseLeave={hidePreview}\n onBlur={event => {\n const nextFocus = event.relatedTarget;\n if (!(nextFocus instanceof Node) || !event.currentTarget.contains(nextFocus)) hidePreview();\n }}\n >\n <ScrollArea\n data-testid=\"thread-rail-scroll-area\"\n maxHeight={maxHeight}\n className={cn('w-8', scrollAreaClassName)}\n viewPortClassName=\"pr-3\"\n >\n <div className=\"flex w-4 flex-col items-start gap-2 py-2\">\n {turns.map((turn, index) => {\n const distance = hoveredIndex === null ? null : Math.abs(index - hoveredIndex);\n const active = turn.messageId === activeMessageId;\n const inView = visibleMessageIdSet.has(turn.messageId);\n const previewActive = hoveredIndex === index;\n\n return (\n <ThreadRailItem\n key={turn.key}\n turn={turn}\n index={index}\n distance={distance}\n active={active}\n inView={inView}\n previewId={previewActive ? previewId : undefined}\n onHoverChange={showPreview}\n onSelect={selectTurn}\n />\n );\n })}\n </div>\n </ScrollArea>\n\n {previewState.currentTurn && (\n <ThreadRailPreview\n id={previewId}\n currentTurn={previewState.currentTurn}\n previousTurn={previewState.previousTurn}\n phase={previewState.phase}\n top={previewState.top}\n />\n )}\n </nav>\n );\n}\n\ninterface ThreadRailItemProps {\n turn: ThreadRailTurn;\n index: number;\n distance: number | null;\n active: boolean;\n inView: boolean;\n previewId?: string;\n onHoverChange: (index: number, element: HTMLElement) => void;\n onSelect: (turn: ThreadRailTurn) => void;\n}\n\n/** Width of a rail tick: widest at the hovered item, tapering to neighbours. */\nconst getRailItemWidth = (distance: number | null): string => {\n if (distance === 0) return 'w-4';\n if (distance === 1) return 'w-3';\n return 'w-2';\n};\n\n/** Background tone of a rail tick, prioritising hovered/active, then in-view, then proximity. */\nconst getRailItemTone = ({\n distance,\n active,\n inView,\n}: Pick<ThreadRailItemProps, 'distance' | 'active' | 'inView'>): string => {\n if (distance === 0 || active) return 'bg-neutral6';\n if (inView) return 'bg-neutral5';\n if (distance === 1) return 'bg-neutral4';\n return 'bg-neutral3/60';\n};\n\nfunction ThreadRailItem({\n turn,\n index,\n distance,\n active,\n inView,\n previewId,\n onHoverChange,\n onSelect,\n}: ThreadRailItemProps) {\n const size = getRailItemWidth(distance);\n const tone = getRailItemTone({ distance, active, inView });\n\n return (\n <div\n data-in-view={inView ? 'true' : undefined}\n data-active={active ? 'true' : undefined}\n className=\"group/thread-rail-item relative flex items-center\"\n >\n <button\n type=\"button\"\n aria-label={`Jump to ${turn.prompt}`}\n aria-current={active ? 'location' : undefined}\n aria-describedby={previewId}\n data-in-view={inView ? 'true' : undefined}\n data-active={active ? 'true' : undefined}\n onClick={() => onSelect(turn)}\n onMouseEnter={event => onHoverChange(index, event.currentTarget)}\n onFocus={event => onHoverChange(index, event.currentTarget)}\n className={cn(\n 'relative block h-px cursor-pointer rounded-full transition-[width,background-color] duration-normal ease-out',\n \"before:absolute before:-inset-y-1 before:inset-x-0 before:content-['']\",\n 'focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-accent1/40',\n size,\n tone,\n )}\n />\n </div>\n );\n}\n\nfunction ThreadRailPreview({\n id,\n currentTurn,\n previousTurn,\n phase,\n top,\n}: {\n id: string;\n currentTurn: ThreadRailTurn;\n previousTurn: ThreadRailTurn | undefined;\n phase: ThreadRailPreviewPhase;\n top: number;\n}) {\n const {\n ref: previewSizerRef,\n heightStyle: previewHeightStyle,\n measure: measurePreviewHeight,\n } = useMeasuredAutoHeight<HTMLDivElement>();\n const containerVisible = phase === 'visible' || (phase === 'entering' && Boolean(previousTurn));\n // Entering and exiting share the same off-screen resting style.\n const hiddenLayerClassName = 'scale-95 opacity-0 blur-xs';\n const visibleLayerClassName = 'scale-100 opacity-100 blur-none';\n const layerClassName =\n 'absolute inset-x-0 top-0 h-full origin-left transition-[opacity,filter,scale] duration-150 ease-in-out will-change-[opacity,filter,scale] motion-reduce:scale-100 motion-reduce:blur-none motion-reduce:transition-none';\n\n React.useLayoutEffect(() => {\n measurePreviewHeight();\n }, [currentTurn.key, phase, measurePreviewHeight]);\n\n return (\n <div\n id={id}\n data-testid=\"thread-rail-preview\"\n data-visible={containerVisible ? 'true' : undefined}\n className={cn(\n 'pointer-events-none absolute left-full top-0 z-30 ml-3 w-72 overflow-hidden rounded-xl border border-border1 bg-surface3 text-left shadow-dialog transition-[height,translate,opacity] duration-360 ease-out-custom will-change-[height,translate,opacity] motion-reduce:transition-none',\n containerVisible ? 'opacity-100' : 'opacity-0',\n )}\n style={{ ...previewHeightStyle, translate: `0 calc(${top}px - 50%)` }}\n >\n <div ref={previewSizerRef} data-testid=\"thread-rail-preview-sizer\" aria-hidden className=\"invisible grid\">\n <ThreadRailPreviewContent turn={currentTurn} className=\"col-start-1 row-start-1 p-3.5\" />\n </div>\n <div data-testid=\"thread-rail-preview-viewport\" className=\"absolute inset-0\">\n <div className=\"relative h-full\">\n {previousTurn && (\n <div\n key={previousTurn.key}\n data-testid=\"thread-rail-preview-previous\"\n aria-hidden\n className={cn(layerClassName, phase === 'entering' ? visibleLayerClassName : hiddenLayerClassName)}\n >\n <ThreadRailPreviewContent turn={previousTurn} className=\"p-3.5\" />\n </div>\n )}\n <div\n key={currentTurn.key}\n data-testid=\"thread-rail-preview-current\"\n className={cn(layerClassName, phase === 'visible' ? visibleLayerClassName : hiddenLayerClassName)}\n >\n <ThreadRailPreviewContent turn={currentTurn} className=\"p-3.5\" />\n </div>\n </div>\n </div>\n </div>\n );\n}\n\nfunction ThreadRailPreviewContent({\n turn,\n className,\n ...props\n}: React.HTMLAttributes<HTMLDivElement> & { turn: ThreadRailTurn }) {\n return (\n <div className={className} {...props}>\n <div className=\"truncate text-ui-md font-medium leading-ui-md text-neutral6\">{turn.prompt}</div>\n {turn.reply && <p className=\"mt-1.5 line-clamp-3 text-ui-sm leading-ui-sm text-neutral4\">{turn.reply}</p>}\n {(turn.files.length > 0 || turn.hiddenFileCount > 0) && (\n <div className=\"mt-3 flex flex-wrap items-center gap-2 border-t border-border1/60 pt-2.5\">\n {turn.files.map(file => (\n <span key={file} className=\"inline-flex max-w-44 items-center gap-1.5 truncate text-ui-sm text-neutral4\">\n <FileText className=\"size-3.5 shrink-0 opacity-70\" aria-hidden />\n {file}\n </span>\n ))}\n {turn.hiddenFileCount > 0 && (\n <span className=\"text-ui-sm font-medium text-neutral4\">+{turn.hiddenFileCount}</span>\n )}\n </div>\n )}\n </div>\n );\n}\n","import type { MastraDBMessage } from '@mastra/core/agent/message-list';\nimport { CLIENT_MESSAGE_ID_KEY } from '@mastra/react';\n\nconst SUMMARY_MAX_LENGTH = 120;\nconst FILE_PREVIEW_LIMIT = 2;\n\nexport interface ThreadRailTurn {\n key: string;\n messageId: string;\n prompt: string;\n reply?: string;\n files: string[];\n hiddenFileCount: number;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nexport const getClientMessageKey = (message: MastraDBMessage): string => {\n const metadata = message.content.metadata;\n const clientMessageId = isRecord(metadata) ? metadata[CLIENT_MESSAGE_ID_KEY] : undefined;\n return typeof clientMessageId === 'string' && clientMessageId.length > 0 ? clientMessageId : message.id;\n};\n\nconst normalizeSummary = (value: string, fallback: string): string => {\n const normalized = value.replace(/\\s+/g, ' ').trim();\n if (normalized.length === 0) return fallback;\n if (normalized.length <= SUMMARY_MAX_LENGTH) return normalized;\n return `${normalized.slice(0, SUMMARY_MAX_LENGTH - 3).trimEnd()}...`;\n};\n\nconst getTextFromParts = (message: MastraDBMessage): string =>\n message.content.parts\n .flatMap(part => {\n if (!isRecord(part) || part.type !== 'text' || typeof part.text !== 'string') return [];\n return [part.text];\n })\n .join('\\n');\n\nconst getStringField = (part: Record<string, unknown>, keys: string[]): string | undefined => {\n for (const key of keys) {\n const value = part[key];\n if (typeof value === 'string' && value.trim().length > 0) return value;\n }\n return undefined;\n};\n\nconst getPathLabel = (value: string): string | undefined => {\n if (value.startsWith('data:')) return undefined;\n\n try {\n const url = new URL(value);\n const candidate = url.pathname.split('/').filter(Boolean).pop();\n return candidate || url.hostname || undefined;\n } catch {\n const candidate = value.split(/[?#]/)[0]?.split('/').filter(Boolean).pop();\n return candidate && !candidate.startsWith('data:') ? candidate : undefined;\n }\n};\n\nconst getFallbackFileLabel = (part: Record<string, unknown>): string => {\n const mediaType = getStringField(part, ['mimeType', 'mediaType']) ?? '';\n if (part.type === 'image' || mediaType.startsWith('image/')) return 'Image';\n if (mediaType === 'application/pdf') return 'PDF';\n if (mediaType.startsWith('video/')) return 'Video';\n if (mediaType.startsWith('audio/')) return 'Audio';\n return 'File';\n};\n\nconst getFileLabelFromPart = (part: MastraDBMessage['content']['parts'][number]): string | undefined => {\n if (!isRecord(part)) return undefined;\n\n const type = getStringField(part, ['type']);\n if (type !== 'file' && type !== 'image') return undefined;\n\n const explicitLabel = getStringField(part, ['filename', 'name']);\n if (explicitLabel) return explicitLabel;\n\n const source = getStringField(part, ['url', 'image', 'data']);\n const pathLabel = source ? getPathLabel(source) : undefined;\n return pathLabel ?? getFallbackFileLabel(part);\n};\n\nconst getFileLabels = (message: MastraDBMessage): string[] =>\n message.content.parts.map(getFileLabelFromPart).filter((label): label is string => Boolean(label));\n\nconst getSignalType = (message: MastraDBMessage): string | undefined => {\n const signal = message.content.metadata?.signal;\n const metadataType = isRecord(signal) ? signal.type : undefined;\n return typeof metadataType === 'string' ? metadataType : message.type;\n};\n\nconst isDisplayableUserMessage = (message: MastraDBMessage): boolean => {\n if (message.role === 'user') return true;\n if (message.role !== 'signal') return false;\n\n const signalType = getSignalType(message);\n return signalType === 'user' || signalType === 'user-message';\n};\n\nconst getNextAssistantReply = (messages: MastraDBMessage[], startIndex: number): string | undefined => {\n for (let index = startIndex + 1; index < messages.length; index += 1) {\n const message = messages[index];\n if (!message) continue;\n if (isDisplayableUserMessage(message)) return undefined;\n if (message.role !== 'assistant') continue;\n\n const reply = normalizeSummary(getTextFromParts(message), '');\n if (reply) return reply;\n }\n\n return undefined;\n};\n\nexport const buildThreadRailTurns = (messages: MastraDBMessage[]): ThreadRailTurn[] =>\n messages.flatMap((message, index) => {\n if (!isDisplayableUserMessage(message)) return [];\n\n const files = getFileLabels(message);\n const visibleFiles = files.slice(0, FILE_PREVIEW_LIMIT);\n\n return [\n {\n key: getClientMessageKey(message),\n messageId: message.id,\n prompt: normalizeSummary(getTextFromParts(message), files.length > 0 ? 'Attached file' : 'User message'),\n reply: getNextAssistantReply(messages, index),\n files: visibleFiles,\n hiddenFileCount: files.length - visibleFiles.length,\n },\n ];\n });\n"],"names":[],"mappings":"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"}
@@ -8,6 +8,7 @@ const primitives_transitions = require('../primitives/transitions.cjs.js');
8
8
  const utils_cn = require('../cn-vA5sWo9W.cjs');
9
9
  const collapsible = require('../collapsible-CCV0eLl-.cjs');
10
10
  const lucideReact = require('lucide-react');
11
+ const hooks_useIsomorphicLayoutEffect = require('../hooks/use-isomorphic-layout-effect.cjs.js');
11
12
 
12
13
  function _interopNamespaceDefault(e) {
13
14
  const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } });
@@ -292,7 +293,6 @@ TreeLabel.displayName = "Tree.Label";
292
293
 
293
294
  const TREE_FOCUSABLE_ITEM_SELECTOR = '[data-tree-item-kind="folder"], [data-tree-item-kind="file"]';
294
295
  const TREE_FOLDER_TRIGGER_SELECTOR = '[data-tree-folder-trigger="true"]';
295
- const useIsomorphicLayoutEffect = typeof window === "undefined" ? React__namespace.useEffect : React__namespace.useLayoutEffect;
296
296
  function assignRef(ref, value) {
297
297
  if (typeof ref === "function") {
298
298
  ref(value);
@@ -450,7 +450,7 @@ const TreeRoot = React__namespace.forwardRef(
450
450
  focusTreeItem(root, nextItem);
451
451
  }
452
452
  }, []);
453
- useIsomorphicLayoutEffect(() => {
453
+ hooks_useIsomorphicLayoutEffect.useIsomorphicLayoutEffect(() => {
454
454
  const root = rootRef.current;
455
455
  if (!root) return;
456
456
  syncTreeTabStops(root, selectedId);