@uipath/apollo-wind 2.72.2 → 2.73.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/components/ui/alert-dialog.cjs +1 -1
  2. package/dist/components/ui/alert-dialog.js +1 -1
  3. package/dist/components/ui/attachment.cjs +40 -8
  4. package/dist/components/ui/attachment.d.ts +11 -1
  5. package/dist/components/ui/attachment.js +43 -11
  6. package/dist/components/ui/bubble.cjs +1 -1
  7. package/dist/components/ui/bubble.d.ts +6 -0
  8. package/dist/components/ui/bubble.js +1 -1
  9. package/dist/components/ui/chat-composer.cjs +8 -2
  10. package/dist/components/ui/chat-composer.d.ts +6 -0
  11. package/dist/components/ui/chat-composer.js +9 -3
  12. package/dist/components/ui/citation.cjs +5 -3
  13. package/dist/components/ui/citation.d.ts +6 -0
  14. package/dist/components/ui/citation.js +5 -3
  15. package/dist/components/ui/code-block.cjs +6 -6
  16. package/dist/components/ui/code-block.d.ts +6 -0
  17. package/dist/components/ui/code-block.js +6 -6
  18. package/dist/components/ui/context-menu.cjs +2 -2
  19. package/dist/components/ui/context-menu.js +2 -2
  20. package/dist/components/ui/dialog.cjs +18 -5
  21. package/dist/components/ui/dialog.d.ts +15 -0
  22. package/dist/components/ui/dialog.js +16 -6
  23. package/dist/components/ui/disclosure-tree.cjs +269 -0
  24. package/dist/components/ui/disclosure-tree.d.ts +45 -0
  25. package/dist/components/ui/disclosure-tree.js +235 -0
  26. package/dist/components/ui/dropdown-menu.cjs +2 -2
  27. package/dist/components/ui/dropdown-menu.js +2 -2
  28. package/dist/components/ui/dropzone-overlay.cjs +21 -5
  29. package/dist/components/ui/dropzone-overlay.d.ts +12 -1
  30. package/dist/components/ui/dropzone-overlay.js +21 -5
  31. package/dist/components/ui/empty-state.cjs +28 -10
  32. package/dist/components/ui/empty-state.d.ts +9 -0
  33. package/dist/components/ui/empty-state.js +30 -12
  34. package/dist/components/ui/hover-card.cjs +1 -1
  35. package/dist/components/ui/hover-card.js +1 -1
  36. package/dist/components/ui/index.cjs +221 -208
  37. package/dist/components/ui/index.d.ts +1 -0
  38. package/dist/components/ui/index.js +1 -0
  39. package/dist/components/ui/markdown.cjs +129 -22
  40. package/dist/components/ui/markdown.d.ts +23 -4
  41. package/dist/components/ui/markdown.js +129 -22
  42. package/dist/components/ui/message-actions.cjs +1 -1
  43. package/dist/components/ui/message-actions.d.ts +3 -0
  44. package/dist/components/ui/message-actions.js +1 -1
  45. package/dist/components/ui/message.cjs +4 -4
  46. package/dist/components/ui/message.d.ts +7 -0
  47. package/dist/components/ui/message.js +4 -4
  48. package/dist/components/ui/popover.cjs +1 -1
  49. package/dist/components/ui/popover.js +1 -1
  50. package/dist/components/ui/search.cjs +16 -5
  51. package/dist/components/ui/search.d.ts +9 -0
  52. package/dist/components/ui/search.js +13 -5
  53. package/dist/components/ui/select.cjs +1 -1
  54. package/dist/components/ui/select.js +1 -1
  55. package/dist/components/ui/sheet.cjs +12 -2
  56. package/dist/components/ui/sheet.d.ts +7 -0
  57. package/dist/components/ui/sheet.js +10 -3
  58. package/dist/components/ui/sources.cjs +1 -1
  59. package/dist/components/ui/sources.d.ts +6 -0
  60. package/dist/components/ui/sources.js +1 -1
  61. package/dist/components/ui/thinking-indicator.cjs +5 -3
  62. package/dist/components/ui/thinking-indicator.d.ts +6 -0
  63. package/dist/components/ui/thinking-indicator.js +5 -3
  64. package/dist/components/ui/tool-call.cjs +10 -7
  65. package/dist/components/ui/tool-call.d.ts +6 -0
  66. package/dist/components/ui/tool-call.js +10 -7
  67. package/dist/components/ui/tooltip.cjs +1 -1
  68. package/dist/components/ui/tooltip.js +1 -1
  69. package/dist/index.cjs +14 -1
  70. package/dist/index.d.ts +10 -6
  71. package/dist/index.js +5 -4
  72. package/dist/lib/disclosure-row.cjs +36 -0
  73. package/dist/lib/disclosure-row.d.ts +1 -0
  74. package/dist/lib/disclosure-row.js +2 -0
  75. package/dist/lib/use-ancestor-density.cjs +65 -0
  76. package/dist/lib/use-ancestor-density.d.ts +8 -0
  77. package/dist/lib/use-ancestor-density.js +31 -0
  78. package/dist/styles.css +681 -12
  79. package/dist/tailwind.utilities.css +173 -0
  80. package/package.json +1 -1
