@mastra/playground-ui 51.0.0-alpha.5 → 51.0.1-alpha.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # @mastra/playground-ui
2
2
 
3
+ ## 51.0.1-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`f95f468`](https://github.com/mastra-ai/mastra/commit/f95f468cf1e7c2b924a13826494f98b8f2ccd581)]:
8
+ - @mastra/core@1.61.1-alpha.1
9
+ - @mastra/client-js@1.42.1-alpha.1
10
+ - @mastra/react@1.4.6-alpha.1
11
+
12
+ ## 51.0.1-alpha.0
13
+
14
+ ### Patch Changes
15
+
16
+ - Fixed code blocks stretching the page. A long line inside a fenced markdown block used to widen everything around it, pushing the layout past the window. A code block now keeps to the width it is given, and scrolls horizontally inside itself when set to `overflow="scroll"`. ([#22018](https://github.com/mastra-ai/mastra/pull/22018))
17
+
18
+ - Updated dependencies [[`1e47b75`](https://github.com/mastra-ai/mastra/commit/1e47b7520cab4cfaa8daed52f17e2e6d14ff7539)]:
19
+ - @mastra/core@1.61.1-alpha.0
20
+ - @mastra/client-js@1.42.1-alpha.0
21
+ - @mastra/react@1.4.6-alpha.0
22
+
23
+ ## 51.0.0
24
+
25
+ ### Minor Changes
26
+
27
+ - Added controlled theme selection to Sankey signals so host applications can persist and restore the open theme panel. ([#21968](https://github.com/mastra-ai/mastra/pull/21968))
28
+
29
+ - Added `flat` and `factory` variants to `Section`, including standard, view-only, and destructive row compositions. ([#21939](https://github.com/mastra-ai/mastra/pull/21939))
30
+
31
+ ```tsx
32
+ <Section variant="factory">
33
+ <Section.Header>
34
+ <div>
35
+ <Section.Heading>Security</Section.Heading>
36
+ <Section.Description>Manage sign-in requirements.</Section.Description>
37
+ </div>
38
+ </Section.Header>
39
+ <Section.Content>
40
+ <Section.Row label="Two-factor authentication">
41
+ <Switch />
42
+ </Section.Row>
43
+ </Section.Content>
44
+ </Section>
45
+ ```
46
+
47
+ ### Patch Changes
48
+
49
+ - Improved floating surfaces with softer, consistent elevation. ([#21980](https://github.com/mastra-ai/mastra/pull/21980))
50
+
51
+ - Improved plan cards to show expansion controls only when content is clipped and keep approval actions readable. ([#21891](https://github.com/mastra-ai/mastra/pull/21891))
52
+
53
+ - Aligned the `flat` and `factory` Section layouts so their headings, row content, and actions share consistent horizontal edges. ([#21970](https://github.com/mastra-ai/mastra/pull/21970))
54
+
55
+ - Fixed hidden search field labels taking up layout space. ([#21918](https://github.com/mastra-ai/mastra/pull/21918))
56
+
57
+ - Updated dependencies [[`88d14ca`](https://github.com/mastra-ai/mastra/commit/88d14cac008582a618fecc3d5c7fd3bdf4f6ddc3), [`26d4016`](https://github.com/mastra-ai/mastra/commit/26d40160ff7f7d8bf95fee2039a52cbc83863533), [`480e491`](https://github.com/mastra-ai/mastra/commit/480e491588bd6a7a1c9ee4407590ad625dd33952), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`acc3471`](https://github.com/mastra-ai/mastra/commit/acc3471de5f3fde8027ee4e355af292b2bc1bc30), [`b6a771e`](https://github.com/mastra-ai/mastra/commit/b6a771ef23d203ddb348efca8065eff65def8191), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`3bb88dd`](https://github.com/mastra-ai/mastra/commit/3bb88ddf07fb98f3cd16d3bff94e51cd3b45d011), [`d23e75d`](https://github.com/mastra-ai/mastra/commit/d23e75d57cc7cf5b9bfdbee896bf5a6a2484fed7), [`c8faa4e`](https://github.com/mastra-ai/mastra/commit/c8faa4e1cfebaec56b65e754e90b9fe46d153359), [`d378d75`](https://github.com/mastra-ai/mastra/commit/d378d7511f71309ed61a8f6b93cd0361dc6cb70f), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`26d4016`](https://github.com/mastra-ai/mastra/commit/26d40160ff7f7d8bf95fee2039a52cbc83863533), [`7c60df5`](https://github.com/mastra-ai/mastra/commit/7c60df5c7872343fbac5c3e5b1175c8076a5abfd), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`84a5b69`](https://github.com/mastra-ai/mastra/commit/84a5b699f84d6bae0a34efe5a970d891090b9f41), [`f2031a4`](https://github.com/mastra-ai/mastra/commit/f2031a47445e8f67a89ba1309036816f97ab7a65), [`9267e9b`](https://github.com/mastra-ai/mastra/commit/9267e9b3d9c2fcf16936050495a787054c2431ab), [`cad4208`](https://github.com/mastra-ai/mastra/commit/cad42082e6aa1776168a94914f523334be45d929), [`8e529d4`](https://github.com/mastra-ai/mastra/commit/8e529d4ac754efef04b225841349e0da9edf89a6), [`57c5103`](https://github.com/mastra-ai/mastra/commit/57c51035a2a36e3df3c4f32f46bb789a66ed5946), [`038b7b4`](https://github.com/mastra-ai/mastra/commit/038b7b405cb4ac25ab3f3031334111b1f87ac112), [`4132d61`](https://github.com/mastra-ai/mastra/commit/4132d61f8367077120ee9e6420d3224dffd93c93), [`d378d75`](https://github.com/mastra-ai/mastra/commit/d378d7511f71309ed61a8f6b93cd0361dc6cb70f)]:
58
+ - @mastra/core@1.61.0
59
+ - @mastra/client-js@1.42.0
60
+ - @mastra/react@1.4.5
61
+
3
62
  ## 51.0.0-alpha.5
4
63
 
5
64
  ### Patch Changes
@@ -30,7 +30,7 @@ function CodeBlock({
30
30
  "figure",
31
31
  {
32
32
  className: cn(
33
- "group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2",
33
+ "group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2 [contain:inline-size]",
34
34
  className
35
35
  ),
36
36
  children: [
@@ -83,4 +83,4 @@ function CodeBlock({
83
83
  }
84
84
 
85
85
  export { CodeBlock as C };
86
- //# sourceMappingURL=code-block-DR6-quU0.js.map
86
+ //# sourceMappingURL=code-block-CA9sa6yS.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block-CA9sa6yS.js","sources":["../src/ds/components/CodeBlock/code-block.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Code } from '../Code/code';\nimport { CopyButton } from '../CopyButton/copy-button';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select/select';\nimport { TabList } from '../Tabs/tabs-list';\nimport { Tabs } from '../Tabs/tabs-root';\nimport { Tab } from '../Tabs/tabs-tab';\nimport { transitions } from '@/ds/primitives/transitions';\nimport { cn } from '@/lib/utils';\n\nexport type CodeBlockSelector = 'select' | 'tabs';\n\nexport type CodeBlockOverflow = 'wrap' | 'scroll';\n\nexport interface CodeBlockOption {\n label: string;\n value: string;\n}\n\nexport interface CodeBlockProps {\n code: string;\n options?: CodeBlockOption[];\n value?: string;\n onValueChange?: (value: string) => void;\n selector?: CodeBlockSelector;\n fileName?: string;\n lang?: string;\n /** `wrap` (default) breaks long lines — best for commands and snippets.\n * `scroll` preserves columns behind a horizontal scroll — best for source code. */\n overflow?: CodeBlockOverflow;\n copyMessage?: string;\n copyTooltip?: string;\n actions?: ReactNode;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n options,\n value,\n onValueChange,\n selector = 'select',\n fileName,\n lang,\n overflow = 'wrap',\n copyMessage,\n copyTooltip,\n actions,\n className,\n}: CodeBlockProps) {\n const hasOptions = options && options.length > 0;\n const useTabs = hasOptions && selector === 'tabs';\n const useSelect = hasOptions && selector === 'select';\n const firstOption = options?.[0];\n const activeValue = value ?? firstOption?.value;\n\n return (\n <figure\n // A scrolling `pre` still reports its longest line as an intrinsic width, which\n // grows every ancestor; containment keeps the block inside the width it is given.\n className={cn(\n 'group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2 [contain:inline-size]',\n className,\n )}\n >\n {useTabs && firstOption && (\n <Tabs defaultTab={firstOption.value} value={activeValue} onValueChange={onValueChange ?? (() => {})}>\n <div className=\"flex items-stretch\">\n <div className=\"min-w-0 flex-1\">\n <TabList>\n {options.map(opt => (\n <Tab key={opt.value} value={opt.value}>\n {opt.label}\n </Tab>\n ))}\n </TabList>\n </div>\n {actions && <div className=\"border-border1 flex shrink-0 items-center border-b pr-2 pl-3\">{actions}</div>}\n </div>\n </Tabs>\n )}\n\n {useSelect && options && (\n <div className=\"border-border2/40 flex items-center border-b px-2 py-1.5\">\n <Select value={activeValue} onValueChange={onValueChange}>\n <SelectTrigger size=\"sm\" variant=\"ghost\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {options.map(opt => (\n <SelectItem key={opt.value} value={opt.value}>\n {opt.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && fileName && (\n <div className=\"border-border2/40 flex items-center border-b px-4 py-2\">\n <figcaption className=\"text-ui-sm text-neutral4 font-mono\">{fileName}</figcaption>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && !fileName && actions && (\n <div className=\"border-border2/40 flex items-center justify-end border-b px-2 py-1.5\">{actions}</div>\n )}\n\n <div className=\"relative\">\n <Code\n code={code}\n lang={lang}\n className={cn(\n 'px-4 py-3 font-mono text-ui-sm text-neutral5',\n overflow === 'scroll' ? 'overflow-x-auto whitespace-pre' : 'break-all whitespace-pre-wrap',\n )}\n />\n <CopyButton\n content={code}\n copyMessage={copyMessage}\n tooltip={copyTooltip}\n size=\"sm\"\n className={cn(\n 'absolute top-2 right-2 opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 pointer-fine:opacity-0',\n transitions.opacity,\n )}\n />\n </div>\n </figure>\n );\n}\n"],"names":[],"mappings":"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"}
@@ -32,7 +32,7 @@ function CodeBlock({
32
32
  "figure",
33
33
  {
34
34
  className: utils_cn.cn(
35
- "group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2",
35
+ "group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2 [contain:inline-size]",
36
36
  className
37
37
  ),
38
38
  children: [
@@ -85,4 +85,4 @@ function CodeBlock({
85
85
  }
86
86
 
87
87
  exports.CodeBlock = CodeBlock;
88
- //# sourceMappingURL=code-block-Cqt3al0k.cjs.map
88
+ //# sourceMappingURL=code-block-DCXZ3HKM.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code-block-DCXZ3HKM.cjs","sources":["../src/ds/components/CodeBlock/code-block.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Code } from '../Code/code';\nimport { CopyButton } from '../CopyButton/copy-button';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select/select';\nimport { TabList } from '../Tabs/tabs-list';\nimport { Tabs } from '../Tabs/tabs-root';\nimport { Tab } from '../Tabs/tabs-tab';\nimport { transitions } from '@/ds/primitives/transitions';\nimport { cn } from '@/lib/utils';\n\nexport type CodeBlockSelector = 'select' | 'tabs';\n\nexport type CodeBlockOverflow = 'wrap' | 'scroll';\n\nexport interface CodeBlockOption {\n label: string;\n value: string;\n}\n\nexport interface CodeBlockProps {\n code: string;\n options?: CodeBlockOption[];\n value?: string;\n onValueChange?: (value: string) => void;\n selector?: CodeBlockSelector;\n fileName?: string;\n lang?: string;\n /** `wrap` (default) breaks long lines — best for commands and snippets.\n * `scroll` preserves columns behind a horizontal scroll — best for source code. */\n overflow?: CodeBlockOverflow;\n copyMessage?: string;\n copyTooltip?: string;\n actions?: ReactNode;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n options,\n value,\n onValueChange,\n selector = 'select',\n fileName,\n lang,\n overflow = 'wrap',\n copyMessage,\n copyTooltip,\n actions,\n className,\n}: CodeBlockProps) {\n const hasOptions = options && options.length > 0;\n const useTabs = hasOptions && selector === 'tabs';\n const useSelect = hasOptions && selector === 'select';\n const firstOption = options?.[0];\n const activeValue = value ?? firstOption?.value;\n\n return (\n <figure\n // A scrolling `pre` still reports its longest line as an intrinsic width, which\n // grows every ancestor; containment keeps the block inside the width it is given.\n className={cn(\n 'group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2 [contain:inline-size]',\n className,\n )}\n >\n {useTabs && firstOption && (\n <Tabs defaultTab={firstOption.value} value={activeValue} onValueChange={onValueChange ?? (() => {})}>\n <div className=\"flex items-stretch\">\n <div className=\"min-w-0 flex-1\">\n <TabList>\n {options.map(opt => (\n <Tab key={opt.value} value={opt.value}>\n {opt.label}\n </Tab>\n ))}\n </TabList>\n </div>\n {actions && <div className=\"border-border1 flex shrink-0 items-center border-b pr-2 pl-3\">{actions}</div>}\n </div>\n </Tabs>\n )}\n\n {useSelect && options && (\n <div className=\"border-border2/40 flex items-center border-b px-2 py-1.5\">\n <Select value={activeValue} onValueChange={onValueChange}>\n <SelectTrigger size=\"sm\" variant=\"ghost\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {options.map(opt => (\n <SelectItem key={opt.value} value={opt.value}>\n {opt.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && fileName && (\n <div className=\"border-border2/40 flex items-center border-b px-4 py-2\">\n <figcaption className=\"text-ui-sm text-neutral4 font-mono\">{fileName}</figcaption>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && !fileName && actions && (\n <div className=\"border-border2/40 flex items-center justify-end border-b px-2 py-1.5\">{actions}</div>\n )}\n\n <div className=\"relative\">\n <Code\n code={code}\n lang={lang}\n className={cn(\n 'px-4 py-3 font-mono text-ui-sm text-neutral5',\n overflow === 'scroll' ? 'overflow-x-auto whitespace-pre' : 'break-all whitespace-pre-wrap',\n )}\n />\n <CopyButton\n content={code}\n copyMessage={copyMessage}\n tooltip={copyTooltip}\n size=\"sm\"\n className={cn(\n 'absolute top-2 right-2 opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 pointer-fine:opacity-0',\n transitions.opacity,\n )}\n />\n </div>\n </figure>\n );\n}\n"],"names":["code","jsxs","cn","jsx","Tabs","TabList","Tab","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Code","CopyButton","transitions"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- const codeBlock = require('../code-block-Cqt3al0k.cjs');
5
+ const codeBlock = require('../code-block-DCXZ3HKM.cjs');
6
6
 
7
7
 
8
8
 
@@ -1,2 +1,2 @@
1
- export { C as CodeBlock } from '../code-block-DR6-quU0.js';
1
+ export { C as CodeBlock } from '../code-block-CA9sa6yS.js';
2
2
  //# sourceMappingURL=CodeBlock.es.js.map
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
- const markdownRenderer = require('../markdown-renderer-Dp_s_ZUm.cjs');
5
+ const markdownRenderer = require('../markdown-renderer-BQXWT1q2.cjs');
6
6
 
7
7
 
8
8
 
@@ -1,2 +1,2 @@
1
- export { M as MarkdownRenderer } from '../markdown-renderer-ByRLqDFg.js';
1
+ export { M as MarkdownRenderer } from '../markdown-renderer-CrCIi6au.js';
2
2
  //# sourceMappingURL=MarkdownRenderer.es.js.map
@@ -7,7 +7,7 @@ const lucideReact = require('lucide-react');
7
7
  const React = require('react');
8
8
  const Badge = require('../../Badge-BlJpI3fY.cjs');
9
9
  const Button = require('../../Button-BWj3opYd.cjs');
10
- const markdownRenderer = require('../../markdown-renderer-Dp_s_ZUm.cjs');
10
+ const markdownRenderer = require('../../markdown-renderer-BQXWT1q2.cjs');
11
11
  const Txt = require('../../Txt-I5lK8zy7.cjs');
12
12
  const icons_Icon = require('../../icons/Icon.cjs.js');
13
13
  const hooks_useCopyToClipboard = require('../../hooks/use-copy-to-clipboard.cjs.js');
@@ -3,7 +3,7 @@ import { CheckIcon, CopyIcon, Minimize2, Maximize2, ClipboardList } from 'lucide
3
3
  import { useState, useRef, useLayoutEffect, createContext, useContext } from 'react';
4
4
  import { B as Badge } from '../../Badge-woV6OD8k.js';
5
5
  import { B as Button } from '../../Button-XHy01fYR.js';
6
- import { M as MarkdownRenderer } from '../../markdown-renderer-ByRLqDFg.js';
6
+ import { M as MarkdownRenderer } from '../../markdown-renderer-CrCIi6au.js';
7
7
  import { T as Txt } from '../../Txt-Df42XG5p.js';
8
8
  import { Icon } from '../../icons/Icon.es.js';
9
9
  import { useCopyToClipboard } from '../../hooks/use-copy-to-clipboard.es.js';
@@ -5,7 +5,7 @@ const React = require('react');
5
5
  const Markdown = require('react-markdown');
6
6
  const remarkGfm = require('remark-gfm');
7
7
  const remend = require('remend');
8
- const codeBlock = require('./code-block-Cqt3al0k.cjs');
8
+ const codeBlock = require('./code-block-DCXZ3HKM.cjs');
9
9
  const utils_cn = require('./cn-vA5sWo9W.cjs');
10
10
 
11
11
  const ARRIVING = "mastra-markdown-arriving";
@@ -277,4 +277,4 @@ const WINDOW_COMPONENTS = {
277
277
  };
278
278
 
279
279
  exports.MarkdownRenderer = MarkdownRenderer;
280
- //# sourceMappingURL=markdown-renderer-Dp_s_ZUm.cjs.map
280
+ //# sourceMappingURL=markdown-renderer-BQXWT1q2.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-renderer-Dp_s_ZUm.cjs","sources":["../src/ds/components/MarkdownRenderer/arriving.ts","../src/ds/components/MarkdownRenderer/blocks.ts","../src/ds/components/MarkdownRenderer/use-reveal.ts","../src/ds/components/MarkdownRenderer/markdown-renderer.tsx"],"sourcesContent":["import type { ExtraProps } from 'react-markdown';\n\ntype MarkdownElement = NonNullable<ExtraProps['node']>;\ntype MarkdownChild = MarkdownElement['children'][number];\n\nconst ARRIVING = 'mastra-markdown-arriving';\n\n/** Fades whole: a fence renders through `CodeBlock`, and inline code carries a background. */\nconst UNBROKEN = new Set(['pre', 'code']);\n\nconst wrap = (value: string, arriving: boolean): MarkdownChild => ({\n type: 'element',\n tagName: 'span',\n properties: arriving ? { className: [ARRIVING] } : {},\n children: [{ type: 'text', value }],\n});\n\nfunction markArriving(node: MarkdownElement): void {\n const classes = node.properties.className;\n\n node.properties.className = Array.isArray(classes) ? [...classes, ARRIVING] : [ARRIVING];\n}\n\nfunction rebuild(nodes: MarkdownChild[], arriving: () => boolean): MarkdownChild[] {\n const out: MarkdownChild[] = [];\n\n for (const node of nodes) {\n if (node.type === 'text') {\n for (const piece of node.value.match(/\\S+|\\s+/g) ?? []) {\n if (/\\S/.test(piece)) out.push(wrap(piece, arriving()));\n else out.push({ type: 'text', value: piece });\n }\n\n continue;\n }\n\n out.push(node);\n\n if (node.type !== 'element') continue;\n\n if (!UNBROKEN.has(node.tagName)) node.children = rebuild(node.children, arriving);\n else if (arriving()) markArriving(node);\n }\n\n return out;\n}\n\n/**\n * Gives every word of a block an element of its own, and the entrance class to\n * those past the first `settled` — the words that were not on screen yet when\n * the reader joined this reply.\n *\n * Every word, not just the arriving ones: react-markdown parses afresh on each\n * landing and React matches the children it already mounted by position, so a\n * wrapper that came and went would land where a bare text node used to be and\n * remount half the paragraph, replaying entrances that had long finished.\n * Wrapping the lot keeps every position fixed — a new word only ever appends —\n * and a word never gains the class it did not mount with, so nothing replays.\n */\nexport function rehypeArriving(settled: number) {\n return function attach() {\n return (tree: { children: MarkdownChild[] }) => {\n let word = 0;\n\n tree.children = rebuild(tree.children, () => word++ >= settled);\n };\n };\n}\n","const FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})/;\nconst FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})[ \\t]*$/;\nconst LIST_ITEM = /^ {0,3}(?:[-*+]|\\d{1,9}[.)])(?:[ \\t]|$)/;\nconst INDENTED = /^(?:\\t| {2,})/;\nconst DEFINITION = /^ {0,3}\\[[^\\]]+\\]:/;\n\nfunction fenceOpenedBy(line: string): string | undefined {\n return FENCE_OPEN.exec(line)?.[1];\n}\n\n// Both are runs of one character, so `startsWith` is \"same marker, at least as long\".\nfunction closesFence(line: string, marker: string): boolean {\n return FENCE_CLOSE.exec(line)?.[1]?.startsWith(marker) ?? false;\n}\n\nfunction startsBlock(line: string, inList: boolean): boolean {\n if (INDENTED.test(line)) return false;\n\n return !(inList && LIST_ITEM.test(line));\n}\n\n/**\n * Cuts markdown into top-level blocks so a growing reply re-parses its last\n * block instead of all of them. Rejoining the result returns the input, and\n * every block renders as it would have inside the whole.\n *\n * Each rule only ever merges: over-merging costs a re-parse, while cutting a\n * construct in two changes what it renders as. Link reference and footnote\n * definitions resolve across blank lines, which no line-level rule can see, so\n * reaching one outside a fence abandons the split for the whole text.\n */\nexport function splitBlocks(markdown: string): string[] {\n const lines = markdown.split('\\n');\n const starts = [0];\n let fence: string | undefined;\n let started = false;\n let broken = false;\n let inList = false;\n\n for (const [index, line] of lines.entries()) {\n if (fence) {\n if (closesFence(line, fence)) fence = undefined;\n continue;\n }\n\n if (line.trim() === '') {\n broken = started;\n continue;\n }\n\n if (DEFINITION.test(line)) return [markdown];\n\n if (broken && startsBlock(line, inList)) {\n starts.push(index);\n started = false;\n }\n\n if (!started) inList = LIST_ITEM.test(line);\n\n started = true;\n broken = false;\n fence = fenceOpenedBy(line);\n }\n\n return starts.map((start, position) => {\n const end = starts[position + 1];\n const block = lines.slice(start, end ?? lines.length).join('\\n');\n\n return end === undefined ? block : `${block}\\n`;\n });\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\n/** How much of the reply the reveal aims to be holding back, as time at the speed it is playing. */\nconst BUFFER_MS = 1000;\n\n/** How long it takes to work off a buffer that is too full or too empty. */\nconst CORRECT_MS = 1000;\n\n/** How long a word keeps counting towards the speed the reply is arriving at. */\nconst FLOW_MS = 700;\n\n/** How long the reveal takes to adopt a new speed, so a change of pace is never a jolt. */\nconst EASE_MS = 400;\n\n/** Words per second it will not go below: a short burst between two tool calls still reads briskly. */\nconst SLOWEST = 10;\n\n/** Words per second it will not go past: one word a frame, all a screen can draw. */\nconst FASTEST = 60;\n\n/** Words it will never fall further behind than — about five seconds at full speed. */\nconst MAX_LAG = 300;\n\n/** Words a reply already holds on its first render, which it joins rather than retypes. */\nconst LEAD_IN = 12;\n\ninterface Flow {\n /** Words per second the reply is arriving at, as an exponential average. */\n rate: number;\n at: number;\n}\n\n/** Decays what earlier words still count for, then deposits the ones that just arrived. */\nfunction measure(flow: Flow, now: number, gained: number): number {\n flow.rate = flow.rate * Math.exp(-(now - flow.at) / FLOW_MS) + gained / (FLOW_MS / 1000);\n flow.at = now;\n\n return flow.rate;\n}\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Where the reveal can cut the text: before the first word, then after each one. */\nfunction wordStops(text: string): number[] {\n const stops = [0];\n const word = /\\S+/g;\n\n for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);\n\n return stops;\n}\n\n/**\n * A jitter buffer for a streamed reply, counted in words. Chunks reach the\n * browser unevenly — a proxy flushes, a tool call ends, the model changes pace —\n * and drawing each one on arrival makes a reply lurch: ten words at once, then\n * nothing for a fifth of a second.\n *\n * So the reveal runs on its own clock: a frame loop that chunks never interrupt,\n * laying down at most one word per frame however far behind it is. It plays at\n * the speed the reply is arriving at, measured directly, and leans on that only\n * to work the buffer back to `BUFFER_MS` of held text when it drifts. Measuring\n * the speed rather than inferring it from the buffer is what lets the buffer stay\n * shallow: a reply that lasts two seconds still finds its pace in the first few\n * hundred milliseconds, where a deeper buffer would spend the whole reply filling\n * and then sprint to catch up.\n *\n * Nothing here reads `streaming` past the first render: a reply that stops\n * arriving is one whose measured speed decays, which winds the buffer down on its\n * own. Words, not characters, are what a reader sees land, and they are not the\n * same length: an even flow of characters still drops \"and if we do\" in one frame\n * and spends four on \"implementation\".\n */\nexport function useReveal(text: string, streaming: boolean): string {\n const [calm] = useState(prefersReducedMotion);\n const stops = useMemo(() => wordStops(text), [text]);\n const words = stops.length - 1;\n\n const [landed, setLanded] = useState(() => (streaming && !calm ? Math.max(0, words - LEAD_IN) : words));\n\n // Winds the cursor back when a shorter reply replaces the one on screen, which\n // no key can express: same element, same message, new text.\n const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));\n if (shown !== landed) setLanded(shown);\n\n const chasing = shown < words;\n const goal = useRef(words);\n const cursor = useRef(shown);\n const flow = useRef<Flow>({ rate: 0, at: 0 });\n const pace = useRef(SLOWEST);\n\n useEffect(() => {\n measure(flow.current, performance.now(), Math.max(0, words - goal.current));\n goal.current = words;\n\n if (cursor.current < shown || cursor.current > words) cursor.current = shown;\n });\n\n useEffect(() => {\n if (!chasing) return;\n\n let drawn = performance.now();\n let frame = requestAnimationFrame(function step(now) {\n const elapsed = now - drawn;\n drawn = now;\n\n const arriving = measure(flow.current, now, 0);\n const from = cursor.current;\n const behind = goal.current - from;\n\n if (behind > 0) {\n const held = (arriving * BUFFER_MS) / 1000;\n const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + ((behind - held) * 1000) / CORRECT_MS));\n\n pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);\n cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + (elapsed * pace.current) / 1000);\n\n if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));\n }\n\n frame = requestAnimationFrame(step);\n });\n\n return () => cancelAnimationFrame(frame);\n }, [chasing]);\n\n if (!chasing) return text;\n\n return text.slice(0, stops[shown]);\n}\n","import { memo, useMemo, useState } from 'react';\nimport type { MouseEvent, MouseEventHandler, ReactNode } from 'react';\nimport Markdown from 'react-markdown';\nimport type { Components, ExtraProps, Options } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remend from 'remend';\n\nimport { rehypeArriving } from './arriving';\nimport { splitBlocks } from './blocks';\nimport { useReveal } from './use-reveal';\nimport { CodeBlock } from '@/ds/components/CodeBlock';\nimport { cn } from '@/lib/utils';\n\nimport './markdown-renderer.css';\n\nexport type MarkdownExternalLinkTarget = 'tab' | 'window';\n\nexport interface MarkdownRendererProps {\n children: string;\n className?: string;\n externalLinkTarget?: MarkdownExternalLinkTarget;\n /** The text is still being written: reveal it at a steady pace, word by word. */\n streaming?: boolean;\n}\n\n/**\n * Renders a markdown string. Agent output can carry attacker-influenced text\n * (file contents, tool output, web pages): react-markdown escapes raw HTML and\n * drops dangerous link schemes, so nothing here reaches the DOM as markup.\n *\n * react-markdown re-parses on every render, and a streaming reply re-renders\n * its whole transcript on every delta. Memoizing spares the settled messages;\n * rendering block by block — streaming or not — spares every block of the live\n * one but the last, and lets a reply settle without remounting what is already\n * on screen.\n *\n * A streamed reply is paced here rather than by the caller, so the text a block\n * parses and the text a reader sees are one and the same string. Only what lands\n * after the reader joined plays an entrance: a reply opened part-written is\n * already there, and fading in what someone is halfway through reading would be\n * both a lie and a screenful of animations at once.\n */\nexport const MarkdownRenderer = memo(function MarkdownRenderer({\n children,\n className,\n externalLinkTarget = 'tab',\n streaming = false,\n}: MarkdownRendererProps) {\n const full = decodeEscapedNewlines(children);\n const shown = useReveal(full, streaming);\n const blocks = useMemo(() => splitBlocks(shown), [shown]);\n const last = blocks.length - 1;\n const components = externalLinkTarget === 'window' ? WINDOW_COMPONENTS : COMPONENTS;\n const growing = streaming || shown !== full;\n\n const [joined] = useState(() =>\n streaming ? { blocks: blocks.length, words: countWords(blocks[last] ?? '') } : undefined,\n );\n\n // What a block held when the reader joined, and so never animates. A block\n // already whole by then holds all of itself, which is what `undefined` says:\n // leave it as plain text, no spans at all. Position decides it, so it never\n // changes under a word — and counting the source counts its markers too, so\n // the boundary only ever errs towards leaving a word unanimated.\n const settledWords = (index: number): number | undefined => {\n if (!joined || index < joined.blocks - 1) return undefined;\n\n return index === joined.blocks - 1 ? joined.words : 0;\n };\n\n const tail = blocks[last] ?? '';\n const mended = useMemo(() => (growing ? remend(tail, REMEND_OPTIONS) : tail), [growing, tail]);\n\n return (\n <div className={cn('mastra-markdown', className)}>\n {blocks.map((block, index) => (\n <MarkdownBlock\n key={index}\n content={index === last ? mended : block}\n settledWords={settledWords(index)}\n components={components}\n />\n ))}\n </div>\n );\n});\n\n/** Keyed by position at the call site: a content key remounts on every character. */\nconst MarkdownBlock = memo(function MarkdownBlock({\n components,\n content,\n settledWords,\n}: {\n components: Components;\n content: string;\n settledWords?: number;\n}) {\n const rehypePlugins = useMemo(\n () => (settledWords === undefined ? SETTLED : [rehypeArriving(settledWords)]),\n [settledWords],\n );\n\n return (\n <Markdown remarkPlugins={REMARK_PLUGINS} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n );\n});\n\nconst SETTLED: Options['rehypePlugins'] = [];\n\nfunction countWords(text: string): number {\n return text.match(/\\S+/g)?.length ?? 0;\n}\n\n// Agent networks emit their text with literal `\\n`. Only unescape when the text\n// has no real newline, otherwise a `\"a\\nb\"` inside a code fence gets shredded.\nfunction decodeEscapedNewlines(text: string): string {\n return text.includes('\\n') ? text : text.replace(/\\\\n/g, '\\n');\n}\n\ntype MarkdownNode = NonNullable<ExtraProps['node']>;\n\nfunction languageOf(node: MarkdownNode): string | undefined {\n const classNames = node.properties.className;\n if (!Array.isArray(classNames)) return undefined;\n\n const language = classNames.find(entry => typeof entry === 'string' && entry.startsWith('language-'));\n return typeof language === 'string' ? language.slice('language-'.length) : undefined;\n}\n\nfunction fencedCode(node: MarkdownNode | undefined): { code: string; language?: string } | undefined {\n const child = node?.children.find(entry => entry.type === 'element' && entry.tagName === 'code');\n if (child?.type !== 'element') return undefined;\n\n const code = child.children.map(entry => (entry.type === 'text' ? entry.value : '')).join('');\n return { code: code.replace(/\\n$/, ''), language: languageOf(child) };\n}\n\nfunction MarkdownCodeBlock({\n node,\n children,\n className,\n}: {\n node?: MarkdownNode;\n children?: ReactNode;\n className?: string;\n}) {\n const fenced = fencedCode(node);\n if (!fenced) return <pre className={className}>{children}</pre>;\n\n return (\n <CodeBlock\n code={fenced.code}\n lang={fenced.language}\n overflow=\"scroll\"\n className={cn('my-3 bg-surface1', className)}\n copyMessage=\"Copied code to clipboard\"\n />\n );\n}\n\nconst POPUP_WINDOW_FEATURES = 'popup=yes,width=720,height=800,resizable=yes,scrollbars=yes';\n\nfunction isPlainLeftClick(event: MouseEvent): boolean {\n return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;\n}\n\nfunction markdownLink(externalLinkTarget: MarkdownExternalLinkTarget): NonNullable<Components['a']> {\n return function MarkdownLink({ href, title, children }) {\n const isExternal = /^https?:\\/\\//i.test(href ?? '');\n\n const openInPopup: MouseEventHandler<HTMLAnchorElement> = event => {\n if (!isExternal || externalLinkTarget !== 'window' || !isPlainLeftClick(event)) return;\n\n const popup = window.open(href, '_blank', POPUP_WINDOW_FEATURES);\n if (!popup) return;\n\n popup.opener = null;\n event.preventDefault();\n };\n\n return (\n <a\n href={href}\n title={title}\n onClick={openInPopup}\n target={isExternal ? '_blank' : undefined}\n rel={isExternal ? 'noopener noreferrer' : undefined}\n >\n {children}\n </a>\n );\n };\n}\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// Links stay text until their URL lands: remend's placeholder href would render\n// a live anchor to nowhere. No math is rendered here, so pairing `$$` would only\n// turn one literal into another.\nconst REMEND_OPTIONS = { katex: false, linkMode: 'text-only' } as const;\n\n// Elements are listed one by one: react-markdown also passes its `node`, which\n// React would forward to the DOM as a stray attribute. Everything else is\n// styled from markdown-renderer.css.\nconst COMPONENTS: Components = {\n pre: MarkdownCodeBlock,\n a: markdownLink('tab'),\n};\n\nconst WINDOW_COMPONENTS: Components = {\n ...COMPONENTS,\n a: markdownLink('window'),\n};\n"],"names":["useState","useMemo","useRef","useEffect","memo","MarkdownRenderer","jsx","cn","MarkdownBlock","CodeBlock"],"mappings":"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"}
1
+ {"version":3,"file":"markdown-renderer-BQXWT1q2.cjs","sources":["../src/ds/components/MarkdownRenderer/arriving.ts","../src/ds/components/MarkdownRenderer/blocks.ts","../src/ds/components/MarkdownRenderer/use-reveal.ts","../src/ds/components/MarkdownRenderer/markdown-renderer.tsx"],"sourcesContent":["import type { ExtraProps } from 'react-markdown';\n\ntype MarkdownElement = NonNullable<ExtraProps['node']>;\ntype MarkdownChild = MarkdownElement['children'][number];\n\nconst ARRIVING = 'mastra-markdown-arriving';\n\n/** Fades whole: a fence renders through `CodeBlock`, and inline code carries a background. */\nconst UNBROKEN = new Set(['pre', 'code']);\n\nconst wrap = (value: string, arriving: boolean): MarkdownChild => ({\n type: 'element',\n tagName: 'span',\n properties: arriving ? { className: [ARRIVING] } : {},\n children: [{ type: 'text', value }],\n});\n\nfunction markArriving(node: MarkdownElement): void {\n const classes = node.properties.className;\n\n node.properties.className = Array.isArray(classes) ? [...classes, ARRIVING] : [ARRIVING];\n}\n\nfunction rebuild(nodes: MarkdownChild[], arriving: () => boolean): MarkdownChild[] {\n const out: MarkdownChild[] = [];\n\n for (const node of nodes) {\n if (node.type === 'text') {\n for (const piece of node.value.match(/\\S+|\\s+/g) ?? []) {\n if (/\\S/.test(piece)) out.push(wrap(piece, arriving()));\n else out.push({ type: 'text', value: piece });\n }\n\n continue;\n }\n\n out.push(node);\n\n if (node.type !== 'element') continue;\n\n if (!UNBROKEN.has(node.tagName)) node.children = rebuild(node.children, arriving);\n else if (arriving()) markArriving(node);\n }\n\n return out;\n}\n\n/**\n * Gives every word of a block an element of its own, and the entrance class to\n * those past the first `settled` — the words that were not on screen yet when\n * the reader joined this reply.\n *\n * Every word, not just the arriving ones: react-markdown parses afresh on each\n * landing and React matches the children it already mounted by position, so a\n * wrapper that came and went would land where a bare text node used to be and\n * remount half the paragraph, replaying entrances that had long finished.\n * Wrapping the lot keeps every position fixed — a new word only ever appends —\n * and a word never gains the class it did not mount with, so nothing replays.\n */\nexport function rehypeArriving(settled: number) {\n return function attach() {\n return (tree: { children: MarkdownChild[] }) => {\n let word = 0;\n\n tree.children = rebuild(tree.children, () => word++ >= settled);\n };\n };\n}\n","const FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})/;\nconst FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})[ \\t]*$/;\nconst LIST_ITEM = /^ {0,3}(?:[-*+]|\\d{1,9}[.)])(?:[ \\t]|$)/;\nconst INDENTED = /^(?:\\t| {2,})/;\nconst DEFINITION = /^ {0,3}\\[[^\\]]+\\]:/;\n\nfunction fenceOpenedBy(line: string): string | undefined {\n return FENCE_OPEN.exec(line)?.[1];\n}\n\n// Both are runs of one character, so `startsWith` is \"same marker, at least as long\".\nfunction closesFence(line: string, marker: string): boolean {\n return FENCE_CLOSE.exec(line)?.[1]?.startsWith(marker) ?? false;\n}\n\nfunction startsBlock(line: string, inList: boolean): boolean {\n if (INDENTED.test(line)) return false;\n\n return !(inList && LIST_ITEM.test(line));\n}\n\n/**\n * Cuts markdown into top-level blocks so a growing reply re-parses its last\n * block instead of all of them. Rejoining the result returns the input, and\n * every block renders as it would have inside the whole.\n *\n * Each rule only ever merges: over-merging costs a re-parse, while cutting a\n * construct in two changes what it renders as. Link reference and footnote\n * definitions resolve across blank lines, which no line-level rule can see, so\n * reaching one outside a fence abandons the split for the whole text.\n */\nexport function splitBlocks(markdown: string): string[] {\n const lines = markdown.split('\\n');\n const starts = [0];\n let fence: string | undefined;\n let started = false;\n let broken = false;\n let inList = false;\n\n for (const [index, line] of lines.entries()) {\n if (fence) {\n if (closesFence(line, fence)) fence = undefined;\n continue;\n }\n\n if (line.trim() === '') {\n broken = started;\n continue;\n }\n\n if (DEFINITION.test(line)) return [markdown];\n\n if (broken && startsBlock(line, inList)) {\n starts.push(index);\n started = false;\n }\n\n if (!started) inList = LIST_ITEM.test(line);\n\n started = true;\n broken = false;\n fence = fenceOpenedBy(line);\n }\n\n return starts.map((start, position) => {\n const end = starts[position + 1];\n const block = lines.slice(start, end ?? lines.length).join('\\n');\n\n return end === undefined ? block : `${block}\\n`;\n });\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\n/** How much of the reply the reveal aims to be holding back, as time at the speed it is playing. */\nconst BUFFER_MS = 1000;\n\n/** How long it takes to work off a buffer that is too full or too empty. */\nconst CORRECT_MS = 1000;\n\n/** How long a word keeps counting towards the speed the reply is arriving at. */\nconst FLOW_MS = 700;\n\n/** How long the reveal takes to adopt a new speed, so a change of pace is never a jolt. */\nconst EASE_MS = 400;\n\n/** Words per second it will not go below: a short burst between two tool calls still reads briskly. */\nconst SLOWEST = 10;\n\n/** Words per second it will not go past: one word a frame, all a screen can draw. */\nconst FASTEST = 60;\n\n/** Words it will never fall further behind than — about five seconds at full speed. */\nconst MAX_LAG = 300;\n\n/** Words a reply already holds on its first render, which it joins rather than retypes. */\nconst LEAD_IN = 12;\n\ninterface Flow {\n /** Words per second the reply is arriving at, as an exponential average. */\n rate: number;\n at: number;\n}\n\n/** Decays what earlier words still count for, then deposits the ones that just arrived. */\nfunction measure(flow: Flow, now: number, gained: number): number {\n flow.rate = flow.rate * Math.exp(-(now - flow.at) / FLOW_MS) + gained / (FLOW_MS / 1000);\n flow.at = now;\n\n return flow.rate;\n}\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Where the reveal can cut the text: before the first word, then after each one. */\nfunction wordStops(text: string): number[] {\n const stops = [0];\n const word = /\\S+/g;\n\n for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);\n\n return stops;\n}\n\n/**\n * A jitter buffer for a streamed reply, counted in words. Chunks reach the\n * browser unevenly — a proxy flushes, a tool call ends, the model changes pace —\n * and drawing each one on arrival makes a reply lurch: ten words at once, then\n * nothing for a fifth of a second.\n *\n * So the reveal runs on its own clock: a frame loop that chunks never interrupt,\n * laying down at most one word per frame however far behind it is. It plays at\n * the speed the reply is arriving at, measured directly, and leans on that only\n * to work the buffer back to `BUFFER_MS` of held text when it drifts. Measuring\n * the speed rather than inferring it from the buffer is what lets the buffer stay\n * shallow: a reply that lasts two seconds still finds its pace in the first few\n * hundred milliseconds, where a deeper buffer would spend the whole reply filling\n * and then sprint to catch up.\n *\n * Nothing here reads `streaming` past the first render: a reply that stops\n * arriving is one whose measured speed decays, which winds the buffer down on its\n * own. Words, not characters, are what a reader sees land, and they are not the\n * same length: an even flow of characters still drops \"and if we do\" in one frame\n * and spends four on \"implementation\".\n */\nexport function useReveal(text: string, streaming: boolean): string {\n const [calm] = useState(prefersReducedMotion);\n const stops = useMemo(() => wordStops(text), [text]);\n const words = stops.length - 1;\n\n const [landed, setLanded] = useState(() => (streaming && !calm ? Math.max(0, words - LEAD_IN) : words));\n\n // Winds the cursor back when a shorter reply replaces the one on screen, which\n // no key can express: same element, same message, new text.\n const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));\n if (shown !== landed) setLanded(shown);\n\n const chasing = shown < words;\n const goal = useRef(words);\n const cursor = useRef(shown);\n const flow = useRef<Flow>({ rate: 0, at: 0 });\n const pace = useRef(SLOWEST);\n\n useEffect(() => {\n measure(flow.current, performance.now(), Math.max(0, words - goal.current));\n goal.current = words;\n\n if (cursor.current < shown || cursor.current > words) cursor.current = shown;\n });\n\n useEffect(() => {\n if (!chasing) return;\n\n let drawn = performance.now();\n let frame = requestAnimationFrame(function step(now) {\n const elapsed = now - drawn;\n drawn = now;\n\n const arriving = measure(flow.current, now, 0);\n const from = cursor.current;\n const behind = goal.current - from;\n\n if (behind > 0) {\n const held = (arriving * BUFFER_MS) / 1000;\n const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + ((behind - held) * 1000) / CORRECT_MS));\n\n pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);\n cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + (elapsed * pace.current) / 1000);\n\n if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));\n }\n\n frame = requestAnimationFrame(step);\n });\n\n return () => cancelAnimationFrame(frame);\n }, [chasing]);\n\n if (!chasing) return text;\n\n return text.slice(0, stops[shown]);\n}\n","import { memo, useMemo, useState } from 'react';\nimport type { MouseEvent, MouseEventHandler, ReactNode } from 'react';\nimport Markdown from 'react-markdown';\nimport type { Components, ExtraProps, Options } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remend from 'remend';\n\nimport { rehypeArriving } from './arriving';\nimport { splitBlocks } from './blocks';\nimport { useReveal } from './use-reveal';\nimport { CodeBlock } from '@/ds/components/CodeBlock';\nimport { cn } from '@/lib/utils';\n\nimport './markdown-renderer.css';\n\nexport type MarkdownExternalLinkTarget = 'tab' | 'window';\n\nexport interface MarkdownRendererProps {\n children: string;\n className?: string;\n externalLinkTarget?: MarkdownExternalLinkTarget;\n /** The text is still being written: reveal it at a steady pace, word by word. */\n streaming?: boolean;\n}\n\n/**\n * Renders a markdown string. Agent output can carry attacker-influenced text\n * (file contents, tool output, web pages): react-markdown escapes raw HTML and\n * drops dangerous link schemes, so nothing here reaches the DOM as markup.\n *\n * react-markdown re-parses on every render, and a streaming reply re-renders\n * its whole transcript on every delta. Memoizing spares the settled messages;\n * rendering block by block — streaming or not — spares every block of the live\n * one but the last, and lets a reply settle without remounting what is already\n * on screen.\n *\n * A streamed reply is paced here rather than by the caller, so the text a block\n * parses and the text a reader sees are one and the same string. Only what lands\n * after the reader joined plays an entrance: a reply opened part-written is\n * already there, and fading in what someone is halfway through reading would be\n * both a lie and a screenful of animations at once.\n */\nexport const MarkdownRenderer = memo(function MarkdownRenderer({\n children,\n className,\n externalLinkTarget = 'tab',\n streaming = false,\n}: MarkdownRendererProps) {\n const full = decodeEscapedNewlines(children);\n const shown = useReveal(full, streaming);\n const blocks = useMemo(() => splitBlocks(shown), [shown]);\n const last = blocks.length - 1;\n const components = externalLinkTarget === 'window' ? WINDOW_COMPONENTS : COMPONENTS;\n const growing = streaming || shown !== full;\n\n const [joined] = useState(() =>\n streaming ? { blocks: blocks.length, words: countWords(blocks[last] ?? '') } : undefined,\n );\n\n // What a block held when the reader joined, and so never animates. A block\n // already whole by then holds all of itself, which is what `undefined` says:\n // leave it as plain text, no spans at all. Position decides it, so it never\n // changes under a word — and counting the source counts its markers too, so\n // the boundary only ever errs towards leaving a word unanimated.\n const settledWords = (index: number): number | undefined => {\n if (!joined || index < joined.blocks - 1) return undefined;\n\n return index === joined.blocks - 1 ? joined.words : 0;\n };\n\n const tail = blocks[last] ?? '';\n const mended = useMemo(() => (growing ? remend(tail, REMEND_OPTIONS) : tail), [growing, tail]);\n\n return (\n <div className={cn('mastra-markdown', className)}>\n {blocks.map((block, index) => (\n <MarkdownBlock\n key={index}\n content={index === last ? mended : block}\n settledWords={settledWords(index)}\n components={components}\n />\n ))}\n </div>\n );\n});\n\n/** Keyed by position at the call site: a content key remounts on every character. */\nconst MarkdownBlock = memo(function MarkdownBlock({\n components,\n content,\n settledWords,\n}: {\n components: Components;\n content: string;\n settledWords?: number;\n}) {\n const rehypePlugins = useMemo(\n () => (settledWords === undefined ? SETTLED : [rehypeArriving(settledWords)]),\n [settledWords],\n );\n\n return (\n <Markdown remarkPlugins={REMARK_PLUGINS} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n );\n});\n\nconst SETTLED: Options['rehypePlugins'] = [];\n\nfunction countWords(text: string): number {\n return text.match(/\\S+/g)?.length ?? 0;\n}\n\n// Agent networks emit their text with literal `\\n`. Only unescape when the text\n// has no real newline, otherwise a `\"a\\nb\"` inside a code fence gets shredded.\nfunction decodeEscapedNewlines(text: string): string {\n return text.includes('\\n') ? text : text.replace(/\\\\n/g, '\\n');\n}\n\ntype MarkdownNode = NonNullable<ExtraProps['node']>;\n\nfunction languageOf(node: MarkdownNode): string | undefined {\n const classNames = node.properties.className;\n if (!Array.isArray(classNames)) return undefined;\n\n const language = classNames.find(entry => typeof entry === 'string' && entry.startsWith('language-'));\n return typeof language === 'string' ? language.slice('language-'.length) : undefined;\n}\n\nfunction fencedCode(node: MarkdownNode | undefined): { code: string; language?: string } | undefined {\n const child = node?.children.find(entry => entry.type === 'element' && entry.tagName === 'code');\n if (child?.type !== 'element') return undefined;\n\n const code = child.children.map(entry => (entry.type === 'text' ? entry.value : '')).join('');\n return { code: code.replace(/\\n$/, ''), language: languageOf(child) };\n}\n\nfunction MarkdownCodeBlock({\n node,\n children,\n className,\n}: {\n node?: MarkdownNode;\n children?: ReactNode;\n className?: string;\n}) {\n const fenced = fencedCode(node);\n if (!fenced) return <pre className={className}>{children}</pre>;\n\n return (\n <CodeBlock\n code={fenced.code}\n lang={fenced.language}\n overflow=\"scroll\"\n className={cn('my-3 bg-surface1', className)}\n copyMessage=\"Copied code to clipboard\"\n />\n );\n}\n\nconst POPUP_WINDOW_FEATURES = 'popup=yes,width=720,height=800,resizable=yes,scrollbars=yes';\n\nfunction isPlainLeftClick(event: MouseEvent): boolean {\n return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;\n}\n\nfunction markdownLink(externalLinkTarget: MarkdownExternalLinkTarget): NonNullable<Components['a']> {\n return function MarkdownLink({ href, title, children }) {\n const isExternal = /^https?:\\/\\//i.test(href ?? '');\n\n const openInPopup: MouseEventHandler<HTMLAnchorElement> = event => {\n if (!isExternal || externalLinkTarget !== 'window' || !isPlainLeftClick(event)) return;\n\n const popup = window.open(href, '_blank', POPUP_WINDOW_FEATURES);\n if (!popup) return;\n\n popup.opener = null;\n event.preventDefault();\n };\n\n return (\n <a\n href={href}\n title={title}\n onClick={openInPopup}\n target={isExternal ? '_blank' : undefined}\n rel={isExternal ? 'noopener noreferrer' : undefined}\n >\n {children}\n </a>\n );\n };\n}\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// Links stay text until their URL lands: remend's placeholder href would render\n// a live anchor to nowhere. No math is rendered here, so pairing `$$` would only\n// turn one literal into another.\nconst REMEND_OPTIONS = { katex: false, linkMode: 'text-only' } as const;\n\n// Elements are listed one by one: react-markdown also passes its `node`, which\n// React would forward to the DOM as a stray attribute. Everything else is\n// styled from markdown-renderer.css.\nconst COMPONENTS: Components = {\n pre: MarkdownCodeBlock,\n a: markdownLink('tab'),\n};\n\nconst WINDOW_COMPONENTS: Components = {\n ...COMPONENTS,\n a: markdownLink('window'),\n};\n"],"names":["useState","useMemo","useRef","useEffect","memo","MarkdownRenderer","jsx","cn","MarkdownBlock","CodeBlock"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { useState, useMemo, useRef, useEffect, memo } from 'react';
3
3
  import Markdown from 'react-markdown';
4
4
  import remarkGfm from 'remark-gfm';
5
5
  import remend from 'remend';
6
- import { C as CodeBlock } from './code-block-DR6-quU0.js';
6
+ import { C as CodeBlock } from './code-block-CA9sa6yS.js';
7
7
  import { c as cn } from './cn-BakJzhuv.js';
8
8
 
9
9
  import './markdown-renderer.css';const ARRIVING = "mastra-markdown-arriving";
@@ -275,4 +275,4 @@ const WINDOW_COMPONENTS = {
275
275
  };
276
276
 
277
277
  export { MarkdownRenderer as M };
278
- //# sourceMappingURL=markdown-renderer-ByRLqDFg.js.map
278
+ //# sourceMappingURL=markdown-renderer-CrCIi6au.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown-renderer-ByRLqDFg.js","sources":["../src/ds/components/MarkdownRenderer/arriving.ts","../src/ds/components/MarkdownRenderer/blocks.ts","../src/ds/components/MarkdownRenderer/use-reveal.ts","../src/ds/components/MarkdownRenderer/markdown-renderer.tsx"],"sourcesContent":["import type { ExtraProps } from 'react-markdown';\n\ntype MarkdownElement = NonNullable<ExtraProps['node']>;\ntype MarkdownChild = MarkdownElement['children'][number];\n\nconst ARRIVING = 'mastra-markdown-arriving';\n\n/** Fades whole: a fence renders through `CodeBlock`, and inline code carries a background. */\nconst UNBROKEN = new Set(['pre', 'code']);\n\nconst wrap = (value: string, arriving: boolean): MarkdownChild => ({\n type: 'element',\n tagName: 'span',\n properties: arriving ? { className: [ARRIVING] } : {},\n children: [{ type: 'text', value }],\n});\n\nfunction markArriving(node: MarkdownElement): void {\n const classes = node.properties.className;\n\n node.properties.className = Array.isArray(classes) ? [...classes, ARRIVING] : [ARRIVING];\n}\n\nfunction rebuild(nodes: MarkdownChild[], arriving: () => boolean): MarkdownChild[] {\n const out: MarkdownChild[] = [];\n\n for (const node of nodes) {\n if (node.type === 'text') {\n for (const piece of node.value.match(/\\S+|\\s+/g) ?? []) {\n if (/\\S/.test(piece)) out.push(wrap(piece, arriving()));\n else out.push({ type: 'text', value: piece });\n }\n\n continue;\n }\n\n out.push(node);\n\n if (node.type !== 'element') continue;\n\n if (!UNBROKEN.has(node.tagName)) node.children = rebuild(node.children, arriving);\n else if (arriving()) markArriving(node);\n }\n\n return out;\n}\n\n/**\n * Gives every word of a block an element of its own, and the entrance class to\n * those past the first `settled` — the words that were not on screen yet when\n * the reader joined this reply.\n *\n * Every word, not just the arriving ones: react-markdown parses afresh on each\n * landing and React matches the children it already mounted by position, so a\n * wrapper that came and went would land where a bare text node used to be and\n * remount half the paragraph, replaying entrances that had long finished.\n * Wrapping the lot keeps every position fixed — a new word only ever appends —\n * and a word never gains the class it did not mount with, so nothing replays.\n */\nexport function rehypeArriving(settled: number) {\n return function attach() {\n return (tree: { children: MarkdownChild[] }) => {\n let word = 0;\n\n tree.children = rebuild(tree.children, () => word++ >= settled);\n };\n };\n}\n","const FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})/;\nconst FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})[ \\t]*$/;\nconst LIST_ITEM = /^ {0,3}(?:[-*+]|\\d{1,9}[.)])(?:[ \\t]|$)/;\nconst INDENTED = /^(?:\\t| {2,})/;\nconst DEFINITION = /^ {0,3}\\[[^\\]]+\\]:/;\n\nfunction fenceOpenedBy(line: string): string | undefined {\n return FENCE_OPEN.exec(line)?.[1];\n}\n\n// Both are runs of one character, so `startsWith` is \"same marker, at least as long\".\nfunction closesFence(line: string, marker: string): boolean {\n return FENCE_CLOSE.exec(line)?.[1]?.startsWith(marker) ?? false;\n}\n\nfunction startsBlock(line: string, inList: boolean): boolean {\n if (INDENTED.test(line)) return false;\n\n return !(inList && LIST_ITEM.test(line));\n}\n\n/**\n * Cuts markdown into top-level blocks so a growing reply re-parses its last\n * block instead of all of them. Rejoining the result returns the input, and\n * every block renders as it would have inside the whole.\n *\n * Each rule only ever merges: over-merging costs a re-parse, while cutting a\n * construct in two changes what it renders as. Link reference and footnote\n * definitions resolve across blank lines, which no line-level rule can see, so\n * reaching one outside a fence abandons the split for the whole text.\n */\nexport function splitBlocks(markdown: string): string[] {\n const lines = markdown.split('\\n');\n const starts = [0];\n let fence: string | undefined;\n let started = false;\n let broken = false;\n let inList = false;\n\n for (const [index, line] of lines.entries()) {\n if (fence) {\n if (closesFence(line, fence)) fence = undefined;\n continue;\n }\n\n if (line.trim() === '') {\n broken = started;\n continue;\n }\n\n if (DEFINITION.test(line)) return [markdown];\n\n if (broken && startsBlock(line, inList)) {\n starts.push(index);\n started = false;\n }\n\n if (!started) inList = LIST_ITEM.test(line);\n\n started = true;\n broken = false;\n fence = fenceOpenedBy(line);\n }\n\n return starts.map((start, position) => {\n const end = starts[position + 1];\n const block = lines.slice(start, end ?? lines.length).join('\\n');\n\n return end === undefined ? block : `${block}\\n`;\n });\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\n/** How much of the reply the reveal aims to be holding back, as time at the speed it is playing. */\nconst BUFFER_MS = 1000;\n\n/** How long it takes to work off a buffer that is too full or too empty. */\nconst CORRECT_MS = 1000;\n\n/** How long a word keeps counting towards the speed the reply is arriving at. */\nconst FLOW_MS = 700;\n\n/** How long the reveal takes to adopt a new speed, so a change of pace is never a jolt. */\nconst EASE_MS = 400;\n\n/** Words per second it will not go below: a short burst between two tool calls still reads briskly. */\nconst SLOWEST = 10;\n\n/** Words per second it will not go past: one word a frame, all a screen can draw. */\nconst FASTEST = 60;\n\n/** Words it will never fall further behind than — about five seconds at full speed. */\nconst MAX_LAG = 300;\n\n/** Words a reply already holds on its first render, which it joins rather than retypes. */\nconst LEAD_IN = 12;\n\ninterface Flow {\n /** Words per second the reply is arriving at, as an exponential average. */\n rate: number;\n at: number;\n}\n\n/** Decays what earlier words still count for, then deposits the ones that just arrived. */\nfunction measure(flow: Flow, now: number, gained: number): number {\n flow.rate = flow.rate * Math.exp(-(now - flow.at) / FLOW_MS) + gained / (FLOW_MS / 1000);\n flow.at = now;\n\n return flow.rate;\n}\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Where the reveal can cut the text: before the first word, then after each one. */\nfunction wordStops(text: string): number[] {\n const stops = [0];\n const word = /\\S+/g;\n\n for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);\n\n return stops;\n}\n\n/**\n * A jitter buffer for a streamed reply, counted in words. Chunks reach the\n * browser unevenly — a proxy flushes, a tool call ends, the model changes pace —\n * and drawing each one on arrival makes a reply lurch: ten words at once, then\n * nothing for a fifth of a second.\n *\n * So the reveal runs on its own clock: a frame loop that chunks never interrupt,\n * laying down at most one word per frame however far behind it is. It plays at\n * the speed the reply is arriving at, measured directly, and leans on that only\n * to work the buffer back to `BUFFER_MS` of held text when it drifts. Measuring\n * the speed rather than inferring it from the buffer is what lets the buffer stay\n * shallow: a reply that lasts two seconds still finds its pace in the first few\n * hundred milliseconds, where a deeper buffer would spend the whole reply filling\n * and then sprint to catch up.\n *\n * Nothing here reads `streaming` past the first render: a reply that stops\n * arriving is one whose measured speed decays, which winds the buffer down on its\n * own. Words, not characters, are what a reader sees land, and they are not the\n * same length: an even flow of characters still drops \"and if we do\" in one frame\n * and spends four on \"implementation\".\n */\nexport function useReveal(text: string, streaming: boolean): string {\n const [calm] = useState(prefersReducedMotion);\n const stops = useMemo(() => wordStops(text), [text]);\n const words = stops.length - 1;\n\n const [landed, setLanded] = useState(() => (streaming && !calm ? Math.max(0, words - LEAD_IN) : words));\n\n // Winds the cursor back when a shorter reply replaces the one on screen, which\n // no key can express: same element, same message, new text.\n const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));\n if (shown !== landed) setLanded(shown);\n\n const chasing = shown < words;\n const goal = useRef(words);\n const cursor = useRef(shown);\n const flow = useRef<Flow>({ rate: 0, at: 0 });\n const pace = useRef(SLOWEST);\n\n useEffect(() => {\n measure(flow.current, performance.now(), Math.max(0, words - goal.current));\n goal.current = words;\n\n if (cursor.current < shown || cursor.current > words) cursor.current = shown;\n });\n\n useEffect(() => {\n if (!chasing) return;\n\n let drawn = performance.now();\n let frame = requestAnimationFrame(function step(now) {\n const elapsed = now - drawn;\n drawn = now;\n\n const arriving = measure(flow.current, now, 0);\n const from = cursor.current;\n const behind = goal.current - from;\n\n if (behind > 0) {\n const held = (arriving * BUFFER_MS) / 1000;\n const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + ((behind - held) * 1000) / CORRECT_MS));\n\n pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);\n cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + (elapsed * pace.current) / 1000);\n\n if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));\n }\n\n frame = requestAnimationFrame(step);\n });\n\n return () => cancelAnimationFrame(frame);\n }, [chasing]);\n\n if (!chasing) return text;\n\n return text.slice(0, stops[shown]);\n}\n","import { memo, useMemo, useState } from 'react';\nimport type { MouseEvent, MouseEventHandler, ReactNode } from 'react';\nimport Markdown from 'react-markdown';\nimport type { Components, ExtraProps, Options } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remend from 'remend';\n\nimport { rehypeArriving } from './arriving';\nimport { splitBlocks } from './blocks';\nimport { useReveal } from './use-reveal';\nimport { CodeBlock } from '@/ds/components/CodeBlock';\nimport { cn } from '@/lib/utils';\n\nimport './markdown-renderer.css';\n\nexport type MarkdownExternalLinkTarget = 'tab' | 'window';\n\nexport interface MarkdownRendererProps {\n children: string;\n className?: string;\n externalLinkTarget?: MarkdownExternalLinkTarget;\n /** The text is still being written: reveal it at a steady pace, word by word. */\n streaming?: boolean;\n}\n\n/**\n * Renders a markdown string. Agent output can carry attacker-influenced text\n * (file contents, tool output, web pages): react-markdown escapes raw HTML and\n * drops dangerous link schemes, so nothing here reaches the DOM as markup.\n *\n * react-markdown re-parses on every render, and a streaming reply re-renders\n * its whole transcript on every delta. Memoizing spares the settled messages;\n * rendering block by block — streaming or not — spares every block of the live\n * one but the last, and lets a reply settle without remounting what is already\n * on screen.\n *\n * A streamed reply is paced here rather than by the caller, so the text a block\n * parses and the text a reader sees are one and the same string. Only what lands\n * after the reader joined plays an entrance: a reply opened part-written is\n * already there, and fading in what someone is halfway through reading would be\n * both a lie and a screenful of animations at once.\n */\nexport const MarkdownRenderer = memo(function MarkdownRenderer({\n children,\n className,\n externalLinkTarget = 'tab',\n streaming = false,\n}: MarkdownRendererProps) {\n const full = decodeEscapedNewlines(children);\n const shown = useReveal(full, streaming);\n const blocks = useMemo(() => splitBlocks(shown), [shown]);\n const last = blocks.length - 1;\n const components = externalLinkTarget === 'window' ? WINDOW_COMPONENTS : COMPONENTS;\n const growing = streaming || shown !== full;\n\n const [joined] = useState(() =>\n streaming ? { blocks: blocks.length, words: countWords(blocks[last] ?? '') } : undefined,\n );\n\n // What a block held when the reader joined, and so never animates. A block\n // already whole by then holds all of itself, which is what `undefined` says:\n // leave it as plain text, no spans at all. Position decides it, so it never\n // changes under a word — and counting the source counts its markers too, so\n // the boundary only ever errs towards leaving a word unanimated.\n const settledWords = (index: number): number | undefined => {\n if (!joined || index < joined.blocks - 1) return undefined;\n\n return index === joined.blocks - 1 ? joined.words : 0;\n };\n\n const tail = blocks[last] ?? '';\n const mended = useMemo(() => (growing ? remend(tail, REMEND_OPTIONS) : tail), [growing, tail]);\n\n return (\n <div className={cn('mastra-markdown', className)}>\n {blocks.map((block, index) => (\n <MarkdownBlock\n key={index}\n content={index === last ? mended : block}\n settledWords={settledWords(index)}\n components={components}\n />\n ))}\n </div>\n );\n});\n\n/** Keyed by position at the call site: a content key remounts on every character. */\nconst MarkdownBlock = memo(function MarkdownBlock({\n components,\n content,\n settledWords,\n}: {\n components: Components;\n content: string;\n settledWords?: number;\n}) {\n const rehypePlugins = useMemo(\n () => (settledWords === undefined ? SETTLED : [rehypeArriving(settledWords)]),\n [settledWords],\n );\n\n return (\n <Markdown remarkPlugins={REMARK_PLUGINS} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n );\n});\n\nconst SETTLED: Options['rehypePlugins'] = [];\n\nfunction countWords(text: string): number {\n return text.match(/\\S+/g)?.length ?? 0;\n}\n\n// Agent networks emit their text with literal `\\n`. Only unescape when the text\n// has no real newline, otherwise a `\"a\\nb\"` inside a code fence gets shredded.\nfunction decodeEscapedNewlines(text: string): string {\n return text.includes('\\n') ? text : text.replace(/\\\\n/g, '\\n');\n}\n\ntype MarkdownNode = NonNullable<ExtraProps['node']>;\n\nfunction languageOf(node: MarkdownNode): string | undefined {\n const classNames = node.properties.className;\n if (!Array.isArray(classNames)) return undefined;\n\n const language = classNames.find(entry => typeof entry === 'string' && entry.startsWith('language-'));\n return typeof language === 'string' ? language.slice('language-'.length) : undefined;\n}\n\nfunction fencedCode(node: MarkdownNode | undefined): { code: string; language?: string } | undefined {\n const child = node?.children.find(entry => entry.type === 'element' && entry.tagName === 'code');\n if (child?.type !== 'element') return undefined;\n\n const code = child.children.map(entry => (entry.type === 'text' ? entry.value : '')).join('');\n return { code: code.replace(/\\n$/, ''), language: languageOf(child) };\n}\n\nfunction MarkdownCodeBlock({\n node,\n children,\n className,\n}: {\n node?: MarkdownNode;\n children?: ReactNode;\n className?: string;\n}) {\n const fenced = fencedCode(node);\n if (!fenced) return <pre className={className}>{children}</pre>;\n\n return (\n <CodeBlock\n code={fenced.code}\n lang={fenced.language}\n overflow=\"scroll\"\n className={cn('my-3 bg-surface1', className)}\n copyMessage=\"Copied code to clipboard\"\n />\n );\n}\n\nconst POPUP_WINDOW_FEATURES = 'popup=yes,width=720,height=800,resizable=yes,scrollbars=yes';\n\nfunction isPlainLeftClick(event: MouseEvent): boolean {\n return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;\n}\n\nfunction markdownLink(externalLinkTarget: MarkdownExternalLinkTarget): NonNullable<Components['a']> {\n return function MarkdownLink({ href, title, children }) {\n const isExternal = /^https?:\\/\\//i.test(href ?? '');\n\n const openInPopup: MouseEventHandler<HTMLAnchorElement> = event => {\n if (!isExternal || externalLinkTarget !== 'window' || !isPlainLeftClick(event)) return;\n\n const popup = window.open(href, '_blank', POPUP_WINDOW_FEATURES);\n if (!popup) return;\n\n popup.opener = null;\n event.preventDefault();\n };\n\n return (\n <a\n href={href}\n title={title}\n onClick={openInPopup}\n target={isExternal ? '_blank' : undefined}\n rel={isExternal ? 'noopener noreferrer' : undefined}\n >\n {children}\n </a>\n );\n };\n}\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// Links stay text until their URL lands: remend's placeholder href would render\n// a live anchor to nowhere. No math is rendered here, so pairing `$$` would only\n// turn one literal into another.\nconst REMEND_OPTIONS = { katex: false, linkMode: 'text-only' } as const;\n\n// Elements are listed one by one: react-markdown also passes its `node`, which\n// React would forward to the DOM as a stray attribute. Everything else is\n// styled from markdown-renderer.css.\nconst COMPONENTS: Components = {\n pre: MarkdownCodeBlock,\n a: markdownLink('tab'),\n};\n\nconst WINDOW_COMPONENTS: Components = {\n ...COMPONENTS,\n a: markdownLink('window'),\n};\n"],"names":["MarkdownRenderer","MarkdownBlock"],"mappings":"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"}
1
+ {"version":3,"file":"markdown-renderer-CrCIi6au.js","sources":["../src/ds/components/MarkdownRenderer/arriving.ts","../src/ds/components/MarkdownRenderer/blocks.ts","../src/ds/components/MarkdownRenderer/use-reveal.ts","../src/ds/components/MarkdownRenderer/markdown-renderer.tsx"],"sourcesContent":["import type { ExtraProps } from 'react-markdown';\n\ntype MarkdownElement = NonNullable<ExtraProps['node']>;\ntype MarkdownChild = MarkdownElement['children'][number];\n\nconst ARRIVING = 'mastra-markdown-arriving';\n\n/** Fades whole: a fence renders through `CodeBlock`, and inline code carries a background. */\nconst UNBROKEN = new Set(['pre', 'code']);\n\nconst wrap = (value: string, arriving: boolean): MarkdownChild => ({\n type: 'element',\n tagName: 'span',\n properties: arriving ? { className: [ARRIVING] } : {},\n children: [{ type: 'text', value }],\n});\n\nfunction markArriving(node: MarkdownElement): void {\n const classes = node.properties.className;\n\n node.properties.className = Array.isArray(classes) ? [...classes, ARRIVING] : [ARRIVING];\n}\n\nfunction rebuild(nodes: MarkdownChild[], arriving: () => boolean): MarkdownChild[] {\n const out: MarkdownChild[] = [];\n\n for (const node of nodes) {\n if (node.type === 'text') {\n for (const piece of node.value.match(/\\S+|\\s+/g) ?? []) {\n if (/\\S/.test(piece)) out.push(wrap(piece, arriving()));\n else out.push({ type: 'text', value: piece });\n }\n\n continue;\n }\n\n out.push(node);\n\n if (node.type !== 'element') continue;\n\n if (!UNBROKEN.has(node.tagName)) node.children = rebuild(node.children, arriving);\n else if (arriving()) markArriving(node);\n }\n\n return out;\n}\n\n/**\n * Gives every word of a block an element of its own, and the entrance class to\n * those past the first `settled` — the words that were not on screen yet when\n * the reader joined this reply.\n *\n * Every word, not just the arriving ones: react-markdown parses afresh on each\n * landing and React matches the children it already mounted by position, so a\n * wrapper that came and went would land where a bare text node used to be and\n * remount half the paragraph, replaying entrances that had long finished.\n * Wrapping the lot keeps every position fixed — a new word only ever appends —\n * and a word never gains the class it did not mount with, so nothing replays.\n */\nexport function rehypeArriving(settled: number) {\n return function attach() {\n return (tree: { children: MarkdownChild[] }) => {\n let word = 0;\n\n tree.children = rebuild(tree.children, () => word++ >= settled);\n };\n };\n}\n","const FENCE_OPEN = /^ {0,3}(`{3,}|~{3,})/;\nconst FENCE_CLOSE = /^ {0,3}(`{3,}|~{3,})[ \\t]*$/;\nconst LIST_ITEM = /^ {0,3}(?:[-*+]|\\d{1,9}[.)])(?:[ \\t]|$)/;\nconst INDENTED = /^(?:\\t| {2,})/;\nconst DEFINITION = /^ {0,3}\\[[^\\]]+\\]:/;\n\nfunction fenceOpenedBy(line: string): string | undefined {\n return FENCE_OPEN.exec(line)?.[1];\n}\n\n// Both are runs of one character, so `startsWith` is \"same marker, at least as long\".\nfunction closesFence(line: string, marker: string): boolean {\n return FENCE_CLOSE.exec(line)?.[1]?.startsWith(marker) ?? false;\n}\n\nfunction startsBlock(line: string, inList: boolean): boolean {\n if (INDENTED.test(line)) return false;\n\n return !(inList && LIST_ITEM.test(line));\n}\n\n/**\n * Cuts markdown into top-level blocks so a growing reply re-parses its last\n * block instead of all of them. Rejoining the result returns the input, and\n * every block renders as it would have inside the whole.\n *\n * Each rule only ever merges: over-merging costs a re-parse, while cutting a\n * construct in two changes what it renders as. Link reference and footnote\n * definitions resolve across blank lines, which no line-level rule can see, so\n * reaching one outside a fence abandons the split for the whole text.\n */\nexport function splitBlocks(markdown: string): string[] {\n const lines = markdown.split('\\n');\n const starts = [0];\n let fence: string | undefined;\n let started = false;\n let broken = false;\n let inList = false;\n\n for (const [index, line] of lines.entries()) {\n if (fence) {\n if (closesFence(line, fence)) fence = undefined;\n continue;\n }\n\n if (line.trim() === '') {\n broken = started;\n continue;\n }\n\n if (DEFINITION.test(line)) return [markdown];\n\n if (broken && startsBlock(line, inList)) {\n starts.push(index);\n started = false;\n }\n\n if (!started) inList = LIST_ITEM.test(line);\n\n started = true;\n broken = false;\n fence = fenceOpenedBy(line);\n }\n\n return starts.map((start, position) => {\n const end = starts[position + 1];\n const block = lines.slice(start, end ?? lines.length).join('\\n');\n\n return end === undefined ? block : `${block}\\n`;\n });\n}\n","import { useEffect, useMemo, useRef, useState } from 'react';\n\n/** How much of the reply the reveal aims to be holding back, as time at the speed it is playing. */\nconst BUFFER_MS = 1000;\n\n/** How long it takes to work off a buffer that is too full or too empty. */\nconst CORRECT_MS = 1000;\n\n/** How long a word keeps counting towards the speed the reply is arriving at. */\nconst FLOW_MS = 700;\n\n/** How long the reveal takes to adopt a new speed, so a change of pace is never a jolt. */\nconst EASE_MS = 400;\n\n/** Words per second it will not go below: a short burst between two tool calls still reads briskly. */\nconst SLOWEST = 10;\n\n/** Words per second it will not go past: one word a frame, all a screen can draw. */\nconst FASTEST = 60;\n\n/** Words it will never fall further behind than — about five seconds at full speed. */\nconst MAX_LAG = 300;\n\n/** Words a reply already holds on its first render, which it joins rather than retypes. */\nconst LEAD_IN = 12;\n\ninterface Flow {\n /** Words per second the reply is arriving at, as an exponential average. */\n rate: number;\n at: number;\n}\n\n/** Decays what earlier words still count for, then deposits the ones that just arrived. */\nfunction measure(flow: Flow, now: number, gained: number): number {\n flow.rate = flow.rate * Math.exp(-(now - flow.at) / FLOW_MS) + gained / (FLOW_MS / 1000);\n flow.at = now;\n\n return flow.rate;\n}\n\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/** Where the reveal can cut the text: before the first word, then after each one. */\nfunction wordStops(text: string): number[] {\n const stops = [0];\n const word = /\\S+/g;\n\n for (let match = word.exec(text); match; match = word.exec(text)) stops.push(match.index + match[0].length);\n\n return stops;\n}\n\n/**\n * A jitter buffer for a streamed reply, counted in words. Chunks reach the\n * browser unevenly — a proxy flushes, a tool call ends, the model changes pace —\n * and drawing each one on arrival makes a reply lurch: ten words at once, then\n * nothing for a fifth of a second.\n *\n * So the reveal runs on its own clock: a frame loop that chunks never interrupt,\n * laying down at most one word per frame however far behind it is. It plays at\n * the speed the reply is arriving at, measured directly, and leans on that only\n * to work the buffer back to `BUFFER_MS` of held text when it drifts. Measuring\n * the speed rather than inferring it from the buffer is what lets the buffer stay\n * shallow: a reply that lasts two seconds still finds its pace in the first few\n * hundred milliseconds, where a deeper buffer would spend the whole reply filling\n * and then sprint to catch up.\n *\n * Nothing here reads `streaming` past the first render: a reply that stops\n * arriving is one whose measured speed decays, which winds the buffer down on its\n * own. Words, not characters, are what a reader sees land, and they are not the\n * same length: an even flow of characters still drops \"and if we do\" in one frame\n * and spends four on \"implementation\".\n */\nexport function useReveal(text: string, streaming: boolean): string {\n const [calm] = useState(prefersReducedMotion);\n const stops = useMemo(() => wordStops(text), [text]);\n const words = stops.length - 1;\n\n const [landed, setLanded] = useState(() => (streaming && !calm ? Math.max(0, words - LEAD_IN) : words));\n\n // Winds the cursor back when a shorter reply replaces the one on screen, which\n // no key can express: same element, same message, new text.\n const shown = calm ? words : Math.min(words, Math.max(landed, words - MAX_LAG));\n if (shown !== landed) setLanded(shown);\n\n const chasing = shown < words;\n const goal = useRef(words);\n const cursor = useRef(shown);\n const flow = useRef<Flow>({ rate: 0, at: 0 });\n const pace = useRef(SLOWEST);\n\n useEffect(() => {\n measure(flow.current, performance.now(), Math.max(0, words - goal.current));\n goal.current = words;\n\n if (cursor.current < shown || cursor.current > words) cursor.current = shown;\n });\n\n useEffect(() => {\n if (!chasing) return;\n\n let drawn = performance.now();\n let frame = requestAnimationFrame(function step(now) {\n const elapsed = now - drawn;\n drawn = now;\n\n const arriving = measure(flow.current, now, 0);\n const from = cursor.current;\n const behind = goal.current - from;\n\n if (behind > 0) {\n const held = (arriving * BUFFER_MS) / 1000;\n const aim = Math.min(FASTEST, Math.max(SLOWEST, arriving + ((behind - held) * 1000) / CORRECT_MS));\n\n pace.current += (aim - pace.current) * Math.min(1, elapsed / EASE_MS);\n cursor.current = Math.min(goal.current, Math.floor(from) + 1, from + (elapsed * pace.current) / 1000);\n\n if (Math.floor(cursor.current) !== Math.floor(from)) setLanded(Math.floor(cursor.current));\n }\n\n frame = requestAnimationFrame(step);\n });\n\n return () => cancelAnimationFrame(frame);\n }, [chasing]);\n\n if (!chasing) return text;\n\n return text.slice(0, stops[shown]);\n}\n","import { memo, useMemo, useState } from 'react';\nimport type { MouseEvent, MouseEventHandler, ReactNode } from 'react';\nimport Markdown from 'react-markdown';\nimport type { Components, ExtraProps, Options } from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport remend from 'remend';\n\nimport { rehypeArriving } from './arriving';\nimport { splitBlocks } from './blocks';\nimport { useReveal } from './use-reveal';\nimport { CodeBlock } from '@/ds/components/CodeBlock';\nimport { cn } from '@/lib/utils';\n\nimport './markdown-renderer.css';\n\nexport type MarkdownExternalLinkTarget = 'tab' | 'window';\n\nexport interface MarkdownRendererProps {\n children: string;\n className?: string;\n externalLinkTarget?: MarkdownExternalLinkTarget;\n /** The text is still being written: reveal it at a steady pace, word by word. */\n streaming?: boolean;\n}\n\n/**\n * Renders a markdown string. Agent output can carry attacker-influenced text\n * (file contents, tool output, web pages): react-markdown escapes raw HTML and\n * drops dangerous link schemes, so nothing here reaches the DOM as markup.\n *\n * react-markdown re-parses on every render, and a streaming reply re-renders\n * its whole transcript on every delta. Memoizing spares the settled messages;\n * rendering block by block — streaming or not — spares every block of the live\n * one but the last, and lets a reply settle without remounting what is already\n * on screen.\n *\n * A streamed reply is paced here rather than by the caller, so the text a block\n * parses and the text a reader sees are one and the same string. Only what lands\n * after the reader joined plays an entrance: a reply opened part-written is\n * already there, and fading in what someone is halfway through reading would be\n * both a lie and a screenful of animations at once.\n */\nexport const MarkdownRenderer = memo(function MarkdownRenderer({\n children,\n className,\n externalLinkTarget = 'tab',\n streaming = false,\n}: MarkdownRendererProps) {\n const full = decodeEscapedNewlines(children);\n const shown = useReveal(full, streaming);\n const blocks = useMemo(() => splitBlocks(shown), [shown]);\n const last = blocks.length - 1;\n const components = externalLinkTarget === 'window' ? WINDOW_COMPONENTS : COMPONENTS;\n const growing = streaming || shown !== full;\n\n const [joined] = useState(() =>\n streaming ? { blocks: blocks.length, words: countWords(blocks[last] ?? '') } : undefined,\n );\n\n // What a block held when the reader joined, and so never animates. A block\n // already whole by then holds all of itself, which is what `undefined` says:\n // leave it as plain text, no spans at all. Position decides it, so it never\n // changes under a word — and counting the source counts its markers too, so\n // the boundary only ever errs towards leaving a word unanimated.\n const settledWords = (index: number): number | undefined => {\n if (!joined || index < joined.blocks - 1) return undefined;\n\n return index === joined.blocks - 1 ? joined.words : 0;\n };\n\n const tail = blocks[last] ?? '';\n const mended = useMemo(() => (growing ? remend(tail, REMEND_OPTIONS) : tail), [growing, tail]);\n\n return (\n <div className={cn('mastra-markdown', className)}>\n {blocks.map((block, index) => (\n <MarkdownBlock\n key={index}\n content={index === last ? mended : block}\n settledWords={settledWords(index)}\n components={components}\n />\n ))}\n </div>\n );\n});\n\n/** Keyed by position at the call site: a content key remounts on every character. */\nconst MarkdownBlock = memo(function MarkdownBlock({\n components,\n content,\n settledWords,\n}: {\n components: Components;\n content: string;\n settledWords?: number;\n}) {\n const rehypePlugins = useMemo(\n () => (settledWords === undefined ? SETTLED : [rehypeArriving(settledWords)]),\n [settledWords],\n );\n\n return (\n <Markdown remarkPlugins={REMARK_PLUGINS} rehypePlugins={rehypePlugins} components={components}>\n {content}\n </Markdown>\n );\n});\n\nconst SETTLED: Options['rehypePlugins'] = [];\n\nfunction countWords(text: string): number {\n return text.match(/\\S+/g)?.length ?? 0;\n}\n\n// Agent networks emit their text with literal `\\n`. Only unescape when the text\n// has no real newline, otherwise a `\"a\\nb\"` inside a code fence gets shredded.\nfunction decodeEscapedNewlines(text: string): string {\n return text.includes('\\n') ? text : text.replace(/\\\\n/g, '\\n');\n}\n\ntype MarkdownNode = NonNullable<ExtraProps['node']>;\n\nfunction languageOf(node: MarkdownNode): string | undefined {\n const classNames = node.properties.className;\n if (!Array.isArray(classNames)) return undefined;\n\n const language = classNames.find(entry => typeof entry === 'string' && entry.startsWith('language-'));\n return typeof language === 'string' ? language.slice('language-'.length) : undefined;\n}\n\nfunction fencedCode(node: MarkdownNode | undefined): { code: string; language?: string } | undefined {\n const child = node?.children.find(entry => entry.type === 'element' && entry.tagName === 'code');\n if (child?.type !== 'element') return undefined;\n\n const code = child.children.map(entry => (entry.type === 'text' ? entry.value : '')).join('');\n return { code: code.replace(/\\n$/, ''), language: languageOf(child) };\n}\n\nfunction MarkdownCodeBlock({\n node,\n children,\n className,\n}: {\n node?: MarkdownNode;\n children?: ReactNode;\n className?: string;\n}) {\n const fenced = fencedCode(node);\n if (!fenced) return <pre className={className}>{children}</pre>;\n\n return (\n <CodeBlock\n code={fenced.code}\n lang={fenced.language}\n overflow=\"scroll\"\n className={cn('my-3 bg-surface1', className)}\n copyMessage=\"Copied code to clipboard\"\n />\n );\n}\n\nconst POPUP_WINDOW_FEATURES = 'popup=yes,width=720,height=800,resizable=yes,scrollbars=yes';\n\nfunction isPlainLeftClick(event: MouseEvent): boolean {\n return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey;\n}\n\nfunction markdownLink(externalLinkTarget: MarkdownExternalLinkTarget): NonNullable<Components['a']> {\n return function MarkdownLink({ href, title, children }) {\n const isExternal = /^https?:\\/\\//i.test(href ?? '');\n\n const openInPopup: MouseEventHandler<HTMLAnchorElement> = event => {\n if (!isExternal || externalLinkTarget !== 'window' || !isPlainLeftClick(event)) return;\n\n const popup = window.open(href, '_blank', POPUP_WINDOW_FEATURES);\n if (!popup) return;\n\n popup.opener = null;\n event.preventDefault();\n };\n\n return (\n <a\n href={href}\n title={title}\n onClick={openInPopup}\n target={isExternal ? '_blank' : undefined}\n rel={isExternal ? 'noopener noreferrer' : undefined}\n >\n {children}\n </a>\n );\n };\n}\n\nconst REMARK_PLUGINS = [remarkGfm];\n\n// Links stay text until their URL lands: remend's placeholder href would render\n// a live anchor to nowhere. No math is rendered here, so pairing `$$` would only\n// turn one literal into another.\nconst REMEND_OPTIONS = { katex: false, linkMode: 'text-only' } as const;\n\n// Elements are listed one by one: react-markdown also passes its `node`, which\n// React would forward to the DOM as a stray attribute. Everything else is\n// styled from markdown-renderer.css.\nconst COMPONENTS: Components = {\n pre: MarkdownCodeBlock,\n a: markdownLink('tab'),\n};\n\nconst WINDOW_COMPONENTS: Components = {\n ...COMPONENTS,\n a: markdownLink('window'),\n};\n"],"names":["MarkdownRenderer","MarkdownBlock"],"mappings":"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"}
package/dist/style.css CHANGED
@@ -5837,6 +5837,10 @@
5837
5837
  will-change: transform;
5838
5838
  }
5839
5839
 
5840
+ .\[contain\:inline-size\] {
5841
+ contain: inline-size;
5842
+ }
5843
+
5840
5844
  .fade-in-0 {
5841
5845
  --tw-enter-opacity: 0;
5842
5846
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mastra/playground-ui",
3
3
  "type": "module",
4
- "version": "51.0.0-alpha.5",
4
+ "version": "51.0.1-alpha.1",
5
5
  "description": "Mastra Playground components",
6
6
  "sideEffects": [
7
7
  "**/*.css"
@@ -151,8 +151,8 @@
151
151
  "react": ">=19.0.0",
152
152
  "react-dom": ">=19.0.0",
153
153
  "tailwindcss": "^4.0.0",
154
- "@mastra/client-js": "^1.42.0-alpha.5",
155
- "@mastra/react": "1.4.5-alpha.5"
154
+ "@mastra/client-js": "^1.42.1-alpha.1",
155
+ "@mastra/react": "1.4.6-alpha.1"
156
156
  },
157
157
  "devDependencies": {
158
158
  "@storybook/addon-a11y": "^10.4.1",
@@ -192,11 +192,11 @@
192
192
  "vite-plugin-dts": "^4.5.4",
193
193
  "vite-plugin-lib-inject-css": "^2.2.2",
194
194
  "vitest": "4.1.10",
195
- "@internal/lint": "0.0.124",
196
- "@mastra/client-js": "^1.42.0-alpha.5",
197
- "@mastra/core": "1.61.0-alpha.5",
198
- "@mastra/react": "1.4.5-alpha.5",
199
- "@mastra/memory": "1.27.0"
195
+ "@internal/lint": "0.0.125",
196
+ "@mastra/client-js": "^1.42.1-alpha.1",
197
+ "@mastra/core": "1.61.1-alpha.1",
198
+ "@mastra/memory": "1.27.0",
199
+ "@mastra/react": "1.4.6-alpha.1"
200
200
  },
201
201
  "homepage": "https://mastra.ai",
202
202
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"code-block-Cqt3al0k.cjs","sources":["../src/ds/components/CodeBlock/code-block.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Code } from '../Code/code';\nimport { CopyButton } from '../CopyButton/copy-button';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select/select';\nimport { TabList } from '../Tabs/tabs-list';\nimport { Tabs } from '../Tabs/tabs-root';\nimport { Tab } from '../Tabs/tabs-tab';\nimport { transitions } from '@/ds/primitives/transitions';\nimport { cn } from '@/lib/utils';\n\nexport type CodeBlockSelector = 'select' | 'tabs';\n\nexport type CodeBlockOverflow = 'wrap' | 'scroll';\n\nexport interface CodeBlockOption {\n label: string;\n value: string;\n}\n\nexport interface CodeBlockProps {\n code: string;\n options?: CodeBlockOption[];\n value?: string;\n onValueChange?: (value: string) => void;\n selector?: CodeBlockSelector;\n fileName?: string;\n lang?: string;\n /** `wrap` (default) breaks long lines — best for commands and snippets.\n * `scroll` preserves columns behind a horizontal scroll — best for source code. */\n overflow?: CodeBlockOverflow;\n copyMessage?: string;\n copyTooltip?: string;\n actions?: ReactNode;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n options,\n value,\n onValueChange,\n selector = 'select',\n fileName,\n lang,\n overflow = 'wrap',\n copyMessage,\n copyTooltip,\n actions,\n className,\n}: CodeBlockProps) {\n const hasOptions = options && options.length > 0;\n const useTabs = hasOptions && selector === 'tabs';\n const useSelect = hasOptions && selector === 'select';\n const firstOption = options?.[0];\n const activeValue = value ?? firstOption?.value;\n\n return (\n <figure\n className={cn(\n 'group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2',\n className,\n )}\n >\n {useTabs && firstOption && (\n <Tabs defaultTab={firstOption.value} value={activeValue} onValueChange={onValueChange ?? (() => {})}>\n <div className=\"flex items-stretch\">\n <div className=\"min-w-0 flex-1\">\n <TabList>\n {options.map(opt => (\n <Tab key={opt.value} value={opt.value}>\n {opt.label}\n </Tab>\n ))}\n </TabList>\n </div>\n {actions && <div className=\"border-border1 flex shrink-0 items-center border-b pr-2 pl-3\">{actions}</div>}\n </div>\n </Tabs>\n )}\n\n {useSelect && options && (\n <div className=\"border-border2/40 flex items-center border-b px-2 py-1.5\">\n <Select value={activeValue} onValueChange={onValueChange}>\n <SelectTrigger size=\"sm\" variant=\"ghost\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {options.map(opt => (\n <SelectItem key={opt.value} value={opt.value}>\n {opt.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && fileName && (\n <div className=\"border-border2/40 flex items-center border-b px-4 py-2\">\n <figcaption className=\"text-ui-sm text-neutral4 font-mono\">{fileName}</figcaption>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && !fileName && actions && (\n <div className=\"border-border2/40 flex items-center justify-end border-b px-2 py-1.5\">{actions}</div>\n )}\n\n <div className=\"relative\">\n <Code\n code={code}\n lang={lang}\n className={cn(\n 'px-4 py-3 font-mono text-ui-sm text-neutral5',\n overflow === 'scroll' ? 'overflow-x-auto whitespace-pre' : 'break-all whitespace-pre-wrap',\n )}\n />\n <CopyButton\n content={code}\n copyMessage={copyMessage}\n tooltip={copyTooltip}\n size=\"sm\"\n className={cn(\n 'absolute top-2 right-2 opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 pointer-fine:opacity-0',\n transitions.opacity,\n )}\n />\n </div>\n </figure>\n );\n}\n"],"names":["code","jsxs","cn","jsx","Tabs","TabList","Tab","Select","SelectTrigger","SelectValue","SelectContent","SelectItem","Code","CopyButton","transitions"],"mappings":";;;;;;;;;;;AAoCO,SAAS,SAAA,CAAU;AAAA,QACxBA,MAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA,GAAW,QAAA;AAAA,EACX,QAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA,GAAW,MAAA;AAAA,EACX,WAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,UAAA,GAAa,OAAA,IAAW,OAAA,CAAQ,MAAA,GAAS,CAAA;AAC/C,EAAA,MAAM,OAAA,GAAU,cAAc,QAAA,KAAa,MAAA;AAC3C,EAAA,MAAM,SAAA,GAAY,cAAc,QAAA,KAAa,QAAA;AAC7C,EAAA,MAAM,WAAA,GAAc,UAAU,CAAC,CAAA;AAC/B,EAAA,MAAM,WAAA,GAAc,SAAS,WAAA,EAAa,KAAA;AAE1C,EAAA,uBACEC,eAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAWC,WAAA;AAAA,QACT,sGAAA;AAAA,QACA;AAAA,OACF;AAAA,MAEC,QAAA,EAAA;AAAA,QAAA,OAAA,IAAW,WAAA,oBACVC,cAAA,CAACC,aAAA,EAAA,EAAK,UAAA,EAAY,WAAA,CAAY,OAAO,KAAA,EAAO,WAAA,EAAa,aAAA,EAAe,aAAA,KAAkB,MAAM;AAAA,QAAC,CAAA,CAAA,EAC/F,QAAA,kBAAAH,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oBAAA,EACb,QAAA,EAAA;AAAA,0BAAAE,cAAA,CAAC,SAAI,SAAA,EAAU,gBAAA,EACb,yCAACE,gBAAA,EAAA,EACE,QAAA,EAAA,OAAA,CAAQ,IAAI,CAAA,GAAA,qBACXF,cAAA,CAACG,eAAoB,KAAA,EAAO,GAAA,CAAI,OAC7B,QAAA,EAAA,GAAA,CAAI,KAAA,EAAA,EADG,IAAI,KAEd,CACD,GACH,CAAA,EACF,CAAA;AAAA,UACC,OAAA,oBAAWH,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gEAAgE,QAAA,EAAA,OAAA,EAAQ;AAAA,SAAA,EACrG,CAAA,EACF,CAAA;AAAA,QAGD,SAAA,IAAa,OAAA,oBACZF,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,0DAAA,EACb,QAAA,EAAA;AAAA,0BAAAA,eAAA,CAACM,aAAA,EAAA,EAAO,KAAA,EAAO,WAAA,EAAa,aAAA,EAC1B,QAAA,EAAA;AAAA,4BAAAJ,cAAA,CAACK,wBAAc,IAAA,EAAK,IAAA,EAAK,SAAQ,OAAA,EAC/B,QAAA,kBAAAL,cAAA,CAACM,sBAAY,CAAA,EACf,CAAA;AAAA,4BACAN,cAAA,CAACO,oBAAA,EAAA,EACE,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,yBACXP,cAAA,CAACQ,iBAAA,EAAA,EAA2B,KAAA,EAAO,GAAA,CAAI,OACpC,QAAA,EAAA,GAAA,CAAI,KAAA,EAAA,EADU,GAAA,CAAI,KAErB,CACD,CAAA,EACH;AAAA,WAAA,EACF,CAAA;AAAA,UACC,OAAA,oBAAWR,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6BAA6B,QAAA,EAAA,OAAA,EAAQ;AAAA,SAAA,EAClE,CAAA;AAAA,QAGD,CAAC,UAAA,IAAc,QAAA,oBACdF,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,wDAAA,EACb,QAAA,EAAA;AAAA,0BAAAE,cAAA,CAAC,YAAA,EAAA,EAAW,SAAA,EAAU,oCAAA,EAAsC,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,UACpE,OAAA,oBAAWA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6BAA6B,QAAA,EAAA,OAAA,EAAQ;AAAA,SAAA,EAClE,CAAA;AAAA,QAGD,CAAC,cAAc,CAAC,QAAA,IAAY,2BAC3BA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,sEAAA,EAAwE,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,wBAGjGF,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,UAAA,EACb,QAAA,EAAA;AAAA,0BAAAE,cAAA;AAAA,YAACS,SAAA;AAAA,YAAA;AAAA,oBACCZ,MAAA;AAAA,cACA,IAAA;AAAA,cACA,SAAA,EAAWE,WAAA;AAAA,gBACT,8CAAA;AAAA,gBACA,QAAA,KAAa,WAAW,gCAAA,GAAmC;AAAA;AAC7D;AAAA,WACF;AAAA,0BACAC,cAAA;AAAA,YAACU,qBAAA;AAAA,YAAA;AAAA,cACC,OAAA,EAASb,MAAA;AAAA,cACT,WAAA;AAAA,cACA,OAAA,EAAS,WAAA;AAAA,cACT,IAAA,EAAK,IAAA;AAAA,cACL,SAAA,EAAWE,WAAA;AAAA,gBACT,kHAAA;AAAA,gBACAY,kCAAA,CAAY;AAAA;AACd;AAAA;AACF,SAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"code-block-DR6-quU0.js","sources":["../src/ds/components/CodeBlock/code-block.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { Code } from '../Code/code';\nimport { CopyButton } from '../CopyButton/copy-button';\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../Select/select';\nimport { TabList } from '../Tabs/tabs-list';\nimport { Tabs } from '../Tabs/tabs-root';\nimport { Tab } from '../Tabs/tabs-tab';\nimport { transitions } from '@/ds/primitives/transitions';\nimport { cn } from '@/lib/utils';\n\nexport type CodeBlockSelector = 'select' | 'tabs';\n\nexport type CodeBlockOverflow = 'wrap' | 'scroll';\n\nexport interface CodeBlockOption {\n label: string;\n value: string;\n}\n\nexport interface CodeBlockProps {\n code: string;\n options?: CodeBlockOption[];\n value?: string;\n onValueChange?: (value: string) => void;\n selector?: CodeBlockSelector;\n fileName?: string;\n lang?: string;\n /** `wrap` (default) breaks long lines — best for commands and snippets.\n * `scroll` preserves columns behind a horizontal scroll — best for source code. */\n overflow?: CodeBlockOverflow;\n copyMessage?: string;\n copyTooltip?: string;\n actions?: ReactNode;\n className?: string;\n}\n\nexport function CodeBlock({\n code,\n options,\n value,\n onValueChange,\n selector = 'select',\n fileName,\n lang,\n overflow = 'wrap',\n copyMessage,\n copyTooltip,\n actions,\n className,\n}: CodeBlockProps) {\n const hasOptions = options && options.length > 0;\n const useTabs = hasOptions && selector === 'tabs';\n const useSelect = hasOptions && selector === 'select';\n const firstOption = options?.[0];\n const activeValue = value ?? firstOption?.value;\n\n return (\n <figure\n className={cn(\n 'group relative flex w-full flex-col overflow-hidden rounded-2xl border border-border2/40 bg-surface2',\n className,\n )}\n >\n {useTabs && firstOption && (\n <Tabs defaultTab={firstOption.value} value={activeValue} onValueChange={onValueChange ?? (() => {})}>\n <div className=\"flex items-stretch\">\n <div className=\"min-w-0 flex-1\">\n <TabList>\n {options.map(opt => (\n <Tab key={opt.value} value={opt.value}>\n {opt.label}\n </Tab>\n ))}\n </TabList>\n </div>\n {actions && <div className=\"border-border1 flex shrink-0 items-center border-b pr-2 pl-3\">{actions}</div>}\n </div>\n </Tabs>\n )}\n\n {useSelect && options && (\n <div className=\"border-border2/40 flex items-center border-b px-2 py-1.5\">\n <Select value={activeValue} onValueChange={onValueChange}>\n <SelectTrigger size=\"sm\" variant=\"ghost\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {options.map(opt => (\n <SelectItem key={opt.value} value={opt.value}>\n {opt.label}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && fileName && (\n <div className=\"border-border2/40 flex items-center border-b px-4 py-2\">\n <figcaption className=\"text-ui-sm text-neutral4 font-mono\">{fileName}</figcaption>\n {actions && <div className=\"ml-auto flex items-center\">{actions}</div>}\n </div>\n )}\n\n {!hasOptions && !fileName && actions && (\n <div className=\"border-border2/40 flex items-center justify-end border-b px-2 py-1.5\">{actions}</div>\n )}\n\n <div className=\"relative\">\n <Code\n code={code}\n lang={lang}\n className={cn(\n 'px-4 py-3 font-mono text-ui-sm text-neutral5',\n overflow === 'scroll' ? 'overflow-x-auto whitespace-pre' : 'break-all whitespace-pre-wrap',\n )}\n />\n <CopyButton\n content={code}\n copyMessage={copyMessage}\n tooltip={copyTooltip}\n size=\"sm\"\n className={cn(\n 'absolute top-2 right-2 opacity-100 group-focus-within:opacity-100 group-hover:opacity-100 pointer-fine:opacity-0',\n transitions.opacity,\n )}\n />\n </div>\n </figure>\n );\n}\n"],"names":[],"mappings":"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"}