@ant-design/agentic-ui 2.30.6 → 2.30.7

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.
@@ -0,0 +1,15 @@
1
+ import type { Processor } from 'unified';
2
+ import React from 'react';
3
+ export interface MarkdownBlockPieceProps {
4
+ /** 末块为 tail(生长中);一旦其后出现新块,同一段内容变为 sealed,保持同一 React key 可避免重组件卸载 */
5
+ variant: 'sealed' | 'tail';
6
+ blockSource: string;
7
+ processor: Processor;
8
+ components: Record<string, any>;
9
+ /** 仅末块且处于流式模式时为 true,用于节流与末段动画 */
10
+ streaming: boolean;
11
+ }
12
+ /**
13
+ * 统一的块级渲染:封版与末块使用同一组件类型;按 blockSource 缓存解析结果引用,使 tail→sealed 时与旧 Map 缓存一样复用同一棵 React 子树。
14
+ */
15
+ export declare const MarkdownBlockPiece: React.NamedExoticComponent<MarkdownBlockPieceProps>;
@@ -0,0 +1,61 @@
1
+ import React, { memo, useMemo, useRef } from "react";
2
+ import { renderMarkdownBlock } from "../markdownReactShared";
3
+ import { StreamingAnimationContext } from "../StreamingAnimationContext";
4
+ import { shouldReparseLastBlock } from "./lastBlockThrottle";
5
+ /**
6
+ * 统一的块级渲染:封版与末块使用同一组件类型;按 blockSource 缓存解析结果引用,使 tail→sealed 时与旧 Map 缓存一样复用同一棵 React 子树。
7
+ */ export var MarkdownBlockPiece = /*#__PURE__*/ memo(function MarkdownBlockPiece(param) {
8
+ var variant = param.variant, blockSource = param.blockSource, processor = param.processor, components = param.components, streaming = param.streaming;
9
+ var lastParsedRef = useRef(null);
10
+ /** 完整 parse 结果缓存:键为 block 源串,供 sealed 与 tail 晋升时复用同一引用 */ var parseBySourceRef = useRef(new Map());
11
+ var node = useMemo(function() {
12
+ var cached = parseBySourceRef.current.get(blockSource);
13
+ if (cached && variant === 'sealed') {
14
+ return cached;
15
+ }
16
+ if (variant === 'sealed') {
17
+ var el = renderMarkdownBlock(blockSource, processor, components, {
18
+ markStreamingTailParagraph: false
19
+ });
20
+ parseBySourceRef.current.set(blockSource, el);
21
+ return el;
22
+ }
23
+ if (!streaming) {
24
+ var el1 = renderMarkdownBlock(blockSource, processor, components, {
25
+ markStreamingTailParagraph: false
26
+ });
27
+ parseBySourceRef.current.set(blockSource, el1);
28
+ lastParsedRef.current = {
29
+ source: blockSource,
30
+ node: el1
31
+ };
32
+ return el1;
33
+ }
34
+ var prev = lastParsedRef.current;
35
+ if (prev && !shouldReparseLastBlock(prev.source, blockSource, true)) {
36
+ return prev.node;
37
+ }
38
+ var el2 = renderMarkdownBlock(blockSource, processor, components, {
39
+ markStreamingTailParagraph: true
40
+ });
41
+ parseBySourceRef.current.set(blockSource, el2);
42
+ lastParsedRef.current = {
43
+ source: blockSource,
44
+ node: el2
45
+ };
46
+ return el2;
47
+ }, [
48
+ variant,
49
+ blockSource,
50
+ processor,
51
+ components,
52
+ streaming
53
+ ]);
54
+ var animateBlock = variant === 'tail' && streaming;
55
+ return /*#__PURE__*/ React.createElement(StreamingAnimationContext.Provider, {
56
+ value: {
57
+ animateBlock: animateBlock
58
+ }
59
+ }, node);
60
+ });
61
+ MarkdownBlockPiece.displayName = 'MarkdownBlockPiece';
@@ -0,0 +1,4 @@
1
+ /**
2
+ * 流式末块:是否应重新 parse(相对上一次已 parse 的源)。
3
+ */
4
+ export declare const shouldReparseLastBlock: (prevParsedSource: string | undefined, newSource: string, streaming: boolean) => boolean;
@@ -0,0 +1,14 @@
1
+ var LAST_BLOCK_THROTTLE_CHARS = 20;
2
+ var BLOCK_BOUNDARY_TRIGGERS = /[\n`|#>*\-!$[\]]/;
3
+ /**
4
+ * 流式末块:是否应重新 parse(相对上一次已 parse 的源)。
5
+ */ export var shouldReparseLastBlock = function shouldReparseLastBlock(prevParsedSource, newSource, streaming) {
6
+ if (!streaming) return true;
7
+ if (!prevParsedSource) return true;
8
+ if (newSource.length < prevParsedSource.length) return true;
9
+ if (!newSource.startsWith(prevParsedSource)) return true;
10
+ var added = newSource.slice(prevParsedSource.length);
11
+ if (added.length >= LAST_BLOCK_THROTTLE_CHARS) return true;
12
+ if (BLOCK_BOUNDARY_TRIGGERS.test(added)) return true;
13
+ return false;
14
+ };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 判断是否应视为「非前缀修订」,从而放弃基于前缀的块级复用。
3
+ * revisionSource 应为单调前缀流(如 displayedContent);若未传则调用方用 content 自身。
4
+ */
5
+ export declare const shouldResetRevisionProgress: (previous: string | undefined, next: string) => boolean;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 判断是否应视为「非前缀修订」,从而放弃基于前缀的块级复用。
3
+ * revisionSource 应为单调前缀流(如 displayedContent);若未传则调用方用 content 自身。
4
+ */ export var shouldResetRevisionProgress = function shouldResetRevisionProgress(previous, next) {
5
+ if (previous === undefined || previous === '') return false;
6
+ if (next === previous) return false;
7
+ if (next.startsWith(previous)) return false;
8
+ if (previous.startsWith(next)) return false;
9
+ return true;
10
+ };
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import { type UseMarkdownToReactOptions } from '../markdownReactShared';
3
+ /**
4
+ * 流式优先的 Markdown → React:每块独立 memo 组件;tail 与 sealed 共用组件类型以便块晋升时复用实例。
5
+ */
6
+ export declare const useStreamingMarkdownReact: (content: string, options?: UseMarkdownToReactOptions) => React.ReactNode;
@@ -0,0 +1,70 @@
1
+ import { JINJA_DOLLAR_PLACEHOLDER } from "../../MarkdownEditor/editor/parser/constants";
2
+ import React, { useMemo, useRef } from "react";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { buildEditorAlignedComponents, createHastProcessor, splitMarkdownBlocks } from "../markdownReactShared";
5
+ import { MarkdownBlockPiece } from "./MarkdownBlockPiece";
6
+ import { shouldResetRevisionProgress } from "./revisionPolicy";
7
+ /**
8
+ * 流式优先的 Markdown → React:每块独立 memo 组件;tail 与 sealed 共用组件类型以便块晋升时复用实例。
9
+ */ export var useStreamingMarkdownReact = function useStreamingMarkdownReact(content, options) {
10
+ var revisionSource = (options === null || options === void 0 ? void 0 : options.contentRevisionSource) !== undefined ? options.contentRevisionSource : content;
11
+ var prevRevisionRef = useRef(undefined);
12
+ var revisionGenerationRef = useRef(0);
13
+ var processor = useMemo(function() {
14
+ return createHastProcessor(options === null || options === void 0 ? void 0 : options.remarkPlugins, options === null || options === void 0 ? void 0 : options.htmlConfig);
15
+ }, [
16
+ options === null || options === void 0 ? void 0 : options.remarkPlugins,
17
+ options === null || options === void 0 ? void 0 : options.htmlConfig
18
+ ]);
19
+ var prefixCls = (options === null || options === void 0 ? void 0 : options.prefixCls) || 'ant-agentic-md-editor';
20
+ var components = useMemo(function() {
21
+ return buildEditorAlignedComponents(prefixCls, (options === null || options === void 0 ? void 0 : options.components) || {}, options === null || options === void 0 ? void 0 : options.streaming, options === null || options === void 0 ? void 0 : options.linkConfig, options === null || options === void 0 ? void 0 : options.streamingParagraphAnimation);
22
+ }, [
23
+ prefixCls,
24
+ options === null || options === void 0 ? void 0 : options.components,
25
+ options === null || options === void 0 ? void 0 : options.streaming,
26
+ options === null || options === void 0 ? void 0 : options.linkConfig,
27
+ options === null || options === void 0 ? void 0 : options.streamingParagraphAnimation
28
+ ]);
29
+ return useMemo(function() {
30
+ if (!content) {
31
+ prevRevisionRef.current = '';
32
+ return null;
33
+ }
34
+ var prevRev = prevRevisionRef.current;
35
+ if (prevRev !== undefined && shouldResetRevisionProgress(prevRev, revisionSource)) {
36
+ revisionGenerationRef.current += 1;
37
+ }
38
+ prevRevisionRef.current = revisionSource;
39
+ try {
40
+ var preprocessed = content.replace(new RegExp(JINJA_DOLLAR_PLACEHOLDER, 'g'), '$');
41
+ var blocks = splitMarkdownBlocks(preprocessed);
42
+ if (blocks.length === 0) return null;
43
+ var gen = revisionGenerationRef.current;
44
+ var elements = blocks.map(function(blockSource, index) {
45
+ var isLast = index === blocks.length - 1;
46
+ // 仅用修订代 + 块下标作 key,避免末块随文本增长导致 identity 变化而整段 remount
47
+ var key = "b-".concat(gen, "-").concat(index);
48
+ return jsx(MarkdownBlockPiece, {
49
+ variant: isLast ? 'tail' : 'sealed',
50
+ blockSource: blockSource,
51
+ processor: processor,
52
+ components: components,
53
+ streaming: !!((options === null || options === void 0 ? void 0 : options.streaming) && isLast)
54
+ }, key);
55
+ });
56
+ return jsxs(Fragment, {
57
+ children: elements
58
+ });
59
+ } catch (error) {
60
+ console.error('Failed to render markdown:', error);
61
+ return null;
62
+ }
63
+ }, [
64
+ content,
65
+ revisionSource,
66
+ processor,
67
+ components,
68
+ options === null || options === void 0 ? void 0 : options.streaming
69
+ ]);
70
+ };
@@ -1,28 +1,9 @@
1
1
  import React from 'react';
2
- import { type MarkdownRemarkPlugin, type MarkdownToHtmlConfig } from '../MarkdownEditor/editor/utils/markdownToHtml';
2
+ import type { MarkdownRemarkPlugin, MarkdownToHtmlConfig } from '../MarkdownEditor/editor/utils/markdownToHtml';
3
3
  import type { RendererBlockProps } from './types';
4
- interface UseMarkdownToReactOptions {
5
- remarkPlugins?: MarkdownRemarkPlugin[];
6
- htmlConfig?: MarkdownToHtmlConfig;
7
- components?: Record<string, React.ComponentType<RendererBlockProps>>;
8
- /** MarkdownEditor 的 CSS 前缀,用于生成对齐的 className */
9
- prefixCls?: string;
10
- /** 链接配置:onClick 拦截、openInNewTab 控制 */
11
- linkConfig?: {
12
- openInNewTab?: boolean;
13
- onClick?: (url?: string) => boolean | void;
14
- };
15
- /** 是否处于流式状态,用于最后一个块的打字动画 */
16
- streaming?: boolean;
17
- /**
18
- * 流式时是否对「生长中的末段」启用段落淡入(AnimationText)。
19
- * 默认 false:重解析时频繁触发动画易导致整页闪动;需要时再显式传入 true。
20
- */
21
- streamingParagraphAnimation?: boolean;
22
- }
23
- export declare const useMarkdownToReact: (content: string, options?: UseMarkdownToReactOptions) => React.ReactNode;
4
+ export type { UseMarkdownToReactOptions } from './markdownReactShared';
5
+ export declare const useMarkdownToReact: (content: string, options?: import("./markdownReactShared").UseMarkdownToReactOptions | undefined) => React.ReactNode;
24
6
  /**
25
7
  * 同步将 markdown 转为 React 元素(非 hook 版本,用于测试或一次性转换)
26
8
  */
27
9
  export declare const markdownToReactSync: (content: string, components?: Record<string, React.ComponentType<RendererBlockProps>>, remarkPlugins?: MarkdownRemarkPlugin[], htmlConfig?: MarkdownToHtmlConfig) => React.ReactNode;
28
- export {};