@lobehub/ui 5.23.5 → 5.25.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.
- package/es/A/index.mjs +2 -1
- package/es/A/index.mjs.map +1 -1
- package/es/Accordion/Accordion.mjs.map +1 -1
- package/es/Accordion/AccordionItem.mjs +0 -1
- package/es/Accordion/AccordionItem.mjs.map +1 -1
- package/es/Accordion/ArrowIcon.mjs.map +1 -1
- package/es/ActionIcon/ActionIcon.mjs.map +1 -1
- package/es/ActionIcon/components/utils.mjs +7 -9
- package/es/ActionIcon/components/utils.mjs.map +1 -1
- package/es/ActionIconGroup/ActionIconGroup.mjs.map +1 -1
- package/es/Alert/Alert.mjs.map +1 -1
- package/es/Avatar/Avatar.mjs.map +1 -1
- package/es/Avatar/AvatarGroup/index.mjs.map +1 -1
- package/es/Burger/Burger.mjs.map +1 -1
- package/es/Checkbox/Checkbox.mjs.map +1 -1
- package/es/Checkbox/CheckboxGroup.mjs +4 -2
- package/es/Checkbox/CheckboxGroup.mjs.map +1 -1
- package/es/CodeDiff/CodeDiff.mjs +20 -18
- package/es/CodeDiff/CodeDiff.mjs.map +1 -1
- package/es/CodeDiff/DiffPanel.mjs.map +1 -1
- package/es/CodeDiff/PatchDiff.mjs +18 -16
- package/es/CodeDiff/PatchDiff.mjs.map +1 -1
- package/es/CodeEditor/CodeEditor.mjs.map +1 -1
- package/es/Collapse/Collapse.mjs.map +1 -1
- package/es/ColorSwatches/ColorSwatches.mjs.map +1 -1
- package/es/ConfigProvider/index.mjs.map +1 -1
- package/es/ContextMenu/index.d.mts +2 -2
- package/es/ContextMenu/index.mjs +2 -2
- package/es/CopyButton/CopyButton.mjs +2 -1
- package/es/CopyButton/CopyButton.mjs.map +1 -1
- package/es/DraggablePanel/DraggablePanel.mjs.map +1 -1
- package/es/DraggablePanel/components/DraggablePanelHeader.mjs.map +1 -1
- package/es/DraggableSideNav/DraggableSideNav.mjs.map +1 -1
- package/es/Drawer/Drawer.mjs.map +1 -1
- package/es/Dropdown/Dropdown.mjs.map +1 -1
- package/es/EditableText/ControlInput.mjs.map +1 -1
- package/es/EditableText/EditableText.mjs.map +1 -1
- package/es/EditorSlashMenu/EditorSlashMenu.mjs.map +1 -1
- package/es/EditorSlashMenu/MenuItemRenderer.mjs.map +1 -1
- package/es/EmojiPicker/AvatarUploader.mjs.map +1 -1
- package/es/EmojiPicker/EmojiPicker.mjs.map +1 -1
- package/es/Empty/Empty.mjs.map +1 -1
- package/es/FileTypeIcon/FileTypeIcon.mjs.map +1 -1
- package/es/FileTypeIcon/components/FileIcon.mjs.map +1 -1
- package/es/FileTypeIcon/components/FolderIcon.mjs.map +1 -1
- package/es/FluentEmoji/FluentEmoji.mjs.map +1 -1
- package/es/Footer/Footer.mjs.map +1 -1
- package/es/Form/Form.mjs.map +1 -1
- package/es/Form/components/FormGroup.mjs.map +1 -1
- package/es/Form/components/FormSubmitFooter.mjs.map +1 -1
- package/es/Form/components/FormTitle.mjs.map +1 -1
- package/es/FormModal/FormModal.mjs.map +1 -1
- package/es/Freeze/Freeze.mjs.map +1 -1
- package/es/GroupAvatar/GroupAvatar.mjs.map +1 -1
- package/es/GuideCard/GuideCard.mjs.map +1 -1
- package/es/Header/Header.mjs.map +1 -1
- package/es/Highlighter/FullFeatured.mjs.map +1 -1
- package/es/Highlighter/Highlighter.mjs.map +1 -1
- package/es/Highlighter/LangSelect.mjs +41 -40
- package/es/Highlighter/LangSelect.mjs.map +1 -1
- package/es/Highlighter/SyntaxHighlighter/StaticRenderer.mjs +2 -1
- package/es/Highlighter/SyntaxHighlighter/StaticRenderer.mjs.map +1 -1
- package/es/Highlighter/SyntaxHighlighter/StreamRenderer.mjs.map +1 -1
- package/es/Highlighter/SyntaxHighlighter/style.mjs +2 -2
- package/es/Highlighter/SyntaxHighlighter/style.mjs.map +1 -1
- package/es/Hotkey/Hotkey.mjs.map +1 -1
- package/es/HotkeyInput/HotkeyInput.mjs +3 -1
- package/es/HotkeyInput/HotkeyInput.mjs.map +1 -1
- package/es/HtmlPreview/HtmlPreview.mjs.map +1 -1
- package/es/HtmlPreview/Iframe.mjs.map +1 -1
- package/es/HtmlPreview/const.mjs +1 -1
- package/es/HtmlPreview/const.mjs.map +1 -1
- package/es/Icon/Icon.mjs.map +1 -1
- package/es/Icon/components/utils.mjs +7 -9
- package/es/Icon/components/utils.mjs.map +1 -1
- package/es/Image/Image.mjs.map +1 -1
- package/es/Image/components/Toolbar.mjs +2 -1
- package/es/Image/components/Toolbar.mjs.map +1 -1
- package/es/Image/components/usePreview.mjs.map +1 -1
- package/es/Image/components/usePreviewGroup.mjs.map +1 -1
- package/es/ImageSelect/ImageSelect.mjs.map +1 -1
- package/es/Img/index.mjs +2 -1
- package/es/Img/index.mjs.map +1 -1
- package/es/Layout/Layout.mjs.map +1 -1
- package/es/List/List.mjs.map +1 -1
- package/es/List/ListItem/index.mjs.map +1 -1
- package/es/Markdown/Markdown.mjs.map +1 -1
- package/es/Markdown/SyntaxMarkdown/MarkdownRender.mjs.map +1 -1
- package/es/Markdown/SyntaxMarkdown/StreamdownRender.mjs +2 -1
- package/es/Markdown/SyntaxMarkdown/StreamdownRender.mjs.map +1 -1
- package/es/Markdown/SyntaxMarkdown/style.mjs.map +1 -1
- package/es/Markdown/SyntaxMarkdown/useSmoothStreamContent.mjs +2 -2
- package/es/Markdown/SyntaxMarkdown/useSmoothStreamContent.mjs.map +1 -1
- package/es/Markdown/components/CodeBlock.mjs.map +1 -1
- package/es/Markdown/components/Footnotes.mjs.map +1 -1
- package/es/Markdown/components/MarkdownTable/index.mjs.map +1 -1
- package/es/Markdown/components/SearchResultCards/SearchResultCard.mjs.map +1 -1
- package/es/Markdown/components/SearchResultCards/index.mjs.map +1 -1
- package/es/MaterialFileTypeIcon/MaterialFileTypeIcon.mjs.map +1 -1
- package/es/Menu/Menu.mjs.map +1 -1
- package/es/Mermaid/FullFeatured.mjs.map +1 -1
- package/es/Mermaid/Mermaid.mjs.map +1 -1
- package/es/Mermaid/SyntaxMermaid/MermaidFallback.mjs +35 -0
- package/es/Mermaid/SyntaxMermaid/MermaidFallback.mjs.map +1 -0
- package/es/Mermaid/SyntaxMermaid/MermaidSvg.mjs +52 -0
- package/es/Mermaid/SyntaxMermaid/MermaidSvg.mjs.map +1 -0
- package/es/Mermaid/SyntaxMermaid/StaticMermaid.mjs +13 -42
- package/es/Mermaid/SyntaxMermaid/StaticMermaid.mjs.map +1 -1
- package/es/Mermaid/SyntaxMermaid/StreamMermaid.mjs +13 -43
- package/es/Mermaid/SyntaxMermaid/StreamMermaid.mjs.map +1 -1
- package/es/Mermaid/SyntaxMermaid/prepareInlineSvg.mjs +52 -0
- package/es/Mermaid/SyntaxMermaid/prepareInlineSvg.mjs.map +1 -0
- package/es/Mermaid/SyntaxMermaid/prepareMermaidSvg.mjs +20 -0
- package/es/Mermaid/SyntaxMermaid/prepareMermaidSvg.mjs.map +1 -0
- package/es/Mermaid/SyntaxMermaid/style.mjs +11 -0
- package/es/Mermaid/SyntaxMermaid/style.mjs.map +1 -1
- package/es/Mermaid/const.mjs +10 -31
- package/es/Mermaid/const.mjs.map +1 -1
- package/es/Mermaid/index.d.mts +2 -1
- package/es/Mermaid/index.mjs +2 -1
- package/es/Mermaid/type.d.mts +2 -2
- package/es/Modal/Modal.mjs.map +1 -1
- package/es/Modal/ModalStackItem.mjs.map +1 -1
- package/es/Modal/RawModalStackItem.mjs +6 -5
- package/es/Modal/RawModalStackItem.mjs.map +1 -1
- package/es/Modal/imperative.mjs +4 -2
- package/es/Modal/imperative.mjs.map +1 -1
- package/es/Modal/style.mjs.map +1 -1
- package/es/NeuralNetworkLoading/NeuralNetworkLoading.mjs +1 -1
- package/es/NeuralNetworkLoading/NeuralNetworkLoading.mjs.map +1 -1
- package/es/ScrollShadow/ScrollShadow.mjs +13 -12
- package/es/ScrollShadow/ScrollShadow.mjs.map +1 -1
- package/es/SearchBar/SearchBar.mjs.map +1 -1
- package/es/SideNav/SideNav.mjs.map +1 -1
- package/es/Skeleton/Skeleton.mjs.map +1 -1
- package/es/Skeleton/SkeletonButton.mjs +2 -1
- package/es/Skeleton/SkeletonButton.mjs.map +1 -1
- package/es/Skeleton/SkeletonParagraph.mjs.map +1 -1
- package/es/Skeleton/SkeletonTags.mjs.map +1 -1
- package/es/SliderWithInput/SliderWithInput.mjs.map +1 -1
- package/es/Snippet/Snippet.mjs.map +1 -1
- package/es/SortableList/SortableList.mjs +5 -1
- package/es/SortableList/SortableList.mjs.map +1 -1
- package/es/SortableList/components/SortableItem.mjs.map +1 -1
- package/es/Text/Text.mjs +22 -21
- package/es/Text/Text.mjs.map +1 -1
- package/es/ThemeProvider/ThemeProvider.mjs +4 -3
- package/es/ThemeProvider/ThemeProvider.mjs.map +1 -1
- package/es/ThemeSwitch/ThemeSwitch.mjs.map +1 -1
- package/es/Toc/Toc.mjs.map +1 -1
- package/es/Toc/TocMobile.mjs.map +1 -1
- package/es/Video/index.mjs.map +1 -1
- package/es/awesome/AuroraBackground/AuroraBackground.mjs.map +1 -1
- package/es/awesome/Features/FeatureItem.mjs.map +1 -1
- package/es/awesome/Giscus/Giscus.mjs.map +1 -1
- package/es/awesome/GradientButton/GradientButton.mjs +1 -3
- package/es/awesome/GradientButton/GradientButton.mjs.map +1 -1
- package/es/awesome/GridBackground/GridBackground.mjs.map +1 -1
- package/es/awesome/GridBackground/GridShowcase.mjs.map +1 -1
- package/es/awesome/GridBackground/components/Grid.mjs.map +1 -1
- package/es/awesome/Hero/Hero.mjs.map +1 -1
- package/es/awesome/Spline/ParentSize.mjs.map +1 -1
- package/es/awesome/Spline/Spine.mjs.map +1 -1
- package/es/awesome/Spotlight/Spotlight.mjs +2 -1
- package/es/awesome/Spotlight/Spotlight.mjs.map +1 -1
- package/es/awesome/SpotlightCard/SpotlightCard.mjs.map +1 -1
- package/es/awesome/SpotlightCard/SpotlightCardItem.mjs.map +1 -1
- package/es/awesome/TypewriterEffect/TypewriterEffect.mjs.map +1 -1
- package/es/base-ui/AutoComplete/AutoComplete.mjs.map +1 -1
- package/es/base-ui/Button/Button.mjs +13 -11
- package/es/base-ui/Button/Button.mjs.map +1 -1
- package/es/base-ui/Button/SplitButton.mjs +2 -1
- package/es/base-ui/Button/SplitButton.mjs.map +1 -1
- package/es/base-ui/Checkbox/Checkbox.mjs.map +1 -1
- package/es/base-ui/Checkbox/CheckboxGroup.mjs.map +1 -1
- package/es/base-ui/ContextMenu/ContextMenuHost.mjs.map +1 -1
- package/es/base-ui/ContextMenu/ContextMenuTrigger.mjs +2 -1
- package/es/base-ui/ContextMenu/ContextMenuTrigger.mjs.map +1 -1
- package/es/base-ui/ContextMenu/imperative.d.mts +2 -2
- package/es/base-ui/ContextMenu/index.d.mts +2 -2
- package/es/base-ui/ContextMenu/renderItems.mjs +2 -1
- package/es/base-ui/ContextMenu/renderItems.mjs.map +1 -1
- package/es/base-ui/ContextMenu/store.d.mts +13 -1
- package/es/base-ui/ContextMenu/store.mjs +29 -4
- package/es/base-ui/ContextMenu/store.mjs.map +1 -1
- package/es/base-ui/Drawer/Drawer.d.mts +6 -0
- package/es/base-ui/Drawer/Drawer.mjs +152 -0
- package/es/base-ui/Drawer/Drawer.mjs.map +1 -0
- package/es/base-ui/Drawer/DrawerLayerContext.mjs +10 -0
- package/es/base-ui/Drawer/DrawerLayerContext.mjs.map +1 -0
- package/es/base-ui/Drawer/DrawerPushContext.mjs +27 -0
- package/es/base-ui/Drawer/DrawerPushContext.mjs.map +1 -0
- package/es/base-ui/Drawer/atoms.d.mts +58 -0
- package/es/base-ui/Drawer/atoms.mjs +262 -0
- package/es/base-ui/Drawer/atoms.mjs.map +1 -0
- package/es/base-ui/Drawer/constants.d.mts +17 -0
- package/es/base-ui/Drawer/constants.mjs +72 -0
- package/es/base-ui/Drawer/constants.mjs.map +1 -0
- package/es/base-ui/Drawer/index.d.mts +5 -0
- package/es/base-ui/Drawer/style.mjs +295 -0
- package/es/base-ui/Drawer/style.mjs.map +1 -0
- package/es/base-ui/Drawer/type.d.mts +65 -0
- package/es/base-ui/DropdownMenu/DropdownMenu.mjs +2 -1
- package/es/base-ui/DropdownMenu/DropdownMenu.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/atoms.mjs +2 -1
- package/es/base-ui/DropdownMenu/atoms.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/renderItems.mjs +2 -1
- package/es/base-ui/DropdownMenu/renderItems.mjs.map +1 -1
- package/es/base-ui/DropdownMenu/sharedStyle.mjs +3 -0
- package/es/base-ui/DropdownMenu/sharedStyle.mjs.map +1 -1
- package/es/base-ui/FloatingPanel/FloatingPanel.mjs.map +1 -1
- package/es/base-ui/FloatingSheet/FloatingSheet.mjs +4 -1
- package/es/base-ui/FloatingSheet/FloatingSheet.mjs.map +1 -1
- package/es/base-ui/FloatingSheet/FloatingSheetHeader.mjs.map +1 -1
- package/es/base-ui/Form/Form.mjs.map +1 -1
- package/es/base-ui/Form/components/FormField.mjs.map +1 -1
- package/es/base-ui/Form/components/FormGroup.mjs.map +1 -1
- package/es/base-ui/Form/components/FormSubmitFooter.mjs.map +1 -1
- package/es/base-ui/Form/components/FormTitle.mjs.map +1 -1
- package/es/base-ui/Input/Input.mjs.map +1 -1
- package/es/base-ui/Input/InputNumber.mjs.map +1 -1
- package/es/base-ui/Input/InputOTP.mjs.map +1 -1
- package/es/base-ui/Input/InputPassword.mjs.map +1 -1
- package/es/base-ui/Input/TextArea.mjs.map +1 -1
- package/es/base-ui/Modal/Modal.mjs.map +1 -1
- package/es/base-ui/Modal/atoms.mjs +7 -5
- package/es/base-ui/Modal/atoms.mjs.map +1 -1
- package/es/base-ui/Modal/imperative.mjs +2 -1
- package/es/base-ui/Modal/imperative.mjs.map +1 -1
- package/es/base-ui/Popover/ArrowIcon.mjs.map +1 -1
- package/es/base-ui/Popover/PopoverGroup.mjs.map +1 -1
- package/es/base-ui/Popover/PopoverStandalone.mjs.map +1 -1
- package/es/base-ui/Popover/atoms.mjs +2 -1
- package/es/base-ui/Popover/atoms.mjs.map +1 -1
- package/es/base-ui/Popover/context.mjs +4 -2
- package/es/base-ui/Popover/context.mjs.map +1 -1
- package/es/base-ui/Radio/Radio.mjs.map +1 -1
- package/es/base-ui/Radio/RadioGroup.mjs.map +1 -1
- package/es/base-ui/ScrollArea/ScrollArea.mjs.map +1 -1
- package/es/base-ui/Segmented/Segmented.mjs.map +1 -1
- package/es/base-ui/Select/Select.mjs.map +1 -1
- package/es/base-ui/Select/atoms.mjs +2 -1
- package/es/base-ui/Select/atoms.mjs.map +1 -1
- package/es/base-ui/Select/parts.mjs.map +1 -1
- package/es/base-ui/Select/renderOptions.mjs.map +1 -1
- package/es/base-ui/Slider/Slider.mjs.map +1 -1
- package/es/base-ui/Slider/SliderWithInput.mjs.map +1 -1
- package/es/base-ui/SubmenuArrowIcon.mjs.map +1 -1
- package/es/base-ui/Switch/Switch.mjs.map +1 -1
- package/es/base-ui/Switch/atoms.d.mts +3 -3
- package/es/base-ui/Switch/atoms.mjs +99 -50
- package/es/base-ui/Switch/atoms.mjs.map +1 -1
- package/es/base-ui/Switch/style.mjs +44 -1
- package/es/base-ui/Switch/style.mjs.map +1 -1
- package/es/base-ui/Switch/type.d.mts +3 -7
- package/es/base-ui/Tabs/Tabs.mjs.map +1 -1
- package/es/base-ui/Tabs/atoms.mjs.map +1 -1
- package/es/base-ui/Toast/Toast.mjs.map +1 -1
- package/es/base-ui/Toast/imperative.mjs.map +1 -1
- package/es/base-ui/Tooltip/ArrowIcon.mjs.map +1 -1
- package/es/base-ui/Tooltip/TooltipGroup.mjs.map +1 -1
- package/es/base-ui/Tooltip/TooltipStandalone.mjs.map +1 -1
- package/es/base-ui/index.d.mts +7 -2
- package/es/base-ui/index.mjs +5 -2
- package/es/brand/LobeChat/index.mjs +0 -1
- package/es/brand/LobeChat/index.mjs.map +1 -1
- package/es/brand/LobeChatText/index.mjs.map +1 -1
- package/es/brand/LobeHub/index.mjs +0 -1
- package/es/brand/LobeHub/index.mjs.map +1 -1
- package/es/brand/LobeHubText/index.mjs.map +1 -1
- package/es/brand/Logo3d/index.mjs +2 -1
- package/es/brand/Logo3d/index.mjs.map +1 -1
- package/es/brand/LogoThree/Loading.mjs.map +1 -1
- package/es/brand/LogoThree/LogoSpline.mjs.map +1 -1
- package/es/brand/LogoThree/index.mjs.map +1 -1
- package/es/brand/components/Divider.mjs.map +1 -1
- package/es/chat/BackBottom/BackBottom.mjs.map +1 -1
- package/es/chat/ChatHeader/ChatHeader.mjs.map +1 -1
- package/es/chat/ChatHeader/ChatHeaderTitle.mjs.map +1 -1
- package/es/chat/ChatInputArea/ChatInputArea.mjs.map +1 -1
- package/es/chat/ChatInputArea/components/ChatInputActionBar.mjs.map +1 -1
- package/es/chat/ChatInputArea/components/ChatSendButton.mjs.map +1 -1
- package/es/chat/ChatItem/ChatItem.mjs.map +1 -1
- package/es/chat/ChatItem/components/Actions.mjs +5 -4
- package/es/chat/ChatItem/components/Actions.mjs.map +1 -1
- package/es/chat/ChatItem/components/Avatar.mjs.map +1 -1
- package/es/chat/ChatItem/components/ErrorContent.mjs.map +1 -1
- package/es/chat/ChatItem/components/Loading.mjs.map +1 -1
- package/es/chat/ChatItem/components/MessageContent.mjs.map +1 -1
- package/es/chat/ChatItem/components/Title.mjs.map +1 -1
- package/es/chat/ChatList/ChatList.mjs +2 -1
- package/es/chat/ChatList/ChatList.mjs.map +1 -1
- package/es/chat/ChatList/components/HistoryDivider.mjs.map +1 -1
- package/es/chat/EditableMessage/EditableMessage.mjs.map +1 -1
- package/es/chat/EditableMessageList/EditableMessageList.mjs.map +1 -1
- package/es/chat/LoadingDots/LoadingDots.mjs.map +1 -1
- package/es/chat/MessageInput/MessageInput.mjs.map +1 -1
- package/es/chat/MessageModal/MessageModal.mjs.map +1 -1
- package/es/color/ColorScales/ScaleRow.mjs +0 -2
- package/es/color/ColorScales/ScaleRow.mjs.map +1 -1
- package/es/color/ColorScales/index.mjs.map +1 -1
- package/es/color/CssVar/ScaleRow.mjs.map +1 -1
- package/es/color/CssVar/VarRow.mjs.map +1 -1
- package/es/color/CssVar/index.mjs.map +1 -1
- package/es/hooks/useMarkdown/latex.mjs.map +1 -1
- package/es/hooks/useMarkdown/useMarkdownContent.mjs.map +1 -1
- package/es/hooks/useMermaid.mjs +81 -116
- package/es/hooks/useMermaid.mjs.map +1 -1
- package/es/hooks/useMermaidCdn.d.mts +10 -0
- package/es/hooks/useMermaidCdn.mjs +97 -0
- package/es/hooks/useMermaidCdn.mjs.map +1 -0
- package/es/hooks/useStreamMermaid.mjs +19 -70
- package/es/hooks/useStreamMermaid.mjs.map +1 -1
- package/es/icons/Auth0/components/Mono.mjs.map +1 -1
- package/es/icons/Authelia/components/Color.mjs.map +1 -1
- package/es/icons/Authelia/components/Mono.mjs.map +1 -1
- package/es/icons/Authentik/components/Color.mjs.map +1 -1
- package/es/icons/Authentik/components/Mono.mjs.map +1 -1
- package/es/icons/Casdoor/components/Color.mjs.map +1 -1
- package/es/icons/Casdoor/components/Mono.mjs.map +1 -1
- package/es/icons/Clerk/components/Color.mjs.map +1 -1
- package/es/icons/Clerk/components/Mono.mjs.map +1 -1
- package/es/icons/DingTalk/components/Color.mjs.map +1 -1
- package/es/icons/DingTalk/components/Mono.mjs.map +1 -1
- package/es/icons/Discord/components/Color.mjs.map +1 -1
- package/es/icons/Discord/components/Mono.mjs.map +1 -1
- package/es/icons/GoogleChat/components/Color.mjs.map +1 -1
- package/es/icons/GoogleChat/components/Mono.mjs.map +1 -1
- package/es/icons/IMessage/components/Color.mjs.map +1 -1
- package/es/icons/IMessage/components/Inner.mjs.map +1 -1
- package/es/icons/IMessage/components/Mono.mjs.map +1 -1
- package/es/icons/Lark/components/Color.mjs.map +1 -1
- package/es/icons/Lark/components/Mono.mjs.map +1 -1
- package/es/icons/Line/components/Color.mjs.map +1 -1
- package/es/icons/Line/components/Mono.mjs.map +1 -1
- package/es/icons/Logto/components/Color.mjs.map +1 -1
- package/es/icons/Logto/components/Mono.mjs.map +1 -1
- package/es/icons/MicrosoftEntra/components/Color.mjs.map +1 -1
- package/es/icons/MicrosoftEntra/components/Mono.mjs.map +1 -1
- package/es/icons/MicrosoftTeams/components/Color.mjs.map +1 -1
- package/es/icons/MicrosoftTeams/components/Mono.mjs.map +1 -1
- package/es/icons/NextAuth/components/Color.mjs.map +1 -1
- package/es/icons/NextAuth/components/Mono.mjs.map +1 -1
- package/es/icons/QQ/components/Color.mjs.map +1 -1
- package/es/icons/QQ/components/Mono.mjs.map +1 -1
- package/es/icons/Slack/components/Color.mjs.map +1 -1
- package/es/icons/Slack/components/Mono.mjs.map +1 -1
- package/es/icons/Telegram/components/Color.mjs.map +1 -1
- package/es/icons/Telegram/components/Inner.mjs.map +1 -1
- package/es/icons/Telegram/components/Mono.mjs.map +1 -1
- package/es/icons/WeChat/components/Color.mjs.map +1 -1
- package/es/icons/WeChat/components/Mono.mjs.map +1 -1
- package/es/icons/WhatsApp/components/Color.mjs.map +1 -1
- package/es/icons/WhatsApp/components/Mono.mjs.map +1 -1
- package/es/icons/Zitadel/components/Color.mjs.map +1 -1
- package/es/icons/Zitadel/components/Mono.mjs.map +1 -1
- package/es/index.d.mts +2 -2
- package/es/index.mjs +2 -2
- package/es/mdx/Callout/index.mjs.map +1 -1
- package/es/mdx/Cards/Card.mjs.map +1 -1
- package/es/mdx/FileTree/File.mjs.map +1 -1
- package/es/mdx/FileTree/Folder.mjs.map +1 -1
- package/es/mdx/Mdx/index.mjs.map +1 -1
- package/es/mdx/Tabs/Tab.mjs.map +1 -1
- package/es/mdx/Tabs/index.mjs.map +1 -1
- package/es/mdx/mdxComponents/Citation/PopoverPanel.mjs.map +1 -1
- package/es/mdx/mdxComponents/Citation/index.mjs.map +1 -1
- package/es/mdx/mdxComponents/CodeBlock.mjs.map +1 -1
- package/es/mdx/mdxComponents/Link.mjs.map +1 -1
- package/es/mobile/ChatHeader/ChatHeader.mjs.map +1 -1
- package/es/mobile/ChatHeader/ChatHeaderTitle.mjs.map +1 -1
- package/es/mobile/ChatInputArea/ChatInputArea.mjs.map +1 -1
- package/es/mobile/TabBar/TabBar.mjs.map +1 -1
- package/es/storybook/StoryBook/index.mjs.map +1 -1
- package/package.json +3 -4
package/es/Image/Image.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Image.mjs","names":["Image","Flexbox","AntImage"],"sources":["../../src/Image/Image.tsx"],"sourcesContent":["'use client';\n\nimport { Image as AntImage, Skeleton } from 'antd';\nimport { cssVar, cx, useThemeMode } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport usePreview from './components/usePreview';\nimport { FALLBACK_DARK, FALLBACK_LIGHT, styles, variants } from './style';\nimport type { ImageProps } from './type';\n\nconst Image = memo<ImageProps>(\n ({\n ref,\n style,\n preview,\n isLoading,\n maxHeight = '100%',\n maxWidth = '100%',\n minHeight,\n minWidth,\n actions,\n className,\n alwaysShowActions,\n variant = 'filled',\n objectFit = 'cover',\n classNames,\n styles: customStyles,\n onClick,\n width,\n height,\n ...rest\n }) => {\n const { isDarkMode } = useThemeMode();\n const actionsClassName = alwaysShowActions ? styles.actionsVisible : styles.actionsHidden;\n const mergePreview = usePreview(preview);\n\n if (isLoading)\n return (\n <div onClick={onClick}>\n <Skeleton.Avatar\n active\n style={{\n borderRadius: cssVar.borderRadius,\n height,\n maxHeight,\n maxWidth,\n minHeight,\n minWidth,\n width,\n }}\n />\n </div>\n );\n\n return (\n <Flexbox className={cx(variants({ variant }), className)} ref={ref} style={style}>\n {actions && (\n <div className={cx(actionsClassName, alwaysShowActions ? '' : 'actions-hidden')}>\n {actions}\n </div>\n )}\n <AntImage\n className={cx(styles.image, classNames?.image)}\n fallback={isDarkMode ? FALLBACK_DARK : FALLBACK_LIGHT}\n height={height}\n loading={'lazy'}\n preview={preview === false ? false : (mergePreview as any)}\n width={width}\n classNames={{\n root: cx(styles.wrapper, classNames?.wrapper),\n }}\n style={{\n maxHeight,\n maxWidth,\n minHeight,\n minWidth,\n objectFit: objectFit || 'cover',\n ...customStyles?.image,\n }}\n styles={{\n root: customStyles?.wrapper,\n }}\n onClick={onClick}\n {...rest}\n />\n </Flexbox>\n );\n },\n);\n\nImage.displayName = 'Image';\n\nexport default Image;\n"],"mappings":";;;;;;;;;AAYA,MAAMA,UAAQ,MACX,EACC,KACA,OACA,SACA,WACA,YAAY,QACZ,WAAW,QACX,WACA,UACA,SACA,WACA,mBACA,UAAU,UACV,YAAY,SACZ,YACA,QAAQ,cACR,SACA,OACA,QACA,GAAG,WACC;CACJ,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,mBAAmB,oBAAoB,OAAO,iBAAiB,OAAO;CAC5E,MAAM,eAAe,WAAW,OAAO;CAEvC,IAAI,WACF,OACE,oBAAC,OAAD;EAAc;
|
|
1
|
+
{"version":3,"file":"Image.mjs","names":["Image","Flexbox","AntImage"],"sources":["../../src/Image/Image.tsx"],"sourcesContent":["'use client';\n\nimport { Image as AntImage, Skeleton } from 'antd';\nimport { cssVar, cx, useThemeMode } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport usePreview from './components/usePreview';\nimport { FALLBACK_DARK, FALLBACK_LIGHT, styles, variants } from './style';\nimport type { ImageProps } from './type';\n\nconst Image = memo<ImageProps>(\n ({\n ref,\n style,\n preview,\n isLoading,\n maxHeight = '100%',\n maxWidth = '100%',\n minHeight,\n minWidth,\n actions,\n className,\n alwaysShowActions,\n variant = 'filled',\n objectFit = 'cover',\n classNames,\n styles: customStyles,\n onClick,\n width,\n height,\n ...rest\n }) => {\n const { isDarkMode } = useThemeMode();\n const actionsClassName = alwaysShowActions ? styles.actionsVisible : styles.actionsHidden;\n const mergePreview = usePreview(preview);\n\n if (isLoading)\n return (\n <div onClick={onClick}>\n <Skeleton.Avatar\n active\n style={{\n borderRadius: cssVar.borderRadius,\n height,\n maxHeight,\n maxWidth,\n minHeight,\n minWidth,\n width,\n }}\n />\n </div>\n );\n\n return (\n <Flexbox className={cx(variants({ variant }), className)} ref={ref} style={style}>\n {actions && (\n <div className={cx(actionsClassName, alwaysShowActions ? '' : 'actions-hidden')}>\n {actions}\n </div>\n )}\n <AntImage\n className={cx(styles.image, classNames?.image)}\n fallback={isDarkMode ? FALLBACK_DARK : FALLBACK_LIGHT}\n height={height}\n loading={'lazy'}\n preview={preview === false ? false : (mergePreview as any)}\n width={width}\n classNames={{\n root: cx(styles.wrapper, classNames?.wrapper),\n }}\n style={{\n maxHeight,\n maxWidth,\n minHeight,\n minWidth,\n objectFit: objectFit || 'cover',\n ...customStyles?.image,\n }}\n styles={{\n root: customStyles?.wrapper,\n }}\n onClick={onClick}\n {...rest}\n />\n </Flexbox>\n );\n },\n);\n\nImage.displayName = 'Image';\n\nexport default Image;\n"],"mappings":";;;;;;;;;AAYA,MAAMA,UAAQ,MACX,EACC,KACA,OACA,SACA,WACA,YAAY,QACZ,WAAW,QACX,WACA,UACA,SACA,WACA,mBACA,UAAU,UACV,YAAY,SACZ,YACA,QAAQ,cACR,SACA,OACA,QACA,GAAG,WACC;CACJ,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,mBAAmB,oBAAoB,OAAO,iBAAiB,OAAO;CAC5E,MAAM,eAAe,WAAW,OAAO;CAEvC,IAAI,WACF,OACE,oBAAC,OAAD;EAAc;EACZ,UAAA,oBAAC,SAAS,QAAV;GACE,QAAA;GACA,OAAO;IACL,cAAc,OAAO;IACrB;IACA;IACA;IACA;IACA;IACA;GACF;EACD,CAAA;CACE,CAAA;CAGT,OACE,qBAACC,mBAAD;EAAS,WAAW,GAAG,SAAS,EAAE,QAAQ,CAAC,GAAG,SAAS;EAAQ;EAAY;EAA3E,UAAA,CACG,WACC,oBAAC,OAAD;GAAK,WAAW,GAAG,kBAAkB,oBAAoB,KAAK,gBAAgB;GAC3E,UAAA;EACE,CAAA,GAEP,oBAACC,OAAD;GACE,WAAW,GAAG,OAAO,OAAO,YAAY,KAAK;GAC7C,UAAU,aAAa,gBAAgB;GAC/B;GACR,SAAS;GACT,SAAS,YAAY,QAAQ,QAAS;GAC/B;GACP,YAAY,EACV,MAAM,GAAG,OAAO,SAAS,YAAY,OAAO,EAC9C;GACA,OAAO;IACL;IACA;IACA;IACA;IACA,WAAW,aAAa;IACxB,GAAG,cAAc;GACnB;GACA,QAAQ,EACN,MAAM,cAAc,QACtB;GACS;GACT,GAAI;EACL,CAAA,CACM;;AAEb,CACF;AAEA,QAAM,cAAc"}
|
|
@@ -56,7 +56,8 @@ const Toolbar = memo(({ children, info, minScale, maxScale }) => {
|
|
|
56
56
|
const handleCopy = useCallback(async () => {
|
|
57
57
|
setCopyLoading(true);
|
|
58
58
|
try {
|
|
59
|
-
const
|
|
59
|
+
const blob = await (await fetch(url, { mode: "cors" })).blob();
|
|
60
|
+
const clipboardBlob = await getClipboardBlob(blob);
|
|
60
61
|
await navigator.clipboard.write([new ClipboardItem(clipboardBlob)]);
|
|
61
62
|
message.success(t("image.copySuccess"));
|
|
62
63
|
} catch {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Toolbar.mjs","names":["imageMessages","Flexbox"],"sources":["../../../src/Image/components/Toolbar.tsx"],"sourcesContent":["import { message } from 'antd';\nimport {\n Copy,\n Download,\n FlipHorizontal,\n FlipVertical,\n RotateCcw,\n RotateCw,\n ZoomIn,\n ZoomOut,\n} from 'lucide-react';\nimport { type ToolbarRenderInfoType } from 'rc-image/lib/Preview';\nimport { memo, type ReactNode, useCallback, useState } from 'react';\n\nimport ActionIcon from '@/ActionIcon';\nimport { Flexbox } from '@/Flex';\nimport imageMessages from '@/i18n/resources/en/image';\nimport { useTranslation } from '@/i18n/useTranslation';\nimport { TooltipGroup } from '@/Tooltip';\nimport { getClipboardBlob } from '@/utils/blobToPng';\nimport { downloadBlob } from '@/utils/downloadBlob';\n\nimport { styles } from '../style';\n\nconst getFileNameFromUrl = (url: string): string => {\n try {\n const pathname = new URL(url).pathname;\n const match = pathname.match(/\\/([^/]+)$/);\n return match ? decodeURIComponent(match[1]) : 'image';\n } catch {\n return 'image';\n }\n};\n\nconst getExtensionFromMimeType = (mimeType: string): string => {\n const map: Record<string, string> = {\n 'image/svg+xml': 'svg',\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/jpg': 'jpg',\n 'image/webp': 'webp',\n 'image/gif': 'gif',\n };\n return map[mimeType?.toLowerCase()] || mimeType?.split('/')[1]?.split('+')[0] || 'png';\n};\n\nexport interface ToolbarProps {\n children?: ReactNode;\n info: Omit<ToolbarRenderInfoType, 'current' | 'total'>;\n maxScale: number;\n minScale: number;\n}\n\nconst Toolbar = memo<ToolbarProps>(({ children, info, minScale, maxScale }) => {\n const { t } = useTranslation(imageMessages);\n const [containerEl, setContainerEl] = useState<HTMLElement | null>(null);\n const [copyLoading, setCopyLoading] = useState(false);\n const [downloadLoading, setDownloadLoading] = useState(false);\n const {\n transform: { scale },\n actions: { onFlipY, onFlipX, onRotateLeft, onRotateRight, onZoomOut, onZoomIn },\n image: { url },\n } = info;\n\n const handleDownload = useCallback(async () => {\n setDownloadLoading(true);\n try {\n const response = await fetch(url, { mode: 'cors' });\n const blob = await response.blob();\n const blobUrl = URL.createObjectURL(blob);\n let fileName = getFileNameFromUrl(url);\n const ext = getExtensionFromMimeType(blob.type);\n if (!fileName.includes('.')) {\n fileName = `${fileName}.${ext}`;\n } else if (fileName.endsWith('.svg+xml')) {\n fileName = fileName.replace(/\\.svg\\+xml$/i, '.svg');\n }\n await downloadBlob(blobUrl, fileName);\n URL.revokeObjectURL(blobUrl);\n message.success(t('image.downloadSuccess'));\n } catch {\n message.error(t('image.downloadFailed'));\n } finally {\n setDownloadLoading(false);\n }\n }, [url, t]);\n\n const handleCopy = useCallback(async () => {\n setCopyLoading(true);\n try {\n const response = await fetch(url, { mode: 'cors' });\n const blob = await response.blob();\n const clipboardBlob = await getClipboardBlob(blob);\n await navigator.clipboard.write([new ClipboardItem(clipboardBlob)]);\n message.success(t('image.copySuccess'));\n } catch {\n message.error(t('image.copyFailed'));\n } finally {\n setCopyLoading(false);\n }\n }, [url, t]);\n\n return (\n <TooltipGroup popupContainer={containerEl ?? undefined}>\n <Flexbox horizontal className={styles.toolbar} gap={4} ref={setContainerEl}>\n <ActionIcon icon={FlipHorizontal} title={t('image.flipHorizontal')} onClick={onFlipX} />\n <ActionIcon icon={FlipVertical} title={t('image.flipVertical')} onClick={onFlipY} />\n <ActionIcon icon={RotateCcw} title={t('image.rotateLeft')} onClick={onRotateLeft} />\n <ActionIcon icon={RotateCw} title={t('image.rotateRight')} onClick={onRotateRight} />\n <ActionIcon\n disabled={scale === minScale}\n icon={ZoomOut}\n title={t('image.zoomOut')}\n onClick={onZoomOut}\n />\n <ActionIcon\n disabled={scale === maxScale}\n icon={ZoomIn}\n title={t('image.zoomIn')}\n onClick={onZoomIn}\n />\n <ActionIcon\n icon={Copy}\n loading={copyLoading}\n title={t('image.copy')}\n onClick={handleCopy}\n />\n <ActionIcon\n icon={Download}\n loading={downloadLoading}\n title={t('image.download')}\n onClick={handleDownload}\n />\n {children}\n </Flexbox>\n </TooltipGroup>\n );\n});\n\nexport default Toolbar;\n"],"mappings":";;;;;;;;;;;;;AAwBA,MAAM,sBAAsB,QAAwB;CAClD,IAAI;EAEF,MAAM,QADW,IAAI,IAAI,GAAG,CAAC,CAAC,SACP,MAAM,YAAY;EACzC,OAAO,QAAQ,mBAAmB,MAAM,EAAE,IAAI;CAChD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,4BAA4B,aAA6B;CAS7D,OAAO;EAPL,iBAAiB;EACjB,aAAa;EACb,cAAc;EACd,aAAa;EACb,cAAc;EACd,aAAa;CAEN,EAAE,UAAU,YAAY,MAAM,UAAU,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM;AACnF;AASA,MAAM,UAAU,MAAoB,EAAE,UAAU,MAAM,UAAU,eAAe;CAC7E,MAAM,EAAE,MAAM,eAAeA,aAAa;CAC1C,MAAM,CAAC,aAAa,kBAAkB,SAA6B,IAAI;CACvE,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,KAAK;CAC5D,MAAM,EACJ,WAAW,EAAE,SACb,SAAS,EAAE,SAAS,SAAS,cAAc,eAAe,WAAW,YACrE,OAAO,EAAE,UACP;CAEJ,MAAM,iBAAiB,YAAY,YAAY;EAC7C,mBAAmB,IAAI;EACvB,IAAI;GAEF,MAAM,OAAO,OAAM,MADI,MAAM,KAAK,EAAE,MAAM,OAAO,CAAC,EAAA,CACtB,KAAK;GACjC,MAAM,UAAU,IAAI,gBAAgB,IAAI;GACxC,IAAI,WAAW,mBAAmB,GAAG;GACrC,MAAM,MAAM,yBAAyB,KAAK,IAAI;GAC9C,IAAI,CAAC,SAAS,SAAS,GAAG,GACxB,WAAW,GAAG,SAAS,GAAG;QACrB,IAAI,SAAS,SAAS,UAAU,GACrC,WAAW,SAAS,QAAQ,gBAAgB,MAAM;GAEpD,MAAM,aAAa,SAAS,QAAQ;GACpC,IAAI,gBAAgB,OAAO;GAC3B,QAAQ,QAAQ,EAAE,uBAAuB,CAAC;EAC5C,QAAQ;GACN,QAAQ,MAAM,EAAE,sBAAsB,CAAC;EACzC,UAAU;GACR,mBAAmB,KAAK;EAC1B;CACF,GAAG,CAAC,KAAK,CAAC,CAAC;CAEX,MAAM,aAAa,YAAY,YAAY;EACzC,eAAe,IAAI;EACnB,IAAI;
|
|
1
|
+
{"version":3,"file":"Toolbar.mjs","names":["imageMessages","Flexbox"],"sources":["../../../src/Image/components/Toolbar.tsx"],"sourcesContent":["import { message } from 'antd';\nimport {\n Copy,\n Download,\n FlipHorizontal,\n FlipVertical,\n RotateCcw,\n RotateCw,\n ZoomIn,\n ZoomOut,\n} from 'lucide-react';\nimport { type ToolbarRenderInfoType } from 'rc-image/lib/Preview';\nimport { memo, type ReactNode, useCallback, useState } from 'react';\n\nimport ActionIcon from '@/ActionIcon';\nimport { Flexbox } from '@/Flex';\nimport imageMessages from '@/i18n/resources/en/image';\nimport { useTranslation } from '@/i18n/useTranslation';\nimport { TooltipGroup } from '@/Tooltip';\nimport { getClipboardBlob } from '@/utils/blobToPng';\nimport { downloadBlob } from '@/utils/downloadBlob';\n\nimport { styles } from '../style';\n\nconst getFileNameFromUrl = (url: string): string => {\n try {\n const pathname = new URL(url).pathname;\n const match = pathname.match(/\\/([^/]+)$/);\n return match ? decodeURIComponent(match[1]) : 'image';\n } catch {\n return 'image';\n }\n};\n\nconst getExtensionFromMimeType = (mimeType: string): string => {\n const map: Record<string, string> = {\n 'image/svg+xml': 'svg',\n 'image/png': 'png',\n 'image/jpeg': 'jpg',\n 'image/jpg': 'jpg',\n 'image/webp': 'webp',\n 'image/gif': 'gif',\n };\n return map[mimeType?.toLowerCase()] || mimeType?.split('/')[1]?.split('+')[0] || 'png';\n};\n\nexport interface ToolbarProps {\n children?: ReactNode;\n info: Omit<ToolbarRenderInfoType, 'current' | 'total'>;\n maxScale: number;\n minScale: number;\n}\n\nconst Toolbar = memo<ToolbarProps>(({ children, info, minScale, maxScale }) => {\n const { t } = useTranslation(imageMessages);\n const [containerEl, setContainerEl] = useState<HTMLElement | null>(null);\n const [copyLoading, setCopyLoading] = useState(false);\n const [downloadLoading, setDownloadLoading] = useState(false);\n const {\n transform: { scale },\n actions: { onFlipY, onFlipX, onRotateLeft, onRotateRight, onZoomOut, onZoomIn },\n image: { url },\n } = info;\n\n const handleDownload = useCallback(async () => {\n setDownloadLoading(true);\n try {\n const response = await fetch(url, { mode: 'cors' });\n const blob = await response.blob();\n const blobUrl = URL.createObjectURL(blob);\n let fileName = getFileNameFromUrl(url);\n const ext = getExtensionFromMimeType(blob.type);\n if (!fileName.includes('.')) {\n fileName = `${fileName}.${ext}`;\n } else if (fileName.endsWith('.svg+xml')) {\n fileName = fileName.replace(/\\.svg\\+xml$/i, '.svg');\n }\n await downloadBlob(blobUrl, fileName);\n URL.revokeObjectURL(blobUrl);\n message.success(t('image.downloadSuccess'));\n } catch {\n message.error(t('image.downloadFailed'));\n } finally {\n setDownloadLoading(false);\n }\n }, [url, t]);\n\n const handleCopy = useCallback(async () => {\n setCopyLoading(true);\n try {\n const response = await fetch(url, { mode: 'cors' });\n const blob = await response.blob();\n const clipboardBlob = await getClipboardBlob(blob);\n await navigator.clipboard.write([new ClipboardItem(clipboardBlob)]);\n message.success(t('image.copySuccess'));\n } catch {\n message.error(t('image.copyFailed'));\n } finally {\n setCopyLoading(false);\n }\n }, [url, t]);\n\n return (\n <TooltipGroup popupContainer={containerEl ?? undefined}>\n <Flexbox horizontal className={styles.toolbar} gap={4} ref={setContainerEl}>\n <ActionIcon icon={FlipHorizontal} title={t('image.flipHorizontal')} onClick={onFlipX} />\n <ActionIcon icon={FlipVertical} title={t('image.flipVertical')} onClick={onFlipY} />\n <ActionIcon icon={RotateCcw} title={t('image.rotateLeft')} onClick={onRotateLeft} />\n <ActionIcon icon={RotateCw} title={t('image.rotateRight')} onClick={onRotateRight} />\n <ActionIcon\n disabled={scale === minScale}\n icon={ZoomOut}\n title={t('image.zoomOut')}\n onClick={onZoomOut}\n />\n <ActionIcon\n disabled={scale === maxScale}\n icon={ZoomIn}\n title={t('image.zoomIn')}\n onClick={onZoomIn}\n />\n <ActionIcon\n icon={Copy}\n loading={copyLoading}\n title={t('image.copy')}\n onClick={handleCopy}\n />\n <ActionIcon\n icon={Download}\n loading={downloadLoading}\n title={t('image.download')}\n onClick={handleDownload}\n />\n {children}\n </Flexbox>\n </TooltipGroup>\n );\n});\n\nexport default Toolbar;\n"],"mappings":";;;;;;;;;;;;;AAwBA,MAAM,sBAAsB,QAAwB;CAClD,IAAI;EAEF,MAAM,QADW,IAAI,IAAI,GAAG,CAAC,CAAC,SACP,MAAM,YAAY;EACzC,OAAO,QAAQ,mBAAmB,MAAM,EAAE,IAAI;CAChD,QAAQ;EACN,OAAO;CACT;AACF;AAEA,MAAM,4BAA4B,aAA6B;CAS7D,OAAO;EAPL,iBAAiB;EACjB,aAAa;EACb,cAAc;EACd,aAAa;EACb,cAAc;EACd,aAAa;CAEN,EAAE,UAAU,YAAY,MAAM,UAAU,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC,MAAM;AACnF;AASA,MAAM,UAAU,MAAoB,EAAE,UAAU,MAAM,UAAU,eAAe;CAC7E,MAAM,EAAE,MAAM,eAAeA,aAAa;CAC1C,MAAM,CAAC,aAAa,kBAAkB,SAA6B,IAAI;CACvE,MAAM,CAAC,aAAa,kBAAkB,SAAS,KAAK;CACpD,MAAM,CAAC,iBAAiB,sBAAsB,SAAS,KAAK;CAC5D,MAAM,EACJ,WAAW,EAAE,SACb,SAAS,EAAE,SAAS,SAAS,cAAc,eAAe,WAAW,YACrE,OAAO,EAAE,UACP;CAEJ,MAAM,iBAAiB,YAAY,YAAY;EAC7C,mBAAmB,IAAI;EACvB,IAAI;GAEF,MAAM,OAAO,OAAM,MADI,MAAM,KAAK,EAAE,MAAM,OAAO,CAAC,EAAA,CACtB,KAAK;GACjC,MAAM,UAAU,IAAI,gBAAgB,IAAI;GACxC,IAAI,WAAW,mBAAmB,GAAG;GACrC,MAAM,MAAM,yBAAyB,KAAK,IAAI;GAC9C,IAAI,CAAC,SAAS,SAAS,GAAG,GACxB,WAAW,GAAG,SAAS,GAAG;QACrB,IAAI,SAAS,SAAS,UAAU,GACrC,WAAW,SAAS,QAAQ,gBAAgB,MAAM;GAEpD,MAAM,aAAa,SAAS,QAAQ;GACpC,IAAI,gBAAgB,OAAO;GAC3B,QAAQ,QAAQ,EAAE,uBAAuB,CAAC;EAC5C,QAAQ;GACN,QAAQ,MAAM,EAAE,sBAAsB,CAAC;EACzC,UAAU;GACR,mBAAmB,KAAK;EAC1B;CACF,GAAG,CAAC,KAAK,CAAC,CAAC;CAEX,MAAM,aAAa,YAAY,YAAY;EACzC,eAAe,IAAI;EACnB,IAAI;GAEF,MAAM,OAAO,OAAM,MADI,MAAM,KAAK,EAAE,MAAM,OAAO,CAAC,EAAA,CACtB,KAAK;GACjC,MAAM,gBAAgB,MAAM,iBAAiB,IAAI;GACjD,MAAM,UAAU,UAAU,MAAM,CAAC,IAAI,cAAc,aAAa,CAAC,CAAC;GAClE,QAAQ,QAAQ,EAAE,mBAAmB,CAAC;EACxC,QAAQ;GACN,QAAQ,MAAM,EAAE,kBAAkB,CAAC;EACrC,UAAU;GACR,eAAe,KAAK;EACtB;CACF,GAAG,CAAC,KAAK,CAAC,CAAC;CAEX,OACE,oBAAC,cAAD;EAAc,gBAAgB,eAAe,KAAA;EAC3C,UAAA,qBAACC,mBAAD;GAAS,YAAA;GAAW,WAAW,OAAO;GAAS,KAAK;GAAG,KAAK;GAA5D,UAAA;IACE,oBAAC,YAAD;KAAY,MAAM;KAAgB,OAAO,EAAE,sBAAsB;KAAG,SAAS;IAAU,CAAA;IACvF,oBAAC,YAAD;KAAY,MAAM;KAAc,OAAO,EAAE,oBAAoB;KAAG,SAAS;IAAU,CAAA;IACnF,oBAAC,YAAD;KAAY,MAAM;KAAW,OAAO,EAAE,kBAAkB;KAAG,SAAS;IAAe,CAAA;IACnF,oBAAC,YAAD;KAAY,MAAM;KAAU,OAAO,EAAE,mBAAmB;KAAG,SAAS;IAAgB,CAAA;IACpF,oBAAC,YAAD;KACE,UAAU,UAAU;KACpB,MAAM;KACN,OAAO,EAAE,eAAe;KACxB,SAAS;IACV,CAAA;IACD,oBAAC,YAAD;KACE,UAAU,UAAU;KACpB,MAAM;KACN,OAAO,EAAE,cAAc;KACvB,SAAS;IACV,CAAA;IACD,oBAAC,YAAD;KACE,MAAM;KACN,SAAS;KACT,OAAO,EAAE,YAAY;KACrB,SAAS;IACV,CAAA;IACD,oBAAC,YAAD;KACE,MAAM;KACN,SAAS;KACT,OAAO,EAAE,gBAAgB;KACzB,SAAS;IACV,CAAA;IACA;GACM;;CACG,CAAA;AAElB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePreview.mjs","names":[],"sources":["../../../src/Image/components/usePreview.tsx"],"sourcesContent":["import type { ImageProps as AntdImageProps } from 'antd';\nimport { cx } from 'antd-style';\nimport { X } from 'lucide-react';\nimport { useMemo, useState } from 'react';\n\nimport Icon from '@/Icon';\n\nimport { styles } from '../style';\nimport type { ImagePreviewOptions } from '../type';\nimport Preview from './Preview';\nimport Toolbar from './Toolbar';\n\nexport const usePreview = (\n props: ImagePreviewOptions | boolean | undefined,\n): AntdImageProps['preview'] => {\n const [visible, setVisible] = useState(false);\n\n return useMemo(() => {\n if (props === false) return props;\n\n const {\n onVisibleChange,\n onOpenChange,\n minScale = 0.32,\n maxScale = 32,\n toolbarAddon,\n rootClassName,\n imageRender,\n toolbarRender,\n actionsRender,\n ...rest\n }: ImagePreviewOptions = (props === true ? {} : props || {}) as ImagePreviewOptions;\n\n return {\n actionsRender:\n actionsRender ||\n ((_, info) => {\n const originalNode = (\n <Toolbar info={info} maxScale={maxScale} minScale={minScale}>\n {toolbarAddon}\n </Toolbar>\n );\n // 向后兼容 toolbarRender\n if (toolbarRender) return toolbarRender(originalNode, info);\n return originalNode;\n }),\n closeIcon: <Icon color={'#fff'} icon={X} />,\n imageRender: (originalNode, info) => {\n const node = <Preview visible={visible}>{originalNode}</Preview>;\n if (imageRender) return imageRender(node, info);\n return node;\n },\n maxScale,\n minScale,\n onOpenChange: (open: boolean) => {\n setVisible(open);\n // 支持新的 onOpenChange\n onOpenChange?.(open);\n // 向后兼容旧的 onVisibleChange\n onVisibleChange?.(open, !open);\n },\n rootClassName: cx(styles.preview, rootClassName),\n styles: { mask: { backdropFilter: 'blur(8px)' } },\n ...rest,\n };\n }, [props, visible, styles]);\n};\n\nexport default usePreview;\n"],"mappings":";;;;;;;;;AAYA,MAAa,cACX,UAC8B;CAC9B,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAE5C,OAAO,cAAc;EACnB,IAAI,UAAU,OAAO,OAAO;EAE5B,MAAM,EACJ,iBACA,cACA,WAAW,KACX,WAAW,IACX,cACA,eACA,aACA,eACA,eACA,GAAG,SACqB,UAAU,OAAO,CAAC,IAAI,SAAS,CAAC;EAE1D,OAAO;GACL,eACE,mBACE,GAAG,SAAS;IACZ,MAAM,eACJ,oBAAC,SAAD;KAAe;KAAgB;KAAoB;
|
|
1
|
+
{"version":3,"file":"usePreview.mjs","names":[],"sources":["../../../src/Image/components/usePreview.tsx"],"sourcesContent":["import type { ImageProps as AntdImageProps } from 'antd';\nimport { cx } from 'antd-style';\nimport { X } from 'lucide-react';\nimport { useMemo, useState } from 'react';\n\nimport Icon from '@/Icon';\n\nimport { styles } from '../style';\nimport type { ImagePreviewOptions } from '../type';\nimport Preview from './Preview';\nimport Toolbar from './Toolbar';\n\nexport const usePreview = (\n props: ImagePreviewOptions | boolean | undefined,\n): AntdImageProps['preview'] => {\n const [visible, setVisible] = useState(false);\n\n return useMemo(() => {\n if (props === false) return props;\n\n const {\n onVisibleChange,\n onOpenChange,\n minScale = 0.32,\n maxScale = 32,\n toolbarAddon,\n rootClassName,\n imageRender,\n toolbarRender,\n actionsRender,\n ...rest\n }: ImagePreviewOptions = (props === true ? {} : props || {}) as ImagePreviewOptions;\n\n return {\n actionsRender:\n actionsRender ||\n ((_, info) => {\n const originalNode = (\n <Toolbar info={info} maxScale={maxScale} minScale={minScale}>\n {toolbarAddon}\n </Toolbar>\n );\n // 向后兼容 toolbarRender\n if (toolbarRender) return toolbarRender(originalNode, info);\n return originalNode;\n }),\n closeIcon: <Icon color={'#fff'} icon={X} />,\n imageRender: (originalNode, info) => {\n const node = <Preview visible={visible}>{originalNode}</Preview>;\n if (imageRender) return imageRender(node, info);\n return node;\n },\n maxScale,\n minScale,\n onOpenChange: (open: boolean) => {\n setVisible(open);\n // 支持新的 onOpenChange\n onOpenChange?.(open);\n // 向后兼容旧的 onVisibleChange\n onVisibleChange?.(open, !open);\n },\n rootClassName: cx(styles.preview, rootClassName),\n styles: { mask: { backdropFilter: 'blur(8px)' } },\n ...rest,\n };\n }, [props, visible, styles]);\n};\n\nexport default usePreview;\n"],"mappings":";;;;;;;;;AAYA,MAAa,cACX,UAC8B;CAC9B,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAE5C,OAAO,cAAc;EACnB,IAAI,UAAU,OAAO,OAAO;EAE5B,MAAM,EACJ,iBACA,cACA,WAAW,KACX,WAAW,IACX,cACA,eACA,aACA,eACA,eACA,GAAG,SACqB,UAAU,OAAO,CAAC,IAAI,SAAS,CAAC;EAE1D,OAAO;GACL,eACE,mBACE,GAAG,SAAS;IACZ,MAAM,eACJ,oBAAC,SAAD;KAAe;KAAgB;KAAoB;KAChD,UAAA;IACM,CAAA;IAGX,IAAI,eAAe,OAAO,cAAc,cAAc,IAAI;IAC1D,OAAO;GACT;GACF,WAAW,oBAAC,MAAD;IAAM,OAAO;IAAQ,MAAM;GAAI,CAAA;GAC1C,cAAc,cAAc,SAAS;IACnC,MAAM,OAAO,oBAAC,SAAD;KAAkB;KAAU,UAAA;IAAsB,CAAA;IAC/D,IAAI,aAAa,OAAO,YAAY,MAAM,IAAI;IAC9C,OAAO;GACT;GACA;GACA;GACA,eAAe,SAAkB;IAC/B,WAAW,IAAI;IAEf,eAAe,IAAI;IAEnB,kBAAkB,MAAM,CAAC,IAAI;GAC/B;GACA,eAAe,GAAG,OAAO,SAAS,aAAa;GAC/C,QAAQ,EAAE,MAAM,EAAE,gBAAgB,YAAY,EAAE;GAChD,GAAG;EACL;CACF,GAAG;EAAC;EAAO;EAAS;CAAM,CAAC;AAC7B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePreviewGroup.mjs","names":["componentStyles"],"sources":["../../../src/Image/components/usePreviewGroup.tsx"],"sourcesContent":["import { type GroupPreviewConfig } from 'antd/es/image/PreviewGroup';\nimport { cx } from 'antd-style';\nimport { X } from 'lucide-react';\nimport { useMemo, useState } from 'react';\n\nimport Icon from '@/Icon';\n\nimport { styles as componentStyles, styles } from '../style';\nimport { type PreviewGroupPreviewOptions } from '../type';\nimport Preview from './Preview';\nimport Toolbar from './Toolbar';\n\nexport const usePreview = (\n props: PreviewGroupPreviewOptions | boolean | undefined,\n): GroupPreviewConfig | boolean => {\n const [visible, setVisible] = useState(false);\n\n return useMemo(() => {\n if (props === false) return props;\n\n const {\n onVisibleChange,\n onOpenChange,\n minScale = 0.32,\n maxScale = 32,\n toolbarAddon,\n rootClassName,\n imageRender,\n toolbarRender,\n ...rest\n }: PreviewGroupPreviewOptions = (\n props === true ? {} : props || {}\n ) as PreviewGroupPreviewOptions;\n\n return {\n actionsRender: (_, info) => {\n const originalNode = (\n <Toolbar info={info} maxScale={maxScale} minScale={minScale}>\n {toolbarAddon}\n </Toolbar>\n );\n if (toolbarRender) return toolbarRender(originalNode, info);\n return originalNode;\n },\n closeIcon: <Icon color={'#fff'} icon={X} />,\n\n imageRender: (originalNode, info) => {\n const node = <Preview visible={visible}>{originalNode}</Preview>;\n if (imageRender) return imageRender(node, info);\n return node;\n },\n maxScale,\n minScale,\n onOpenChange: (open: boolean, info: { current: number }) => {\n setVisible(open);\n // 支持新的 onOpenChange\n onOpenChange?.(open, info);\n // 向后兼容旧的 onVisibleChange (注意参数差异)\n onVisibleChange?.(open, !open, info.current);\n },\n rootClassName: cx(styles.preview, rootClassName),\n ...rest,\n } satisfies GroupPreviewConfig;\n }, [props, visible, componentStyles]);\n};\n\nexport default usePreview;\n"],"mappings":";;;;;;;;;AAYA,MAAa,cACX,UACiC;CACjC,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAE5C,OAAO,cAAc;EACnB,IAAI,UAAU,OAAO,OAAO;EAE5B,MAAM,EACJ,iBACA,cACA,WAAW,KACX,WAAW,IACX,cACA,eACA,aACA,eACA,GAAG,SAEH,UAAU,OAAO,CAAC,IAAI,SAAS,CAAC;EAGlC,OAAO;GACL,gBAAgB,GAAG,SAAS;IAC1B,MAAM,eACJ,oBAAC,SAAD;KAAe;KAAgB;KAAoB;
|
|
1
|
+
{"version":3,"file":"usePreviewGroup.mjs","names":["componentStyles"],"sources":["../../../src/Image/components/usePreviewGroup.tsx"],"sourcesContent":["import { type GroupPreviewConfig } from 'antd/es/image/PreviewGroup';\nimport { cx } from 'antd-style';\nimport { X } from 'lucide-react';\nimport { useMemo, useState } from 'react';\n\nimport Icon from '@/Icon';\n\nimport { styles as componentStyles, styles } from '../style';\nimport { type PreviewGroupPreviewOptions } from '../type';\nimport Preview from './Preview';\nimport Toolbar from './Toolbar';\n\nexport const usePreview = (\n props: PreviewGroupPreviewOptions | boolean | undefined,\n): GroupPreviewConfig | boolean => {\n const [visible, setVisible] = useState(false);\n\n return useMemo(() => {\n if (props === false) return props;\n\n const {\n onVisibleChange,\n onOpenChange,\n minScale = 0.32,\n maxScale = 32,\n toolbarAddon,\n rootClassName,\n imageRender,\n toolbarRender,\n ...rest\n }: PreviewGroupPreviewOptions = (\n props === true ? {} : props || {}\n ) as PreviewGroupPreviewOptions;\n\n return {\n actionsRender: (_, info) => {\n const originalNode = (\n <Toolbar info={info} maxScale={maxScale} minScale={minScale}>\n {toolbarAddon}\n </Toolbar>\n );\n if (toolbarRender) return toolbarRender(originalNode, info);\n return originalNode;\n },\n closeIcon: <Icon color={'#fff'} icon={X} />,\n\n imageRender: (originalNode, info) => {\n const node = <Preview visible={visible}>{originalNode}</Preview>;\n if (imageRender) return imageRender(node, info);\n return node;\n },\n maxScale,\n minScale,\n onOpenChange: (open: boolean, info: { current: number }) => {\n setVisible(open);\n // 支持新的 onOpenChange\n onOpenChange?.(open, info);\n // 向后兼容旧的 onVisibleChange (注意参数差异)\n onVisibleChange?.(open, !open, info.current);\n },\n rootClassName: cx(styles.preview, rootClassName),\n ...rest,\n } satisfies GroupPreviewConfig;\n }, [props, visible, componentStyles]);\n};\n\nexport default usePreview;\n"],"mappings":";;;;;;;;;AAYA,MAAa,cACX,UACiC;CACjC,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAE5C,OAAO,cAAc;EACnB,IAAI,UAAU,OAAO,OAAO;EAE5B,MAAM,EACJ,iBACA,cACA,WAAW,KACX,WAAW,IACX,cACA,eACA,aACA,eACA,GAAG,SAEH,UAAU,OAAO,CAAC,IAAI,SAAS,CAAC;EAGlC,OAAO;GACL,gBAAgB,GAAG,SAAS;IAC1B,MAAM,eACJ,oBAAC,SAAD;KAAe;KAAgB;KAAoB;KAChD,UAAA;IACM,CAAA;IAEX,IAAI,eAAe,OAAO,cAAc,cAAc,IAAI;IAC1D,OAAO;GACT;GACA,WAAW,oBAAC,MAAD;IAAM,OAAO;IAAQ,MAAM;GAAI,CAAA;GAE1C,cAAc,cAAc,SAAS;IACnC,MAAM,OAAO,oBAAC,SAAD;KAAkB;KAAU,UAAA;IAAsB,CAAA;IAC/D,IAAI,aAAa,OAAO,YAAY,MAAM,IAAI;IAC9C,OAAO;GACT;GACA;GACA;GACA,eAAe,MAAe,SAA8B;IAC1D,WAAW,IAAI;IAEf,eAAe,MAAM,IAAI;IAEzB,kBAAkB,MAAM,CAAC,MAAM,KAAK,OAAO;GAC7C;GACA,eAAe,GAAG,OAAO,SAAS,aAAa;GAC/C,GAAG;EACL;CACF,GAAG;EAAC;EAAO;EAASA;CAAe,CAAC;AACtC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ImageSelect.mjs","names":["useControlledState","Flexbox"],"sources":["../../src/ImageSelect/ImageSelect.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { Flexbox } from '@/Flex';\nimport Icon from '@/Icon';\nimport Img from '@/Img';\n\nimport { styles } from './styles';\nimport type { ImageSelectProps } from './type';\n\nconst ImageSelect = memo<ImageSelectProps>(\n ({\n ref,\n className,\n style,\n value,\n defaultValue,\n onChange,\n options,\n width = 144,\n height = 86,\n styles: customStyles,\n classNames,\n unoptimized,\n ...rest\n }) => {\n const [currentValue, setCurrentValue] = useControlledState<string>(defaultValue, {\n defaultValue,\n onChange,\n value,\n });\n\n return (\n <Flexbox horizontal className={className} gap={16} ref={ref} style={style} {...rest}>\n {options?.map((item) => {\n const isActive = item.value === currentValue;\n return (\n <Flexbox\n align={'center'}\n className={cx(styles.container, isActive && styles.active)}\n gap={4}\n key={item.value}\n onClick={() => setCurrentValue(item.value)}\n >\n <Img\n alt={item.alt || item.value}\n className={cx(styles.img, isActive && styles.imgActive, classNames?.img)}\n height={height}\n src={item.img}\n unoptimized={unoptimized}\n width={width}\n style={{\n ...customStyles?.img,\n height,\n width,\n }}\n />\n\n <Flexbox horizontal align={'center'} gap={4}>\n {item.icon && <Icon icon={item.icon} />}\n {item.label}\n </Flexbox>\n </Flexbox>\n );\n })}\n </Flexbox>\n );\n },\n);\n\nImageSelect.displayName = 'ImageSelect';\n\nexport default ImageSelect;\n"],"mappings":";;;;;;;;;;AAaA,MAAM,cAAc,MACjB,EACC,KACA,WACA,OACA,OACA,cACA,UACA,SACA,QAAQ,KACR,SAAS,IACT,QAAQ,cACR,YACA,aACA,GAAG,WACC;CACJ,MAAM,CAAC,cAAc,mBAAmBA,cAA2B,cAAc;EAC/E;EACA;EACA;CACF,CAAC;CAED,OACE,oBAACC,mBAAD;EAAS,YAAA;EAAsB;EAAW,KAAK;EAAS;EAAY;EAAO,GAAI;
|
|
1
|
+
{"version":3,"file":"ImageSelect.mjs","names":["useControlledState","Flexbox"],"sources":["../../src/ImageSelect/ImageSelect.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo } from 'react';\nimport useControlledState from 'use-merge-value';\n\nimport { Flexbox } from '@/Flex';\nimport Icon from '@/Icon';\nimport Img from '@/Img';\n\nimport { styles } from './styles';\nimport type { ImageSelectProps } from './type';\n\nconst ImageSelect = memo<ImageSelectProps>(\n ({\n ref,\n className,\n style,\n value,\n defaultValue,\n onChange,\n options,\n width = 144,\n height = 86,\n styles: customStyles,\n classNames,\n unoptimized,\n ...rest\n }) => {\n const [currentValue, setCurrentValue] = useControlledState<string>(defaultValue, {\n defaultValue,\n onChange,\n value,\n });\n\n return (\n <Flexbox horizontal className={className} gap={16} ref={ref} style={style} {...rest}>\n {options?.map((item) => {\n const isActive = item.value === currentValue;\n return (\n <Flexbox\n align={'center'}\n className={cx(styles.container, isActive && styles.active)}\n gap={4}\n key={item.value}\n onClick={() => setCurrentValue(item.value)}\n >\n <Img\n alt={item.alt || item.value}\n className={cx(styles.img, isActive && styles.imgActive, classNames?.img)}\n height={height}\n src={item.img}\n unoptimized={unoptimized}\n width={width}\n style={{\n ...customStyles?.img,\n height,\n width,\n }}\n />\n\n <Flexbox horizontal align={'center'} gap={4}>\n {item.icon && <Icon icon={item.icon} />}\n {item.label}\n </Flexbox>\n </Flexbox>\n );\n })}\n </Flexbox>\n );\n },\n);\n\nImageSelect.displayName = 'ImageSelect';\n\nexport default ImageSelect;\n"],"mappings":";;;;;;;;;;AAaA,MAAM,cAAc,MACjB,EACC,KACA,WACA,OACA,OACA,cACA,UACA,SACA,QAAQ,KACR,SAAS,IACT,QAAQ,cACR,YACA,aACA,GAAG,WACC;CACJ,MAAM,CAAC,cAAc,mBAAmBA,cAA2B,cAAc;EAC/E;EACA;EACA;CACF,CAAC;CAED,OACE,oBAACC,mBAAD;EAAS,YAAA;EAAsB;EAAW,KAAK;EAAS;EAAY;EAAO,GAAI;EAC5E,UAAA,SAAS,KAAK,SAAS;GACtB,MAAM,WAAW,KAAK,UAAU;GAChC,OACE,qBAACA,mBAAD;IACE,OAAO;IACP,WAAW,GAAG,OAAO,WAAW,YAAY,OAAO,MAAM;IACzD,KAAK;IAEL,eAAe,gBAAgB,KAAK,KAAK;IAL3C,UAAA,CAOE,oBAAC,KAAD;KACE,KAAK,KAAK,OAAO,KAAK;KACtB,WAAW,GAAG,OAAO,KAAK,YAAY,OAAO,WAAW,YAAY,GAAG;KAC/D;KACR,KAAK,KAAK;KACG;KACN;KACP,OAAO;MACL,GAAG,cAAc;MACjB;MACA;KACF;IACD,CAAA,GAED,qBAACA,mBAAD;KAAS,YAAA;KAAW,OAAO;KAAU,KAAK;KAA1C,UAAA,CACG,KAAK,QAAQ,oBAAC,MAAD,EAAM,MAAM,KAAK,KAAO,CAAA,GACrC,KAAK,KACC;IACF,CAAA,CAAA;GArBF,GAAA,KAAK,KAqBH;EAEb,CAAC;CACM,CAAA;AAEb,CACF;AAEA,YAAY,cAAc"}
|
package/es/Img/index.mjs
CHANGED
|
@@ -7,7 +7,8 @@ const createContainer = (as) => memo((props) => createElement(as, props));
|
|
|
7
7
|
const Img = ({ unoptimized, ...rest }) => {
|
|
8
8
|
const config = use(ConfigContext);
|
|
9
9
|
const render = config?.imgAs || "img";
|
|
10
|
-
|
|
10
|
+
const ImgContainer = useMemo(() => createContainer(render), [render]);
|
|
11
|
+
return /* @__PURE__ */ jsx(ImgContainer, {
|
|
11
12
|
unoptimized: unoptimized === void 0 ? config?.imgUnoptimized : unoptimized,
|
|
12
13
|
...rest
|
|
13
14
|
});
|
package/es/Img/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/Img/index.tsx"],"sourcesContent":["'use client';\n\nimport { type ImageProps } from 'antd';\nimport { createElement, type ElementType, type FC, memo, type Ref, use, useMemo } from 'react';\n\nimport { ConfigContext } from '@/ConfigProvider';\nimport { type ImgProps as HtmlImgeProps } from '@/types';\n\nconst createContainer = (as: ElementType) => memo((props: any) => createElement(as, props));\n\ntype ImgProps = HtmlImgeProps & ImageProps & { ref?: Ref<HTMLImageElement>; unoptimized?: boolean };\n\nconst Img: FC<ImgProps> = ({ unoptimized, ...rest }) => {\n const config = use(ConfigContext);\n const render = config?.imgAs || 'img';\n\n const ImgContainer = useMemo(() => createContainer(render), [render]);\n\n return (\n <ImgContainer\n unoptimized={unoptimized === undefined ? config?.imgUnoptimized : unoptimized}\n {...rest}\n />\n );\n};\n\nImg.displayName = 'Img';\n\nexport default Img;\n"],"mappings":";;;;;AAQA,MAAM,mBAAmB,OAAoB,MAAM,UAAe,cAAc,IAAI,KAAK,CAAC;AAI1F,MAAM,OAAqB,EAAE,aAAa,GAAG,WAAW;CACtD,MAAM,SAAS,IAAI,aAAa;CAChC,MAAM,SAAS,QAAQ,SAAS;
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/Img/index.tsx"],"sourcesContent":["'use client';\n\nimport { type ImageProps } from 'antd';\nimport { createElement, type ElementType, type FC, memo, type Ref, use, useMemo } from 'react';\n\nimport { ConfigContext } from '@/ConfigProvider';\nimport { type ImgProps as HtmlImgeProps } from '@/types';\n\nconst createContainer = (as: ElementType) => memo((props: any) => createElement(as, props));\n\ntype ImgProps = HtmlImgeProps & ImageProps & { ref?: Ref<HTMLImageElement>; unoptimized?: boolean };\n\nconst Img: FC<ImgProps> = ({ unoptimized, ...rest }) => {\n const config = use(ConfigContext);\n const render = config?.imgAs || 'img';\n\n const ImgContainer = useMemo(() => createContainer(render), [render]);\n\n return (\n <ImgContainer\n unoptimized={unoptimized === undefined ? config?.imgUnoptimized : unoptimized}\n {...rest}\n />\n );\n};\n\nImg.displayName = 'Img';\n\nexport default Img;\n"],"mappings":";;;;;AAQA,MAAM,mBAAmB,OAAoB,MAAM,UAAe,cAAc,IAAI,KAAK,CAAC;AAI1F,MAAM,OAAqB,EAAE,aAAa,GAAG,WAAW;CACtD,MAAM,SAAS,IAAI,aAAa;CAChC,MAAM,SAAS,QAAQ,SAAS;CAEhC,MAAM,eAAe,cAAc,gBAAgB,MAAM,GAAG,CAAC,MAAM,CAAC;CAEpE,OACE,oBAAC,cAAD;EACE,aAAa,gBAAgB,KAAA,IAAY,QAAQ,iBAAiB;EAClE,GAAI;CACL,CAAA;AAEL;AAEA,IAAI,cAAc"}
|
package/es/Layout/Layout.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Layout.mjs","names":[],"sources":["../../src/Layout/Layout.tsx"],"sourcesContent":["'use client';\n\nimport { useResponsive } from 'antd-style';\nimport { memo, useEffect, useMemo, useState } from 'react';\n\nimport DraggablePanel from '@/DraggablePanel';\n\nimport LayoutFooter from './components/LayoutFooter';\nimport LayoutHeader from './components/LayoutHeader';\nimport LayoutMain from './components/LayoutMain';\nimport LayoutSidebar from './components/LayoutSidebar';\nimport LayoutSidebarInner from './components/LayoutSidebarInner';\nimport LayoutToc from './components/LayoutToc';\nimport { styles } from './style';\nimport type { LayoutProps } from './type';\n\nconst Layout = memo<LayoutProps>(\n ({ helmet, headerHeight = 64, header, footer, sidebar, asideWidth, toc, children, tocWidth }) => {\n // Convert headerHeight prop to CSS variable\n const cssVariables = useMemo<Record<string, string>>(\n () => ({\n '--layout-header-height': `${headerHeight}px`,\n }),\n [headerHeight],\n );\n const { mobile, laptop } = useResponsive();\n const [expand, setExpand] = useState(true);\n useEffect(() => {\n setExpand(Boolean(laptop));\n }, [laptop]);\n\n return (\n <div style={cssVariables}>\n {helmet}\n {header && (\n <LayoutHeader headerHeight={headerHeight}>\n {header}\n {mobile && toc && <LayoutToc>{toc}</LayoutToc>}\n </LayoutHeader>\n )}\n <LayoutMain>\n {!mobile && !sidebar && <nav style={{ width: tocWidth }} />}\n {!mobile && sidebar && (\n <LayoutSidebar headerHeight={headerHeight}>\n <DraggablePanel\n expand={expand}\n maxWidth={asideWidth}\n placement=\"left\"\n onExpandChange={setExpand}\n >\n <LayoutSidebarInner headerHeight={headerHeight}>{sidebar}</LayoutSidebarInner>\n </DraggablePanel>\n </LayoutSidebar>\n )}\n <section className={styles.content}>{children}</section>\n {!mobile && toc && <LayoutToc tocWidth={tocWidth}>{toc}</LayoutToc>}\n </LayoutMain>\n {footer && <LayoutFooter>{footer}</LayoutFooter>}\n </div>\n );\n },\n);\n\nexport default Layout;\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAM,SAAS,MACZ,EAAE,QAAQ,eAAe,IAAI,QAAQ,QAAQ,SAAS,YAAY,KAAK,UAAU,eAAe;CAE/F,MAAM,eAAe,eACZ,EACL,0BAA0B,GAAG,aAAa,IAC5C,IACA,CAAC,YAAY,CACf;CACA,MAAM,EAAE,QAAQ,WAAW,cAAc;CACzC,MAAM,CAAC,QAAQ,aAAa,SAAS,IAAI;CACzC,gBAAgB;EACd,UAAU,QAAQ,MAAM,CAAC;CAC3B,GAAG,CAAC,MAAM,CAAC;CAEX,OACE,qBAAC,OAAD;EAAK,OAAO;
|
|
1
|
+
{"version":3,"file":"Layout.mjs","names":[],"sources":["../../src/Layout/Layout.tsx"],"sourcesContent":["'use client';\n\nimport { useResponsive } from 'antd-style';\nimport { memo, useEffect, useMemo, useState } from 'react';\n\nimport DraggablePanel from '@/DraggablePanel';\n\nimport LayoutFooter from './components/LayoutFooter';\nimport LayoutHeader from './components/LayoutHeader';\nimport LayoutMain from './components/LayoutMain';\nimport LayoutSidebar from './components/LayoutSidebar';\nimport LayoutSidebarInner from './components/LayoutSidebarInner';\nimport LayoutToc from './components/LayoutToc';\nimport { styles } from './style';\nimport type { LayoutProps } from './type';\n\nconst Layout = memo<LayoutProps>(\n ({ helmet, headerHeight = 64, header, footer, sidebar, asideWidth, toc, children, tocWidth }) => {\n // Convert headerHeight prop to CSS variable\n const cssVariables = useMemo<Record<string, string>>(\n () => ({\n '--layout-header-height': `${headerHeight}px`,\n }),\n [headerHeight],\n );\n const { mobile, laptop } = useResponsive();\n const [expand, setExpand] = useState(true);\n useEffect(() => {\n setExpand(Boolean(laptop));\n }, [laptop]);\n\n return (\n <div style={cssVariables}>\n {helmet}\n {header && (\n <LayoutHeader headerHeight={headerHeight}>\n {header}\n {mobile && toc && <LayoutToc>{toc}</LayoutToc>}\n </LayoutHeader>\n )}\n <LayoutMain>\n {!mobile && !sidebar && <nav style={{ width: tocWidth }} />}\n {!mobile && sidebar && (\n <LayoutSidebar headerHeight={headerHeight}>\n <DraggablePanel\n expand={expand}\n maxWidth={asideWidth}\n placement=\"left\"\n onExpandChange={setExpand}\n >\n <LayoutSidebarInner headerHeight={headerHeight}>{sidebar}</LayoutSidebarInner>\n </DraggablePanel>\n </LayoutSidebar>\n )}\n <section className={styles.content}>{children}</section>\n {!mobile && toc && <LayoutToc tocWidth={tocWidth}>{toc}</LayoutToc>}\n </LayoutMain>\n {footer && <LayoutFooter>{footer}</LayoutFooter>}\n </div>\n );\n },\n);\n\nexport default Layout;\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAM,SAAS,MACZ,EAAE,QAAQ,eAAe,IAAI,QAAQ,QAAQ,SAAS,YAAY,KAAK,UAAU,eAAe;CAE/F,MAAM,eAAe,eACZ,EACL,0BAA0B,GAAG,aAAa,IAC5C,IACA,CAAC,YAAY,CACf;CACA,MAAM,EAAE,QAAQ,WAAW,cAAc;CACzC,MAAM,CAAC,QAAQ,aAAa,SAAS,IAAI;CACzC,gBAAgB;EACd,UAAU,QAAQ,MAAM,CAAC;CAC3B,GAAG,CAAC,MAAM,CAAC;CAEX,OACE,qBAAC,OAAD;EAAK,OAAO;EAAZ,UAAA;GACG;GACA,UACC,qBAAC,cAAD;IAA4B;IAA5B,UAAA,CACG,QACA,UAAU,OAAO,oBAAC,WAAD,EAAA,UAAY,IAAe,CAAA,CACjC;;GAEhB,qBAAC,YAAD,EAAA,UAAA;IACG,CAAC,UAAU,CAAC,WAAW,oBAAC,OAAD,EAAK,OAAO,EAAE,OAAO,SAAS,EAAI,CAAA;IACzD,CAAC,UAAU,WACV,oBAAC,eAAD;KAA6B;KAC3B,UAAA,oBAAC,gBAAD;MACU;MACR,UAAU;MACV,WAAU;MACV,gBAAgB;MAEhB,UAAA,oBAAC,oBAAD;OAAkC;OAAe,UAAA;MAA4B,CAAA;KAC/D,CAAA;IACH,CAAA;IAEjB,oBAAC,WAAD;KAAS,WAAW,OAAO;KAAU;IAAkB,CAAA;IACtD,CAAC,UAAU,OAAO,oBAAC,WAAD;KAAqB;KAAW,UAAA;IAAe,CAAA;GACxD,EAAA,CAAA;GACX,UAAU,oBAAC,cAAD,EAAA,UAAe,OAAqB,CAAA;EAC5C;;AAET,CACF"}
|
package/es/List/List.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"List.mjs","names":["Flexbox"],"sources":["../../src/List/List.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport ListItem from './ListItem';\nimport type { ListProps } from './type';\n\nconst List = memo<ListProps>(({ ref, activeKey, classNames, styles, onClick, items, ...rest }) => {\n return (\n <Flexbox gap={4} padding={4} {...rest}>\n {items.map((item) => {\n const {\n key,\n onClick: itemOnClick,\n className: itemClassName,\n style: itemStyle,\n ...itemRest\n } = item;\n const { item: customItemClassName, ...restClassName } = classNames || {};\n const { item: customItemStyle, ...restStyles } = styles || {};\n return (\n <ListItem\n active={item.key === activeKey}\n className={cx(customItemClassName, itemClassName)}\n classNames={restClassName}\n key={key}\n ref={ref}\n style={{ ...customItemStyle, ...itemStyle }}\n styles={restStyles}\n onClick={(e) => {\n onClick?.({\n item,\n key,\n });\n itemOnClick?.(e);\n }}\n {...itemRest}\n />\n );\n })}\n </Flexbox>\n );\n});\n\nList.displayName = 'List';\n\nexport default List;\n"],"mappings":";;;;;;;AAUA,MAAM,OAAO,MAAiB,EAAE,KAAK,WAAW,YAAY,QAAQ,SAAS,OAAO,GAAG,WAAW;CAChG,OACE,oBAACA,mBAAD;EAAS,KAAK;EAAG,SAAS;EAAG,GAAI;
|
|
1
|
+
{"version":3,"file":"List.mjs","names":["Flexbox"],"sources":["../../src/List/List.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport ListItem from './ListItem';\nimport type { ListProps } from './type';\n\nconst List = memo<ListProps>(({ ref, activeKey, classNames, styles, onClick, items, ...rest }) => {\n return (\n <Flexbox gap={4} padding={4} {...rest}>\n {items.map((item) => {\n const {\n key,\n onClick: itemOnClick,\n className: itemClassName,\n style: itemStyle,\n ...itemRest\n } = item;\n const { item: customItemClassName, ...restClassName } = classNames || {};\n const { item: customItemStyle, ...restStyles } = styles || {};\n return (\n <ListItem\n active={item.key === activeKey}\n className={cx(customItemClassName, itemClassName)}\n classNames={restClassName}\n key={key}\n ref={ref}\n style={{ ...customItemStyle, ...itemStyle }}\n styles={restStyles}\n onClick={(e) => {\n onClick?.({\n item,\n key,\n });\n itemOnClick?.(e);\n }}\n {...itemRest}\n />\n );\n })}\n </Flexbox>\n );\n});\n\nList.displayName = 'List';\n\nexport default List;\n"],"mappings":";;;;;;;AAUA,MAAM,OAAO,MAAiB,EAAE,KAAK,WAAW,YAAY,QAAQ,SAAS,OAAO,GAAG,WAAW;CAChG,OACE,oBAACA,mBAAD;EAAS,KAAK;EAAG,SAAS;EAAG,GAAI;EAC9B,UAAA,MAAM,KAAK,SAAS;GACnB,MAAM,EACJ,KACA,SAAS,aACT,WAAW,eACX,OAAO,WACP,GAAG,aACD;GACJ,MAAM,EAAE,MAAM,qBAAqB,GAAG,kBAAkB,cAAc,CAAC;GACvE,MAAM,EAAE,MAAM,iBAAiB,GAAG,eAAe,UAAU,CAAC;GAC5D,OACE,oBAAC,UAAD;IACE,QAAQ,KAAK,QAAQ;IACrB,WAAW,GAAG,qBAAqB,aAAa;IAChD,YAAY;IAEP;IACL,OAAO;KAAE,GAAG;KAAiB,GAAG;IAAU;IAC1C,QAAQ;IACR,UAAU,MAAM;KACd,UAAU;MACR;MACA;KACF,CAAC;KACD,cAAc,CAAC;IACjB;IACA,GAAI;GACL,GAZM,GAYN;EAEL,CAAC;CACM,CAAA;AAEb,CAAC;AAED,KAAK,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["Flexbox"],"sources":["../../../src/List/ListItem/index.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { Loader2, MessageSquare } from 'lucide-react';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport Icon from '@/Icon';\nimport Text from '@/Text';\nimport { preventDefaultAndStopPropagation } from '@/utils/dom';\n\nimport type { ListItemProps } from '../type';\nimport { styles } from './style';\nimport { getChatItemTime } from './time';\n\nconst ListItem = memo<ListItemProps>(\n ({\n ref,\n active,\n avatar,\n loading,\n description,\n date,\n title,\n onHoverChange,\n actions,\n className,\n style,\n showAction,\n children,\n classNames,\n addon,\n pin,\n styles: customStyles,\n ...rest\n }) => {\n const loadingNode = <Icon spin icon={Loader2} />;\n\n const pinNode = pin && (\n <div className={cx(styles.pin, classNames?.pin)} style={customStyles?.pin}>\n <div className={styles.triangle} />\n </div>\n );\n\n const actionsNode = actions && (\n <Flexbox\n horizontal\n className={cx(styles.actions, classNames?.actions)}\n gap={4}\n style={{ display: showAction ? undefined : 'none', ...customStyles?.actions }}\n onClick={preventDefaultAndStopPropagation}\n >\n {actions}\n </Flexbox>\n );\n\n const timeNode = date && (\n <div\n className={cx(styles.date, classNames?.date)}\n style={{ opacity: showAction ? 0 : undefined, ...customStyles?.date }}\n >\n {getChatItemTime(date)}\n </div>\n );\n\n return (\n <Flexbox\n horizontal\n align={'flex-start'}\n className={cx(styles.root, active && styles.active, className)}\n distribution={'space-between'}\n gap={8}\n padding={12}\n ref={ref}\n style={style}\n onMouseEnter={() => {\n onHoverChange?.(true);\n }}\n onMouseLeave={() => {\n onHoverChange?.(false);\n }}\n {...rest}\n >\n {pinNode}\n <Flexbox\n horizontal\n align={'flex-start'}\n className={classNames?.container}\n flex={1}\n gap={8}\n style={{ overflow: 'hidden', ...customStyles?.container }}\n >\n {avatar ?? <Icon icon={MessageSquare} style={{ marginTop: 4 }} />}\n <Flexbox\n className={cx(styles.content, classNames?.content)}\n gap={4}\n style={customStyles?.content}\n >\n <Text\n ellipsis\n as={'h3'}\n className={cx(styles.title, classNames?.title)}\n style={customStyles?.title}\n >\n {title}\n </Text>\n {description && (\n <Text\n ellipsis\n className={cx(styles.desc, classNames?.desc)}\n style={customStyles?.desc}\n >\n {description}\n </Text>\n )}\n {addon}\n </Flexbox>\n </Flexbox>\n {loading ? (\n loadingNode\n ) : (\n <>\n {actionsNode}\n {timeNode}\n </>\n )}\n {children}\n </Flexbox>\n );\n },\n);\n\nListItem.displayName = 'ListItem';\n\nexport default ListItem;\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,WAAW,MACd,EACC,KACA,QACA,QACA,SACA,aACA,MACA,OACA,eACA,SACA,WACA,OACA,YACA,UACA,YACA,OACA,KACA,QAAQ,cACR,GAAG,WACC;CACJ,MAAM,cAAc,oBAAC,MAAD;EAAM,MAAA;EAAK,MAAM;CAAU,CAAA;CAE/C,MAAM,UAAU,OACd,oBAAC,OAAD;EAAK,WAAW,GAAG,OAAO,KAAK,YAAY,GAAG;EAAG,OAAO,cAAc;
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["Flexbox"],"sources":["../../../src/List/ListItem/index.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { Loader2, MessageSquare } from 'lucide-react';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport Icon from '@/Icon';\nimport Text from '@/Text';\nimport { preventDefaultAndStopPropagation } from '@/utils/dom';\n\nimport type { ListItemProps } from '../type';\nimport { styles } from './style';\nimport { getChatItemTime } from './time';\n\nconst ListItem = memo<ListItemProps>(\n ({\n ref,\n active,\n avatar,\n loading,\n description,\n date,\n title,\n onHoverChange,\n actions,\n className,\n style,\n showAction,\n children,\n classNames,\n addon,\n pin,\n styles: customStyles,\n ...rest\n }) => {\n const loadingNode = <Icon spin icon={Loader2} />;\n\n const pinNode = pin && (\n <div className={cx(styles.pin, classNames?.pin)} style={customStyles?.pin}>\n <div className={styles.triangle} />\n </div>\n );\n\n const actionsNode = actions && (\n <Flexbox\n horizontal\n className={cx(styles.actions, classNames?.actions)}\n gap={4}\n style={{ display: showAction ? undefined : 'none', ...customStyles?.actions }}\n onClick={preventDefaultAndStopPropagation}\n >\n {actions}\n </Flexbox>\n );\n\n const timeNode = date && (\n <div\n className={cx(styles.date, classNames?.date)}\n style={{ opacity: showAction ? 0 : undefined, ...customStyles?.date }}\n >\n {getChatItemTime(date)}\n </div>\n );\n\n return (\n <Flexbox\n horizontal\n align={'flex-start'}\n className={cx(styles.root, active && styles.active, className)}\n distribution={'space-between'}\n gap={8}\n padding={12}\n ref={ref}\n style={style}\n onMouseEnter={() => {\n onHoverChange?.(true);\n }}\n onMouseLeave={() => {\n onHoverChange?.(false);\n }}\n {...rest}\n >\n {pinNode}\n <Flexbox\n horizontal\n align={'flex-start'}\n className={classNames?.container}\n flex={1}\n gap={8}\n style={{ overflow: 'hidden', ...customStyles?.container }}\n >\n {avatar ?? <Icon icon={MessageSquare} style={{ marginTop: 4 }} />}\n <Flexbox\n className={cx(styles.content, classNames?.content)}\n gap={4}\n style={customStyles?.content}\n >\n <Text\n ellipsis\n as={'h3'}\n className={cx(styles.title, classNames?.title)}\n style={customStyles?.title}\n >\n {title}\n </Text>\n {description && (\n <Text\n ellipsis\n className={cx(styles.desc, classNames?.desc)}\n style={customStyles?.desc}\n >\n {description}\n </Text>\n )}\n {addon}\n </Flexbox>\n </Flexbox>\n {loading ? (\n loadingNode\n ) : (\n <>\n {actionsNode}\n {timeNode}\n </>\n )}\n {children}\n </Flexbox>\n );\n },\n);\n\nListItem.displayName = 'ListItem';\n\nexport default ListItem;\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,WAAW,MACd,EACC,KACA,QACA,QACA,SACA,aACA,MACA,OACA,eACA,SACA,WACA,OACA,YACA,UACA,YACA,OACA,KACA,QAAQ,cACR,GAAG,WACC;CACJ,MAAM,cAAc,oBAAC,MAAD;EAAM,MAAA;EAAK,MAAM;CAAU,CAAA;CAE/C,MAAM,UAAU,OACd,oBAAC,OAAD;EAAK,WAAW,GAAG,OAAO,KAAK,YAAY,GAAG;EAAG,OAAO,cAAc;EACpE,UAAA,oBAAC,OAAD,EAAK,WAAW,OAAO,SAAW,CAAA;CAC/B,CAAA;CAGP,MAAM,cAAc,WAClB,oBAACA,mBAAD;EACE,YAAA;EACA,WAAW,GAAG,OAAO,SAAS,YAAY,OAAO;EACjD,KAAK;EACL,OAAO;GAAE,SAAS,aAAa,KAAA,IAAY;GAAQ,GAAG,cAAc;EAAQ;EAC5E,SAAS;EAER,UAAA;CACM,CAAA;CAGX,MAAM,WAAW,QACf,oBAAC,OAAD;EACE,WAAW,GAAG,OAAO,MAAM,YAAY,IAAI;EAC3C,OAAO;GAAE,SAAS,aAAa,IAAI,KAAA;GAAW,GAAG,cAAc;EAAK;EAEnE,UAAA,gBAAgB,IAAI;CAClB,CAAA;CAGP,OACE,qBAACA,mBAAD;EACE,YAAA;EACA,OAAO;EACP,WAAW,GAAG,OAAO,MAAM,UAAU,OAAO,QAAQ,SAAS;EAC7D,cAAc;EACd,KAAK;EACL,SAAS;EACJ;EACE;EACP,oBAAoB;GAClB,gBAAgB,IAAI;EACtB;EACA,oBAAoB;GAClB,gBAAgB,KAAK;EACvB;EACA,GAAI;EAfN,UAAA;GAiBG;GACD,qBAACA,mBAAD;IACE,YAAA;IACA,OAAO;IACP,WAAW,YAAY;IACvB,MAAM;IACN,KAAK;IACL,OAAO;KAAE,UAAU;KAAU,GAAG,cAAc;IAAU;IAN1D,UAAA,CAQG,UAAU,oBAAC,MAAD;KAAM,MAAM;KAAe,OAAO,EAAE,WAAW,EAAE;IAAI,CAAA,GAChE,qBAACA,mBAAD;KACE,WAAW,GAAG,OAAO,SAAS,YAAY,OAAO;KACjD,KAAK;KACL,OAAO,cAAc;KAHvB,UAAA;MAKE,oBAAC,MAAD;OACE,UAAA;OACA,IAAI;OACJ,WAAW,GAAG,OAAO,OAAO,YAAY,KAAK;OAC7C,OAAO,cAAc;OAEpB,UAAA;MACG,CAAA;MACL,eACC,oBAAC,MAAD;OACE,UAAA;OACA,WAAW,GAAG,OAAO,MAAM,YAAY,IAAI;OAC3C,OAAO,cAAc;OAEpB,UAAA;MACG,CAAA;MAEP;KACM;IACF,CAAA,CAAA;;GACR,UACC,cAEA,qBAAA,YAAA,EAAA,UAAA,CACG,aACA,QACD,EAAA,CAAA;GAEH;EACM;;AAEb,CACF;AAEA,SAAS,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Markdown.mjs","names":["MarkdownRender"],"sources":["../../src/Markdown/Markdown.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo, useCallback } from 'react';\n\nimport { useStableValue } from '@/hooks/useStableValue';\nimport { PreviewGroup } from '@/Image';\n\nimport { MarkdownProvider } from './components/MarkdownProvider';\nimport { useDelayedAnimated } from './components/useDelayedAnimated';\nimport { variants } from './style';\nimport { MarkdownRender, StreamdownRender } from './SyntaxMarkdown';\nimport { type MarkdownProps } from './type';\nimport Typography from './Typography';\n\nconst Markdown = memo<MarkdownProps>((props) => {\n const {\n ref,\n children = '',\n className,\n style,\n fullFeaturedCodeBlock,\n onDoubleClick,\n animated,\n enableHtmlPreview = false,\n enableLatex = true,\n enableMermaid = true,\n enableImageGallery,\n enableCustomFootnotes,\n enableGithubAlert,\n enableStream = true,\n componentProps,\n rehypePluginsAhead,\n allowHtml,\n borderRadius,\n fontSize = props.variant === 'chat' ? 14 : undefined,\n headerMultiple = props.variant === 'chat' ? 0.25 : undefined,\n marginMultiple = props.variant === 'chat' ? 1 : undefined,\n variant = 'default',\n reactMarkdownProps,\n lineHeight = props.variant === 'chat' ? 1.6 : undefined,\n rehypePlugins,\n remarkPlugins,\n remarkPluginsAhead,\n components = {},\n customRender,\n showFootnotes = true,\n streamAnimationGranularity,\n streamSmoothingPreset,\n citations,\n ...rest\n } = props;\n\n const delayedAnimated = useDelayedAnimated(animated);\n\n // Stabilise structural props so an inline `componentProps={{ html:\n // {...} }}` from the caller doesn't cascade through MarkdownProvider →\n // useMarkdownComponents → react-markdown's `components` and remount the\n // entire code-block subtree (including the HtmlPreview iframe) on\n // every parent render. The deep-equal compare treats inline literals\n // as the same object as long as their structure matches. Inline\n // callbacks (`actionsRender`, custom `components`) still need\n // `useCallback` at the call site — function bodies aren't compared.\n const stableComponentProps = useStableValue(componentProps);\n const stableComponents = useStableValue(components);\n\n const Render = useCallback(\n ({\n enableStream,\n children,\n reactMarkdownProps,\n }: Pick<MarkdownProps, 'children' | 'enableStream' | 'reactMarkdownProps'>) => {\n const DefaultRender = enableStream ? StreamdownRender : MarkdownRender;\n const defaultDOM = <DefaultRender {...reactMarkdownProps}>{children}</DefaultRender>;\n return customRender ? customRender(defaultDOM, { text: children }) : defaultDOM;\n },\n [customRender],\n );\n\n return (\n <PreviewGroup enable={enableImageGallery}>\n <Typography\n borderRadius={borderRadius}\n className={cx(variants({ enableLatex, variant }), className)}\n data-code-type=\"markdown\"\n fontSize={fontSize}\n headerMultiple={headerMultiple}\n lineHeight={lineHeight}\n marginMultiple={marginMultiple}\n ref={ref}\n style={style}\n onDoubleClick={onDoubleClick}\n {...rest}\n >\n <MarkdownProvider\n allowHtml={allowHtml}\n animated={delayedAnimated}\n citations={citations}\n componentProps={stableComponentProps}\n components={stableComponents}\n enableCustomFootnotes={enableCustomFootnotes}\n enableGithubAlert={enableGithubAlert}\n enableHtmlPreview={enableHtmlPreview}\n enableLatex={enableLatex}\n enableMermaid={enableMermaid}\n fullFeaturedCodeBlock={fullFeaturedCodeBlock}\n rehypePlugins={rehypePlugins}\n rehypePluginsAhead={rehypePluginsAhead}\n remarkPlugins={remarkPlugins}\n remarkPluginsAhead={remarkPluginsAhead}\n showFootnotes={showFootnotes}\n streamAnimationGranularity={streamAnimationGranularity}\n streamSmoothingPreset={streamSmoothingPreset}\n variant={variant}\n >\n <Render\n enableStream={enableStream && delayedAnimated}\n reactMarkdownProps={reactMarkdownProps}\n >\n {children}\n </Render>\n </MarkdownProvider>\n </Typography>\n </PreviewGroup>\n );\n});\n\nMarkdown.displayName = 'Markdown';\n\nexport default Markdown;\n"],"mappings":";;;;;;;;;;;;;AAeA,MAAM,WAAW,MAAqB,UAAU;CAC9C,MAAM,EACJ,KACA,WAAW,IACX,WACA,OACA,uBACA,eACA,UACA,oBAAoB,OACpB,cAAc,MACd,gBAAgB,MAChB,oBACA,uBACA,mBACA,eAAe,MACf,gBACA,oBACA,WACA,cACA,WAAW,MAAM,YAAY,SAAS,KAAK,KAAA,GAC3C,iBAAiB,MAAM,YAAY,SAAS,MAAO,KAAA,GACnD,iBAAiB,MAAM,YAAY,SAAS,IAAI,KAAA,GAChD,UAAU,WACV,oBACA,aAAa,MAAM,YAAY,SAAS,MAAM,KAAA,GAC9C,eACA,eACA,oBACA,aAAa,CAAC,GACd,cACA,gBAAgB,MAChB,4BACA,uBACA,WACA,GAAG,SACD;CAEJ,MAAM,kBAAkB,mBAAmB,QAAQ;CAUnD,MAAM,uBAAuB,eAAe,cAAc;CAC1D,MAAM,mBAAmB,eAAe,UAAU;CAElD,MAAM,SAAS,aACZ,EACC,cACA,UACA,yBAC6E;EAE7E,MAAM,aAAa,oBADG,eAAe,mBAAmBA,kBACrC;GAAe,GAAI;GAAqB;EAAwB,CAAA;EACnF,OAAO,eAAe,aAAa,YAAY,EAAE,MAAM,SAAS,CAAC,IAAI;CACvE,GACA,CAAC,YAAY,CACf;CAEA,OACE,oBAAC,cAAD;EAAc,QAAQ;
|
|
1
|
+
{"version":3,"file":"Markdown.mjs","names":["MarkdownRender"],"sources":["../../src/Markdown/Markdown.tsx"],"sourcesContent":["'use client';\n\nimport { cx } from 'antd-style';\nimport { memo, useCallback } from 'react';\n\nimport { useStableValue } from '@/hooks/useStableValue';\nimport { PreviewGroup } from '@/Image';\n\nimport { MarkdownProvider } from './components/MarkdownProvider';\nimport { useDelayedAnimated } from './components/useDelayedAnimated';\nimport { variants } from './style';\nimport { MarkdownRender, StreamdownRender } from './SyntaxMarkdown';\nimport { type MarkdownProps } from './type';\nimport Typography from './Typography';\n\nconst Markdown = memo<MarkdownProps>((props) => {\n const {\n ref,\n children = '',\n className,\n style,\n fullFeaturedCodeBlock,\n onDoubleClick,\n animated,\n enableHtmlPreview = false,\n enableLatex = true,\n enableMermaid = true,\n enableImageGallery,\n enableCustomFootnotes,\n enableGithubAlert,\n enableStream = true,\n componentProps,\n rehypePluginsAhead,\n allowHtml,\n borderRadius,\n fontSize = props.variant === 'chat' ? 14 : undefined,\n headerMultiple = props.variant === 'chat' ? 0.25 : undefined,\n marginMultiple = props.variant === 'chat' ? 1 : undefined,\n variant = 'default',\n reactMarkdownProps,\n lineHeight = props.variant === 'chat' ? 1.6 : undefined,\n rehypePlugins,\n remarkPlugins,\n remarkPluginsAhead,\n components = {},\n customRender,\n showFootnotes = true,\n streamAnimationGranularity,\n streamSmoothingPreset,\n citations,\n ...rest\n } = props;\n\n const delayedAnimated = useDelayedAnimated(animated);\n\n // Stabilise structural props so an inline `componentProps={{ html:\n // {...} }}` from the caller doesn't cascade through MarkdownProvider →\n // useMarkdownComponents → react-markdown's `components` and remount the\n // entire code-block subtree (including the HtmlPreview iframe) on\n // every parent render. The deep-equal compare treats inline literals\n // as the same object as long as their structure matches. Inline\n // callbacks (`actionsRender`, custom `components`) still need\n // `useCallback` at the call site — function bodies aren't compared.\n const stableComponentProps = useStableValue(componentProps);\n const stableComponents = useStableValue(components);\n\n const Render = useCallback(\n ({\n enableStream,\n children,\n reactMarkdownProps,\n }: Pick<MarkdownProps, 'children' | 'enableStream' | 'reactMarkdownProps'>) => {\n const DefaultRender = enableStream ? StreamdownRender : MarkdownRender;\n const defaultDOM = <DefaultRender {...reactMarkdownProps}>{children}</DefaultRender>;\n return customRender ? customRender(defaultDOM, { text: children }) : defaultDOM;\n },\n [customRender],\n );\n\n return (\n <PreviewGroup enable={enableImageGallery}>\n <Typography\n borderRadius={borderRadius}\n className={cx(variants({ enableLatex, variant }), className)}\n data-code-type=\"markdown\"\n fontSize={fontSize}\n headerMultiple={headerMultiple}\n lineHeight={lineHeight}\n marginMultiple={marginMultiple}\n ref={ref}\n style={style}\n onDoubleClick={onDoubleClick}\n {...rest}\n >\n <MarkdownProvider\n allowHtml={allowHtml}\n animated={delayedAnimated}\n citations={citations}\n componentProps={stableComponentProps}\n components={stableComponents}\n enableCustomFootnotes={enableCustomFootnotes}\n enableGithubAlert={enableGithubAlert}\n enableHtmlPreview={enableHtmlPreview}\n enableLatex={enableLatex}\n enableMermaid={enableMermaid}\n fullFeaturedCodeBlock={fullFeaturedCodeBlock}\n rehypePlugins={rehypePlugins}\n rehypePluginsAhead={rehypePluginsAhead}\n remarkPlugins={remarkPlugins}\n remarkPluginsAhead={remarkPluginsAhead}\n showFootnotes={showFootnotes}\n streamAnimationGranularity={streamAnimationGranularity}\n streamSmoothingPreset={streamSmoothingPreset}\n variant={variant}\n >\n <Render\n enableStream={enableStream && delayedAnimated}\n reactMarkdownProps={reactMarkdownProps}\n >\n {children}\n </Render>\n </MarkdownProvider>\n </Typography>\n </PreviewGroup>\n );\n});\n\nMarkdown.displayName = 'Markdown';\n\nexport default Markdown;\n"],"mappings":";;;;;;;;;;;;;AAeA,MAAM,WAAW,MAAqB,UAAU;CAC9C,MAAM,EACJ,KACA,WAAW,IACX,WACA,OACA,uBACA,eACA,UACA,oBAAoB,OACpB,cAAc,MACd,gBAAgB,MAChB,oBACA,uBACA,mBACA,eAAe,MACf,gBACA,oBACA,WACA,cACA,WAAW,MAAM,YAAY,SAAS,KAAK,KAAA,GAC3C,iBAAiB,MAAM,YAAY,SAAS,MAAO,KAAA,GACnD,iBAAiB,MAAM,YAAY,SAAS,IAAI,KAAA,GAChD,UAAU,WACV,oBACA,aAAa,MAAM,YAAY,SAAS,MAAM,KAAA,GAC9C,eACA,eACA,oBACA,aAAa,CAAC,GACd,cACA,gBAAgB,MAChB,4BACA,uBACA,WACA,GAAG,SACD;CAEJ,MAAM,kBAAkB,mBAAmB,QAAQ;CAUnD,MAAM,uBAAuB,eAAe,cAAc;CAC1D,MAAM,mBAAmB,eAAe,UAAU;CAElD,MAAM,SAAS,aACZ,EACC,cACA,UACA,yBAC6E;EAE7E,MAAM,aAAa,oBADG,eAAe,mBAAmBA,kBACrC;GAAe,GAAI;GAAqB;EAAwB,CAAA;EACnF,OAAO,eAAe,aAAa,YAAY,EAAE,MAAM,SAAS,CAAC,IAAI;CACvE,GACA,CAAC,YAAY,CACf;CAEA,OACE,oBAAC,cAAD;EAAc,QAAQ;EACpB,UAAA,oBAAC,YAAD;GACgB;GACd,WAAW,GAAG,SAAS;IAAE;IAAa;GAAQ,CAAC,GAAG,SAAS;GAC3D,kBAAe;GACL;GACM;GACJ;GACI;GACX;GACE;GACQ;GACf,GAAI;GAEJ,UAAA,oBAAC,kBAAD;IACa;IACX,UAAU;IACC;IACX,gBAAgB;IAChB,YAAY;IACW;IACJ;IACA;IACN;IACE;IACQ;IACR;IACK;IACL;IACK;IACL;IACa;IACL;IACd;IAET,UAAA,oBAAC,QAAD;KACE,cAAc,gBAAgB;KACV;KAEnB;IACK,CAAA;GACQ,CAAA;EACR,CAAA;CACA,CAAA;AAElB,CAAC;AAED,SAAS,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MarkdownRender.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/MarkdownRender.tsx"],"sourcesContent":["'use client';\n\nimport { memo } from 'react';\nimport Markdown, { type Options } from 'react-markdown';\n\nimport {\n useMarkdownComponents,\n useMarkdownContent,\n useMarkdownRehypePlugins,\n useMarkdownRemarkPlugins,\n} from '@/hooks/useMarkdown';\n\nconst MarkdownRenderer = memo<Options>(\n ({ children, ...rest }) => {\n const escapedContent = useMarkdownContent(children || '');\n const components = useMarkdownComponents();\n const rehypePluginsList = useMarkdownRehypePlugins();\n const remarkPluginsList = useMarkdownRemarkPlugins();\n\n return (\n <Markdown\n {...rest}\n components={components}\n rehypePlugins={rehypePluginsList}\n remarkPlugins={remarkPluginsList}\n >\n {escapedContent}\n </Markdown>\n );\n },\n (prevProps, nextProps) => prevProps.children === nextProps.children,\n);\n\nexport default MarkdownRenderer;\n"],"mappings":";;;;;;;;;AAYA,MAAM,mBAAmB,MACtB,EAAE,UAAU,GAAG,WAAW;CACzB,MAAM,iBAAiB,mBAAmB,YAAY,EAAE;CACxD,MAAM,aAAa,sBAAsB;CACzC,MAAM,oBAAoB,yBAAyB;CACnD,MAAM,oBAAoB,yBAAyB;CAEnD,OACE,oBAAC,UAAD;EACE,GAAI;EACQ;EACZ,eAAe;EACf,eAAe;
|
|
1
|
+
{"version":3,"file":"MarkdownRender.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/MarkdownRender.tsx"],"sourcesContent":["'use client';\n\nimport { memo } from 'react';\nimport Markdown, { type Options } from 'react-markdown';\n\nimport {\n useMarkdownComponents,\n useMarkdownContent,\n useMarkdownRehypePlugins,\n useMarkdownRemarkPlugins,\n} from '@/hooks/useMarkdown';\n\nconst MarkdownRenderer = memo<Options>(\n ({ children, ...rest }) => {\n const escapedContent = useMarkdownContent(children || '');\n const components = useMarkdownComponents();\n const rehypePluginsList = useMarkdownRehypePlugins();\n const remarkPluginsList = useMarkdownRemarkPlugins();\n\n return (\n <Markdown\n {...rest}\n components={components}\n rehypePlugins={rehypePluginsList}\n remarkPlugins={remarkPluginsList}\n >\n {escapedContent}\n </Markdown>\n );\n },\n (prevProps, nextProps) => prevProps.children === nextProps.children,\n);\n\nexport default MarkdownRenderer;\n"],"mappings":";;;;;;;;;AAYA,MAAM,mBAAmB,MACtB,EAAE,UAAU,GAAG,WAAW;CACzB,MAAM,iBAAiB,mBAAmB,YAAY,EAAE;CACxD,MAAM,aAAa,sBAAsB;CACzC,MAAM,oBAAoB,yBAAyB;CACnD,MAAM,oBAAoB,yBAAyB;CAEnD,OACE,oBAAC,UAAD;EACE,GAAI;EACQ;EACZ,eAAe;EACf,eAAe;EAEd,UAAA;CACO,CAAA;AAEd,IACC,WAAW,cAAc,UAAU,aAAa,UAAU,QAC7D"}
|
|
@@ -97,10 +97,11 @@ const updateBlockAnimation = ({ blocks, charDelay, getBlockState, pluginsCache,
|
|
|
97
97
|
settled: true
|
|
98
98
|
};
|
|
99
99
|
else {
|
|
100
|
+
const lastBirthTs = births.length > 0 ? births.at(-1) ?? renderNow : renderNow;
|
|
100
101
|
meta = resolveBlockAnimationMeta({
|
|
101
102
|
currentCharDelay: charDelay,
|
|
102
103
|
fadeDuration: 180,
|
|
103
|
-
lastElapsedMs: renderNow -
|
|
104
|
+
lastElapsedMs: renderNow - lastBirthTs,
|
|
104
105
|
previousCharDelay: runtime.charDelay,
|
|
105
106
|
state
|
|
106
107
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StreamdownRender.mjs","names":[],"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 { 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 { useStableValue } from '@/hooks/useStableValue';\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\nimport {\n rehypeStreamAnimated,\n type StreamAnimatedRuntime,\n} from '@/Markdown/plugins/rehypeStreamAnimated';\nimport { useStreamdownProfiler } from '@/Markdown/streamProfiler';\nimport { type StreamAnimationGranularity } from '@/Markdown/type';\nimport { getNow } from '@/utils/getNow';\nimport { isDeepEqual } from '@/utils/isDeepEqual';\n\nimport { CachedMarkdown } from './CachedMarkdown';\nimport { type BlockAnimationMeta, resolveBlockAnimationMeta } from './streamAnimationMeta';\nimport { STREAM_FADE_DURATION, styles } from './style';\nimport { countChars, useSmoothStreamContent } from './useSmoothStreamContent';\nimport { type BlockInfo, type BlockState, useStreamQueue } from './useStreamQueue';\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 isDeepEqual(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 <CachedMarkdown {...rest}>{children}</CachedMarkdown>;\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\ninterface BlockRuntime extends StreamAnimatedRuntime {\n charCount: number;\n charDelay?: number;\n rawLength: number;\n settled: boolean;\n}\n\ninterface BlockPluginsCacheEntry {\n base: PluggableList;\n granularity: StreamAnimationGranularity;\n value: PluggableList;\n}\n\ninterface UpdateBlockAnimationArgs {\n blocks: BlockInfo[];\n charDelay: number;\n getBlockState: (index: number) => BlockState;\n pluginsCache: Map<number, BlockPluginsCacheEntry>;\n renderNow: number;\n revealClock: { lastTs: number };\n runtimes: Map<number, BlockRuntime>;\n}\n\nconst MIN_STREAM_CHAR_PACE_MS = 2;\nconst MAX_REVEAL_GAP_MS = 160;\n\n// Runs in the render phase: extends each visible block's birth timeline in\n// place and resolves its animation meta in one pass. Mutations are\n// idempotent for a given block content/length, so discarded or StrictMode\n// double renders re-derive the same state.\nconst updateBlockAnimation = ({\n blocks,\n charDelay,\n getBlockState,\n pluginsCache,\n renderNow,\n revealClock,\n runtimes,\n}: UpdateBlockAnimationArgs): Map<number, BlockAnimationMeta> => {\n const blockAnimationMeta = new Map<number, BlockAnimationMeta>();\n const alive = new Set<number>();\n let revealedNewChars = false;\n\n for (const [index, block] of blocks.entries()) {\n alive.add(block.startOffset);\n\n // Queued blocks are not rendered. Defer birth assignment so that\n // when the block later transitions to animating/streaming, its\n // chars start fading from that moment instead of having already\n // \"aged out\" of the fade window.\n const state = getBlockState(index);\n if (state === 'queued') continue;\n\n let runtime = runtimes.get(block.startOffset);\n if (!runtime) {\n runtime = { births: [], charCount: 0, rawLength: -1, settled: false, styles: [] };\n runtimes.set(block.startOffset, runtime);\n }\n\n if (runtime.rawLength !== block.content.length) {\n runtime.charCount = countChars(block.content);\n runtime.rawLength = block.content.length;\n }\n\n const blockCharCount = runtime.charCount;\n const births = runtime.births;\n\n if (births.length > blockCharCount) {\n // Block content shrunk (stream restart or upstream rewrite).\n births.length = blockCharCount;\n runtime.styles.length = blockCharCount;\n }\n\n if (births.length < blockCharCount) {\n // Chain each new char monotonically after the previous one so fades\n // never race out of order. Cap how far the fade queue can run ahead\n // of renderNow to prevent stream-faster-than-fade producing seconds\n // of invisible backlog at the tail.\n //\n // The streaming tail paces its stagger from the observed reveal-commit\n // gap instead of the queue's fixed charDelay: a commit's chars are\n // spread to land exactly until the next commit arrives, so the flow\n // stays per-char continuous no matter how far apart the throttled\n // commits are.\n const newChars = blockCharCount - births.length;\n let pace = charDelay;\n let cap = renderNow + STREAM_FADE_DURATION;\n if (state === 'streaming') {\n revealedNewChars = true;\n const gapMs = Math.min(Math.max(renderNow - revealClock.lastTs, 16), MAX_REVEAL_GAP_MS);\n pace = Math.min(charDelay, Math.max(gapMs / newChars, MIN_STREAM_CHAR_PACE_MS));\n cap = renderNow + gapMs + STREAM_FADE_DURATION;\n }\n for (let i = births.length; i < blockCharCount; i++) {\n const prevBirth = i > 0 ? births[i - 1] : renderNow - pace;\n const chained = prevBirth + pace;\n births.push(Math.min(cap, Math.max(chained, renderNow)));\n }\n }\n\n let meta: BlockAnimationMeta;\n if (runtime.settled) {\n // Settled is monotone: a revealed block's births are frozen, so once\n // its last fade completed it stays settled until the runtime is\n // pruned by a stream restart.\n meta = { charDelay: runtime.charDelay ?? charDelay, settled: true };\n } else {\n const lastBirthTs = births.length > 0 ? (births.at(-1) ?? renderNow) : renderNow;\n meta = resolveBlockAnimationMeta({\n currentCharDelay: charDelay,\n fadeDuration: STREAM_FADE_DURATION,\n lastElapsedMs: renderNow - lastBirthTs,\n previousCharDelay: runtime.charDelay,\n state,\n });\n runtime.settled = meta.settled;\n }\n runtime.charDelay = meta.charDelay;\n\n blockAnimationMeta.set(block.startOffset, meta);\n }\n\n if (revealedNewChars) {\n revealClock.lastTs = renderNow;\n }\n\n for (const key of runtimes.keys()) {\n if (!alive.has(key)) {\n runtimes.delete(key);\n pluginsCache.delete(key);\n }\n }\n\n return blockAnimationMeta;\n};\n\ninterface StreamdownBlocksProps {\n content: string;\n markdownOptions: Omit<Options, 'children'>;\n}\n\nconst StreamdownBlocks = memo<StreamdownBlocksProps>(\n ({ content: smoothedContent, markdownOptions: rest }) => {\n const { streamAnimationGranularity = 'char' } = useMarkdownContext();\n const profiler = useStreamdownProfiler();\n const components = useMarkdownComponents();\n const baseRehypePlugins = useStablePlugins(useMarkdownRehypePlugins());\n const remarkPlugins = useStablePlugins(useMarkdownRemarkPlugins());\n const generatedId = useId();\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 blockRuntimesRef = useRef<Map<number, BlockRuntime>>(new Map());\n const blockPluginsRef = useRef<Map<number, BlockPluginsCacheEntry>>(new Map());\n const revealClockRef = useRef<{ lastTs: number }>({ lastTs: 0 });\n\n const renderNow = getNow();\n\n const animationStart = profiler ? getNow() : 0;\n const blockAnimationMeta = updateBlockAnimation({\n blocks,\n charDelay,\n getBlockState,\n pluginsCache: blockPluginsRef.current,\n renderNow,\n revealClock: revealClockRef.current,\n runtimes: blockRuntimesRef.current,\n });\n const blockAnimationDurationMs = profiler ? getNow() - animationStart : 0;\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: blockAnimationDurationMs,\n itemCount: blocks.length,\n name: 'block-births',\n textLength: processedContent.length,\n });\n }, [blockAnimationDurationMs, blocks.length, processedContent.length, profiler]);\n\n const resolveBlockPlugins = (startOffset: number, settled: boolean): PluggableList => {\n if (settled) return baseRehypePlugins;\n\n const cache = blockPluginsRef.current;\n const entry = cache.get(startOffset);\n if (\n entry &&\n entry.base === baseRehypePlugins &&\n entry.granularity === streamAnimationGranularity\n ) {\n return entry.value;\n }\n\n const runtime = blockRuntimesRef.current.get(startOffset);\n const value: PluggableList = [\n ...baseRehypePlugins,\n [\n rehypeStreamAnimated,\n {\n fadeDuration: STREAM_FADE_DURATION,\n granularity: streamAnimationGranularity,\n runtime,\n },\n ],\n ];\n cache.set(startOffset, {\n base: baseRehypePlugins,\n granularity: streamAnimationGranularity,\n value,\n });\n return value;\n };\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 animationMeta = blockAnimationMeta.get(block.startOffset);\n if (!animationMeta) return null;\n\n const plugins = resolveBlockPlugins(block.startOffset, animationMeta.settled);\n const key = `${generatedId}-${block.startOffset}`;\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 <StreamdownBlock\n {...rest}\n components={components}\n rehypePlugins={plugins}\n remarkPlugins={remarkPlugins}\n >\n {block.content}\n </StreamdownBlock>\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);\n\nStreamdownBlocks.displayName = 'StreamdownBlocks';\n\n// The outer component absorbs the upstream per-chunk prop churn: every\n// streamed chunk re-renders it, but it only feeds the smoother and renders\n// a memoized child keyed on the smoother's output — so the expensive block\n// pipeline runs per reveal commit, not per chunk AND per commit.\nexport const StreamdownRender = memo<Options>(({ children, ...rest }) => {\n const { streamSmoothingPreset = 'balanced' } = useMarkdownContext();\n const escapedContent = useMarkdownContent(children || '');\n const smoothedContent = useSmoothStreamContent(\n typeof escapedContent === 'string' ? escapedContent : '',\n { preset: streamSmoothingPreset },\n );\n const markdownOptions = useStableValue(rest);\n\n return <StreamdownBlocks content={smoothedContent} markdownOptions={markdownOptions} />;\n});\n\nStreamdownRender.displayName = 'StreamdownRender';\n\nexport default StreamdownRender;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"StreamdownRender.mjs","names":[],"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 { 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 { useStableValue } from '@/hooks/useStableValue';\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\nimport {\n rehypeStreamAnimated,\n type StreamAnimatedRuntime,\n} from '@/Markdown/plugins/rehypeStreamAnimated';\nimport { useStreamdownProfiler } from '@/Markdown/streamProfiler';\nimport { type StreamAnimationGranularity } from '@/Markdown/type';\nimport { getNow } from '@/utils/getNow';\nimport { isDeepEqual } from '@/utils/isDeepEqual';\n\nimport { CachedMarkdown } from './CachedMarkdown';\nimport { type BlockAnimationMeta, resolveBlockAnimationMeta } from './streamAnimationMeta';\nimport { STREAM_FADE_DURATION, styles } from './style';\nimport { countChars, useSmoothStreamContent } from './useSmoothStreamContent';\nimport { type BlockInfo, type BlockState, useStreamQueue } from './useStreamQueue';\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 isDeepEqual(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 <CachedMarkdown {...rest}>{children}</CachedMarkdown>;\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\ninterface BlockRuntime extends StreamAnimatedRuntime {\n charCount: number;\n charDelay?: number;\n rawLength: number;\n settled: boolean;\n}\n\ninterface BlockPluginsCacheEntry {\n base: PluggableList;\n granularity: StreamAnimationGranularity;\n value: PluggableList;\n}\n\ninterface UpdateBlockAnimationArgs {\n blocks: BlockInfo[];\n charDelay: number;\n getBlockState: (index: number) => BlockState;\n pluginsCache: Map<number, BlockPluginsCacheEntry>;\n renderNow: number;\n revealClock: { lastTs: number };\n runtimes: Map<number, BlockRuntime>;\n}\n\nconst MIN_STREAM_CHAR_PACE_MS = 2;\nconst MAX_REVEAL_GAP_MS = 160;\n\n// Runs in the render phase: extends each visible block's birth timeline in\n// place and resolves its animation meta in one pass. Mutations are\n// idempotent for a given block content/length, so discarded or StrictMode\n// double renders re-derive the same state.\nconst updateBlockAnimation = ({\n blocks,\n charDelay,\n getBlockState,\n pluginsCache,\n renderNow,\n revealClock,\n runtimes,\n}: UpdateBlockAnimationArgs): Map<number, BlockAnimationMeta> => {\n const blockAnimationMeta = new Map<number, BlockAnimationMeta>();\n const alive = new Set<number>();\n let revealedNewChars = false;\n\n for (const [index, block] of blocks.entries()) {\n alive.add(block.startOffset);\n\n // Queued blocks are not rendered. Defer birth assignment so that\n // when the block later transitions to animating/streaming, its\n // chars start fading from that moment instead of having already\n // \"aged out\" of the fade window.\n const state = getBlockState(index);\n if (state === 'queued') continue;\n\n let runtime = runtimes.get(block.startOffset);\n if (!runtime) {\n runtime = { births: [], charCount: 0, rawLength: -1, settled: false, styles: [] };\n runtimes.set(block.startOffset, runtime);\n }\n\n if (runtime.rawLength !== block.content.length) {\n runtime.charCount = countChars(block.content);\n runtime.rawLength = block.content.length;\n }\n\n const blockCharCount = runtime.charCount;\n const births = runtime.births;\n\n if (births.length > blockCharCount) {\n // Block content shrunk (stream restart or upstream rewrite).\n births.length = blockCharCount;\n runtime.styles.length = blockCharCount;\n }\n\n if (births.length < blockCharCount) {\n // Chain each new char monotonically after the previous one so fades\n // never race out of order. Cap how far the fade queue can run ahead\n // of renderNow to prevent stream-faster-than-fade producing seconds\n // of invisible backlog at the tail.\n //\n // The streaming tail paces its stagger from the observed reveal-commit\n // gap instead of the queue's fixed charDelay: a commit's chars are\n // spread to land exactly until the next commit arrives, so the flow\n // stays per-char continuous no matter how far apart the throttled\n // commits are.\n const newChars = blockCharCount - births.length;\n let pace = charDelay;\n let cap = renderNow + STREAM_FADE_DURATION;\n if (state === 'streaming') {\n revealedNewChars = true;\n const gapMs = Math.min(Math.max(renderNow - revealClock.lastTs, 16), MAX_REVEAL_GAP_MS);\n pace = Math.min(charDelay, Math.max(gapMs / newChars, MIN_STREAM_CHAR_PACE_MS));\n cap = renderNow + gapMs + STREAM_FADE_DURATION;\n }\n for (let i = births.length; i < blockCharCount; i++) {\n const prevBirth = i > 0 ? births[i - 1] : renderNow - pace;\n const chained = prevBirth + pace;\n births.push(Math.min(cap, Math.max(chained, renderNow)));\n }\n }\n\n let meta: BlockAnimationMeta;\n if (runtime.settled) {\n // Settled is monotone: a revealed block's births are frozen, so once\n // its last fade completed it stays settled until the runtime is\n // pruned by a stream restart.\n meta = { charDelay: runtime.charDelay ?? charDelay, settled: true };\n } else {\n const lastBirthTs = births.length > 0 ? (births.at(-1) ?? renderNow) : renderNow;\n meta = resolveBlockAnimationMeta({\n currentCharDelay: charDelay,\n fadeDuration: STREAM_FADE_DURATION,\n lastElapsedMs: renderNow - lastBirthTs,\n previousCharDelay: runtime.charDelay,\n state,\n });\n runtime.settled = meta.settled;\n }\n runtime.charDelay = meta.charDelay;\n\n blockAnimationMeta.set(block.startOffset, meta);\n }\n\n if (revealedNewChars) {\n revealClock.lastTs = renderNow;\n }\n\n for (const key of runtimes.keys()) {\n if (!alive.has(key)) {\n runtimes.delete(key);\n pluginsCache.delete(key);\n }\n }\n\n return blockAnimationMeta;\n};\n\ninterface StreamdownBlocksProps {\n content: string;\n markdownOptions: Omit<Options, 'children'>;\n}\n\nconst StreamdownBlocks = memo<StreamdownBlocksProps>(\n ({ content: smoothedContent, markdownOptions: rest }) => {\n const { streamAnimationGranularity = 'char' } = useMarkdownContext();\n const profiler = useStreamdownProfiler();\n const components = useMarkdownComponents();\n const baseRehypePlugins = useStablePlugins(useMarkdownRehypePlugins());\n const remarkPlugins = useStablePlugins(useMarkdownRemarkPlugins());\n const generatedId = useId();\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 blockRuntimesRef = useRef<Map<number, BlockRuntime>>(new Map());\n const blockPluginsRef = useRef<Map<number, BlockPluginsCacheEntry>>(new Map());\n const revealClockRef = useRef<{ lastTs: number }>({ lastTs: 0 });\n\n const renderNow = getNow();\n\n const animationStart = profiler ? getNow() : 0;\n const blockAnimationMeta = updateBlockAnimation({\n blocks,\n charDelay,\n getBlockState,\n pluginsCache: blockPluginsRef.current,\n renderNow,\n revealClock: revealClockRef.current,\n runtimes: blockRuntimesRef.current,\n });\n const blockAnimationDurationMs = profiler ? getNow() - animationStart : 0;\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: blockAnimationDurationMs,\n itemCount: blocks.length,\n name: 'block-births',\n textLength: processedContent.length,\n });\n }, [blockAnimationDurationMs, blocks.length, processedContent.length, profiler]);\n\n const resolveBlockPlugins = (startOffset: number, settled: boolean): PluggableList => {\n if (settled) return baseRehypePlugins;\n\n const cache = blockPluginsRef.current;\n const entry = cache.get(startOffset);\n if (\n entry &&\n entry.base === baseRehypePlugins &&\n entry.granularity === streamAnimationGranularity\n ) {\n return entry.value;\n }\n\n const runtime = blockRuntimesRef.current.get(startOffset);\n const value: PluggableList = [\n ...baseRehypePlugins,\n [\n rehypeStreamAnimated,\n {\n fadeDuration: STREAM_FADE_DURATION,\n granularity: streamAnimationGranularity,\n runtime,\n },\n ],\n ];\n cache.set(startOffset, {\n base: baseRehypePlugins,\n granularity: streamAnimationGranularity,\n value,\n });\n return value;\n };\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 animationMeta = blockAnimationMeta.get(block.startOffset);\n if (!animationMeta) return null;\n\n const plugins = resolveBlockPlugins(block.startOffset, animationMeta.settled);\n const key = `${generatedId}-${block.startOffset}`;\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 <StreamdownBlock\n {...rest}\n components={components}\n rehypePlugins={plugins}\n remarkPlugins={remarkPlugins}\n >\n {block.content}\n </StreamdownBlock>\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);\n\nStreamdownBlocks.displayName = 'StreamdownBlocks';\n\n// The outer component absorbs the upstream per-chunk prop churn: every\n// streamed chunk re-renders it, but it only feeds the smoother and renders\n// a memoized child keyed on the smoother's output — so the expensive block\n// pipeline runs per reveal commit, not per chunk AND per commit.\nexport const StreamdownRender = memo<Options>(({ children, ...rest }) => {\n const { streamSmoothingPreset = 'balanced' } = useMarkdownContext();\n const escapedContent = useMarkdownContent(children || '');\n const smoothedContent = useSmoothStreamContent(\n typeof escapedContent === 'string' ? escapedContent : '',\n { preset: streamSmoothingPreset },\n );\n const markdownOptions = useStableValue(rest);\n\n return <StreamdownBlocks content={smoothedContent} markdownOptions={markdownOptions} />;\n});\n\nStreamdownRender.displayName = 'StreamdownRender';\n\nexport default StreamdownRender;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwCA,MAAM,gBAAgB,YAAuB,eAAmC;CAC9E,MAAM,YAAY,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;CACtE,MAAM,YAAY,MAAM,QAAQ,UAAU,IAAI,aAAa,CAAC,UAAU;CAEtE,IAAI,UAAU,WAAW,UAAU,QAAQ,OAAO;CAClD,IAAI,UAAU,OAAO,UAAU,IAAI,OAAO;CAE1C,OAAO,YAAY,UAAU,MAAM,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC;AAC3D;AAEA,MAAM,iBACJ,aACA,gBACY;CACZ,IAAI,gBAAgB,aAAa,OAAO;CACxC,IAAI,CAAC,eAAe,CAAC,aAAa,OAAO,CAAC,eAAe,CAAC;CAC1D,IAAI,YAAY,WAAW,YAAY,QAAQ,OAAO;CAEtD,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KACtC,IAAI,CAAC,aAAa,YAAY,IAAI,YAAY,EAAE,GAAG,OAAO;CAG5D,OAAO;AACT;AAEA,MAAM,oBAAoB,YAA0C;CAClE,MAAM,YAAY,OAAsB,OAAO;CAE/C,IAAI,CAAC,cAAc,UAAU,SAAS,OAAO,GAC3C,UAAU,UAAU;CAGtB,OAAO,UAAU;AACnB;AAEA,MAAM,kBAAkB,MACrB,EAAE,UAAU,GAAG,WAAW;CACzB,OAAO,oBAAC,gBAAD;EAAgB,GAAI;EAAO;CAAyB,CAAA;AAC7D,IACC,WAAW,cACV,UAAU,aAAa,UAAU,YACjC,UAAU,eAAe,UAAU,cACnC,cAAc,UAAU,eAAe,UAAU,aAAa,KAC9D,cAAc,UAAU,eAAe,UAAU,aAAa,CAClE;AAEA,gBAAgB,cAAc;AAyB9B,MAAM,0BAA0B;AAChC,MAAM,oBAAoB;AAM1B,MAAM,wBAAwB,EAC5B,QACA,WACA,eACA,cACA,WACA,aACA,eAC+D;CAC/D,MAAM,qCAAqB,IAAI,IAAgC;CAC/D,MAAM,wBAAQ,IAAI,IAAY;CAC9B,IAAI,mBAAmB;CAEvB,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,GAAG;EAC7C,MAAM,IAAI,MAAM,WAAW;EAM3B,MAAM,QAAQ,cAAc,KAAK;EACjC,IAAI,UAAU,UAAU;EAExB,IAAI,UAAU,SAAS,IAAI,MAAM,WAAW;EAC5C,IAAI,CAAC,SAAS;GACZ,UAAU;IAAE,QAAQ,CAAC;IAAG,WAAW;IAAG,WAAW;IAAI,SAAS;IAAO,QAAQ,CAAC;GAAE;GAChF,SAAS,IAAI,MAAM,aAAa,OAAO;EACzC;EAEA,IAAI,QAAQ,cAAc,MAAM,QAAQ,QAAQ;GAC9C,QAAQ,YAAY,WAAW,MAAM,OAAO;GAC5C,QAAQ,YAAY,MAAM,QAAQ;EACpC;EAEA,MAAM,iBAAiB,QAAQ;EAC/B,MAAM,SAAS,QAAQ;EAEvB,IAAI,OAAO,SAAS,gBAAgB;GAElC,OAAO,SAAS;GAChB,QAAQ,OAAO,SAAS;EAC1B;EAEA,IAAI,OAAO,SAAS,gBAAgB;GAWlC,MAAM,WAAW,iBAAiB,OAAO;GACzC,IAAI,OAAO;GACX,IAAI,MAAM,YAAA;GACV,IAAI,UAAU,aAAa;IACzB,mBAAmB;IACnB,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,YAAY,YAAY,QAAQ,EAAE,GAAG,iBAAiB;IACtF,OAAO,KAAK,IAAI,WAAW,KAAK,IAAI,QAAQ,UAAU,uBAAuB,CAAC;IAC9E,MAAM,YAAY,QAAA;GACpB;GACA,KAAK,IAAI,IAAI,OAAO,QAAQ,IAAI,gBAAgB,KAAK;IAEnD,MAAM,WADY,IAAI,IAAI,OAAO,IAAI,KAAK,YAAY,QAC1B;IAC5B,OAAO,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,SAAS,SAAS,CAAC,CAAC;GACzD;EACF;EAEA,IAAI;EACJ,IAAI,QAAQ,SAIV,OAAO;GAAE,WAAW,QAAQ,aAAa;GAAW,SAAS;EAAK;OAC7D;GACL,MAAM,cAAc,OAAO,SAAS,IAAK,OAAO,GAAG,EAAE,KAAK,YAAa;GACvE,OAAO,0BAA0B;IAC/B,kBAAkB;IAClB,cAAA;IACA,eAAe,YAAY;IAC3B,mBAAmB,QAAQ;IAC3B;GACF,CAAC;GACD,QAAQ,UAAU,KAAK;EACzB;EACA,QAAQ,YAAY,KAAK;EAEzB,mBAAmB,IAAI,MAAM,aAAa,IAAI;CAChD;CAEA,IAAI,kBACF,YAAY,SAAS;CAGvB,KAAK,MAAM,OAAO,SAAS,KAAK,GAC9B,IAAI,CAAC,MAAM,IAAI,GAAG,GAAG;EACnB,SAAS,OAAO,GAAG;EACnB,aAAa,OAAO,GAAG;CACzB;CAGF,OAAO;AACT;AAOA,MAAM,mBAAmB,MACtB,EAAE,SAAS,iBAAiB,iBAAiB,WAAW;CACvD,MAAM,EAAE,6BAA6B,WAAW,mBAAmB;CACnE,MAAM,WAAW,sBAAsB;CACvC,MAAM,aAAa,sBAAsB;CACzC,MAAM,oBAAoB,iBAAiB,yBAAyB,CAAC;CACrE,MAAM,gBAAgB,iBAAiB,yBAAyB,CAAC;CACjE,MAAM,cAAc,MAAM;CAE1B,MAAM,yBAAyB,cAAc;EAC3C,MAAM,QAAQ,WAAW,OAAO,IAAI;EACpC,MAAM,QAAQ,OAAO,eAAe;EAEpC,OAAO;GACL,YAAY,WAAW,OAAO,IAAI,QAAQ;GAC1C;EACF;CACF,GAAG,CAAC,UAAU,eAAe,CAAC;CAC9B,MAAM,mBAAmB,uBAAuB;CAEhD,MAAM,eAAe,cAAc;EACjC,MAAM,QAAQ,WAAW,OAAO,IAAI;EACpC,MAAM,SAAS,OAAO,MAAM,gBAAgB;EAC5C,IAAI,SAAS;EAEb,MAAM,QAAQ,OAAO,KAAK,UAAU;GAClC,MAAM,QAAQ;IAAE,SAAS,MAAM;IAAK,aAAa;GAAO;GACxD,UAAU,MAAM,IAAI;GACpB,OAAO;EACT,CAAC;EAED,OAAO;GACL,YAAY,WAAW,OAAO,IAAI,QAAQ;GAC1C;EACF;CACF,GAAG,CAAC,kBAAkB,QAAQ,CAAC;CAC/B,MAAM,SAAsB,aAAa;CAEzC,MAAM,EAAE,eAAe,cAAc,eAAe,MAAM;CAC1D,MAAM,mBAAmB,uBAAkC,IAAI,IAAI,CAAC;CACpE,MAAM,kBAAkB,uBAA4C,IAAI,IAAI,CAAC;CAC7E,MAAM,iBAAiB,OAA2B,EAAE,QAAQ,EAAE,CAAC;CAE/D,MAAM,YAAY,OAAO;CAEzB,MAAM,iBAAiB,WAAW,OAAO,IAAI;CAC7C,MAAM,qBAAqB,qBAAqB;EAC9C;EACA;EACA;EACA,cAAc,gBAAgB;EAC9B;EACA,aAAa,eAAe;EAC5B,UAAU,iBAAiB;CAC7B,CAAC;CACD,MAAM,2BAA2B,WAAW,OAAO,IAAI,iBAAiB;CAExE,gBAAgB;EACd,IAAI,CAAC,UAAU;EAEf,SAAS,kBAAkB;GACzB,YAAY,uBAAuB;GACnC,MAAM;GACN,YAAY,iBAAiB;EAC/B,CAAC;CACH,GAAG;EAAC,iBAAiB;EAAQ,uBAAuB;EAAY;CAAQ,CAAC;CAEzE,gBAAgB;EACd,IAAI,CAAC,UAAU;EAEf,SAAS,kBAAkB;GACzB,YAAY,aAAa;GACzB,WAAW,OAAO;GAClB,MAAM;GACN,YAAY,iBAAiB;EAC/B,CAAC;CACH,GAAG;EAAC,OAAO;EAAQ,aAAa;EAAY,iBAAiB;EAAQ;CAAQ,CAAC;CAE9E,gBAAgB;EACd,IAAI,CAAC,UAAU;EAEf,SAAS,kBAAkB;GACzB,YAAY;GACZ,WAAW,OAAO;GAClB,MAAM;GACN,YAAY,iBAAiB;EAC/B,CAAC;CACH,GAAG;EAAC;EAA0B,OAAO;EAAQ,iBAAiB;EAAQ;CAAQ,CAAC;CAE/E,MAAM,uBAAuB,aAAqB,YAAoC;EACpF,IAAI,SAAS,OAAO;EAEpB,MAAM,QAAQ,gBAAgB;EAC9B,MAAM,QAAQ,MAAM,IAAI,WAAW;EACnC,IACE,SACA,MAAM,SAAS,qBACf,MAAM,gBAAgB,4BAEtB,OAAO,MAAM;EAGf,MAAM,UAAU,iBAAiB,QAAQ,IAAI,WAAW;EACxD,MAAM,QAAuB,CAC3B,GAAG,mBACH,CACE,sBACA;GACE,cAAA;GACA,aAAa;GACb;EACF,CACF,CACF;EACA,MAAM,IAAI,aAAa;GACrB,MAAM;GACN,aAAa;GACb;EACF,CAAC;EACD,OAAO;CACT;CAEA,MAAM,mBAAmB,aACtB,GAAG,OAAO,gBAAgB,iBAAiB;EAC1C,UAAU,iBAAiB;GACzB;GACA;GACA,YAAY,OAAO;GACnB;GACA,YAAY,iBAAiB;EAC/B,CAAC;CACH,GACA;EAAC,OAAO;EAAQ,iBAAiB;EAAQ;CAAQ,CACnD;CAEA,MAAM,oBAAoB,aACvB,IAAI,OAAO,gBAAgB,iBAAiB;EAC3C,IAAI,CAAC,UAAU;EAEf,MAAM,GAAG,WAAW,cAAc,GAAG,MAAM,GAAG;EAC9C,MAAM,aAAa,OAAO,SAAS;EAEnC,IAAI,CAAC,OAAO,SAAS,UAAU,GAAG;EAElC,MAAM,QAAQ,OAAO;EACrB,IAAI,CAAC,OAAO;EAEZ,SAAS,kBAAkB;GACzB;GACA;GACA,YAAY,WAAW,MAAM,OAAO;GACpC;GACA,UAAU,cAAc,OAAO,MAAM,WAAW;GAChD;GACA,OAAO,cAAc,UAAU;EACjC,CAAC;CACH,GACA;EAAC;EAAQ;EAAe;CAAQ,CAClC;CAEA,MAAM,UACJ,oBAAC,OAAD;EAAK,WAAW,OAAO;EACpB,UAAA,OAAO,KAAK,OAAO,UAAU;GAC5B,MAAM,gBAAgB,mBAAmB,IAAI,MAAM,WAAW;GAC9D,IAAI,CAAC,eAAe,OAAO;GAE3B,MAAM,UAAU,oBAAoB,MAAM,aAAa,cAAc,OAAO;GAC5E,MAAM,MAAM,GAAG,YAAY,GAAG,MAAM;GAEpC,IAAI,CAAC,UACH,OACE,8BAAC,iBAAD;IACE,GAAI;IACQ;IACP;IACL,eAAe;IACA;GAGA,GADd,MAAM,OACQ;GAIrB,OACE,oBAAC,UAAD;IACE,IAAI,oBAAoB,MAAM,GAAG,MAAM;IAEvC,UAAU;IAEV,UAAA,oBAAC,iBAAD;KACE,GAAI;KACQ;KACZ,eAAe;KACA;KAEd,UAAA,MAAM;IACQ,CAAA;GACT,GAXH,GAWG;EAEd,CAAC;CACE,CAAA;CAGP,IAAI,CAAC,UAAU,OAAO;CAEtB,OACE,oBAAC,UAAD;EAAU,IAAI;EAAmB,UAAU;EACxC,UAAA;CACO,CAAA;AAEd,CACF;AAEA,iBAAiB,cAAc;AAM/B,MAAa,mBAAmB,MAAe,EAAE,UAAU,GAAG,WAAW;CACvE,MAAM,EAAE,wBAAwB,eAAe,mBAAmB;CAClE,MAAM,iBAAiB,mBAAmB,YAAY,EAAE;CACxD,MAAM,kBAAkB,uBACtB,OAAO,mBAAmB,WAAW,iBAAiB,IACtD,EAAE,QAAQ,sBAAsB,CAClC;CACA,MAAM,kBAAkB,eAAe,IAAI;CAE3C,OAAO,oBAAC,kBAAD;EAAkB,SAAS;EAAkC;CAAkB,CAAA;AACxF,CAAC;AAED,iBAAiB,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nimport { fadeIn } from '@/styles/animations';\n\nexport const STREAM_FADE_DURATION = 180;\n\nexport const styles = createStaticStyles(({ css }) => {\n return {\n animated: css`\n .stream-char {\n opacity: 0;\n\n animation-name: ${fadeIn};\n animation-duration: ${STREAM_FADE_DURATION}ms;\n animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);\n animation-fill-mode: forwards;\n }\n\n .stream-char-revealed {\n opacity: 1;\n animation: none;\n }\n\n .katex-display .katex-html span {\n mask: none !important;\n animation: none !important;\n }\n `,\n };\n});\n"],"mappings":";;AAMA,MAAa,SAAS,oBAAoB,EAAE,UAAU;CACpD,OAAO,EACL,UAAU,GAAG;;;;0BAIS,OAAO;
|
|
1
|
+
{"version":3,"file":"style.mjs","names":[],"sources":["../../../src/Markdown/SyntaxMarkdown/style.ts"],"sourcesContent":["import { createStaticStyles } from 'antd-style';\n\nimport { fadeIn } from '@/styles/animations';\n\nexport const STREAM_FADE_DURATION = 180;\n\nexport const styles = createStaticStyles(({ css }) => {\n return {\n animated: css`\n .stream-char {\n opacity: 0;\n\n animation-name: ${fadeIn};\n animation-duration: ${STREAM_FADE_DURATION}ms;\n animation-timing-function: cubic-bezier(0.33, 0, 0.67, 1);\n animation-fill-mode: forwards;\n }\n\n .stream-char-revealed {\n opacity: 1;\n animation: none;\n }\n\n .katex-display .katex-html span {\n mask: none !important;\n animation: none !important;\n }\n `,\n };\n});\n"],"mappings":";;AAMA,MAAa,SAAS,oBAAoB,EAAE,UAAU;CACpD,OAAO,EACL,UAAU,GAAG;;;;0BAIS,OAAO;8BACkB,IAAA;;;;;;;;;;;;;;MAejD;AACF,CAAC"}
|
|
@@ -279,8 +279,8 @@ const useSmoothStreamContent = (content, { enabled = true, preset = "balanced" }
|
|
|
279
279
|
const instantCps = deltaChars * 1e3 / deltaMs;
|
|
280
280
|
const normalizedInstantCps = clamp(instantCps, config.minCps, config.maxFlushCps * 2);
|
|
281
281
|
const chunkEmaAlpha = .35;
|
|
282
|
-
chunkSizeEmaRef.current = chunkSizeEmaRef.current *
|
|
283
|
-
arrivalCpsEmaRef.current = arrivalCpsEmaRef.current *
|
|
282
|
+
chunkSizeEmaRef.current = chunkSizeEmaRef.current * .65 + appendedCount * chunkEmaAlpha;
|
|
283
|
+
arrivalCpsEmaRef.current = arrivalCpsEmaRef.current * .65 + normalizedInstantCps * chunkEmaAlpha;
|
|
284
284
|
const clampedCps = clamp(instantCps, config.minCps, config.maxActiveCps);
|
|
285
285
|
emaCpsRef.current = emaCpsRef.current * (1 - config.emaAlpha) + clampedCps * config.emaAlpha;
|
|
286
286
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSmoothStreamContent.mjs","names":["now"],"sources":["../../../src/Markdown/SyntaxMarkdown/useSmoothStreamContent.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { useStreamdownProfiler } from '@/Markdown/streamProfiler';\nimport { type StreamSmoothingPreset } from '@/Markdown/type';\nimport { getNow } from '@/utils/getNow';\n\nimport { findOpenFenceLanguage } from './fenceState';\n\ninterface StreamSmoothingPresetConfig {\n activeInputWindowMs: number;\n /**\n * Code-fence languages whose contents bypass smoothing entirely. While\n * the input ends inside an open fence in this set, every chunk is\n * `syncImmediate`-d to the display so downstream consumers (the\n * HtmlPreview iframe in particular) see partial HTML at the demo's\n * actual production rate instead of waiting on the smoother's\n * ~maxFlushCps budget. As soon as the fence closes — or another\n * non-bypass fence opens — smoothing resumes for the rest of the\n * stream. Default `['html']` covers the artifact case that motivated\n * this; tune via preset if you need to bypass `mermaid`, `svg`, etc.\n */\n bypassFencedLanguages: readonly string[];\n defaultCps: number;\n emaAlpha: number;\n flushCps: number;\n largeAppendChars: number;\n maxActiveCps: number;\n maxCps: number;\n maxFlushCps: number;\n minCommitIntervalMs: number;\n minCps: number;\n settleAfterMs: number;\n settleDrainMaxMs: number;\n settleDrainMinMs: number;\n targetBufferMs: number;\n}\n\nconst DEFAULT_BYPASS_LANGUAGES = ['html'] as const;\n\nconst PRESET_CONFIG: Record<StreamSmoothingPreset, StreamSmoothingPresetConfig> = {\n balanced: {\n activeInputWindowMs: 220,\n bypassFencedLanguages: DEFAULT_BYPASS_LANGUAGES,\n defaultCps: 38,\n emaAlpha: 0.2,\n flushCps: 120,\n largeAppendChars: 120,\n maxActiveCps: 132,\n maxCps: 72,\n maxFlushCps: 280,\n minCommitIntervalMs: 48,\n minCps: 18,\n settleAfterMs: 360,\n settleDrainMaxMs: 520,\n settleDrainMinMs: 180,\n targetBufferMs: 120,\n },\n realtime: {\n activeInputWindowMs: 140,\n bypassFencedLanguages: DEFAULT_BYPASS_LANGUAGES,\n defaultCps: 50,\n emaAlpha: 0.3,\n flushCps: 170,\n largeAppendChars: 180,\n maxActiveCps: 180,\n maxCps: 96,\n maxFlushCps: 360,\n minCommitIntervalMs: 32,\n minCps: 24,\n settleAfterMs: 260,\n settleDrainMaxMs: 360,\n settleDrainMinMs: 140,\n targetBufferMs: 40,\n },\n silky: {\n activeInputWindowMs: 320,\n bypassFencedLanguages: DEFAULT_BYPASS_LANGUAGES,\n defaultCps: 28,\n emaAlpha: 0.14,\n flushCps: 96,\n largeAppendChars: 100,\n maxActiveCps: 102,\n maxCps: 56,\n maxFlushCps: 220,\n minCommitIntervalMs: 56,\n minCps: 14,\n settleAfterMs: 460,\n settleDrainMaxMs: 680,\n settleDrainMinMs: 240,\n targetBufferMs: 170,\n },\n};\n\nconst clamp = (value: number, min: number, max: number): number => {\n return Math.min(max, Math.max(min, value));\n};\n\n// Every reveal commit re-parses and re-wraps the entire trailing block, so\n// the per-commit cost grows linearly with how far the content is from the\n// last block boundary. Widen the commit interval as that distance grows —\n// long paragraphs/code fences keep total work bounded while short blocks\n// stay at the preset's snappy interval. Per-char animation-delay stagger\n// hides the lower commit rate.\nconst MAX_COMMIT_INTERVAL_MS = 96;\nconst COMMIT_INTERVAL_TAIL_SCALE_UNITS = 256;\n\nconst findTailUnits = (content: string): number => {\n const boundary = content.lastIndexOf('\\n\\n');\n return boundary === -1 ? content.length : content.length - boundary - 2;\n};\n\nexport const countChars = (text: string): number => {\n let count = 0;\n for (const _char of text) count += 1;\n return count;\n};\n\ninterface UseSmoothStreamContentOptions {\n enabled?: boolean;\n preset?: StreamSmoothingPreset;\n}\n\nexport const useSmoothStreamContent = (\n content: string,\n { enabled = true, preset = 'balanced' }: UseSmoothStreamContentOptions = {},\n): string => {\n const config = PRESET_CONFIG[preset];\n const profiler = useStreamdownProfiler();\n const [displayedContent, setDisplayedContent] = useState(content);\n\n const displayedContentRef = useRef(content);\n const displayedCountRef = useRef(countChars(content));\n\n const targetContentRef = useRef(content);\n const targetCharsRef = useRef([...content]);\n const targetCountRef = useRef(targetCharsRef.current.length);\n\n const emaCpsRef = useRef(config.defaultCps);\n const tailUnitsRef = useRef(findTailUnits(content));\n const lastInputTsRef = useRef(0);\n const lastInputCountRef = useRef(targetCountRef.current);\n const chunkSizeEmaRef = useRef(1);\n const arrivalCpsEmaRef = useRef(config.defaultCps);\n\n const rafRef = useRef<number | null>(null);\n const lastFrameTsRef = useRef<number | null>(null);\n const wakeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearWakeTimer = useCallback(() => {\n if (wakeTimerRef.current !== null) {\n clearTimeout(wakeTimerRef.current);\n wakeTimerRef.current = null;\n }\n }, []);\n\n const stopFrameLoop = useCallback(() => {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n lastFrameTsRef.current = null;\n }, []);\n\n const stopScheduling = useCallback(() => {\n stopFrameLoop();\n clearWakeTimer();\n }, [clearWakeTimer, stopFrameLoop]);\n\n const startFrameLoopRef = useRef<() => void>(() => {});\n\n const scheduleFrameWake = useCallback(\n (delayMs: number) => {\n clearWakeTimer();\n\n wakeTimerRef.current = setTimeout(\n () => {\n wakeTimerRef.current = null;\n startFrameLoopRef.current();\n },\n Math.max(1, Math.ceil(delayMs)),\n );\n },\n [clearWakeTimer],\n );\n\n const syncImmediate = useCallback(\n (nextContent: string) => {\n stopScheduling();\n\n const chars = [...nextContent];\n const now = getNow();\n\n targetContentRef.current = nextContent;\n targetCharsRef.current = chars;\n targetCountRef.current = chars.length;\n\n displayedContentRef.current = nextContent;\n displayedCountRef.current = chars.length;\n setDisplayedContent(nextContent);\n\n emaCpsRef.current = config.defaultCps;\n chunkSizeEmaRef.current = 1;\n arrivalCpsEmaRef.current = config.defaultCps;\n tailUnitsRef.current = findTailUnits(nextContent);\n lastInputTsRef.current = now;\n lastInputCountRef.current = chars.length;\n },\n [config.defaultCps, stopScheduling],\n );\n\n const startFrameLoop = useCallback(() => {\n clearWakeTimer();\n if (rafRef.current !== null) return;\n\n const tick = (ts: number) => {\n const targetCount = targetCountRef.current;\n const displayedCount = displayedCountRef.current;\n const backlog = targetCount - displayedCount;\n\n if (backlog <= 0) {\n stopFrameLoop();\n return;\n }\n\n if (lastFrameTsRef.current === null) {\n lastFrameTsRef.current = ts;\n rafRef.current = requestAnimationFrame(tick);\n return;\n }\n\n // Reveal commits are throttled below the display refresh rate: each\n // commit re-renders the tail block and re-runs remend + lexing, so\n // committing at 60-120fps burns CPU without visible benefit — the\n // per-char stagger inside a commit is carried by animation-delay.\n const commitIntervalMs = Math.min(\n MAX_COMMIT_INTERVAL_MS,\n config.minCommitIntervalMs * (1 + tailUnitsRef.current / COMMIT_INTERVAL_TAIL_SCALE_UNITS),\n );\n const frameIntervalMs = Math.max(0, ts - lastFrameTsRef.current);\n if (frameIntervalMs < commitIntervalMs) {\n rafRef.current = requestAnimationFrame(tick);\n return;\n }\n\n const frameStart = getNow();\n const dtSeconds = Math.max(0.001, Math.min(frameIntervalMs / 1000, 0.12));\n lastFrameTsRef.current = ts;\n\n const now = frameStart;\n const idleMs = now - lastInputTsRef.current;\n const inputActive = idleMs <= config.activeInputWindowMs;\n const settling = !inputActive && idleMs >= config.settleAfterMs;\n\n const baseCps = clamp(emaCpsRef.current, config.minCps, config.maxCps);\n const baseLagChars = Math.max(1, Math.round((baseCps * config.targetBufferMs) / 1000));\n const lagUpperBound = Math.max(baseLagChars + 2, baseLagChars * 3);\n const targetLagChars = inputActive\n ? Math.round(\n clamp(baseLagChars + chunkSizeEmaRef.current * 0.35, baseLagChars, lagUpperBound),\n )\n : 0;\n const desiredDisplayed = Math.max(0, targetCount - targetLagChars);\n\n let currentCps: number;\n if (inputActive) {\n const backlogPressure = targetLagChars > 0 ? backlog / targetLagChars : 1;\n const chunkPressure = targetLagChars > 0 ? chunkSizeEmaRef.current / targetLagChars : 1;\n const arrivalPressure = arrivalCpsEmaRef.current / Math.max(baseCps, 1);\n const combinedPressure = clamp(\n backlogPressure * 0.6 + chunkPressure * 0.25 + arrivalPressure * 0.15,\n 1,\n 4.5,\n );\n const activeCap = clamp(\n config.maxActiveCps + chunkSizeEmaRef.current * 6,\n config.maxActiveCps,\n config.maxFlushCps,\n );\n currentCps = clamp(baseCps * combinedPressure, config.minCps, activeCap);\n } else if (settling) {\n // If upstream likely ended, cap the remaining tail duration so\n // we do not keep replaying old backlog for seconds.\n const drainTargetMs = clamp(backlog * 8, config.settleDrainMinMs, config.settleDrainMaxMs);\n const settleCps = (backlog * 1000) / drainTargetMs;\n currentCps = clamp(settleCps, config.flushCps, config.maxFlushCps);\n } else {\n const idleFlushCps = Math.max(\n config.flushCps,\n baseCps * 1.8,\n arrivalCpsEmaRef.current * 0.8,\n );\n currentCps = clamp(idleFlushCps, config.flushCps, config.maxFlushCps);\n }\n\n const urgentBacklog = inputActive && targetLagChars > 0 && backlog > targetLagChars * 2.2;\n const burstyInput = inputActive && chunkSizeEmaRef.current >= targetLagChars * 0.9;\n const minRevealChars = inputActive ? (urgentBacklog || burstyInput ? 2 : 1) : 2;\n let revealChars = Math.max(minRevealChars, Math.round(currentCps * dtSeconds));\n\n if (inputActive) {\n const shortfall = desiredDisplayed - displayedCount;\n if (shortfall <= 0) {\n stopFrameLoop();\n scheduleFrameWake(config.activeInputWindowMs - idleMs);\n\n profiler?.recordAnimationFrame({\n backlog,\n durationMs: getNow() - frameStart,\n frameIntervalMs,\n inputActive,\n revealChars: 0,\n settling,\n });\n return;\n }\n revealChars = Math.min(revealChars, shortfall, backlog);\n } else {\n revealChars = Math.min(revealChars, backlog);\n }\n\n const nextCount = displayedCount + revealChars;\n const segment = targetCharsRef.current.slice(displayedCount, nextCount).join('');\n\n if (segment) {\n const nextDisplayed = displayedContentRef.current + segment;\n displayedContentRef.current = nextDisplayed;\n displayedCountRef.current = nextCount;\n setDisplayedContent(nextDisplayed);\n } else {\n displayedContentRef.current = targetContentRef.current;\n displayedCountRef.current = targetCount;\n setDisplayedContent(targetContentRef.current);\n }\n\n profiler?.recordAnimationFrame({\n backlog,\n durationMs: getNow() - frameStart,\n frameIntervalMs,\n inputActive,\n revealChars: segment ? revealChars : backlog,\n settling,\n });\n\n rafRef.current = requestAnimationFrame(tick);\n };\n\n rafRef.current = requestAnimationFrame(tick);\n }, [\n clearWakeTimer,\n config.activeInputWindowMs,\n config.flushCps,\n config.maxActiveCps,\n config.maxCps,\n config.maxFlushCps,\n config.minCommitIntervalMs,\n config.minCps,\n config.settleAfterMs,\n config.settleDrainMaxMs,\n config.settleDrainMinMs,\n config.targetBufferMs,\n scheduleFrameWake,\n stopFrameLoop,\n ]);\n startFrameLoopRef.current = startFrameLoop;\n\n useEffect(() => {\n if (!enabled) {\n syncImmediate(content);\n return;\n }\n\n const prevTargetContent = targetContentRef.current;\n if (content === prevTargetContent) return;\n\n const now = getNow();\n const appendOnly = content.startsWith(prevTargetContent);\n\n if (!appendOnly) {\n syncImmediate(content);\n return;\n }\n\n // Bypass smoothing entirely while the input ends inside an open\n // fence whose language is opted out — see the preset config.\n // Without this, a 5 KB inline `<style>` block can keep `</style>`\n // (and therefore the HtmlPreview head-close trigger) trapped in the\n // smoother's buffer for tens of seconds, leaving the iframe pinned\n // on the loading placeholder while the artifact \"looks stuck\".\n if (config.bypassFencedLanguages.length > 0) {\n const openLang = findOpenFenceLanguage(content);\n if (openLang !== null && config.bypassFencedLanguages.includes(openLang)) {\n syncImmediate(content);\n return;\n }\n }\n\n const appended = content.slice(prevTargetContent.length);\n const appendedChars = [...appended];\n const appendedCount = appendedChars.length;\n\n profiler?.recordInputAppend({\n appendedChars: appendedCount,\n contentLength: countChars(content),\n });\n\n if (appendedCount > config.largeAppendChars) {\n syncImmediate(content);\n return;\n }\n\n targetContentRef.current = content;\n targetCharsRef.current.push(...appendedChars);\n targetCountRef.current += appendedCount;\n\n tailUnitsRef.current = findTailUnits(content);\n\n const deltaChars = targetCountRef.current - lastInputCountRef.current;\n const deltaMs = Math.max(1, now - lastInputTsRef.current);\n\n if (deltaChars > 0) {\n const instantCps = (deltaChars * 1000) / deltaMs;\n const normalizedInstantCps = clamp(instantCps, config.minCps, config.maxFlushCps * 2);\n const chunkEmaAlpha = 0.35;\n chunkSizeEmaRef.current =\n chunkSizeEmaRef.current * (1 - chunkEmaAlpha) + appendedCount * chunkEmaAlpha;\n arrivalCpsEmaRef.current =\n arrivalCpsEmaRef.current * (1 - chunkEmaAlpha) + normalizedInstantCps * chunkEmaAlpha;\n\n const clampedCps = clamp(instantCps, config.minCps, config.maxActiveCps);\n emaCpsRef.current = emaCpsRef.current * (1 - config.emaAlpha) + clampedCps * config.emaAlpha;\n }\n\n lastInputTsRef.current = now;\n lastInputCountRef.current = targetCountRef.current;\n\n startFrameLoop();\n }, [\n config.bypassFencedLanguages,\n config.emaAlpha,\n config.largeAppendChars,\n config.maxActiveCps,\n config.maxCps,\n config.maxFlushCps,\n config.minCps,\n content,\n enabled,\n startFrameLoop,\n syncImmediate,\n profiler,\n ]);\n\n useEffect(() => {\n return () => {\n stopScheduling();\n };\n }, [stopScheduling]);\n\n return displayedContent;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSmoothStreamContent.mjs","names":["now"],"sources":["../../../src/Markdown/SyntaxMarkdown/useSmoothStreamContent.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { useStreamdownProfiler } from '@/Markdown/streamProfiler';\nimport { type StreamSmoothingPreset } from '@/Markdown/type';\nimport { getNow } from '@/utils/getNow';\n\nimport { findOpenFenceLanguage } from './fenceState';\n\ninterface StreamSmoothingPresetConfig {\n activeInputWindowMs: number;\n /**\n * Code-fence languages whose contents bypass smoothing entirely. While\n * the input ends inside an open fence in this set, every chunk is\n * `syncImmediate`-d to the display so downstream consumers (the\n * HtmlPreview iframe in particular) see partial HTML at the demo's\n * actual production rate instead of waiting on the smoother's\n * ~maxFlushCps budget. As soon as the fence closes — or another\n * non-bypass fence opens — smoothing resumes for the rest of the\n * stream. Default `['html']` covers the artifact case that motivated\n * this; tune via preset if you need to bypass `mermaid`, `svg`, etc.\n */\n bypassFencedLanguages: readonly string[];\n defaultCps: number;\n emaAlpha: number;\n flushCps: number;\n largeAppendChars: number;\n maxActiveCps: number;\n maxCps: number;\n maxFlushCps: number;\n minCommitIntervalMs: number;\n minCps: number;\n settleAfterMs: number;\n settleDrainMaxMs: number;\n settleDrainMinMs: number;\n targetBufferMs: number;\n}\n\nconst DEFAULT_BYPASS_LANGUAGES = ['html'] as const;\n\nconst PRESET_CONFIG: Record<StreamSmoothingPreset, StreamSmoothingPresetConfig> = {\n balanced: {\n activeInputWindowMs: 220,\n bypassFencedLanguages: DEFAULT_BYPASS_LANGUAGES,\n defaultCps: 38,\n emaAlpha: 0.2,\n flushCps: 120,\n largeAppendChars: 120,\n maxActiveCps: 132,\n maxCps: 72,\n maxFlushCps: 280,\n minCommitIntervalMs: 48,\n minCps: 18,\n settleAfterMs: 360,\n settleDrainMaxMs: 520,\n settleDrainMinMs: 180,\n targetBufferMs: 120,\n },\n realtime: {\n activeInputWindowMs: 140,\n bypassFencedLanguages: DEFAULT_BYPASS_LANGUAGES,\n defaultCps: 50,\n emaAlpha: 0.3,\n flushCps: 170,\n largeAppendChars: 180,\n maxActiveCps: 180,\n maxCps: 96,\n maxFlushCps: 360,\n minCommitIntervalMs: 32,\n minCps: 24,\n settleAfterMs: 260,\n settleDrainMaxMs: 360,\n settleDrainMinMs: 140,\n targetBufferMs: 40,\n },\n silky: {\n activeInputWindowMs: 320,\n bypassFencedLanguages: DEFAULT_BYPASS_LANGUAGES,\n defaultCps: 28,\n emaAlpha: 0.14,\n flushCps: 96,\n largeAppendChars: 100,\n maxActiveCps: 102,\n maxCps: 56,\n maxFlushCps: 220,\n minCommitIntervalMs: 56,\n minCps: 14,\n settleAfterMs: 460,\n settleDrainMaxMs: 680,\n settleDrainMinMs: 240,\n targetBufferMs: 170,\n },\n};\n\nconst clamp = (value: number, min: number, max: number): number => {\n return Math.min(max, Math.max(min, value));\n};\n\n// Every reveal commit re-parses and re-wraps the entire trailing block, so\n// the per-commit cost grows linearly with how far the content is from the\n// last block boundary. Widen the commit interval as that distance grows —\n// long paragraphs/code fences keep total work bounded while short blocks\n// stay at the preset's snappy interval. Per-char animation-delay stagger\n// hides the lower commit rate.\nconst MAX_COMMIT_INTERVAL_MS = 96;\nconst COMMIT_INTERVAL_TAIL_SCALE_UNITS = 256;\n\nconst findTailUnits = (content: string): number => {\n const boundary = content.lastIndexOf('\\n\\n');\n return boundary === -1 ? content.length : content.length - boundary - 2;\n};\n\nexport const countChars = (text: string): number => {\n let count = 0;\n for (const _char of text) count += 1;\n return count;\n};\n\ninterface UseSmoothStreamContentOptions {\n enabled?: boolean;\n preset?: StreamSmoothingPreset;\n}\n\nexport const useSmoothStreamContent = (\n content: string,\n { enabled = true, preset = 'balanced' }: UseSmoothStreamContentOptions = {},\n): string => {\n const config = PRESET_CONFIG[preset];\n const profiler = useStreamdownProfiler();\n const [displayedContent, setDisplayedContent] = useState(content);\n\n const displayedContentRef = useRef(content);\n const displayedCountRef = useRef(countChars(content));\n\n const targetContentRef = useRef(content);\n const targetCharsRef = useRef([...content]);\n const targetCountRef = useRef(targetCharsRef.current.length);\n\n const emaCpsRef = useRef(config.defaultCps);\n const tailUnitsRef = useRef(findTailUnits(content));\n const lastInputTsRef = useRef(0);\n const lastInputCountRef = useRef(targetCountRef.current);\n const chunkSizeEmaRef = useRef(1);\n const arrivalCpsEmaRef = useRef(config.defaultCps);\n\n const rafRef = useRef<number | null>(null);\n const lastFrameTsRef = useRef<number | null>(null);\n const wakeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearWakeTimer = useCallback(() => {\n if (wakeTimerRef.current !== null) {\n clearTimeout(wakeTimerRef.current);\n wakeTimerRef.current = null;\n }\n }, []);\n\n const stopFrameLoop = useCallback(() => {\n if (rafRef.current !== null) {\n cancelAnimationFrame(rafRef.current);\n rafRef.current = null;\n }\n lastFrameTsRef.current = null;\n }, []);\n\n const stopScheduling = useCallback(() => {\n stopFrameLoop();\n clearWakeTimer();\n }, [clearWakeTimer, stopFrameLoop]);\n\n const startFrameLoopRef = useRef<() => void>(() => {});\n\n const scheduleFrameWake = useCallback(\n (delayMs: number) => {\n clearWakeTimer();\n\n wakeTimerRef.current = setTimeout(\n () => {\n wakeTimerRef.current = null;\n startFrameLoopRef.current();\n },\n Math.max(1, Math.ceil(delayMs)),\n );\n },\n [clearWakeTimer],\n );\n\n const syncImmediate = useCallback(\n (nextContent: string) => {\n stopScheduling();\n\n const chars = [...nextContent];\n const now = getNow();\n\n targetContentRef.current = nextContent;\n targetCharsRef.current = chars;\n targetCountRef.current = chars.length;\n\n displayedContentRef.current = nextContent;\n displayedCountRef.current = chars.length;\n setDisplayedContent(nextContent);\n\n emaCpsRef.current = config.defaultCps;\n chunkSizeEmaRef.current = 1;\n arrivalCpsEmaRef.current = config.defaultCps;\n tailUnitsRef.current = findTailUnits(nextContent);\n lastInputTsRef.current = now;\n lastInputCountRef.current = chars.length;\n },\n [config.defaultCps, stopScheduling],\n );\n\n const startFrameLoop = useCallback(() => {\n clearWakeTimer();\n if (rafRef.current !== null) return;\n\n const tick = (ts: number) => {\n const targetCount = targetCountRef.current;\n const displayedCount = displayedCountRef.current;\n const backlog = targetCount - displayedCount;\n\n if (backlog <= 0) {\n stopFrameLoop();\n return;\n }\n\n if (lastFrameTsRef.current === null) {\n lastFrameTsRef.current = ts;\n rafRef.current = requestAnimationFrame(tick);\n return;\n }\n\n // Reveal commits are throttled below the display refresh rate: each\n // commit re-renders the tail block and re-runs remend + lexing, so\n // committing at 60-120fps burns CPU without visible benefit — the\n // per-char stagger inside a commit is carried by animation-delay.\n const commitIntervalMs = Math.min(\n MAX_COMMIT_INTERVAL_MS,\n config.minCommitIntervalMs * (1 + tailUnitsRef.current / COMMIT_INTERVAL_TAIL_SCALE_UNITS),\n );\n const frameIntervalMs = Math.max(0, ts - lastFrameTsRef.current);\n if (frameIntervalMs < commitIntervalMs) {\n rafRef.current = requestAnimationFrame(tick);\n return;\n }\n\n const frameStart = getNow();\n const dtSeconds = Math.max(0.001, Math.min(frameIntervalMs / 1000, 0.12));\n lastFrameTsRef.current = ts;\n\n const now = frameStart;\n const idleMs = now - lastInputTsRef.current;\n const inputActive = idleMs <= config.activeInputWindowMs;\n const settling = !inputActive && idleMs >= config.settleAfterMs;\n\n const baseCps = clamp(emaCpsRef.current, config.minCps, config.maxCps);\n const baseLagChars = Math.max(1, Math.round((baseCps * config.targetBufferMs) / 1000));\n const lagUpperBound = Math.max(baseLagChars + 2, baseLagChars * 3);\n const targetLagChars = inputActive\n ? Math.round(\n clamp(baseLagChars + chunkSizeEmaRef.current * 0.35, baseLagChars, lagUpperBound),\n )\n : 0;\n const desiredDisplayed = Math.max(0, targetCount - targetLagChars);\n\n let currentCps: number;\n if (inputActive) {\n const backlogPressure = targetLagChars > 0 ? backlog / targetLagChars : 1;\n const chunkPressure = targetLagChars > 0 ? chunkSizeEmaRef.current / targetLagChars : 1;\n const arrivalPressure = arrivalCpsEmaRef.current / Math.max(baseCps, 1);\n const combinedPressure = clamp(\n backlogPressure * 0.6 + chunkPressure * 0.25 + arrivalPressure * 0.15,\n 1,\n 4.5,\n );\n const activeCap = clamp(\n config.maxActiveCps + chunkSizeEmaRef.current * 6,\n config.maxActiveCps,\n config.maxFlushCps,\n );\n currentCps = clamp(baseCps * combinedPressure, config.minCps, activeCap);\n } else if (settling) {\n // If upstream likely ended, cap the remaining tail duration so\n // we do not keep replaying old backlog for seconds.\n const drainTargetMs = clamp(backlog * 8, config.settleDrainMinMs, config.settleDrainMaxMs);\n const settleCps = (backlog * 1000) / drainTargetMs;\n currentCps = clamp(settleCps, config.flushCps, config.maxFlushCps);\n } else {\n const idleFlushCps = Math.max(\n config.flushCps,\n baseCps * 1.8,\n arrivalCpsEmaRef.current * 0.8,\n );\n currentCps = clamp(idleFlushCps, config.flushCps, config.maxFlushCps);\n }\n\n const urgentBacklog = inputActive && targetLagChars > 0 && backlog > targetLagChars * 2.2;\n const burstyInput = inputActive && chunkSizeEmaRef.current >= targetLagChars * 0.9;\n const minRevealChars = inputActive ? (urgentBacklog || burstyInput ? 2 : 1) : 2;\n let revealChars = Math.max(minRevealChars, Math.round(currentCps * dtSeconds));\n\n if (inputActive) {\n const shortfall = desiredDisplayed - displayedCount;\n if (shortfall <= 0) {\n stopFrameLoop();\n scheduleFrameWake(config.activeInputWindowMs - idleMs);\n\n profiler?.recordAnimationFrame({\n backlog,\n durationMs: getNow() - frameStart,\n frameIntervalMs,\n inputActive,\n revealChars: 0,\n settling,\n });\n return;\n }\n revealChars = Math.min(revealChars, shortfall, backlog);\n } else {\n revealChars = Math.min(revealChars, backlog);\n }\n\n const nextCount = displayedCount + revealChars;\n const segment = targetCharsRef.current.slice(displayedCount, nextCount).join('');\n\n if (segment) {\n const nextDisplayed = displayedContentRef.current + segment;\n displayedContentRef.current = nextDisplayed;\n displayedCountRef.current = nextCount;\n setDisplayedContent(nextDisplayed);\n } else {\n displayedContentRef.current = targetContentRef.current;\n displayedCountRef.current = targetCount;\n setDisplayedContent(targetContentRef.current);\n }\n\n profiler?.recordAnimationFrame({\n backlog,\n durationMs: getNow() - frameStart,\n frameIntervalMs,\n inputActive,\n revealChars: segment ? revealChars : backlog,\n settling,\n });\n\n rafRef.current = requestAnimationFrame(tick);\n };\n\n rafRef.current = requestAnimationFrame(tick);\n }, [\n clearWakeTimer,\n config.activeInputWindowMs,\n config.flushCps,\n config.maxActiveCps,\n config.maxCps,\n config.maxFlushCps,\n config.minCommitIntervalMs,\n config.minCps,\n config.settleAfterMs,\n config.settleDrainMaxMs,\n config.settleDrainMinMs,\n config.targetBufferMs,\n scheduleFrameWake,\n stopFrameLoop,\n ]);\n startFrameLoopRef.current = startFrameLoop;\n\n useEffect(() => {\n if (!enabled) {\n syncImmediate(content);\n return;\n }\n\n const prevTargetContent = targetContentRef.current;\n if (content === prevTargetContent) return;\n\n const now = getNow();\n const appendOnly = content.startsWith(prevTargetContent);\n\n if (!appendOnly) {\n syncImmediate(content);\n return;\n }\n\n // Bypass smoothing entirely while the input ends inside an open\n // fence whose language is opted out — see the preset config.\n // Without this, a 5 KB inline `<style>` block can keep `</style>`\n // (and therefore the HtmlPreview head-close trigger) trapped in the\n // smoother's buffer for tens of seconds, leaving the iframe pinned\n // on the loading placeholder while the artifact \"looks stuck\".\n if (config.bypassFencedLanguages.length > 0) {\n const openLang = findOpenFenceLanguage(content);\n if (openLang !== null && config.bypassFencedLanguages.includes(openLang)) {\n syncImmediate(content);\n return;\n }\n }\n\n const appended = content.slice(prevTargetContent.length);\n const appendedChars = [...appended];\n const appendedCount = appendedChars.length;\n\n profiler?.recordInputAppend({\n appendedChars: appendedCount,\n contentLength: countChars(content),\n });\n\n if (appendedCount > config.largeAppendChars) {\n syncImmediate(content);\n return;\n }\n\n targetContentRef.current = content;\n targetCharsRef.current.push(...appendedChars);\n targetCountRef.current += appendedCount;\n\n tailUnitsRef.current = findTailUnits(content);\n\n const deltaChars = targetCountRef.current - lastInputCountRef.current;\n const deltaMs = Math.max(1, now - lastInputTsRef.current);\n\n if (deltaChars > 0) {\n const instantCps = (deltaChars * 1000) / deltaMs;\n const normalizedInstantCps = clamp(instantCps, config.minCps, config.maxFlushCps * 2);\n const chunkEmaAlpha = 0.35;\n chunkSizeEmaRef.current =\n chunkSizeEmaRef.current * (1 - chunkEmaAlpha) + appendedCount * chunkEmaAlpha;\n arrivalCpsEmaRef.current =\n arrivalCpsEmaRef.current * (1 - chunkEmaAlpha) + normalizedInstantCps * chunkEmaAlpha;\n\n const clampedCps = clamp(instantCps, config.minCps, config.maxActiveCps);\n emaCpsRef.current = emaCpsRef.current * (1 - config.emaAlpha) + clampedCps * config.emaAlpha;\n }\n\n lastInputTsRef.current = now;\n lastInputCountRef.current = targetCountRef.current;\n\n startFrameLoop();\n }, [\n config.bypassFencedLanguages,\n config.emaAlpha,\n config.largeAppendChars,\n config.maxActiveCps,\n config.maxCps,\n config.maxFlushCps,\n config.minCps,\n content,\n enabled,\n startFrameLoop,\n syncImmediate,\n profiler,\n ]);\n\n useEffect(() => {\n return () => {\n stopScheduling();\n };\n }, [stopScheduling]);\n\n return displayedContent;\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeBlock.mjs","names":[],"sources":["../../../src/Markdown/components/CodeBlock.tsx"],"sourcesContent":["import { memo } from 'react';\n\nimport type { HighlighterProps } from '@/Highlighter';\nimport { FALLBACK_LANG } from '@/Highlighter/const';\nimport { isFullHtmlDocument } from '@/HtmlPreview/const';\nimport type { HtmlPreviewProps } from '@/HtmlPreview/type';\nimport Pre, { PreHtmlPreview, PreMermaid, PreSingleLine } from '@/mdx/mdxComponents/Pre';\nimport type { MermaidProps } from '@/Mermaid';\n\nconst countLines = (str: string): number => {\n const regex = /\\n/g;\n const matches = str.match(regex);\n return matches ? matches.length : 1;\n};\n\nexport const useCode = (raw: any) => {\n if (!raw) return;\n\n const { children = '', className } = raw?.props || { children: '' };\n\n if (!children) return;\n\n const content = Array.isArray(children) ? (children[0] as string) : children;\n\n const lang = className?.replace('language-', '') || FALLBACK_LANG;\n\n const isSingleLine = countLines(content) <= 1 && content.length <= 32;\n\n return {\n content,\n isSingleLine,\n lang,\n };\n};\n\ninterface CodeBlockProps {\n animated?: boolean;\n children: any;\n enableHtmlPreview?: boolean;\n enableMermaid?: boolean;\n fullFeatured?: boolean;\n highlight?: HighlighterProps;\n html?: HtmlPreviewProps;\n mermaid?: MermaidProps;\n}\n\nexport const CodeBlock = memo<CodeBlockProps>(\n ({\n fullFeatured,\n enableHtmlPreview,\n enableMermaid,\n highlight,\n html,\n mermaid,\n children,\n animated,\n ...rest\n }) => {\n const code = useCode(children);\n\n if (!code) return;\n\n if (enableMermaid && code.lang === 'mermaid')\n return (\n <PreMermaid animated={animated} fullFeatured={fullFeatured} {...mermaid} {...rest}>\n {code.content}\n </PreMermaid>\n );\n\n // Auto-route to HTML preview only for full HTML documents. Fragments fall\n // through to the normal highlighter — inline-rendering a `<div>` snippet\n // produces a degraded experience and risks hiding the actual code from\n // the reader.\n if (enableHtmlPreview && code.lang === 'html' && isFullHtmlDocument(code.content))\n return (\n <PreHtmlPreview animated={animated} fullFeatured={fullFeatured} {...html} {...rest}>\n {code.content}\n </PreHtmlPreview>\n );\n\n if (!highlight && code.isSingleLine)\n return <PreSingleLine language={code.lang}>{code.content}</PreSingleLine>;\n\n return (\n <Pre\n animated={animated}\n fullFeatured={fullFeatured}\n language={code.lang}\n {...highlight}\n {...rest}\n >\n {code.content}\n </Pre>\n );\n },\n (prevProps, nextProps) => prevProps.children === nextProps.children,\n);\n"],"mappings":";;;;;;AASA,MAAM,cAAc,QAAwB;CAE1C,MAAM,UAAU,IAAI,MAAM,KAAK;CAC/B,OAAO,UAAU,QAAQ,SAAS;AACpC;AAEA,MAAa,WAAW,QAAa;CACnC,IAAI,CAAC,KAAK;CAEV,MAAM,EAAE,WAAW,IAAI,cAAc,KAAK,SAAS,EAAE,UAAU,GAAG;CAElE,IAAI,CAAC,UAAU;CAEf,MAAM,UAAU,MAAM,QAAQ,QAAQ,IAAK,SAAS,KAAgB;CAEpE,MAAM,OAAO,WAAW,QAAQ,aAAa,EAAE,KAAA;CAI/C,OAAO;EACL;EACA,cAJmB,WAAW,OAAO,KAAK,KAAK,QAAQ,UAAU;EAKjE;CACF;AACF;AAaA,MAAa,YAAY,MACtB,EACC,cACA,mBACA,eACA,WACA,MACA,SACA,UACA,UACA,GAAG,WACC;CACJ,MAAM,OAAO,QAAQ,QAAQ;CAE7B,IAAI,CAAC,MAAM;CAEX,IAAI,iBAAiB,KAAK,SAAS,WACjC,OACE,oBAAC,YAAD;EAAsB;EAAwB;EAAc,GAAI;EAAS,GAAI;
|
|
1
|
+
{"version":3,"file":"CodeBlock.mjs","names":[],"sources":["../../../src/Markdown/components/CodeBlock.tsx"],"sourcesContent":["import { memo } from 'react';\n\nimport type { HighlighterProps } from '@/Highlighter';\nimport { FALLBACK_LANG } from '@/Highlighter/const';\nimport { isFullHtmlDocument } from '@/HtmlPreview/const';\nimport type { HtmlPreviewProps } from '@/HtmlPreview/type';\nimport Pre, { PreHtmlPreview, PreMermaid, PreSingleLine } from '@/mdx/mdxComponents/Pre';\nimport type { MermaidProps } from '@/Mermaid';\n\nconst countLines = (str: string): number => {\n const regex = /\\n/g;\n const matches = str.match(regex);\n return matches ? matches.length : 1;\n};\n\nexport const useCode = (raw: any) => {\n if (!raw) return;\n\n const { children = '', className } = raw?.props || { children: '' };\n\n if (!children) return;\n\n const content = Array.isArray(children) ? (children[0] as string) : children;\n\n const lang = className?.replace('language-', '') || FALLBACK_LANG;\n\n const isSingleLine = countLines(content) <= 1 && content.length <= 32;\n\n return {\n content,\n isSingleLine,\n lang,\n };\n};\n\ninterface CodeBlockProps {\n animated?: boolean;\n children: any;\n enableHtmlPreview?: boolean;\n enableMermaid?: boolean;\n fullFeatured?: boolean;\n highlight?: HighlighterProps;\n html?: HtmlPreviewProps;\n mermaid?: MermaidProps;\n}\n\nexport const CodeBlock = memo<CodeBlockProps>(\n ({\n fullFeatured,\n enableHtmlPreview,\n enableMermaid,\n highlight,\n html,\n mermaid,\n children,\n animated,\n ...rest\n }) => {\n const code = useCode(children);\n\n if (!code) return;\n\n if (enableMermaid && code.lang === 'mermaid')\n return (\n <PreMermaid animated={animated} fullFeatured={fullFeatured} {...mermaid} {...rest}>\n {code.content}\n </PreMermaid>\n );\n\n // Auto-route to HTML preview only for full HTML documents. Fragments fall\n // through to the normal highlighter — inline-rendering a `<div>` snippet\n // produces a degraded experience and risks hiding the actual code from\n // the reader.\n if (enableHtmlPreview && code.lang === 'html' && isFullHtmlDocument(code.content))\n return (\n <PreHtmlPreview animated={animated} fullFeatured={fullFeatured} {...html} {...rest}>\n {code.content}\n </PreHtmlPreview>\n );\n\n if (!highlight && code.isSingleLine)\n return <PreSingleLine language={code.lang}>{code.content}</PreSingleLine>;\n\n return (\n <Pre\n animated={animated}\n fullFeatured={fullFeatured}\n language={code.lang}\n {...highlight}\n {...rest}\n >\n {code.content}\n </Pre>\n );\n },\n (prevProps, nextProps) => prevProps.children === nextProps.children,\n);\n"],"mappings":";;;;;;AASA,MAAM,cAAc,QAAwB;CAE1C,MAAM,UAAU,IAAI,MAAM,KAAK;CAC/B,OAAO,UAAU,QAAQ,SAAS;AACpC;AAEA,MAAa,WAAW,QAAa;CACnC,IAAI,CAAC,KAAK;CAEV,MAAM,EAAE,WAAW,IAAI,cAAc,KAAK,SAAS,EAAE,UAAU,GAAG;CAElE,IAAI,CAAC,UAAU;CAEf,MAAM,UAAU,MAAM,QAAQ,QAAQ,IAAK,SAAS,KAAgB;CAEpE,MAAM,OAAO,WAAW,QAAQ,aAAa,EAAE,KAAA;CAI/C,OAAO;EACL;EACA,cAJmB,WAAW,OAAO,KAAK,KAAK,QAAQ,UAAU;EAKjE;CACF;AACF;AAaA,MAAa,YAAY,MACtB,EACC,cACA,mBACA,eACA,WACA,MACA,SACA,UACA,UACA,GAAG,WACC;CACJ,MAAM,OAAO,QAAQ,QAAQ;CAE7B,IAAI,CAAC,MAAM;CAEX,IAAI,iBAAiB,KAAK,SAAS,WACjC,OACE,oBAAC,YAAD;EAAsB;EAAwB;EAAc,GAAI;EAAS,GAAI;EAC1E,UAAA,KAAK;CACI,CAAA;CAOhB,IAAI,qBAAqB,KAAK,SAAS,UAAU,mBAAmB,KAAK,OAAO,GAC9E,OACE,oBAAC,gBAAD;EAA0B;EAAwB;EAAc,GAAI;EAAM,GAAI;EAC3E,UAAA,KAAK;CACQ,CAAA;CAGpB,IAAI,CAAC,aAAa,KAAK,cACrB,OAAO,oBAAC,eAAD;EAAe,UAAU,KAAK;EAAO,UAAA,KAAK;CAAuB,CAAA;CAE1E,OACE,oBAAC,KAAD;EACY;EACI;EACd,UAAU,KAAK;EACf,GAAI;EACJ,GAAI;EAEH,UAAA,KAAK;CACH,CAAA;AAET,IACC,WAAW,cAAc,UAAU,aAAa,UAAU,QAC7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Footnotes.mjs","names":["Flexbox"],"sources":["../../../src/Markdown/components/Footnotes.tsx"],"sourcesContent":["'use client';\n\nimport { memo, type ReactNode, useMemo } from 'react';\n\nimport A from '@/A';\nimport Block from '@/Block';\nimport { Flexbox } from '@/Flex';\nimport Text from '@/Text';\n\nimport SearchResultCards from './SearchResultCards';\n\ninterface FootnotesProps {\n 'children': ReactNode;\n 'data-footnote-links'?: string;\n 'data-footnotes'?: boolean;\n}\n\nconst DefaultFootnotes = memo<{ dataSource: any[] }>(({ dataSource }) => {\n const items = useMemo(\n () =>\n dataSource\n .find((child) => child?.type === 'ol')\n ?.props?.children?.map((item: any) => {\n if (typeof item === 'string' || item?.type !== 'li') return false;\n const data = item?.props?.children?.find((note: any) => note?.props?.children)?.props\n ?.children;\n if (!data || !Array.isArray(data)) return false;\n return {\n children: data[0],\n props: data[1]?.props || {},\n };\n })\n .filter(Boolean),\n [dataSource],\n );\n\n if (!Array.isArray(items)) return null;\n\n return (\n <Flexbox\n horizontal\n align={'flex-start'}\n as={'section'}\n className={'footnotes'}\n data-footnotes=\"true\"\n gap={'0.5em'}\n justify={'flex-start'}\n wrap={'wrap'}\n >\n {items.map(({ children, props }, index) => {\n const { node, href, ...rest } = props;\n const Container = href ? A : 'div';\n return (\n <Container {...(href ? { href, ...rest } : rest)} key={index}>\n <Block\n horizontal\n align={'stretch'}\n style={{ overflow: 'hidden', position: 'relative' }}\n variant={'outlined'}\n >\n <Block paddingInline={'0.66em'} style={{ borderRadius: 0 }} variant={'filled'}>\n <Text code as=\"span\" type={'secondary'}>\n {index + 1}\n </Text>\n </Block>\n <Text as=\"span\" style={{ paddingInline: '0.66em' }} type={'secondary'}>\n {children}\n </Text>\n </Block>\n </Container>\n );\n })}\n </Flexbox>\n );\n});\n\nconst Footnotes = memo<FootnotesProps>(({ children, ...rest }) => {\n const links = useMemo(() => {\n try {\n return JSON.parse(rest['data-footnote-links'] || '[]');\n } catch (error) {\n console.error('Failed to parse footnote links:', error);\n return [];\n }\n }, [rest['data-footnote-links']]);\n\n const isError = links.length === 0;\n\n if (!children) return;\n\n if (isError) {\n if (!Array.isArray(children)) return children;\n return <DefaultFootnotes dataSource={children} />;\n }\n\n return (\n <section className={'footnotes'} data-footnotes=\"true\">\n <SearchResultCards dataSource={links} />\n </section>\n );\n});\n\nFootnotes.displayName = 'Footnotes';\n\nexport default Footnotes;\n"],"mappings":";;;;;;;;;AAiBA,MAAM,mBAAmB,MAA6B,EAAE,iBAAiB;CACvE,MAAM,QAAQ,cAEV,WACG,MAAM,UAAU,OAAO,SAAS,IAAI,CAAC,EACpC,OAAO,UAAU,KAAK,SAAc;EACpC,IAAI,OAAO,SAAS,YAAY,MAAM,SAAS,MAAM,OAAO;EAC5D,MAAM,OAAO,MAAM,OAAO,UAAU,MAAM,SAAc,MAAM,OAAO,QAAQ,CAAC,EAAE,OAC5E;EACJ,IAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAAG,OAAO;EAC1C,OAAO;GACL,UAAU,KAAK;GACf,OAAO,KAAK,EAAE,EAAE,SAAS,CAAC;EAC5B;CACF,CAAC,CAAC,CACD,OAAO,OAAO,GACnB,CAAC,UAAU,CACb;CAEA,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CAElC,OACE,oBAACA,mBAAD;EACE,YAAA;EACA,OAAO;EACP,IAAI;EACJ,WAAW;EACX,kBAAe;EACf,KAAK;EACL,SAAS;EACT,MAAM;
|
|
1
|
+
{"version":3,"file":"Footnotes.mjs","names":["Flexbox"],"sources":["../../../src/Markdown/components/Footnotes.tsx"],"sourcesContent":["'use client';\n\nimport { memo, type ReactNode, useMemo } from 'react';\n\nimport A from '@/A';\nimport Block from '@/Block';\nimport { Flexbox } from '@/Flex';\nimport Text from '@/Text';\n\nimport SearchResultCards from './SearchResultCards';\n\ninterface FootnotesProps {\n 'children': ReactNode;\n 'data-footnote-links'?: string;\n 'data-footnotes'?: boolean;\n}\n\nconst DefaultFootnotes = memo<{ dataSource: any[] }>(({ dataSource }) => {\n const items = useMemo(\n () =>\n dataSource\n .find((child) => child?.type === 'ol')\n ?.props?.children?.map((item: any) => {\n if (typeof item === 'string' || item?.type !== 'li') return false;\n const data = item?.props?.children?.find((note: any) => note?.props?.children)?.props\n ?.children;\n if (!data || !Array.isArray(data)) return false;\n return {\n children: data[0],\n props: data[1]?.props || {},\n };\n })\n .filter(Boolean),\n [dataSource],\n );\n\n if (!Array.isArray(items)) return null;\n\n return (\n <Flexbox\n horizontal\n align={'flex-start'}\n as={'section'}\n className={'footnotes'}\n data-footnotes=\"true\"\n gap={'0.5em'}\n justify={'flex-start'}\n wrap={'wrap'}\n >\n {items.map(({ children, props }, index) => {\n const { node, href, ...rest } = props;\n const Container = href ? A : 'div';\n return (\n <Container {...(href ? { href, ...rest } : rest)} key={index}>\n <Block\n horizontal\n align={'stretch'}\n style={{ overflow: 'hidden', position: 'relative' }}\n variant={'outlined'}\n >\n <Block paddingInline={'0.66em'} style={{ borderRadius: 0 }} variant={'filled'}>\n <Text code as=\"span\" type={'secondary'}>\n {index + 1}\n </Text>\n </Block>\n <Text as=\"span\" style={{ paddingInline: '0.66em' }} type={'secondary'}>\n {children}\n </Text>\n </Block>\n </Container>\n );\n })}\n </Flexbox>\n );\n});\n\nconst Footnotes = memo<FootnotesProps>(({ children, ...rest }) => {\n const links = useMemo(() => {\n try {\n return JSON.parse(rest['data-footnote-links'] || '[]');\n } catch (error) {\n console.error('Failed to parse footnote links:', error);\n return [];\n }\n }, [rest['data-footnote-links']]);\n\n const isError = links.length === 0;\n\n if (!children) return;\n\n if (isError) {\n if (!Array.isArray(children)) return children;\n return <DefaultFootnotes dataSource={children} />;\n }\n\n return (\n <section className={'footnotes'} data-footnotes=\"true\">\n <SearchResultCards dataSource={links} />\n </section>\n );\n});\n\nFootnotes.displayName = 'Footnotes';\n\nexport default Footnotes;\n"],"mappings":";;;;;;;;;AAiBA,MAAM,mBAAmB,MAA6B,EAAE,iBAAiB;CACvE,MAAM,QAAQ,cAEV,WACG,MAAM,UAAU,OAAO,SAAS,IAAI,CAAC,EACpC,OAAO,UAAU,KAAK,SAAc;EACpC,IAAI,OAAO,SAAS,YAAY,MAAM,SAAS,MAAM,OAAO;EAC5D,MAAM,OAAO,MAAM,OAAO,UAAU,MAAM,SAAc,MAAM,OAAO,QAAQ,CAAC,EAAE,OAC5E;EACJ,IAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAAG,OAAO;EAC1C,OAAO;GACL,UAAU,KAAK;GACf,OAAO,KAAK,EAAE,EAAE,SAAS,CAAC;EAC5B;CACF,CAAC,CAAC,CACD,OAAO,OAAO,GACnB,CAAC,UAAU,CACb;CAEA,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,OAAO;CAElC,OACE,oBAACA,mBAAD;EACE,YAAA;EACA,OAAO;EACP,IAAI;EACJ,WAAW;EACX,kBAAe;EACf,KAAK;EACL,SAAS;EACT,MAAM;EAEL,UAAA,MAAM,KAAK,EAAE,UAAU,SAAS,UAAU;GACzC,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS;GAEhC,OACE,8BAFgB,OAAO,IAAI,OAE3B;IAAW,GAAK,OAAO;KAAE;KAAM,GAAG;IAAK,IAAI;IAAO,KAAK;GAgB5C,GAfT,qBAAC,OAAD;IACE,YAAA;IACA,OAAO;IACP,OAAO;KAAE,UAAU;KAAU,UAAU;IAAW;IAClD,SAAS;IAJX,UAAA,CAME,oBAAC,OAAD;KAAO,eAAe;KAAU,OAAO,EAAE,cAAc,EAAE;KAAG,SAAS;KACnE,UAAA,oBAAC,MAAD;MAAM,MAAA;MAAK,IAAG;MAAO,MAAM;MACxB,UAAA,QAAQ;KACL,CAAA;IACD,CAAA,GACP,oBAAC,MAAD;KAAM,IAAG;KAAO,OAAO,EAAE,eAAe,SAAS;KAAG,MAAM;KACvD;IACG,CAAA,CACD;GACE,CAAA,CAAA;EAEf,CAAC;CACM,CAAA;AAEb,CAAC;AAED,MAAM,YAAY,MAAsB,EAAE,UAAU,GAAG,WAAW;CAChE,MAAM,QAAQ,cAAc;EAC1B,IAAI;GACF,OAAO,KAAK,MAAM,KAAK,0BAA0B,IAAI;EACvD,SAAS,OAAO;GACd,QAAQ,MAAM,mCAAmC,KAAK;GACtD,OAAO,CAAC;EACV;CACF,GAAG,CAAC,KAAK,sBAAsB,CAAC;CAEhC,MAAM,UAAU,MAAM,WAAW;CAEjC,IAAI,CAAC,UAAU;CAEf,IAAI,SAAS;EACX,IAAI,CAAC,MAAM,QAAQ,QAAQ,GAAG,OAAO;EACrC,OAAO,oBAAC,kBAAD,EAAkB,YAAY,SAAW,CAAA;CAClD;CAEA,OACE,oBAAC,WAAD;EAAS,WAAW;EAAa,kBAAe;EAC9C,UAAA,oBAAC,mBAAD,EAAmB,YAAY,MAAQ,CAAA;CAChC,CAAA;AAEb,CAAC;AAED,UAAU,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/Markdown/components/MarkdownTable/index.tsx"],"sourcesContent":["'use client';\n\nimport { createStyles } from 'antd-style';\nimport { memo, useCallback, useRef } from 'react';\n\nimport CopyButton from '@/CopyButton';\n\nimport { hastTableToMarkdown } from './hastTableToMarkdown';\n\nconst useStyles = createStyles(({ css, token }) => ({\n copyButton: css`\n position: absolute;\n z-index: 1;\n\n /* Vertical center of the header row = top padding (0.75em) + half of\n the text line-box (line-height * 0.5em). Pulling the button up by\n 50% of its own height with transform parks it on that exact line. */\n inset-block-start: calc(0.75em + (var(--lobe-markdown-line-height) * 0.5em));\n inset-inline-end: 0.5em;\n transform: translateY(-50%);\n\n opacity: 0;\n background: ${token.colorBgContainer};\n box-shadow: 0 0 0 1px ${token.colorBorderSecondary};\n\n transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};\n `,\n wrapper: css`\n position: relative;\n\n display: block;\n\n width: max-content;\n max-width: 100%;\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n\n &:hover .table-copy-button,\n &:focus-within .table-copy-button {\n opacity: 1;\n }\n\n /* Hand spacing to the wrapper so the absolutely-positioned copy\n button anchors against the visible table edge instead of empty\n margin space. */\n > table {\n margin-block: 0;\n }\n\n /* Reserve room for the copy button so right-aligned header text\n doesn't slide under it. */\n > table thead th:last-child {\n padding-inline-end: calc(1em + 32px);\n }\n `,\n}));\n\ninterface MarkdownTableProps {\n children?: React.ReactNode;\n node?: any;\n}\n\nconst MarkdownTable = memo<MarkdownTableProps>(({ node, children, ...rest }) => {\n const { styles, cx } = useStyles();\n const nodeRef = useRef(node);\n nodeRef.current = node;\n\n const getMarkdown = useCallback(() => hastTableToMarkdown(nodeRef.current), []);\n\n return (\n <div className={styles.wrapper}>\n <CopyButton\n className={cx(styles.copyButton, 'table-copy-button')}\n content={getMarkdown}\n glass={false}\n size={{ blockSize: 24, size: 14 }}\n title=\"Copy table\"\n variant=\"filled\"\n />\n <table {...rest}>{children}</table>\n </div>\n );\n});\n\nMarkdownTable.displayName = 'MarkdownTable';\n\nexport default MarkdownTable;\n"],"mappings":";;;;;;;AASA,MAAM,YAAY,cAAc,EAAE,KAAK,aAAa;CAClD,YAAY,GAAG;;;;;;;;;;;;kBAYC,MAAM,iBAAiB;4BACb,MAAM,qBAAqB;;0BAE7B,MAAM,kBAAkB,GAAG,MAAM,gBAAgB;;CAEzE,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2Bd,EAAE;AAOF,MAAM,gBAAgB,MAA0B,EAAE,MAAM,UAAU,GAAG,WAAW;CAC9E,MAAM,EAAE,QAAQ,OAAO,UAAU;CACjC,MAAM,UAAU,OAAO,IAAI;CAC3B,QAAQ,UAAU;CAElB,MAAM,cAAc,kBAAkB,oBAAoB,QAAQ,OAAO,GAAG,CAAC,CAAC;CAE9E,OACE,qBAAC,OAAD;EAAK,WAAW,OAAO;
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/Markdown/components/MarkdownTable/index.tsx"],"sourcesContent":["'use client';\n\nimport { createStyles } from 'antd-style';\nimport { memo, useCallback, useRef } from 'react';\n\nimport CopyButton from '@/CopyButton';\n\nimport { hastTableToMarkdown } from './hastTableToMarkdown';\n\nconst useStyles = createStyles(({ css, token }) => ({\n copyButton: css`\n position: absolute;\n z-index: 1;\n\n /* Vertical center of the header row = top padding (0.75em) + half of\n the text line-box (line-height * 0.5em). Pulling the button up by\n 50% of its own height with transform parks it on that exact line. */\n inset-block-start: calc(0.75em + (var(--lobe-markdown-line-height) * 0.5em));\n inset-inline-end: 0.5em;\n transform: translateY(-50%);\n\n opacity: 0;\n background: ${token.colorBgContainer};\n box-shadow: 0 0 0 1px ${token.colorBorderSecondary};\n\n transition: opacity ${token.motionDurationMid} ${token.motionEaseInOut};\n `,\n wrapper: css`\n position: relative;\n\n display: block;\n\n width: max-content;\n max-width: 100%;\n margin-block: calc(var(--lobe-markdown-margin-multiple) * 0.5em);\n\n &:hover .table-copy-button,\n &:focus-within .table-copy-button {\n opacity: 1;\n }\n\n /* Hand spacing to the wrapper so the absolutely-positioned copy\n button anchors against the visible table edge instead of empty\n margin space. */\n > table {\n margin-block: 0;\n }\n\n /* Reserve room for the copy button so right-aligned header text\n doesn't slide under it. */\n > table thead th:last-child {\n padding-inline-end: calc(1em + 32px);\n }\n `,\n}));\n\ninterface MarkdownTableProps {\n children?: React.ReactNode;\n node?: any;\n}\n\nconst MarkdownTable = memo<MarkdownTableProps>(({ node, children, ...rest }) => {\n const { styles, cx } = useStyles();\n const nodeRef = useRef(node);\n nodeRef.current = node;\n\n const getMarkdown = useCallback(() => hastTableToMarkdown(nodeRef.current), []);\n\n return (\n <div className={styles.wrapper}>\n <CopyButton\n className={cx(styles.copyButton, 'table-copy-button')}\n content={getMarkdown}\n glass={false}\n size={{ blockSize: 24, size: 14 }}\n title=\"Copy table\"\n variant=\"filled\"\n />\n <table {...rest}>{children}</table>\n </div>\n );\n});\n\nMarkdownTable.displayName = 'MarkdownTable';\n\nexport default MarkdownTable;\n"],"mappings":";;;;;;;AASA,MAAM,YAAY,cAAc,EAAE,KAAK,aAAa;CAClD,YAAY,GAAG;;;;;;;;;;;;kBAYC,MAAM,iBAAiB;4BACb,MAAM,qBAAqB;;0BAE7B,MAAM,kBAAkB,GAAG,MAAM,gBAAgB;;CAEzE,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2Bd,EAAE;AAOF,MAAM,gBAAgB,MAA0B,EAAE,MAAM,UAAU,GAAG,WAAW;CAC9E,MAAM,EAAE,QAAQ,OAAO,UAAU;CACjC,MAAM,UAAU,OAAO,IAAI;CAC3B,QAAQ,UAAU;CAElB,MAAM,cAAc,kBAAkB,oBAAoB,QAAQ,OAAO,GAAG,CAAC,CAAC;CAE9E,OACE,qBAAC,OAAD;EAAK,WAAW,OAAO;EAAvB,UAAA,CACE,oBAAC,YAAD;GACE,WAAW,GAAG,OAAO,YAAY,mBAAmB;GACpD,SAAS;GACT,OAAO;GACP,MAAM;IAAE,WAAW;IAAI,MAAM;GAAG;GAChC,OAAM;GACN,SAAQ;EACT,CAAA,GACD,oBAAC,SAAD;GAAO,GAAI;GAAO;EAAgB,CAAA,CAC/B;;AAET,CAAC;AAED,cAAc,cAAc"}
|