@@ -26,6 +26,7 @@ export * from './data-table';
26
26
  export * from './date-picker';
27
27
  export * from './datetime-picker';
28
28
  export * from './dialog';
29
+ export * from './disclosure-tree';
29
30
  export * from './drawer';
30
31
  export * from './dropdown-menu';
31
32
  export * from './dropzone-overlay';
@@ -29,6 +29,7 @@ export * from "./data-table.js";
29
29
  export * from "./date-picker.js";
30
30
  export * from "./datetime-picker.js";
31
31
  export * from "./dialog.js";
32
+ export * from "./disclosure-tree.js";
32
33
  export * from "./drawer.js";
33
34
  export * from "./dropdown-menu.js";
34
35
  export * from "./dropzone-overlay.js";
@@ -55,9 +55,99 @@ function hastText(node) {
55
55
  function languageOf(node) {
56
56
  const className = node.properties?.className;
57
57
  const classes = Array.isArray(className) ? className.map(String) : [];
58
- return classes.find((name)=>name.startsWith('language-'))?.slice('language-'.length);
58
+ const fromClass = classes.find((name)=>name.startsWith('language-'))?.slice('language-'.length);
59
+ const dataLanguage = node.properties?.dataLanguage;
60
+ return fromClass ?? ('string' == typeof dataLanguage ? dataLanguage : void 0);
59
61
  }
60
62
  const opensInNewTab = (href)=>!!href && !/^(#|mailto:|tel:)/i.test(href);
63
+ const MATH_FENCE_LANGUAGES = new Set([
64
+ 'math',
65
+ 'latex',
66
+ 'tex'
67
+ ]);
68
+ const OPENING_FENCE = /^[ \t]*(`{3,}|~{3,}|\${2,})/;
69
+ const CLOSING_FENCE = /^( *)(`{3,}|~{3,}|\${2,})[ \t]*$/;
70
+ const QUOTE_MARKERS = /^(?:[ \t]*>[ ]?)*/;
71
+ function unquote(line) {
72
+ const markers = QUOTE_MARKERS.exec(line)?.[0] ?? '';
73
+ const rest = line.slice(markers.length).replace(/\t/g, ' ');
74
+ return {
75
+ depth: markers.split('>').length - 1,
76
+ rest
77
+ };
78
+ }
79
+ function hasClosingFence(node, source) {
80
+ const start = node.position?.start.offset;
81
+ const end = node.position?.end.offset;
82
+ if (void 0 === start || void 0 === end) return true;
83
+ const lines = source.slice(start, end).split(/\r?\n|\r/);
84
+ const open = OPENING_FENCE.exec(lines[0])?.[1];
85
+ if (!open || lines.length < 2) return false;
86
+ const lineStart = Math.max(source.lastIndexOf('\n', start - 1), source.lastIndexOf('\r', start - 1)) + 1;
87
+ const container = unquote(source.slice(lineStart, start));
88
+ const last = unquote(lines[lines.length - 1]);
89
+ const [, indent = '', close = ''] = CLOSING_FENCE.exec(last.rest) ?? [];
90
+ return last.depth === container.depth && indent.length <= container.rest.length + 3 && close[0] === open[0] && close.length >= open.length;
91
+ }
92
+ const isMathFence = (node)=>'code' === node.type && MATH_FENCE_LANGUAGES.has(node.lang?.toLowerCase() ?? '');
93
+ function displayMath(node) {
94
+ const value = node.value ?? '';
95
+ return {
96
+ type: 'math',
97
+ value,
98
+ position: node.position,
99
+ data: {
100
+ hName: 'pre',
101
+ hChildren: [
102
+ {
103
+ type: 'element',
104
+ tagName: 'code',
105
+ properties: {
106
+ className: [
107
+ 'language-math',
108
+ 'math-display'
109
+ ]
110
+ },
111
+ children: [
112
+ {
113
+ type: 'text',
114
+ value
115
+ }
116
+ ]
117
+ }
118
+ ]
119
+ }
120
+ };
121
+ }
122
+ function pendingMath(node) {
123
+ const value = 'math' === node.type ? [
124
+ node.meta,
125
+ node.value
126
+ ].filter(Boolean).join('\n') : node.value;
127
+ return {
128
+ type: 'code',
129
+ lang: null,
130
+ value: value ?? '',
131
+ position: node.position,
132
+ data: {
133
+ hProperties: {
134
+ dataLanguage: 'code' === node.type ? node.lang : 'math'
135
+ }
136
+ }
137
+ };
138
+ }
139
+ function remarkMathBlocks() {
140
+ const visit = (node, source)=>{
141
+ node.children?.forEach((child, index, children)=>{
142
+ const fence = isMathFence(child);
143
+ if (!fence && 'math' !== child.type) return void visit(child, source);
144
+ if (hasClosingFence(child, source)) {
145
+ if (fence) children[index] = displayMath(child);
146
+ } else children[index] = pendingMath(child);
147
+ });
148
+ };
149
+ return (tree, file)=>visit(tree, String(file.value ?? ''));
150
+ }
61
151
  const BR_TAG = /^<br\s*\/?>$/i;
62
152
  function remarkHtmlBreaks() {
63
153
  const visit = (node)=>{
@@ -140,6 +230,14 @@ function rehypeScopeFootnoteLabel(options) {
140
230
  };
141
231
  return (tree)=>visit(tree);
142
232
  }
233
+ function rehypeKatexPerRun(options) {
234
+ return (...args)=>external_rehype_katex_default()({
235
+ ...options,
236
+ macros: {
237
+ ...options.macros
238
+ }
239
+ })(...args);
240
+ }
143
241
  const DEFAULT_MARKDOWN_STRINGS = {
144
242
  ...external_code_block_cjs_namespaceObject.DEFAULT_CODE_BLOCK_STRINGS,
145
243
  footnotes: 'Footnotes',
@@ -235,7 +333,7 @@ function MarkdownInput({ node: _node, className, type, checked, ...rest }) {
235
333
  });
236
334
  }
237
335
  function MarkdownPre({ node, children, ...rest }) {
238
- const { strings, codeWrap, renderCodeActions } = external_react_namespaceObject.useContext(MarkdownContext);
336
+ const { strings, codeWrap, renderCodeActions, renderCodeBlock } = external_react_namespaceObject.useContext(MarkdownContext);
239
337
  const codeNode = node?.children?.find((child)=>'element' === child.type && 'code' === child.tagName);
240
338
  if (!codeNode) return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("pre", {
241
339
  ...rest,
@@ -245,37 +343,40 @@ function MarkdownPre({ node, children, ...rest }) {
245
343
  code: hastText(codeNode).replace(/\n$/, ''),
246
344
  language: languageOf(codeNode)
247
345
  };
248
- return /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_code_block_cjs_namespaceObject.CodeBlock, {
346
+ const props = {
249
347
  code: block.code,
250
348
  language: block.language,
251
349
  wrap: codeWrap,
252
350
  actions: renderCodeActions?.(block),
253
- strings: strings
351
+ strings
352
+ };
353
+ return renderCodeBlock ? renderCodeBlock(block, props) : /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(external_code_block_cjs_namespaceObject.CodeBlock, {
354
+ ...props
254
355
  });
255
356
  }
256
357
  const BUILT_IN_COMPONENTS = {
257
358
  h1: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h1", {
258
- className: (0, index_cjs_namespaceObject.cn)('text-xl font-semibold tracking-tight', className),
359
+ className: (0, index_cjs_namespaceObject.cn)('text-xl font-semibold tracking-tight in-data-[density=compact]:text-lg', className),
259
360
  ...rest
260
361
  }),
261
362
  h2: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h2", {
262
- className: (0, index_cjs_namespaceObject.cn)('text-lg font-semibold tracking-tight', className),
363
+ className: (0, index_cjs_namespaceObject.cn)('text-lg font-semibold tracking-tight in-data-[density=compact]:text-base', className),
263
364
  ...rest
264
365
  }),
265
366
  h3: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h3", {
266
- className: (0, index_cjs_namespaceObject.cn)('text-base font-semibold', className),
367
+ className: (0, index_cjs_namespaceObject.cn)('text-base font-semibold in-data-[density=compact]:text-sm', className),
267
368
  ...rest
268
369
  }),
