@lobehub/ui 5.6.1 → 5.6.3
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/es/Accordion/Accordion.d.mts +2 -2
- package/es/Accordion/AccordionItem.d.mts +2 -2
- package/es/ActionIcon/ActionIcon.d.mts +2 -2
- package/es/Alert/Alert.d.mts +2 -2
- package/es/AutoComplete/Select.d.mts +2 -2
- package/es/Avatar/AvatarGroup/index.d.mts +2 -2
- package/es/Burger/Burger.d.mts +2 -2
- package/es/CodeDiff/CodeDiff.d.mts +2 -2
- package/es/CodeDiff/PatchDiff.d.mts +2 -2
- package/es/CodeEditor/CodeEditor.d.mts +2 -2
- package/es/Collapse/Collapse.d.mts +2 -2
- package/es/ConfigProvider/index.d.mts +2 -2
- package/es/CopyButton/CopyButton.d.mts +2 -2
- package/es/DatePicker/DatePicker.d.mts +2 -2
- package/es/DraggablePanel/components/DraggablePanelBody.d.mts +2 -2
- package/es/DraggablePanel/components/DraggablePanelContainer.d.mts +2 -2
- package/es/DraggablePanel/components/DraggablePanelFooter.d.mts +2 -2
- package/es/DraggablePanel/components/DraggablePanelHeader.d.mts +2 -2
- package/es/DraggableSideNav/DraggableSideNav.d.mts +2 -2
- package/es/Drawer/Drawer.d.mts +2 -2
- package/es/Dropdown/Dropdown.d.mts +2 -2
- package/es/EditableText/EditableText.d.mts +2 -2
- package/es/EditorSlashMenu/atoms.d.mts +13 -13
- package/es/EmojiPicker/EmojiPicker.d.mts +2 -2
- package/es/Flex/FlexBasic.d.mts +2 -2
- package/es/FontLoader/index.d.mts +2 -2
- package/es/Footer/Footer.d.mts +2 -2
- package/es/Form/components/FormGroup.d.mts +2 -2
- package/es/Form/components/FormItem.d.mts +2 -2
- package/es/Form/components/FormSubmitFooter.d.mts +2 -2
- package/es/FormModal/FormModal.d.mts +2 -2
- package/es/GuideCard/GuideCard.d.mts +2 -2
- package/es/Header/Header.d.mts +2 -2
- package/es/Highlighter/Highlighter.d.mts +2 -2
- package/es/Highlighter/SyntaxHighlighter/index.d.mts +2 -2
- package/es/Hotkey/Hotkey.d.mts +2 -2
- package/es/HotkeyInput/HotkeyInput.d.mts +2 -2
- package/es/Icon/Icon.d.mts +2 -2
- package/es/Icon/components/IconProvider.d.mts +3 -3
- package/es/Image/PreviewGroup.d.mts +2 -2
- package/es/ImageSelect/ImageSelect.d.mts +2 -2
- package/es/Input/Input.d.mts +2 -2
- package/es/Input/InputNumber.d.mts +2 -2
- package/es/Input/InputOPT.d.mts +2 -2
- package/es/Input/InputPassword.d.mts +2 -2
- package/es/Input/TextArea.d.mts +2 -2
- package/es/Layout/components/LayoutFooter.d.mts +2 -2
- package/es/Layout/components/LayoutHeader.d.mts +2 -2
- package/es/Layout/components/LayoutMain.d.mts +2 -2
- package/es/Layout/components/LayoutSidebar.d.mts +2 -2
- package/es/Layout/components/LayoutSidebarInner.d.mts +2 -2
- package/es/Layout/components/LayoutToc.d.mts +2 -2
- package/es/List/ListItem/index.d.mts +2 -2
- package/es/Markdown/Markdown.d.mts +2 -2
- package/es/Markdown/SyntaxMarkdown/StreamdownRender.mjs +173 -33
- package/es/Markdown/SyntaxMarkdown/StreamdownRender.mjs.map +1 -1
- package/es/Markdown/SyntaxMarkdown/streamAnimationMeta.mjs +18 -0
- package/es/Markdown/SyntaxMarkdown/streamAnimationMeta.mjs.map +1 -0
- package/es/Markdown/SyntaxMarkdown/useSmoothStreamContent.mjs +62 -10
- package/es/Markdown/SyntaxMarkdown/useSmoothStreamContent.mjs.map +1 -1
- package/es/Markdown/Typography.d.mts +2 -2
- package/es/Markdown/components/SearchResultCards/index.d.mts +2 -2
- package/es/Markdown/streamProfiler/StreamdownProfilerProvider.mjs +21 -0
- package/es/Markdown/streamProfiler/StreamdownProfilerProvider.mjs.map +1 -0
- package/es/MaskShadow/MaskShadow.d.mts +2 -2
- package/es/Menu/Menu.d.mts +2 -2
- package/es/Mermaid/Mermaid.d.mts +2 -2
- package/es/Mermaid/SyntaxMermaid/index.d.mts +2 -2
- package/es/Modal/Modal.d.mts +2 -2
- package/es/Modal/ModalProvider.d.mts +2 -2
- package/es/Modal/imperative.d.mts +2 -2
- package/es/MotionProvider/index.d.mts +2 -2
- package/es/SearchBar/SearchBar.d.mts +2 -2
- package/es/Segmented/Segmented.d.mts +2 -2
- package/es/Select/Select.d.mts +2 -2
- package/es/SideNav/SideNav.d.mts +2 -2
- package/es/SliderWithInput/SliderWithInput.d.mts +2 -2
- package/es/SortableList/components/DragHandle.d.mts +2 -2
- package/es/SortableList/components/SortableItem.d.mts +2 -2
- package/es/ThemeProvider/ThemeProvider.d.mts +2 -2
- package/es/Toc/Toc.d.mts +2 -2
- package/es/Video/index.d.mts +2 -2
- package/es/awesome/AuroraBackground/AuroraBackground.d.mts +2 -2
- package/es/awesome/BottomGradientButton/BottomGradientButton.d.mts +2 -2
- package/es/awesome/Features/Features.d.mts +2 -2
- package/es/awesome/Giscus/Giscus.d.mts +2 -2
- package/es/awesome/GradientButton/GradientButton.d.mts +2 -2
- package/es/awesome/GridBackground/GridBackground.d.mts +2 -2
- package/es/awesome/GridBackground/GridShowcase.d.mts +2 -2
- package/es/awesome/Hero/Hero.d.mts +2 -2
- package/es/awesome/Spline/Spine.d.mts +2 -2
- package/es/awesome/Spotlight/Spotlight.d.mts +2 -2
- package/es/awesome/SpotlightCard/SpotlightCard.d.mts +2 -2
- package/es/awesome/TypewriterEffect/TypewriterEffect.d.mts +2 -2
- package/es/base-ui/DropdownMenu/DropdownMenu.d.mts +2 -2
- package/es/base-ui/Modal/context.d.mts +2 -2
- package/es/base-ui/Modal/imperative.d.mts +2 -2
- package/es/base-ui/Popover/atoms.d.mts +2 -2
- package/es/base-ui/Popover/context.d.mts +2 -2
- package/es/base-ui/Select/Select.d.mts +2 -2
- package/es/base-ui/Select/atoms.d.mts +19 -19
- package/es/base-ui/Switch/Switch.d.mts +2 -2
- package/es/base-ui/Switch/atoms.d.mts +4 -4
- package/es/base-ui/Toast/Toast.mjs +32 -24
- package/es/base-ui/Toast/Toast.mjs.map +1 -1
- package/es/base-ui/Toast/imperative.d.mts +2 -2
- package/es/base-ui/Toast/style.mjs +5 -0
- package/es/base-ui/Toast/style.mjs.map +1 -1
- package/es/brand/LobeChat/index.d.mts +2 -2
- package/es/brand/LobeHub/index.d.mts +2 -2
- package/es/brand/LogoThree/LogoSpline.d.mts +2 -2
- package/es/brand/LogoThree/index.d.mts +2 -2
- package/es/chat/BackBottom/BackBottom.d.mts +2 -2
- package/es/chat/ChatInputArea/components/ChatInputAreaInner.d.mts +2 -2
- package/es/chat/ChatItem/ChatItem.d.mts +2 -2
- package/es/chat/ChatList/ChatList.d.mts +2 -2
- package/es/chat/EditableMessage/EditableMessage.d.mts +2 -2
- package/es/color/ColorScales/index.d.mts +2 -2
- package/es/color/CssVar/index.d.mts +2 -2
- package/es/i18n/context.d.mts +2 -2
- package/es/icons/lucideExtra/AndroidIcon.d.mts +2 -2
- package/es/icons/lucideExtra/AppleIcon.d.mts +2 -2
- package/es/icons/lucideExtra/AppstoreIcon.d.mts +2 -2
- package/es/icons/lucideExtra/BotPromptIcon.d.mts +3 -3
- package/es/icons/lucideExtra/BrainOffIcon.d.mts +2 -2
- package/es/icons/lucideExtra/ChromeIcon.d.mts +3 -3
- package/es/icons/lucideExtra/CodepenIcon.d.mts +3 -3
- package/es/icons/lucideExtra/CodesandboxIcon.d.mts +3 -3
- package/es/icons/lucideExtra/CreateBotIcon.d.mts +3 -3
- package/es/icons/lucideExtra/DiscordIcon.d.mts +3 -3
- package/es/icons/lucideExtra/FacebookIcon.d.mts +3 -3
- package/es/icons/lucideExtra/FigmaIcon.d.mts +3 -3
- package/es/icons/lucideExtra/FramerIcon.d.mts +3 -3
- package/es/icons/lucideExtra/GithubIcon.d.mts +3 -3
- package/es/icons/lucideExtra/GitlabIcon.d.mts +3 -3
- package/es/icons/lucideExtra/GlobeOffIcon.d.mts +3 -3
- package/es/icons/lucideExtra/GooglePlayIcon.d.mts +3 -3
- package/es/icons/lucideExtra/GroupBotIcon.d.mts +3 -3
- package/es/icons/lucideExtra/GroupBotSquareIcon.d.mts +3 -3
- package/es/icons/lucideExtra/InstagramIcon.d.mts +3 -3
- package/es/icons/lucideExtra/LeftClickIcon.d.mts +3 -3
- package/es/icons/lucideExtra/LeftDoubleClickIcon.d.mts +3 -3
- package/es/icons/lucideExtra/LinkedinIcon.d.mts +3 -3
- package/es/icons/lucideExtra/McpIcon.d.mts +3 -3
- package/es/icons/lucideExtra/NotionIcon.d.mts +2 -2
- package/es/icons/lucideExtra/PocketIcon.d.mts +3 -3
- package/es/icons/lucideExtra/ProviderIcon.d.mts +3 -3
- package/es/icons/lucideExtra/RailSymbolIcon.d.mts +3 -3
- package/es/icons/lucideExtra/RedditIcon.d.mts +3 -3
- package/es/icons/lucideExtra/RightClickIcon.d.mts +3 -3
- package/es/icons/lucideExtra/RightDoubleClickIcon.d.mts +3 -3
- package/es/icons/lucideExtra/ShapesUploadIcon.d.mts +2 -2
- package/es/icons/lucideExtra/SkillsIcon.d.mts +3 -3
- package/es/icons/lucideExtra/SlackIcon.d.mts +3 -3
- package/es/icons/lucideExtra/ThinkIcon.d.mts +3 -3
- package/es/icons/lucideExtra/TreeDownRightIcon.d.mts +3 -3
- package/es/icons/lucideExtra/TreeUpDownRightIcon.d.mts +3 -3
- package/es/mdx/Mdx/index.d.mts +2 -2
- package/es/mobile/ChatHeader/ChatHeaderTitle.d.mts +2 -2
- package/es/mobile/ChatInputArea/components/ChatSendButton.d.mts +2 -2
- package/es/mobile/TabBar/TabBar.d.mts +2 -2
- package/es/storybook/StoryBook/index.d.mts +2 -2
- package/package.json +1 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InputNumberProps } from "./type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react182 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Input/InputNumber.d.ts
|
|
5
|
-
declare const InputNumber:
|
|
5
|
+
declare const InputNumber: react182.NamedExoticComponent<InputNumberProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { InputNumber };
|
|
8
8
|
//# sourceMappingURL=InputNumber.d.mts.map
|
package/es/Input/InputOPT.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InputOPTProps } from "./type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react183 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Input/InputOPT.d.ts
|
|
5
|
-
declare const InputOPT:
|
|
5
|
+
declare const InputOPT: react183.NamedExoticComponent<InputOPTProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { InputOPT };
|
|
8
8
|
//# sourceMappingURL=InputOPT.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { InputPasswordProps } from "./type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react184 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Input/InputPassword.d.ts
|
|
5
|
-
declare const InputPassword:
|
|
5
|
+
declare const InputPassword: react184.NamedExoticComponent<InputPasswordProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { InputPassword };
|
|
8
8
|
//# sourceMappingURL=InputPassword.d.mts.map
|
package/es/Input/TextArea.d.mts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { TextAreaProps } from "./type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react185 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Input/TextArea.d.ts
|
|
5
|
-
declare const TextArea:
|
|
5
|
+
declare const TextArea: react185.NamedExoticComponent<TextAreaProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { TextArea };
|
|
8
8
|
//# sourceMappingURL=TextArea.d.mts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DivProps } from "../../types/index.mjs";
|
|
2
2
|
import "../../index.mjs";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react28 from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/Layout/components/LayoutFooter.d.ts
|
|
6
|
-
declare const LayoutFooter:
|
|
6
|
+
declare const LayoutFooter: react28.NamedExoticComponent<DivProps>;
|
|
7
7
|
//#endregion
|
|
8
8
|
export { LayoutFooter };
|
|
9
9
|
//# sourceMappingURL=LayoutFooter.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LayoutHeaderProps } from "../type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react29 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Layout/components/LayoutHeader.d.ts
|
|
5
|
-
declare const LayoutHeader:
|
|
5
|
+
declare const LayoutHeader: react29.NamedExoticComponent<LayoutHeaderProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { LayoutHeader };
|
|
8
8
|
//# sourceMappingURL=LayoutHeader.d.mts.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { DivProps } from "../../types/index.mjs";
|
|
2
2
|
import "../../index.mjs";
|
|
3
|
-
import * as
|
|
3
|
+
import * as react30 from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/Layout/components/LayoutMain.d.ts
|
|
6
|
-
declare const LayoutMain:
|
|
6
|
+
declare const LayoutMain: react30.NamedExoticComponent<DivProps>;
|
|
7
7
|
//#endregion
|
|
8
8
|
export { LayoutMain };
|
|
9
9
|
//# sourceMappingURL=LayoutMain.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LayoutSidebarProps } from "../type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react31 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Layout/components/LayoutSidebar.d.ts
|
|
5
|
-
declare const LayoutSidebar:
|
|
5
|
+
declare const LayoutSidebar: react31.NamedExoticComponent<LayoutSidebarProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { LayoutSidebar };
|
|
8
8
|
//# sourceMappingURL=LayoutSidebar.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LayoutSidebarInnerProps } from "../type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react32 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Layout/components/LayoutSidebarInner.d.ts
|
|
5
|
-
declare const LayoutSidebarInner:
|
|
5
|
+
declare const LayoutSidebarInner: react32.NamedExoticComponent<LayoutSidebarInnerProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { LayoutSidebarInner };
|
|
8
8
|
//# sourceMappingURL=LayoutSidebarInner.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LayoutTocProps } from "../type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react33 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Layout/components/LayoutToc.d.ts
|
|
5
|
-
declare const LayoutToc:
|
|
5
|
+
declare const LayoutToc: react33.NamedExoticComponent<LayoutTocProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { LayoutToc };
|
|
8
8
|
//# sourceMappingURL=LayoutToc.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { ListItemProps } from "../type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react27 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/List/ListItem/index.d.ts
|
|
5
|
-
declare const ListItem:
|
|
5
|
+
declare const ListItem: react27.NamedExoticComponent<ListItemProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { ListItem };
|
|
8
8
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { MarkdownProps } from "./type.mjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react26 from "react";
|
|
3
3
|
|
|
4
4
|
//#region src/Markdown/Markdown.d.ts
|
|
5
|
-
declare const Markdown:
|
|
5
|
+
declare const Markdown: react26.NamedExoticComponent<MarkdownProps>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { Markdown };
|
|
8
8
|
//# sourceMappingURL=Markdown.d.mts.map
|
|
@@ -6,10 +6,12 @@ import { useMarkdownContent } from "../../hooks/useMarkdown/useMarkdownContent.m
|
|
|
6
6
|
import { useMarkdownRehypePlugins } from "../../hooks/useMarkdown/useMarkdownRehypePlugins.mjs";
|
|
7
7
|
import { useMarkdownRemarkPlugins } from "../../hooks/useMarkdown/useMarkdownRemarkPlugins.mjs";
|
|
8
8
|
import { rehypeStreamAnimated } from "../plugins/rehypeStreamAnimated.mjs";
|
|
9
|
+
import { useStreamdownProfiler } from "../streamProfiler/StreamdownProfilerProvider.mjs";
|
|
10
|
+
import { resolveBlockAnimationMeta } from "./streamAnimationMeta.mjs";
|
|
9
11
|
import { styles } from "./style.mjs";
|
|
10
12
|
import { useSmoothStreamContent } from "./useSmoothStreamContent.mjs";
|
|
11
13
|
import { useStreamQueue } from "./useStreamQueue.mjs";
|
|
12
|
-
import { createElement, memo, useEffect, useId, useMemo, useRef } from "react";
|
|
14
|
+
import { Profiler, createElement, memo, useCallback, useEffect, useId, useMemo, useRef } from "react";
|
|
13
15
|
import { jsx } from "react/jsx-runtime";
|
|
14
16
|
import Markdown from "react-markdown";
|
|
15
17
|
import { marked } from "marked";
|
|
@@ -17,9 +19,13 @@ import remend from "remend";
|
|
|
17
19
|
|
|
18
20
|
//#region src/Markdown/SyntaxMarkdown/StreamdownRender.tsx
|
|
19
21
|
const STREAM_FADE_DURATION = 280;
|
|
22
|
+
const REVEALED_STREAM_PLUGIN = [rehypeStreamAnimated, { revealed: true }];
|
|
20
23
|
function countChars(text) {
|
|
21
24
|
return [...text].length;
|
|
22
25
|
}
|
|
26
|
+
function getNow() {
|
|
27
|
+
return typeof performance === "undefined" ? Date.now() : performance.now();
|
|
28
|
+
}
|
|
23
29
|
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
24
30
|
const isDeepEqualValue = (a, b) => {
|
|
25
31
|
if (a === b) return true;
|
|
@@ -64,19 +70,27 @@ const StreamdownBlock = memo(({ children, ...rest }) => {
|
|
|
64
70
|
StreamdownBlock.displayName = "StreamdownBlock";
|
|
65
71
|
const StreamdownRender = memo(({ children, ...rest }) => {
|
|
66
72
|
const { streamSmoothingPreset = "balanced" } = useMarkdownContext();
|
|
73
|
+
const profiler = useStreamdownProfiler();
|
|
67
74
|
const escapedContent = useMarkdownContent(children || "");
|
|
68
75
|
const components = useMarkdownComponents();
|
|
69
76
|
const baseRehypePlugins = useStablePlugins(useMarkdownRehypePlugins());
|
|
70
77
|
const remarkPlugins = useStablePlugins(useMarkdownRemarkPlugins());
|
|
71
78
|
const generatedId = useId();
|
|
72
79
|
const smoothedContent = useSmoothStreamContent(typeof escapedContent === "string" ? escapedContent : "", { preset: streamSmoothingPreset });
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
80
|
+
const processedContentResult = useMemo(() => {
|
|
81
|
+
const start = profiler ? getNow() : 0;
|
|
82
|
+
const value = remend(smoothedContent);
|
|
83
|
+
return {
|
|
84
|
+
durationMs: profiler ? getNow() - start : 0,
|
|
85
|
+
value
|
|
86
|
+
};
|
|
87
|
+
}, [profiler, smoothedContent]);
|
|
88
|
+
const processedContent = processedContentResult.value;
|
|
89
|
+
const blocksResult = useMemo(() => {
|
|
90
|
+
const start = profiler ? getNow() : 0;
|
|
77
91
|
const tokens = marked.lexer(processedContent);
|
|
78
92
|
let offset = 0;
|
|
79
|
-
|
|
93
|
+
const value = tokens.map((token) => {
|
|
80
94
|
const block = {
|
|
81
95
|
content: token.raw,
|
|
82
96
|
startOffset: offset
|
|
@@ -84,14 +98,21 @@ const StreamdownRender = memo(({ children, ...rest }) => {
|
|
|
84
98
|
offset += token.raw.length;
|
|
85
99
|
return block;
|
|
86
100
|
});
|
|
87
|
-
|
|
101
|
+
return {
|
|
102
|
+
durationMs: profiler ? getNow() - start : 0,
|
|
103
|
+
value
|
|
104
|
+
};
|
|
105
|
+
}, [processedContent, profiler]);
|
|
106
|
+
const blocks = blocksResult.value;
|
|
88
107
|
const { getBlockState, charDelay } = useStreamQueue(blocks);
|
|
89
108
|
const prevBlockCharCountRef = useRef(/* @__PURE__ */ new Map());
|
|
109
|
+
const blockCharDelayRef = useRef(/* @__PURE__ */ new Map());
|
|
90
110
|
const blockTimelineRef = useRef(/* @__PURE__ */ new Map());
|
|
91
111
|
const lastRenderTsRef = useRef(null);
|
|
92
|
-
const renderTs =
|
|
112
|
+
const renderTs = getNow();
|
|
93
113
|
const frameDt = lastRenderTsRef.current === null ? 0 : Math.max(0, Math.min(renderTs - lastRenderTsRef.current, 120));
|
|
94
|
-
const
|
|
114
|
+
const timelineResult = useMemo(() => {
|
|
115
|
+
const start = profiler ? getNow() : 0;
|
|
95
116
|
const next = /* @__PURE__ */ new Map();
|
|
96
117
|
const prevTimeline = blockTimelineRef.current;
|
|
97
118
|
const prevCharCounts = prevBlockCharCountRef.current;
|
|
@@ -108,50 +129,169 @@ const StreamdownRender = memo(({ children, ...rest }) => {
|
|
|
108
129
|
const minElapsed = Math.max(0, latestCharStart - charDelay * 2);
|
|
109
130
|
next.set(block.startOffset, Math.max(elapsedByTime, minElapsed));
|
|
110
131
|
}
|
|
111
|
-
return
|
|
132
|
+
return {
|
|
133
|
+
durationMs: profiler ? getNow() - start : 0,
|
|
134
|
+
value: next
|
|
135
|
+
};
|
|
112
136
|
}, [
|
|
113
137
|
blocks,
|
|
114
138
|
charDelay,
|
|
115
|
-
frameDt
|
|
139
|
+
frameDt,
|
|
140
|
+
profiler
|
|
141
|
+
]);
|
|
142
|
+
const timelineForRender = timelineResult.value;
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (!profiler) return;
|
|
145
|
+
profiler.recordCalculation({
|
|
146
|
+
durationMs: processedContentResult.durationMs,
|
|
147
|
+
name: "content-normalize",
|
|
148
|
+
textLength: processedContent.length
|
|
149
|
+
});
|
|
150
|
+
}, [
|
|
151
|
+
processedContent.length,
|
|
152
|
+
processedContentResult.durationMs,
|
|
153
|
+
profiler
|
|
154
|
+
]);
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (!profiler) return;
|
|
157
|
+
profiler.recordCalculation({
|
|
158
|
+
durationMs: blocksResult.durationMs,
|
|
159
|
+
itemCount: blocks.length,
|
|
160
|
+
name: "block-lex",
|
|
161
|
+
textLength: processedContent.length
|
|
162
|
+
});
|
|
163
|
+
}, [
|
|
164
|
+
blocks.length,
|
|
165
|
+
blocksResult.durationMs,
|
|
166
|
+
processedContent.length,
|
|
167
|
+
profiler
|
|
168
|
+
]);
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
if (!profiler) return;
|
|
171
|
+
profiler.recordCalculation({
|
|
172
|
+
durationMs: timelineResult.durationMs,
|
|
173
|
+
itemCount: blocks.length,
|
|
174
|
+
name: "block-timeline",
|
|
175
|
+
textLength: processedContent.length
|
|
176
|
+
});
|
|
177
|
+
}, [
|
|
178
|
+
blocks.length,
|
|
179
|
+
processedContent.length,
|
|
180
|
+
profiler,
|
|
181
|
+
timelineResult.durationMs
|
|
182
|
+
]);
|
|
183
|
+
const blockAnimationMetaResult = useMemo(() => {
|
|
184
|
+
const nextBlockCharDelay = /* @__PURE__ */ new Map();
|
|
185
|
+
const blockAnimationMeta = /* @__PURE__ */ new Map();
|
|
186
|
+
for (const [index, block] of blocks.entries()) {
|
|
187
|
+
const state = getBlockState(index);
|
|
188
|
+
const timelineElapsedMs = timelineForRender.get(block.startOffset) ?? 0;
|
|
189
|
+
const animationMeta = resolveBlockAnimationMeta({
|
|
190
|
+
blockCharCount: countChars(block.content),
|
|
191
|
+
currentCharDelay: charDelay,
|
|
192
|
+
fadeDuration: STREAM_FADE_DURATION,
|
|
193
|
+
previousCharDelay: blockCharDelayRef.current.get(block.startOffset),
|
|
194
|
+
state,
|
|
195
|
+
timelineElapsedMs
|
|
196
|
+
});
|
|
197
|
+
nextBlockCharDelay.set(block.startOffset, animationMeta.charDelay);
|
|
198
|
+
blockAnimationMeta.set(block.startOffset, animationMeta);
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
blockAnimationMeta,
|
|
202
|
+
blockCharDelay: nextBlockCharDelay
|
|
203
|
+
};
|
|
204
|
+
}, [
|
|
205
|
+
blocks,
|
|
206
|
+
charDelay,
|
|
207
|
+
getBlockState,
|
|
208
|
+
timelineForRender
|
|
116
209
|
]);
|
|
117
210
|
useEffect(() => {
|
|
118
211
|
const nextCharCount = /* @__PURE__ */ new Map();
|
|
119
212
|
for (const block of blocks) nextCharCount.set(block.startOffset, countChars(block.content));
|
|
213
|
+
blockCharDelayRef.current = blockAnimationMetaResult.blockCharDelay;
|
|
120
214
|
prevBlockCharCountRef.current = nextCharCount;
|
|
121
215
|
blockTimelineRef.current = timelineForRender;
|
|
122
|
-
lastRenderTsRef.current =
|
|
123
|
-
}, [
|
|
124
|
-
|
|
216
|
+
lastRenderTsRef.current = getNow();
|
|
217
|
+
}, [
|
|
218
|
+
blockAnimationMetaResult.blockCharDelay,
|
|
219
|
+
blocks,
|
|
220
|
+
timelineForRender
|
|
221
|
+
]);
|
|
222
|
+
const handleRootRender = useCallback((_, phase, actualDuration, baseDuration) => {
|
|
223
|
+
profiler?.recordRootCommit({
|
|
224
|
+
actualDuration,
|
|
225
|
+
baseDuration,
|
|
226
|
+
blockCount: blocks.length,
|
|
227
|
+
phase,
|
|
228
|
+
textLength: processedContent.length
|
|
229
|
+
});
|
|
230
|
+
}, [
|
|
231
|
+
blocks.length,
|
|
232
|
+
processedContent.length,
|
|
233
|
+
profiler
|
|
234
|
+
]);
|
|
235
|
+
const handleBlockRender = useCallback((id, phase, actualDuration, baseDuration) => {
|
|
236
|
+
if (!profiler) return;
|
|
237
|
+
const [, indexText, offsetText] = id.split(":");
|
|
238
|
+
const blockIndex = Number(indexText);
|
|
239
|
+
if (!Number.isFinite(blockIndex)) return;
|
|
240
|
+
const block = blocks[blockIndex];
|
|
241
|
+
if (!block) return;
|
|
242
|
+
profiler.recordBlockCommit({
|
|
243
|
+
actualDuration,
|
|
244
|
+
baseDuration,
|
|
245
|
+
blockChars: countChars(block.content),
|
|
246
|
+
blockIndex,
|
|
247
|
+
blockKey: offsetText ?? String(block.startOffset),
|
|
248
|
+
phase,
|
|
249
|
+
state: getBlockState(blockIndex)
|
|
250
|
+
});
|
|
251
|
+
}, [
|
|
252
|
+
blocks,
|
|
253
|
+
getBlockState,
|
|
254
|
+
profiler
|
|
255
|
+
]);
|
|
256
|
+
const content = /* @__PURE__ */ jsx("div", {
|
|
125
257
|
className: styles.animated,
|
|
126
258
|
children: blocks.map((block, index) => {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
charDelay,
|
|
259
|
+
if (getBlockState(index) === "queued") return null;
|
|
260
|
+
const animationMeta = blockAnimationMetaResult.blockAnimationMeta.get(block.startOffset);
|
|
261
|
+
if (!animationMeta) return null;
|
|
262
|
+
const plugins = animationMeta.settled ? [...baseRehypePlugins, REVEALED_STREAM_PLUGIN] : [...baseRehypePlugins, [rehypeStreamAnimated, {
|
|
263
|
+
charDelay: animationMeta.charDelay,
|
|
133
264
|
fadeDuration: STREAM_FADE_DURATION,
|
|
134
|
-
timelineElapsedMs
|
|
135
|
-
}]];
|
|
136
|
-
else if (state === "animating") plugins = [...baseRehypePlugins, [rehypeStreamAnimated, {
|
|
137
|
-
charDelay,
|
|
138
|
-
fadeDuration: STREAM_FADE_DURATION,
|
|
139
|
-
timelineElapsedMs
|
|
265
|
+
timelineElapsedMs: animationMeta.timelineElapsedMs
|
|
140
266
|
}]];
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
fadeDuration: STREAM_FADE_DURATION,
|
|
144
|
-
timelineElapsedMs
|
|
145
|
-
}]];
|
|
146
|
-
return /* @__PURE__ */ createElement(StreamdownBlock, {
|
|
267
|
+
const key = `${generatedId}-${block.startOffset}`;
|
|
268
|
+
const blockNode = /* @__PURE__ */ jsx(StreamdownBlock, {
|
|
147
269
|
...rest,
|
|
148
270
|
components,
|
|
149
|
-
|
|
271
|
+
rehypePlugins: plugins,
|
|
272
|
+
remarkPlugins,
|
|
273
|
+
children: block.content
|
|
274
|
+
});
|
|
275
|
+
if (!profiler) return /* @__PURE__ */ createElement(StreamdownBlock, {
|
|
276
|
+
...rest,
|
|
277
|
+
components,
|
|
278
|
+
key,
|
|
150
279
|
rehypePlugins: plugins,
|
|
151
280
|
remarkPlugins
|
|
152
281
|
}, block.content);
|
|
282
|
+
return /* @__PURE__ */ jsx(Profiler, {
|
|
283
|
+
id: `streamdown-block:${index}:${block.startOffset}`,
|
|
284
|
+
onRender: handleBlockRender,
|
|
285
|
+
children: blockNode
|
|
286
|
+
}, key);
|
|
153
287
|
})
|
|
154
288
|
});
|
|
289
|
+
if (!profiler) return content;
|
|
290
|
+
return /* @__PURE__ */ jsx(Profiler, {
|
|
291
|
+
id: "streamdown-root",
|
|
292
|
+
onRender: handleRootRender,
|
|
293
|
+
children: content
|
|
294
|
+
});
|
|
155
295
|
});
|
|
156
296
|
StreamdownRender.displayName = "StreamdownRender";
|
|
157
297
|
var StreamdownRender_default = StreamdownRender;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StreamdownRender.mjs","names":["blocks: BlockInfo[]","plugins: Pluggable[]"],"sources":["../../../src/Markdown/SyntaxMarkdown/StreamdownRender.tsx"],"sourcesContent":["'use client';\n\nimport { marked } from 'marked';\nimport { memo, useEffect, useId, useMemo, useRef } from 'react';\nimport Markdown, { type Options } from 'react-markdown';\nimport remend from 'remend';\nimport type { Pluggable, PluggableList } from 'unified';\n\nimport {\n useMarkdownComponents,\n useMarkdownContent,\n useMarkdownRehypePlugins,\n useMarkdownRemarkPlugins,\n} from '@/hooks/useMarkdown';\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\nimport { rehypeStreamAnimated } from '@/Markdown/plugins/rehypeStreamAnimated';\n\nimport { styles } from './style';\nimport { useSmoothStreamContent } from './useSmoothStreamContent';\nimport { type BlockInfo, useStreamQueue } from './useStreamQueue';\n\nconst STREAM_FADE_DURATION = 280;\n\nfunction countChars(text: string): number {\n return [...text].length;\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null;\n\nconst isDeepEqualValue = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b)) return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!isDeepEqualValue(a[i], b[i])) return false;\n }\n return true;\n }\n\n if (!isRecord(a) || !isRecord(b)) return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!isDeepEqualValue(a[key], b[key])) return false;\n }\n\n return true;\n};\n\nconst isSamePlugin = (prevPlugin: Pluggable, nextPlugin: Pluggable): boolean => {\n const prevTuple = Array.isArray(prevPlugin) ? prevPlugin : [prevPlugin];\n const nextTuple = Array.isArray(nextPlugin) ? nextPlugin : [nextPlugin];\n\n if (prevTuple.length !== nextTuple.length) return false;\n if (prevTuple[0] !== nextTuple[0]) return false;\n\n return isDeepEqualValue(prevTuple.slice(1), nextTuple.slice(1));\n};\n\nconst isSamePlugins = (\n prevPlugins?: PluggableList | null,\n nextPlugins?: PluggableList | null,\n): boolean => {\n if (prevPlugins === nextPlugins) return true;\n if (!prevPlugins || !nextPlugins) return !prevPlugins && !nextPlugins;\n if (prevPlugins.length !== nextPlugins.length) return false;\n\n for (let i = 0; i < prevPlugins.length; i++) {\n if (!isSamePlugin(prevPlugins[i], nextPlugins[i])) return false;\n }\n\n return true;\n};\n\nconst useStablePlugins = (plugins: PluggableList): PluggableList => {\n const stableRef = useRef<PluggableList>(plugins);\n\n if (!isSamePlugins(stableRef.current, plugins)) {\n stableRef.current = plugins;\n }\n\n return stableRef.current;\n};\n\nconst StreamdownBlock = memo<Options>(\n ({ children, ...rest }) => {\n return <Markdown {...rest}>{children}</Markdown>;\n },\n (prevProps, nextProps) =>\n prevProps.children === nextProps.children &&\n prevProps.components === nextProps.components &&\n isSamePlugins(prevProps.rehypePlugins, nextProps.rehypePlugins) &&\n isSamePlugins(prevProps.remarkPlugins, nextProps.remarkPlugins),\n);\n\nStreamdownBlock.displayName = 'StreamdownBlock';\n\nexport const StreamdownRender = memo<Options>(({ children, ...rest }) => {\n const { streamSmoothingPreset = 'balanced' } = useMarkdownContext();\n const escapedContent = useMarkdownContent(children || '');\n const components = useMarkdownComponents();\n const baseRehypePlugins = useStablePlugins(useMarkdownRehypePlugins());\n const remarkPlugins = useStablePlugins(useMarkdownRemarkPlugins());\n const generatedId = useId();\n const smoothedContent = useSmoothStreamContent(\n typeof escapedContent === 'string' ? escapedContent : '',\n { preset: streamSmoothingPreset },\n );\n\n const processedContent = useMemo(() => {\n return remend(smoothedContent);\n }, [smoothedContent]);\n\n const blocks: BlockInfo[] = useMemo(() => {\n const tokens = marked.lexer(processedContent);\n let offset = 0;\n return tokens.map((token) => {\n const block = { content: token.raw, startOffset: offset };\n offset += token.raw.length;\n return block;\n });\n }, [processedContent]);\n\n const { getBlockState, charDelay } = useStreamQueue(blocks);\n const prevBlockCharCountRef = useRef<Map<number, number>>(new Map());\n const blockTimelineRef = useRef<Map<number, number>>(new Map());\n const lastRenderTsRef = useRef<number | null>(null);\n\n const renderTs = typeof performance === 'undefined' ? Date.now() : performance.now();\n const frameDt =\n lastRenderTsRef.current === null\n ? 0\n : Math.max(0, Math.min(renderTs - lastRenderTsRef.current, 120));\n\n const timelineForRender = useMemo(() => {\n const next = new Map<number, number>();\n const prevTimeline = blockTimelineRef.current;\n const prevCharCounts = prevBlockCharCountRef.current;\n\n for (const block of blocks) {\n const blockCharCount = countChars(block.content);\n const prevCharCount = prevCharCounts.get(block.startOffset) ?? 0;\n const prevElapsed = prevTimeline.get(block.startOffset);\n const latestCharStart = Math.max(0, (blockCharCount - 1) * charDelay);\n\n if (prevElapsed === undefined || blockCharCount < prevCharCount) {\n next.set(block.startOffset, latestCharStart);\n continue;\n }\n\n const elapsedByTime = prevElapsed + frameDt;\n // Avoid huge hidden backlog when stream updates in bursts.\n const minElapsed = Math.max(0, latestCharStart - charDelay * 2);\n next.set(block.startOffset, Math.max(elapsedByTime, minElapsed));\n }\n\n return next;\n }, [blocks, charDelay, frameDt]);\n\n useEffect(() => {\n const nextCharCount = new Map<number, number>();\n for (const block of blocks) {\n nextCharCount.set(block.startOffset, countChars(block.content));\n }\n prevBlockCharCountRef.current = nextCharCount;\n blockTimelineRef.current = timelineForRender;\n lastRenderTsRef.current = typeof performance === 'undefined' ? Date.now() : performance.now();\n }, [blocks, timelineForRender]);\n\n return (\n <div className={styles.animated}>\n {blocks.map((block, index) => {\n const state = getBlockState(index);\n if (state === 'queued') return null;\n const timelineElapsedMs = timelineForRender.get(block.startOffset) ?? 0;\n\n let plugins: Pluggable[];\n if (state === 'streaming') {\n plugins = [\n ...baseRehypePlugins,\n [\n rehypeStreamAnimated,\n { charDelay, fadeDuration: STREAM_FADE_DURATION, timelineElapsedMs },\n ],\n ];\n } else if (state === 'animating') {\n // Continue from previously rendered progress instead of restarting\n // or force-switching to fully revealed.\n plugins = [\n ...baseRehypePlugins,\n [\n rehypeStreamAnimated,\n { charDelay, fadeDuration: STREAM_FADE_DURATION, timelineElapsedMs },\n ],\n ];\n } else {\n // Keep fade continuity for just-finished chars; avoid instant class\n // switch to stream-char-revealed that would cancel in-flight fades.\n plugins = [\n ...baseRehypePlugins,\n [\n rehypeStreamAnimated,\n { charDelay, fadeDuration: STREAM_FADE_DURATION, timelineElapsedMs },\n ],\n ];\n }\n\n return (\n <StreamdownBlock\n {...rest}\n components={components}\n key={`${generatedId}-${block.startOffset}`}\n rehypePlugins={plugins}\n remarkPlugins={remarkPlugins}\n >\n {block.content}\n </StreamdownBlock>\n );\n })}\n </div>\n );\n});\n\nStreamdownRender.displayName = 'StreamdownRender';\n\nexport default StreamdownRender;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StreamdownRender.mjs","names":["REVEALED_STREAM_PLUGIN: Pluggable","blocks: BlockInfo[]","plugins: Pluggable[]"],"sources":["../../../src/Markdown/SyntaxMarkdown/StreamdownRender.tsx"],"sourcesContent":["'use client';\n\nimport { marked } from 'marked';\nimport {\n memo,\n Profiler,\n type ProfilerOnRenderCallback,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n} from 'react';\nimport Markdown, { type Options } from 'react-markdown';\nimport remend from 'remend';\nimport type { Pluggable, PluggableList } from 'unified';\n\nimport {\n useMarkdownComponents,\n useMarkdownContent,\n useMarkdownRehypePlugins,\n useMarkdownRemarkPlugins,\n} from '@/hooks/useMarkdown';\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\nimport { rehypeStreamAnimated } from '@/Markdown/plugins/rehypeStreamAnimated';\nimport { useStreamdownProfiler } from '@/Markdown/streamProfiler';\n\nimport { resolveBlockAnimationMeta } from './streamAnimationMeta';\nimport { styles } from './style';\nimport { useSmoothStreamContent } from './useSmoothStreamContent';\nimport { type BlockInfo, useStreamQueue } from './useStreamQueue';\n\nconst STREAM_FADE_DURATION = 280;\nconst REVEALED_STREAM_PLUGIN: Pluggable = [rehypeStreamAnimated, { revealed: true }];\n\nfunction countChars(text: string): number {\n return [...text].length;\n}\n\nfunction getNow(): number {\n return typeof performance === 'undefined' ? Date.now() : performance.now();\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null;\n\nconst isDeepEqualValue = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b)) return false;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (!isDeepEqualValue(a[i], b[i])) return false;\n }\n return true;\n }\n\n if (!isRecord(a) || !isRecord(b)) return false;\n\n const keysA = Object.keys(a);\n const keysB = Object.keys(b);\n if (keysA.length !== keysB.length) return false;\n\n for (const key of keysA) {\n if (!isDeepEqualValue(a[key], b[key])) return false;\n }\n\n return true;\n};\n\nconst isSamePlugin = (prevPlugin: Pluggable, nextPlugin: Pluggable): boolean => {\n const prevTuple = Array.isArray(prevPlugin) ? prevPlugin : [prevPlugin];\n const nextTuple = Array.isArray(nextPlugin) ? nextPlugin : [nextPlugin];\n\n if (prevTuple.length !== nextTuple.length) return false;\n if (prevTuple[0] !== nextTuple[0]) return false;\n\n return isDeepEqualValue(prevTuple.slice(1), nextTuple.slice(1));\n};\n\nconst isSamePlugins = (\n prevPlugins?: PluggableList | null,\n nextPlugins?: PluggableList | null,\n): boolean => {\n if (prevPlugins === nextPlugins) return true;\n if (!prevPlugins || !nextPlugins) return !prevPlugins && !nextPlugins;\n if (prevPlugins.length !== nextPlugins.length) return false;\n\n for (let i = 0; i < prevPlugins.length; i++) {\n if (!isSamePlugin(prevPlugins[i], nextPlugins[i])) return false;\n }\n\n return true;\n};\n\nconst useStablePlugins = (plugins: PluggableList): PluggableList => {\n const stableRef = useRef<PluggableList>(plugins);\n\n if (!isSamePlugins(stableRef.current, plugins)) {\n stableRef.current = plugins;\n }\n\n return stableRef.current;\n};\n\nconst StreamdownBlock = memo<Options>(\n ({ children, ...rest }) => {\n return <Markdown {...rest}>{children}</Markdown>;\n },\n (prevProps, nextProps) =>\n prevProps.children === nextProps.children &&\n prevProps.components === nextProps.components &&\n isSamePlugins(prevProps.rehypePlugins, nextProps.rehypePlugins) &&\n isSamePlugins(prevProps.remarkPlugins, nextProps.remarkPlugins),\n);\n\nStreamdownBlock.displayName = 'StreamdownBlock';\n\nexport const StreamdownRender = memo<Options>(({ children, ...rest }) => {\n const { streamSmoothingPreset = 'balanced' } = useMarkdownContext();\n const profiler = useStreamdownProfiler();\n const escapedContent = useMarkdownContent(children || '');\n const components = useMarkdownComponents();\n const baseRehypePlugins = useStablePlugins(useMarkdownRehypePlugins());\n const remarkPlugins = useStablePlugins(useMarkdownRemarkPlugins());\n const generatedId = useId();\n const smoothedContent = useSmoothStreamContent(\n typeof escapedContent === 'string' ? escapedContent : '',\n { preset: streamSmoothingPreset },\n );\n\n const processedContentResult = useMemo(() => {\n const start = profiler ? getNow() : 0;\n const value = remend(smoothedContent);\n\n return {\n durationMs: profiler ? getNow() - start : 0,\n value,\n };\n }, [profiler, smoothedContent]);\n const processedContent = processedContentResult.value;\n\n const blocksResult = useMemo(() => {\n const start = profiler ? getNow() : 0;\n const tokens = marked.lexer(processedContent);\n let offset = 0;\n\n const value = tokens.map((token) => {\n const block = { content: token.raw, startOffset: offset };\n offset += token.raw.length;\n return block;\n });\n\n return {\n durationMs: profiler ? getNow() - start : 0,\n value,\n };\n }, [processedContent, profiler]);\n const blocks: BlockInfo[] = blocksResult.value;\n\n const { getBlockState, charDelay } = useStreamQueue(blocks);\n const prevBlockCharCountRef = useRef<Map<number, number>>(new Map());\n const blockCharDelayRef = useRef<Map<number, number>>(new Map());\n const blockTimelineRef = useRef<Map<number, number>>(new Map());\n const lastRenderTsRef = useRef<number | null>(null);\n\n const renderTs = getNow();\n const frameDt =\n lastRenderTsRef.current === null\n ? 0\n : Math.max(0, Math.min(renderTs - lastRenderTsRef.current, 120));\n\n const timelineResult = useMemo(() => {\n const start = profiler ? getNow() : 0;\n const next = new Map<number, number>();\n const prevTimeline = blockTimelineRef.current;\n const prevCharCounts = prevBlockCharCountRef.current;\n\n for (const block of blocks) {\n const blockCharCount = countChars(block.content);\n const prevCharCount = prevCharCounts.get(block.startOffset) ?? 0;\n const prevElapsed = prevTimeline.get(block.startOffset);\n const latestCharStart = Math.max(0, (blockCharCount - 1) * charDelay);\n\n if (prevElapsed === undefined || blockCharCount < prevCharCount) {\n next.set(block.startOffset, latestCharStart);\n continue;\n }\n\n const elapsedByTime = prevElapsed + frameDt;\n // Avoid huge hidden backlog when stream updates in bursts.\n const minElapsed = Math.max(0, latestCharStart - charDelay * 2);\n next.set(block.startOffset, Math.max(elapsedByTime, minElapsed));\n }\n\n return {\n durationMs: profiler ? getNow() - start : 0,\n value: next,\n };\n }, [blocks, charDelay, frameDt, profiler]);\n const timelineForRender = timelineResult.value;\n\n useEffect(() => {\n if (!profiler) return;\n\n profiler.recordCalculation({\n durationMs: processedContentResult.durationMs,\n name: 'content-normalize',\n textLength: processedContent.length,\n });\n }, [processedContent.length, processedContentResult.durationMs, profiler]);\n\n useEffect(() => {\n if (!profiler) return;\n\n profiler.recordCalculation({\n durationMs: blocksResult.durationMs,\n itemCount: blocks.length,\n name: 'block-lex',\n textLength: processedContent.length,\n });\n }, [blocks.length, blocksResult.durationMs, processedContent.length, profiler]);\n\n useEffect(() => {\n if (!profiler) return;\n\n profiler.recordCalculation({\n durationMs: timelineResult.durationMs,\n itemCount: blocks.length,\n name: 'block-timeline',\n textLength: processedContent.length,\n });\n }, [blocks.length, processedContent.length, profiler, timelineResult.durationMs]);\n\n const blockAnimationMetaResult = useMemo(() => {\n const nextBlockCharDelay = new Map<number, number>();\n const blockAnimationMeta = new Map<number, ReturnType<typeof resolveBlockAnimationMeta>>();\n\n for (const [index, block] of blocks.entries()) {\n const state = getBlockState(index);\n const timelineElapsedMs = timelineForRender.get(block.startOffset) ?? 0;\n const animationMeta = resolveBlockAnimationMeta({\n blockCharCount: countChars(block.content),\n currentCharDelay: charDelay,\n fadeDuration: STREAM_FADE_DURATION,\n previousCharDelay: blockCharDelayRef.current.get(block.startOffset),\n state,\n timelineElapsedMs,\n });\n\n nextBlockCharDelay.set(block.startOffset, animationMeta.charDelay);\n blockAnimationMeta.set(block.startOffset, animationMeta);\n }\n\n return {\n blockAnimationMeta,\n blockCharDelay: nextBlockCharDelay,\n };\n }, [blocks, charDelay, getBlockState, timelineForRender]);\n\n useEffect(() => {\n const nextCharCount = new Map<number, number>();\n for (const block of blocks) {\n nextCharCount.set(block.startOffset, countChars(block.content));\n }\n blockCharDelayRef.current = blockAnimationMetaResult.blockCharDelay;\n prevBlockCharCountRef.current = nextCharCount;\n blockTimelineRef.current = timelineForRender;\n lastRenderTsRef.current = getNow();\n }, [blockAnimationMetaResult.blockCharDelay, blocks, timelineForRender]);\n\n const handleRootRender = useCallback<ProfilerOnRenderCallback>(\n (_, phase, actualDuration, baseDuration) => {\n profiler?.recordRootCommit({\n actualDuration,\n baseDuration,\n blockCount: blocks.length,\n phase,\n textLength: processedContent.length,\n });\n },\n [blocks.length, processedContent.length, profiler],\n );\n\n const handleBlockRender = useCallback<ProfilerOnRenderCallback>(\n (id, phase, actualDuration, baseDuration) => {\n if (!profiler) return;\n\n const [, indexText, offsetText] = id.split(':');\n const blockIndex = Number(indexText);\n\n if (!Number.isFinite(blockIndex)) return;\n\n const block = blocks[blockIndex];\n if (!block) return;\n\n profiler.recordBlockCommit({\n actualDuration,\n baseDuration,\n blockChars: countChars(block.content),\n blockIndex,\n blockKey: offsetText ?? String(block.startOffset),\n phase,\n state: getBlockState(blockIndex),\n });\n },\n [blocks, getBlockState, profiler],\n );\n\n const content = (\n <div className={styles.animated}>\n {blocks.map((block, index) => {\n const state = getBlockState(index);\n if (state === 'queued') return null;\n const animationMeta = blockAnimationMetaResult.blockAnimationMeta.get(block.startOffset);\n if (!animationMeta) return null;\n\n const plugins: Pluggable[] = animationMeta.settled\n ? [...baseRehypePlugins, REVEALED_STREAM_PLUGIN]\n : [\n ...baseRehypePlugins,\n [\n rehypeStreamAnimated,\n {\n charDelay: animationMeta.charDelay,\n fadeDuration: STREAM_FADE_DURATION,\n timelineElapsedMs: animationMeta.timelineElapsedMs,\n },\n ],\n ];\n\n const key = `${generatedId}-${block.startOffset}`;\n const blockNode = (\n <StreamdownBlock\n {...rest}\n components={components}\n rehypePlugins={plugins}\n remarkPlugins={remarkPlugins}\n >\n {block.content}\n </StreamdownBlock>\n );\n\n if (!profiler) {\n return (\n <StreamdownBlock\n {...rest}\n components={components}\n key={key}\n rehypePlugins={plugins}\n remarkPlugins={remarkPlugins}\n >\n {block.content}\n </StreamdownBlock>\n );\n }\n\n return (\n <Profiler\n id={`streamdown-block:${index}:${block.startOffset}`}\n key={key}\n onRender={handleBlockRender}\n >\n {blockNode}\n </Profiler>\n );\n })}\n </div>\n );\n\n if (!profiler) return content;\n\n return (\n <Profiler id={'streamdown-root'} onRender={handleRootRender}>\n {content}\n </Profiler>\n );\n});\n\nStreamdownRender.displayName = 'StreamdownRender';\n\nexport default StreamdownRender;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/Markdown/SyntaxMarkdown/streamAnimationMeta.ts
|
|
2
|
+
const isActiveBlock = (state) => {
|
|
3
|
+
return state === "animating" || state === "streaming";
|
|
4
|
+
};
|
|
5
|
+
const resolveBlockAnimationMeta = ({ blockCharCount, currentCharDelay, fadeDuration, previousCharDelay, state, timelineElapsedMs }) => {
|
|
6
|
+
const charDelay = isActiveBlock(state) ? currentCharDelay : previousCharDelay ?? currentCharDelay;
|
|
7
|
+
const latestCharStart = Math.max(0, (blockCharCount - 1) * charDelay);
|
|
8
|
+
const settled = state === "revealed" && timelineElapsedMs >= latestCharStart + fadeDuration;
|
|
9
|
+
return {
|
|
10
|
+
charDelay,
|
|
11
|
+
settled,
|
|
12
|
+
timelineElapsedMs: settled ? latestCharStart + fadeDuration : timelineElapsedMs
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { resolveBlockAnimationMeta };
|
|
18
|
+
//# sourceMappingURL=streamAnimationMeta.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streamAnimationMeta.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/streamAnimationMeta.ts"],"sourcesContent":["import { type BlockState } from './useStreamQueue';\n\nexport interface ResolveBlockAnimationMetaOptions {\n blockCharCount: number;\n currentCharDelay: number;\n fadeDuration: number;\n previousCharDelay?: number;\n state: BlockState;\n timelineElapsedMs: number;\n}\n\nexport interface BlockAnimationMeta {\n charDelay: number;\n settled: boolean;\n timelineElapsedMs: number;\n}\n\nconst isActiveBlock = (state: BlockState) => {\n return state === 'animating' || state === 'streaming';\n};\n\nexport const resolveBlockAnimationMeta = ({\n blockCharCount,\n currentCharDelay,\n fadeDuration,\n previousCharDelay,\n state,\n timelineElapsedMs,\n}: ResolveBlockAnimationMetaOptions): BlockAnimationMeta => {\n const charDelay = isActiveBlock(state)\n ? currentCharDelay\n : (previousCharDelay ?? currentCharDelay);\n const latestCharStart = Math.max(0, (blockCharCount - 1) * charDelay);\n const settled = state === 'revealed' && timelineElapsedMs >= latestCharStart + fadeDuration;\n\n return {\n charDelay,\n settled,\n timelineElapsedMs: settled ? latestCharStart + fadeDuration : timelineElapsedMs,\n };\n};\n"],"mappings":";AAiBA,MAAM,iBAAiB,UAAsB;AAC3C,QAAO,UAAU,eAAe,UAAU;;AAG5C,MAAa,6BAA6B,EACxC,gBACA,kBACA,cACA,mBACA,OACA,wBAC0D;CAC1D,MAAM,YAAY,cAAc,MAAM,GAClC,mBACC,qBAAqB;CAC1B,MAAM,kBAAkB,KAAK,IAAI,IAAI,iBAAiB,KAAK,UAAU;CACrE,MAAM,UAAU,UAAU,cAAc,qBAAqB,kBAAkB;AAE/E,QAAO;EACL;EACA;EACA,mBAAmB,UAAU,kBAAkB,eAAe;EAC/D"}
|