269
370
  h4: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h4", {
270
- className: (0, index_cjs_namespaceObject.cn)('text-sm font-semibold', className),
371
+ className: (0, index_cjs_namespaceObject.cn)('text-sm font-semibold in-data-[density=compact]:text-xs', className),
271
372
  ...rest
272
373
  }),
273
374
  h5: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h5", {
274
- className: (0, index_cjs_namespaceObject.cn)('text-sm font-semibold', className),
375
+ className: (0, index_cjs_namespaceObject.cn)('text-sm font-semibold in-data-[density=compact]:text-xs', className),
275
376
  ...rest
276
377
  }),
277
378
  h6: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("h6", {
278
- className: (0, index_cjs_namespaceObject.cn)('text-sm font-semibold text-muted-foreground', className),
379
+ className: (0, index_cjs_namespaceObject.cn)('text-sm font-semibold text-muted-foreground in-data-[density=compact]:text-xs', className),
279
380
  ...rest
280
381
  }),
281
382
  p: ({ node: _node, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("p", {
@@ -283,20 +384,20 @@ const BUILT_IN_COMPONENTS = {
283
384
  }),
284
385
  a: MarkdownLink,
285
386
  ul: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("ul", {
286
- className: (0, index_cjs_namespaceObject.cn)('flex flex-col gap-1 pl-6', className?.includes('contains-task-list') ? 'list-none pl-1' : 'list-disc', 'marker:text-muted-foreground', className),
387
+ className: (0, index_cjs_namespaceObject.cn)('flex flex-col gap-1 pl-6 in-data-[density=compact]:gap-0.5', className?.includes('contains-task-list') ? 'list-none pl-1' : 'list-disc', 'marker:text-muted-foreground', className),
287
388
  ...rest
288
389
  }),
289
390
  ol: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("ol", {
290
- className: (0, index_cjs_namespaceObject.cn)('flex list-decimal flex-col gap-1 pl-6 marker:text-muted-foreground', className),
391
+ className: (0, index_cjs_namespaceObject.cn)('flex list-decimal flex-col gap-1 pl-6 marker:text-muted-foreground in-data-[density=compact]:gap-0.5', className),
291
392
  ...rest
292
393
  }),
293
394
  li: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("li", {
294
- className: (0, index_cjs_namespaceObject.cn)('pl-1 [&>ol]:mt-1 [&>p+p]:mt-2 [&>ul]:mt-1 [&>ul.contains-task-list]:pl-6', className),
395
+ className: (0, index_cjs_namespaceObject.cn)('pl-1 [&>ol]:mt-1 [&>p+p]:mt-2 [&>ul]:mt-1 [&>ul.contains-task-list]:pl-6 in-data-[density=compact]:[&>p+p]:mt-1.5', className),
295
396
  ...rest
296
397
  }),
297
398
  input: MarkdownInput,
298
399
  blockquote: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("blockquote", {
299
- className: (0, index_cjs_namespaceObject.cn)('flex flex-col gap-2 border-l-2 border-border pl-4 text-muted-foreground', className),
400
+ className: (0, index_cjs_namespaceObject.cn)('flex flex-col gap-2 border-l-2 border-border pl-4 text-muted-foreground in-data-[density=compact]:gap-1.5', className),
300
401
  ...rest
301
402
  }),
302
403
  hr: ({ node: _node, className, ...rest })=>/*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)("hr", {
@@ -327,7 +428,7 @@ const BUILT_IN_COMPONENTS = {
327
428
  }),
328
429
  pre: MarkdownPre
329
430
  };
330
- const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, components, remarkPlugins, rehypePlugins, streaming = false, images = 'none', codeWrap = false, renderCodeActions, strings, className, ...props }, ref)=>{
431
+ const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ children, components, remarkPlugins, rehypePlugins, streaming = false, images = 'none', codeWrap = false, renderCodeActions, renderCodeBlock, katexOptions, strings, className, ...props }, ref)=>{
331
432
  const context = external_react_namespaceObject.useMemo(()=>({
332
433
  strings: {
333
434
  ...DEFAULT_MARKDOWN_STRINGS,
@@ -335,12 +436,14 @@ const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ chil
335
436
  },
336
437
  images,
337
438
  codeWrap,
338
- renderCodeActions
439
+ renderCodeActions,
440
+ renderCodeBlock
339
441
  }), [
340
442
  strings,
341
443
  images,
342
444
  codeWrap,
343
- renderCodeActions
445
+ renderCodeActions,
446
+ renderCodeBlock
344
447
  ]);
345
448
  const { footnotes, footnoteBack } = context.strings;
346
449
  const footnotePrefix = `markdown${external_react_namespaceObject.useId().replace(/[^\w-]/g, '')}-`;
@@ -358,6 +461,7 @@ const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ chil
358
461
  singleDollarTextMath: false
359
462
  }
360
463
  ],
464
+ remarkMathBlocks,
361
465
  remarkHtmlBreaks,
362
466
  ...remarkPlugins ?? []
363
467
  ], [
@@ -371,12 +475,13 @@ const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ chil
371
475
  }
372
476
  ],
373
477
  [
374
- external_rehype_katex_default(),
478
+ rehypeKatexPerRun,
375
479
  {
480
+ strict: katexOptions?.strict ?? 'ignore',
481
+ macros: katexOptions?.macros,
376
482
  output: 'mathml',
377
483
  throwOnError: false,
378
- trust: false,
379
- strict: 'ignore'
484
+ trust: false
380
485
  }
381
486
  ],
382
487
  ...rehypePlugins ?? [],
@@ -386,7 +491,9 @@ const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ chil
386
491
  ], [
387
492
  rehypePlugins,
388
493
  streaming,
389
- footnotePrefix
494
+ footnotePrefix,
495
+ katexOptions?.strict,
496
+ katexOptions?.macros
390
497
  ]);
391
498
  const remarkRehypeOptions = external_react_namespaceObject.useMemo(()=>({
392
499
  clobberPrefix: footnotePrefix,
@@ -402,7 +509,7 @@ const Markdown = /*#__PURE__*/ external_react_namespaceObject.forwardRef(({ chil
402
509
  "data-slot": "markdown",
403
510
  "data-streaming": streaming || void 0,
404
511
  "aria-busy": streaming || void 0,
405
- className: (0, index_cjs_namespaceObject.cn)('flex min-w-0 flex-col gap-3 text-sm leading-relaxed break-words text-foreground [&_math]:text-[1.15em] [&>.katex]:overflow-x-auto [&>.katex]:py-1', className),
512
+ className: (0, index_cjs_namespaceObject.cn)('flex min-w-0 flex-col gap-(--markdown-gap,0.75rem) text-(length:--markdown-font-size,0.875rem) leading-(--markdown-leading,1.625) break-words text-foreground [&_math]:text-[1.15em] [&>.katex]:overflow-x-auto [&>.katex]:overflow-y-hidden [&>.katex]:py-1 in-data-[density=compact]:[--markdown-gap:0.5rem] in-data-[density=compact]:[--markdown-font-size:0.75rem] in-data-[density=compact]:[--markdown-leading:1.5]', className),
406
513
  ...props,
407
514
  children: /*#__PURE__*/ (0, jsx_runtime_namespaceObject.jsx)(MarkdownContext.Provider, {
408
515
  value: context,
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { type Components, type Options } from 'react-markdown';
3
- import { type CodeBlockStrings } from './code-block';
3
+ import { type CodeBlockProps, type CodeBlockStrings } from './code-block';
4
4
  export interface MarkdownStrings extends CodeBlockStrings {
5
5
  /** Heading of the generated footnotes section. */
6
6
  footnotes: string;
@@ -18,7 +18,7 @@ export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>
18
18
  /**
19
19
  * react-markdown renderers merged over the built-in ones. Use it with `remarkPlugins` to render
20
20
  * custom nodes such as citations or resource chips. `code` only styles inline code: fenced blocks
21
- * render through `pre`, so override `pre` (or use `renderCodeActions`) to change them.
21
+ * render through `pre`, so use `renderCodeBlock` or `renderCodeActions` to change them.
22
22
  */
23
23
  components?: Components;
24
24
  /** Extra remark plugins, run after GFM and math. */
@@ -27,7 +27,8 @@ export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>
27
27
  rehypePlugins?: Options['rehypePlugins'];
28
28
  /**
29
29
  * The source is still arriving. Shows a caret after the last text and marks the region busy.
30
- * Partial markdown is safe to pass: unclosed fences render as code and broken TeX as source.
30
+ * Partial markdown is safe to pass: an unclosed fence renders as code, and so does a math block
31
+ * without its closing line (still streaming or cut off) until it closes. Broken TeX shows as source.
31
32
  */
32
33
  streaming?: boolean;
33
34
  /**
@@ -42,12 +43,30 @@ export interface MarkdownProps extends Omit<React.HTMLAttributes<HTMLDivElement>
42
43
  codeWrap?: boolean;
43
44
  /** Extra header actions for each fenced code block (preview, expand), placed before the copy. */
44
45
  renderCodeActions?: (block: MarkdownCodeBlock) => React.ReactNode;
46
+ /**
47
+ * Renders each fenced code block instead of the default `CodeBlock`. `props` are what Markdown
48
+ * would pass it (including the `renderCodeActions` actions), so `<CodeBlock {...props} body={...} />`
49
+ * changes one part. Return a component element to keep state per block, such as a preview toggle.
50
+ */
51
+ renderCodeBlock?: (block: MarkdownCodeBlock, props: CodeBlockProps) => React.ReactNode;
52
+ /** KaTeX options for math. Output stays MathML and `trust` stays off; these cannot be changed. */
53
+ katexOptions?: MarkdownKatexOptions;
45
54
  strings?: Partial<MarkdownStrings>;
46
55
  }
56
+ export interface MarkdownKatexOptions {
57
+ /**
58
+ * KaTeX's handling of non-standard LaTeX. Defaults to `'ignore'`. rehype-katex renders a formula
59
+ * that fails strict mode again with strict mode off, so stricter values report through the
60
+ * unified file messages but do not change what renders.
61
+ */
62
+ strict?: boolean | 'ignore' | 'warn' | 'error';
63
+ /** Macros available to every formula, such as `{ '\\RR': '\\mathbb{R}' }`. */
64
+ macros?: Record<string, string>;
65
+ }
47
66
  export interface MarkdownCodeBlock {
48
67
  /** The block's source without the trailing newline. */
49
68
  code: string;
50
- /** The fence's info string as written, e.g. `ts` or `html`. */
69
+ /** The first word of the fence's info string as written (`ts`, `html`), or `math` for an open `$$` block. */
51
70
  language: string | undefined;
52
71
  }
53
72
  export type MarkdownImagePolicy = 'none' | 'same-origin' | 'all' | ((src: string) => boolean);
@@ -13,9 +13,99 @@ function hastText(node) {
13
13
  function languageOf(node) {
14
14
  const className = node.properties?.className;
15
15
  const classes = Array.isArray(className) ? className.map(String) : [];
16
- return classes.find((name)=>name.startsWith('language-'))?.slice('language-'.length);
16
+ const fromClass = classes.find((name)=>name.startsWith('language-'))?.slice('language-'.length);
17
+ const dataLanguage = node.properties?.dataLanguage;
18
+ return fromClass ?? ('string' == typeof dataLanguage ? dataLanguage : void 0);
17
19
  }
18
20
  const opensInNewTab = (href)=>!!href && !/^(#|mailto:|tel:)/i.test(href);
21
+ const MATH_FENCE_LANGUAGES = new Set([
22
+ 'math',
23
+ 'latex',
24
+ 'tex'
25
+ ]);
26
+ const OPENING_FENCE = /^[ \t]*(`{3,}|~{3,}|\${2,})/;
27
+ const CLOSING_FENCE = /^( *)(`{3,}|~{3,}|\${2,})[ \t]*$/;
28
+ const QUOTE_MARKERS = /^(?:[ \t]*>[ ]?)*/;
29
+ function unquote(line) {
30
+ const markers = QUOTE_MARKERS.exec(line)?.[0] ?? '';
31
+ const rest = line.slice(markers.length).replace(/\t/g, ' ');
32
+ return {
33
+ depth: markers.split('>').length - 1,
34
+ rest
35
+ };
36
+ }
37
+ function hasClosingFence(node, source) {
38
+ const start = node.position?.start.offset;
39
+ const end = node.position?.end.offset;
40
+ if (void 0 === start || void 0 === end) return true;
41
+ const lines = source.slice(start, end).split(/\r?\n|\r/);
42
+ const open = OPENING_FENCE.exec(lines[0])?.[1];
43
+ if (!open || lines.length < 2) return false;
44
+ const lineStart = Math.max(source.lastIndexOf('\n', start - 1), source.lastIndexOf('\r', start - 1)) + 1;
45
+ const container = unquote(source.slice(lineStart, start));
46
+ const last = unquote(lines[lines.length - 1]);
47
+ const [, indent = '', close = ''] = CLOSING_FENCE.exec(last.rest) ?? [];
48
+ return last.depth === container.depth && indent.length <= container.rest.length + 3 && close[0] === open[0] && close.length >= open.length;
49
+ }
50
+ const isMathFence = (node)=>'code' === node.type && MATH_FENCE_LANGUAGES.has(node.lang?.toLowerCase() ?? '');
51
+ function displayMath(node) {
52
+ const value = node.value ?? '';
53
+ return {
54
+ type: 'math',
55
+ value,
56
+ position: node.position,
57
+ data: {
58
+ hName: 'pre',
59
+ hChildren: [
60
+ {
61
+ type: 'element',
62
+ tagName: 'code',
63
+ properties: {
64
+ className: [
65
+ 'language-math',
66
+ 'math-display'
67
+ ]
68
+ },
69
+ children: [
70
+ {
71
+ type: 'text',
72
+ value
73
+ }
74
+ ]
75
+ }
76
+ ]
77
+ }
78
+ };
79
+ }
80
+ function pendingMath(node) {
81
+ const value = 'math' === node.type ? [
82
+ node.meta,
83
+ node.value
84
+ ].filter(Boolean).join('\n') : node.value;
85
+ return {
86
+ type: 'code',
87
+ lang: null,
88
+ value: value ?? '',
89
+ position: node.position,
90
+ data: {
91
+ hProperties: {
92
+ dataLanguage: 'code' === node.type ? node.lang : 'math'
93
+ }
94
+ }
95
+ };
96
+ }
97
+ function remarkMathBlocks() {
98
+ const visit = (node, source)=>{
99
+ node.children?.forEach((child, index, children)=>{
100
+ const fence = isMathFence(child);
101
+ if (!fence && 'math' !== child.type) return void visit(child, source);
102
+ if (hasClosingFence(child, source)) {
103
+ if (fence) children[index] = displayMath(child);
104
+ } else children[index] = pendingMath(child);
105
+ });
106
+ };
107
+ return (tree, file)=>visit(tree, String(file.value ?? ''));
108
+ }
19
109
  const BR_TAG = /^<br\s*\/?>$/i;
20
110
  function remarkHtmlBreaks() {
21
111
  const visit = (node)=>{
@@ -98,6 +188,14 @@ function rehypeScopeFootnoteLabel(options) {
98
188
  };
99
189
  return (tree)=>visit(tree);
100
190
  }
191
+ function rehypeKatexPerRun(options) {
192
+ return (...args)=>rehype_katex({
193
+ ...options,
194
+ macros: {
195
+ ...options.macros
196
+ }
197
+ })(...args);
198
+ }
101
199
  const DEFAULT_MARKDOWN_STRINGS = {
102
200
  ...DEFAULT_CODE_BLOCK_STRINGS,
103
201
  footnotes: 'Footnotes',
@@ -193,7 +291,7 @@ function MarkdownInput({ node: _node, className, type, checked, ...rest }) {
193
291
  });
194
292
  }
195
293
  function MarkdownPre({ node, children, ...rest }) {
196
- const { strings, codeWrap, renderCodeActions } = useContext(MarkdownContext);
294
+ const { strings, codeWrap, renderCodeActions, renderCodeBlock } = useContext(MarkdownContext);
197
295
  const codeNode = node?.children?.find((child)=>'element' === child.type && 'code' === child.tagName);
198
296
  if (!codeNode) return /*#__PURE__*/ jsx("pre", {
199
297
  ...rest,
@@ -203,37 +301,40 @@ function MarkdownPre({ node, children, ...rest }) {
203
301
  code: hastText(codeNode).replace(/\n$/, ''),
204
302
  language: languageOf(codeNode)
205
303
  };
206
- return /*#__PURE__*/ jsx(CodeBlock, {
304
+ const props = {
207
305
  code: block.code,
208
306
  language: block.language,
209
307
  wrap: codeWrap,
210
308
  actions: renderCodeActions?.(block),
211
- strings: strings
309
+ strings
310
+ };
311
+ return renderCodeBlock ? renderCodeBlock(block, props) : /*#__PURE__*/ jsx(CodeBlock, {
312
+ ...props
212
313
  });
213
314
  }
214
315
  const BUILT_IN_COMPONENTS = {
215
316
  h1: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("h1", {
216
- className: cn('text-xl font-semibold tracking-tight', className),
317
+ className: cn('text-xl font-semibold tracking-tight in-data-[density=compact]:text-lg', className),
217
318
  ...rest
218
319
  }),
219
320
  h2: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("h2", {
220
- className: cn('text-lg font-semibold tracking-tight', className),
321
+ className: cn('text-lg font-semibold tracking-tight in-data-[density=compact]:text-base', className),
221
322
  ...rest
222
323
  }),
223
324
  h3: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("h3", {
224
- className: cn('text-base font-semibold', className),
325
+ className: cn('text-base font-semibold in-data-[density=compact]:text-sm', className),
225
326
  ...rest
226
327
  }),
227
328
  h4: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("h4", {
228
- className: cn('text-sm font-semibold', className),
329
+ className: cn('text-sm font-semibold in-data-[density=compact]:text-xs', className),
229
330
  ...rest
230
331
  }),
231
332
  h5: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("h5", {
232
- className: cn('text-sm font-semibold', className),
333
+ className: cn('text-sm font-semibold in-data-[density=compact]:text-xs', className),
233
334
  ...rest
234
335
  }),
235
336
  h6: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("h6", {
236
- className: cn('text-sm font-semibold text-muted-foreground', className),
337
+ className: cn('text-sm font-semibold text-muted-foreground in-data-[density=compact]:text-xs', className),
237
338
  ...rest
238
339
  }),
239
340
  p: ({ node: _node, ...rest })=>/*#__PURE__*/ jsx("p", {
@@ -241,20 +342,20 @@ const BUILT_IN_COMPONENTS = {
241
342
  }),
242
343
  a: MarkdownLink,
243
344
  ul: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("ul", {
244
- className: cn('flex flex-col gap-1 pl-6', className?.includes('contains-task-list') ? 'list-none pl-1' : 'list-disc', 'marker:text-muted-foreground', className),
345
+ className: cn('flex flex-col gap-1 pl-6 in-data-[density=compact]:gap-0.5', className?.includes('contains-task-list') ? 'list-none pl-1' : 'list-disc', 'marker:text-muted-foreground', className),
245
346
  ...rest
246
347
  }),
247
348
  ol: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("ol", {
248
- className: cn('flex list-decimal flex-col gap-1 pl-6 marker:text-muted-foreground', className),
349
+ className: cn('flex list-decimal flex-col gap-1 pl-6 marker:text-muted-foreground in-data-[density=compact]:gap-0.5', className),
249
350
  ...rest
250
351
  }),
251
352
  li: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("li", {
252
- className: cn('pl-1 [&>ol]:mt-1 [&>p+p]:mt-2 [&>ul]:mt-1 [&>ul.contains-task-list]:pl-6', className),
353
+ className: cn('pl-1 [&>ol]:mt-1 [&>p+p]:mt-2 [&>ul]:mt-1 [&>ul.contains-task-list]:pl-6 in-data-[density=compact]:[&>p+p]:mt-1.5', className),
253
354
  ...rest
254
355
  }),
255
356
  input: MarkdownInput,
256
357
  blockquote: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("blockquote", {
257
- className: cn('flex flex-col gap-2 border-l-2 border-border pl-4 text-muted-foreground', className),
358
+ className: cn('flex flex-col gap-2 border-l-2 border-border pl-4 text-muted-foreground in-data-[density=compact]:gap-1.5', className),
258
359
  ...rest
259
360
  }),
260
361
  hr: ({ node: _node, className, ...rest })=>/*#__PURE__*/ jsx("hr", {
@@ -285,7 +386,7 @@ const BUILT_IN_COMPONENTS = {
285
386
  }),
286
387
  pre: MarkdownPre
287
388
  };
288
- const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins, rehypePlugins, streaming = false, images = 'none', codeWrap = false, renderCodeActions, strings, className, ...props }, ref)=>{
389
+ const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins, rehypePlugins, streaming = false, images = 'none', codeWrap = false, renderCodeActions, renderCodeBlock, katexOptions, strings, className, ...props }, ref)=>{
289
390
  const context = useMemo(()=>({
290
391
  strings: {
291
392
  ...DEFAULT_MARKDOWN_STRINGS,
@@ -293,12 +394,14 @@ const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins
293
394
  },
294
395
  images,
295
396
  codeWrap,
296
- renderCodeActions
397
+ renderCodeActions,
398
+ renderCodeBlock
297
399
  }), [
298
400
  strings,
299
401
  images,
300
402
  codeWrap,
301
- renderCodeActions
403
+ renderCodeActions,
404
+ renderCodeBlock
302
405
  ]);
303
406
  const { footnotes, footnoteBack } = context.strings;
304
407
  const footnotePrefix = `markdown${useId().replace(/[^\w-]/g, '')}-`;
@@ -316,6 +419,7 @@ const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins
316
419
  singleDollarTextMath: false
317
420
  }
318
421
  ],
422
+ remarkMathBlocks,
319
423
  remarkHtmlBreaks,
320
424
  ...remarkPlugins ?? []
321
425
  ], [
@@ -329,12 +433,13 @@ const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins
329
433
  }
330
434
  ],
331
435
  [
332
- rehype_katex,
436
+ rehypeKatexPerRun,
333
437
  {
438
+ strict: katexOptions?.strict ?? 'ignore',
439
+ macros: katexOptions?.macros,
334
440
  output: 'mathml',
335
441
  throwOnError: false,
336
- trust: false,
337
- strict: 'ignore'
442
+ trust: false
338
443
  }
339
444
  ],
340
445
  ...rehypePlugins ?? [],
@@ -344,7 +449,9 @@ const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins
344
449
  ], [
345
450
  rehypePlugins,
346
451
  streaming,
347
- footnotePrefix
452
+ footnotePrefix,
453
+ katexOptions?.strict,
454
+ katexOptions?.macros
348
455
  ]);
349
456
  const remarkRehypeOptions = useMemo(()=>({
350
457
  clobberPrefix: footnotePrefix,
@@ -360,7 +467,7 @@ const Markdown = /*#__PURE__*/ forwardRef(({ children, components, remarkPlugins
360
467
  "data-slot": "markdown",
361
468
  "data-streaming": streaming || void 0,
362
469
  "aria-busy": streaming || void 0,
363
- className: cn('flex min-w-0 flex-col gap-3 text-sm leading-relaxed break-words text-foreground [&_math]:text-[1.15em] [&>.katex]:overflow-x-auto [&>.katex]:py-1', className),
470
+ className: cn('flex min-w-0 flex-col gap-(--markdown-gap,0.75rem) text-(length:--markdown-font-size,0.875rem) leading-(--markdown-leading,1.625) break-words text-foreground [&_math]:text-[1.15em] [&>.katex]:overflow-x-auto [&>.katex]:overflow-y-hidden [&>.katex]:py-1 in-data-[density=compact]:[--markdown-gap:0.5rem] in-data-[density=compact]:[--markdown-font-size:0.75rem] in-data-[density=compact]:[--markdown-leading:1.5]', className),
364
471
  ...props,
365
472
  children: /*#__PURE__*/ jsx(MarkdownContext.Provider, {
366
473
  value: context,
@@ -53,7 +53,7 @@ const DEFAULT_MESSAGE_ACTIONS_STRINGS = {
53
53
  ...DEFAULT_MESSAGE_ACTIONS_OVERFLOW_STRINGS,
54
54
  label: 'Message actions'
55
55
  };
56
- const messageActionsVariants = (0, external_class_variance_authority_namespaceObject.cva)('flex w-fit max-w-full items-center gap-0.5 px-2', {
56
+ const messageActionsVariants = (0, external_class_variance_authority_namespaceObject.cva)('flex w-fit max-w-full items-center gap-0.5 px-2 in-data-[density=compact]:[&_[data-slot=message-action]]:size-5 in-data-[density=compact]:[&_[data-slot=message-action]]:min-w-5 in-data-[density=compact]:[&_[data-slot=message-actions-overflow]]:size-5 in-data-[density=compact]:[&_[data-slot=message-action]_svg]:size-3.5 in-data-[density=compact]:[&_[data-slot=message-actions-overflow]_svg]:size-3.5', {
57
57
  variants: {
58
58
  visibility: {
59
59
  always: '',
@@ -14,6 +14,9 @@ import { TooltipContent } from './tooltip';
14
14
  *
15
15
  * The parts use Radix tooltips, which throw without a `TooltipProvider`. `MessageActions` provides
16
16
  * one, so render them inside it or under your own provider.
17
+ *
18
+ * Compact density (Wind's own; Material's action bar does not change): inside an ancestor with
19
+ * `data-density="compact"` the bar's controls drop from 24px to 20px with 14px icons.
17
20
  */
18
21
  export interface MessageActionItem {
19
22
  id: string;
@@ -16,7 +16,7 @@ const DEFAULT_MESSAGE_ACTIONS_STRINGS = {
16
16
  ...DEFAULT_MESSAGE_ACTIONS_OVERFLOW_STRINGS,
17
17
  label: 'Message actions'
18
18
  };
19
- const messageActionsVariants = cva('flex w-fit max-w-full items-center gap-0.5 px-2', {
19
+ const messageActionsVariants = cva('flex w-fit max-w-full items-center gap-0.5 px-2 in-data-[density=compact]:[&_[data-slot=message-action]]:size-5 in-data-[density=compact]:[&_[data-slot=message-action]]:min-w-5 in-data-[density=compact]:[&_[data-slot=message-actions-overflow]]:size-5 in-data-[density=compact]:[&_[data-slot=message-action]_svg]:size-3.5 in-data-[density=compact]:[&_[data-slot=message-actions-overflow]_svg]:size-3.5', {
20
20
  variants: {
21
21
  visibility: {
22
22
  always: '',