@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.
Files changed (375) hide show
  1. package/es/A/index.mjs +2 -1
  2. package/es/A/index.mjs.map +1 -1
  3. package/es/Accordion/Accordion.mjs.map +1 -1
  4. package/es/Accordion/AccordionItem.mjs +0 -1
  5. package/es/Accordion/AccordionItem.mjs.map +1 -1
  6. package/es/Accordion/ArrowIcon.mjs.map +1 -1
  7. package/es/ActionIcon/ActionIcon.mjs.map +1 -1
  8. package/es/ActionIcon/components/utils.mjs +7 -9
  9. package/es/ActionIcon/components/utils.mjs.map +1 -1
  10. package/es/ActionIconGroup/ActionIconGroup.mjs.map +1 -1
  11. package/es/Alert/Alert.mjs.map +1 -1
  12. package/es/Avatar/Avatar.mjs.map +1 -1
  13. package/es/Avatar/AvatarGroup/index.mjs.map +1 -1
  14. package/es/Burger/Burger.mjs.map +1 -1
  15. package/es/Checkbox/Checkbox.mjs.map +1 -1
  16. package/es/Checkbox/CheckboxGroup.mjs +4 -2
  17. package/es/Checkbox/CheckboxGroup.mjs.map +1 -1
  18. package/es/CodeDiff/CodeDiff.mjs +20 -18
  19. package/es/CodeDiff/CodeDiff.mjs.map +1 -1
  20. package/es/CodeDiff/DiffPanel.mjs.map +1 -1
  21. package/es/CodeDiff/PatchDiff.mjs +18 -16
  22. package/es/CodeDiff/PatchDiff.mjs.map +1 -1
  23. package/es/CodeEditor/CodeEditor.mjs.map +1 -1
  24. package/es/Collapse/Collapse.mjs.map +1 -1
  25. package/es/ColorSwatches/ColorSwatches.mjs.map +1 -1
  26. package/es/ConfigProvider/index.mjs.map +1 -1
  27. package/es/ContextMenu/index.d.mts +2 -2
  28. package/es/ContextMenu/index.mjs +2 -2
  29. package/es/CopyButton/CopyButton.mjs +2 -1
  30. package/es/CopyButton/CopyButton.mjs.map +1 -1
  31. package/es/DraggablePanel/DraggablePanel.mjs.map +1 -1
  32. package/es/DraggablePanel/components/DraggablePanelHeader.mjs.map +1 -1
  33. package/es/DraggableSideNav/DraggableSideNav.mjs.map +1 -1
  34. package/es/Drawer/Drawer.mjs.map +1 -1
  35. package/es/Dropdown/Dropdown.mjs.map +1 -1
  36. package/es/EditableText/ControlInput.mjs.map +1 -1
  37. package/es/EditableText/EditableText.mjs.map +1 -1
  38. package/es/EditorSlashMenu/EditorSlashMenu.mjs.map +1 -1
  39. package/es/EditorSlashMenu/MenuItemRenderer.mjs.map +1 -1
  40. package/es/EmojiPicker/AvatarUploader.mjs.map +1 -1
  41. package/es/EmojiPicker/EmojiPicker.mjs.map +1 -1
  42. package/es/Empty/Empty.mjs.map +1 -1
  43. package/es/FileTypeIcon/FileTypeIcon.mjs.map +1 -1
  44. package/es/FileTypeIcon/components/FileIcon.mjs.map +1 -1
  45. package/es/FileTypeIcon/components/FolderIcon.mjs.map +1 -1
  46. package/es/FluentEmoji/FluentEmoji.mjs.map +1 -1
  47. package/es/Footer/Footer.mjs.map +1 -1
  48. package/es/Form/Form.mjs.map +1 -1
  49. package/es/Form/components/FormGroup.mjs.map +1 -1
  50. package/es/Form/components/FormSubmitFooter.mjs.map +1 -1
  51. package/es/Form/components/FormTitle.mjs.map +1 -1
  52. package/es/FormModal/FormModal.mjs.map +1 -1
  53. package/es/Freeze/Freeze.mjs.map +1 -1
  54. package/es/GroupAvatar/GroupAvatar.mjs.map +1 -1
  55. package/es/GuideCard/GuideCard.mjs.map +1 -1
  56. package/es/Header/Header.mjs.map +1 -1
  57. package/es/Highlighter/FullFeatured.mjs.map +1 -1
  58. package/es/Highlighter/Highlighter.mjs.map +1 -1
  59. package/es/Highlighter/LangSelect.mjs +41 -40
  60. package/es/Highlighter/LangSelect.mjs.map +1 -1
  61. package/es/Highlighter/SyntaxHighlighter/StaticRenderer.mjs +2 -1
  62. package/es/Highlighter/SyntaxHighlighter/StaticRenderer.mjs.map +1 -1
  63. package/es/Highlighter/SyntaxHighlighter/StreamRenderer.mjs.map +1 -1
  64. package/es/Highlighter/SyntaxHighlighter/style.mjs +2 -2
  65. package/es/Highlighter/SyntaxHighlighter/style.mjs.map +1 -1
  66. package/es/Hotkey/Hotkey.mjs.map +1 -1
  67. package/es/HotkeyInput/HotkeyInput.mjs +3 -1
  68. package/es/HotkeyInput/HotkeyInput.mjs.map +1 -1
  69. package/es/HtmlPreview/HtmlPreview.mjs.map +1 -1
  70. package/es/HtmlPreview/Iframe.mjs.map +1 -1
  71. package/es/HtmlPreview/const.mjs +1 -1
  72. package/es/HtmlPreview/const.mjs.map +1 -1
  73. package/es/Icon/Icon.mjs.map +1 -1
  74. package/es/Icon/components/utils.mjs +7 -9
  75. package/es/Icon/components/utils.mjs.map +1 -1
  76. package/es/Image/Image.mjs.map +1 -1
  77. package/es/Image/components/Toolbar.mjs +2 -1
  78. package/es/Image/components/Toolbar.mjs.map +1 -1
  79. package/es/Image/components/usePreview.mjs.map +1 -1
  80. package/es/Image/components/usePreviewGroup.mjs.map +1 -1
  81. package/es/ImageSelect/ImageSelect.mjs.map +1 -1
  82. package/es/Img/index.mjs +2 -1
  83. package/es/Img/index.mjs.map +1 -1
  84. package/es/Layout/Layout.mjs.map +1 -1
  85. package/es/List/List.mjs.map +1 -1
  86. package/es/List/ListItem/index.mjs.map +1 -1
  87. package/es/Markdown/Markdown.mjs.map +1 -1
  88. package/es/Markdown/SyntaxMarkdown/MarkdownRender.mjs.map +1 -1
  89. package/es/Markdown/SyntaxMarkdown/StreamdownRender.mjs +2 -1
  90. package/es/Markdown/SyntaxMarkdown/StreamdownRender.mjs.map +1 -1
  91. package/es/Markdown/SyntaxMarkdown/style.mjs.map +1 -1
  92. package/es/Markdown/SyntaxMarkdown/useSmoothStreamContent.mjs +2 -2
  93. package/es/Markdown/SyntaxMarkdown/useSmoothStreamContent.mjs.map +1 -1
  94. package/es/Markdown/components/CodeBlock.mjs.map +1 -1
  95. package/es/Markdown/components/Footnotes.mjs.map +1 -1
  96. package/es/Markdown/components/MarkdownTable/index.mjs.map +1 -1
  97. package/es/Markdown/components/SearchResultCards/SearchResultCard.mjs.map +1 -1
  98. package/es/Markdown/components/SearchResultCards/index.mjs.map +1 -1
  99. package/es/MaterialFileTypeIcon/MaterialFileTypeIcon.mjs.map +1 -1
  100. package/es/Menu/Menu.mjs.map +1 -1
  101. package/es/Mermaid/FullFeatured.mjs.map +1 -1
  102. package/es/Mermaid/Mermaid.mjs.map +1 -1
  103. package/es/Mermaid/SyntaxMermaid/MermaidFallback.mjs +35 -0
  104. package/es/Mermaid/SyntaxMermaid/MermaidFallback.mjs.map +1 -0
  105. package/es/Mermaid/SyntaxMermaid/MermaidSvg.mjs +52 -0
  106. package/es/Mermaid/SyntaxMermaid/MermaidSvg.mjs.map +1 -0
  107. package/es/Mermaid/SyntaxMermaid/StaticMermaid.mjs +13 -42
  108. package/es/Mermaid/SyntaxMermaid/StaticMermaid.mjs.map +1 -1
  109. package/es/Mermaid/SyntaxMermaid/StreamMermaid.mjs +13 -43
  110. package/es/Mermaid/SyntaxMermaid/StreamMermaid.mjs.map +1 -1
  111. package/es/Mermaid/SyntaxMermaid/prepareInlineSvg.mjs +52 -0
  112. package/es/Mermaid/SyntaxMermaid/prepareInlineSvg.mjs.map +1 -0
  113. package/es/Mermaid/SyntaxMermaid/prepareMermaidSvg.mjs +20 -0
  114. package/es/Mermaid/SyntaxMermaid/prepareMermaidSvg.mjs.map +1 -0
  115. package/es/Mermaid/SyntaxMermaid/style.mjs +11 -0
  116. package/es/Mermaid/SyntaxMermaid/style.mjs.map +1 -1
  117. package/es/Mermaid/const.mjs +10 -31
  118. package/es/Mermaid/const.mjs.map +1 -1
  119. package/es/Mermaid/index.d.mts +2 -1
  120. package/es/Mermaid/index.mjs +2 -1
  121. package/es/Mermaid/type.d.mts +2 -2
  122. package/es/Modal/Modal.mjs.map +1 -1
  123. package/es/Modal/ModalStackItem.mjs.map +1 -1
  124. package/es/Modal/RawModalStackItem.mjs +6 -5
  125. package/es/Modal/RawModalStackItem.mjs.map +1 -1
  126. package/es/Modal/imperative.mjs +4 -2
  127. package/es/Modal/imperative.mjs.map +1 -1
  128. package/es/Modal/style.mjs.map +1 -1
  129. package/es/NeuralNetworkLoading/NeuralNetworkLoading.mjs +1 -1
  130. package/es/NeuralNetworkLoading/NeuralNetworkLoading.mjs.map +1 -1
  131. package/es/ScrollShadow/ScrollShadow.mjs +13 -12
  132. package/es/ScrollShadow/ScrollShadow.mjs.map +1 -1
  133. package/es/SearchBar/SearchBar.mjs.map +1 -1
  134. package/es/SideNav/SideNav.mjs.map +1 -1
  135. package/es/Skeleton/Skeleton.mjs.map +1 -1
  136. package/es/Skeleton/SkeletonButton.mjs +2 -1
  137. package/es/Skeleton/SkeletonButton.mjs.map +1 -1
  138. package/es/Skeleton/SkeletonParagraph.mjs.map +1 -1
  139. package/es/Skeleton/SkeletonTags.mjs.map +1 -1
  140. package/es/SliderWithInput/SliderWithInput.mjs.map +1 -1
  141. package/es/Snippet/Snippet.mjs.map +1 -1
  142. package/es/SortableList/SortableList.mjs +5 -1
  143. package/es/SortableList/SortableList.mjs.map +1 -1
  144. package/es/SortableList/components/SortableItem.mjs.map +1 -1
  145. package/es/Text/Text.mjs +22 -21
  146. package/es/Text/Text.mjs.map +1 -1
  147. package/es/ThemeProvider/ThemeProvider.mjs +4 -3
  148. package/es/ThemeProvider/ThemeProvider.mjs.map +1 -1
  149. package/es/ThemeSwitch/ThemeSwitch.mjs.map +1 -1
  150. package/es/Toc/Toc.mjs.map +1 -1
  151. package/es/Toc/TocMobile.mjs.map +1 -1
  152. package/es/Video/index.mjs.map +1 -1
  153. package/es/awesome/AuroraBackground/AuroraBackground.mjs.map +1 -1
  154. package/es/awesome/Features/FeatureItem.mjs.map +1 -1
  155. package/es/awesome/Giscus/Giscus.mjs.map +1 -1
  156. package/es/awesome/GradientButton/GradientButton.mjs +1 -3
  157. package/es/awesome/GradientButton/GradientButton.mjs.map +1 -1
  158. package/es/awesome/GridBackground/GridBackground.mjs.map +1 -1
  159. package/es/awesome/GridBackground/GridShowcase.mjs.map +1 -1
  160. package/es/awesome/GridBackground/components/Grid.mjs.map +1 -1
  161. package/es/awesome/Hero/Hero.mjs.map +1 -1
  162. package/es/awesome/Spline/ParentSize.mjs.map +1 -1
  163. package/es/awesome/Spline/Spine.mjs.map +1 -1
  164. package/es/awesome/Spotlight/Spotlight.mjs +2 -1
  165. package/es/awesome/Spotlight/Spotlight.mjs.map +1 -1
  166. package/es/awesome/SpotlightCard/SpotlightCard.mjs.map +1 -1
  167. package/es/awesome/SpotlightCard/SpotlightCardItem.mjs.map +1 -1
  168. package/es/awesome/TypewriterEffect/TypewriterEffect.mjs.map +1 -1
  169. package/es/base-ui/AutoComplete/AutoComplete.mjs.map +1 -1
  170. package/es/base-ui/Button/Button.mjs +13 -11
  171. package/es/base-ui/Button/Button.mjs.map +1 -1
  172. package/es/base-ui/Button/SplitButton.mjs +2 -1
  173. package/es/base-ui/Button/SplitButton.mjs.map +1 -1
  174. package/es/base-ui/Checkbox/Checkbox.mjs.map +1 -1
  175. package/es/base-ui/Checkbox/CheckboxGroup.mjs.map +1 -1
  176. package/es/base-ui/ContextMenu/ContextMenuHost.mjs.map +1 -1
  177. package/es/base-ui/ContextMenu/ContextMenuTrigger.mjs +2 -1
  178. package/es/base-ui/ContextMenu/ContextMenuTrigger.mjs.map +1 -1
  179. package/es/base-ui/ContextMenu/imperative.d.mts +2 -2
  180. package/es/base-ui/ContextMenu/index.d.mts +2 -2
  181. package/es/base-ui/ContextMenu/renderItems.mjs +2 -1
  182. package/es/base-ui/ContextMenu/renderItems.mjs.map +1 -1
  183. package/es/base-ui/ContextMenu/store.d.mts +13 -1
  184. package/es/base-ui/ContextMenu/store.mjs +29 -4
  185. package/es/base-ui/ContextMenu/store.mjs.map +1 -1
  186. package/es/base-ui/Drawer/Drawer.d.mts +6 -0
  187. package/es/base-ui/Drawer/Drawer.mjs +152 -0
  188. package/es/base-ui/Drawer/Drawer.mjs.map +1 -0
  189. package/es/base-ui/Drawer/DrawerLayerContext.mjs +10 -0
  190. package/es/base-ui/Drawer/DrawerLayerContext.mjs.map +1 -0
  191. package/es/base-ui/Drawer/DrawerPushContext.mjs +27 -0
  192. package/es/base-ui/Drawer/DrawerPushContext.mjs.map +1 -0
  193. package/es/base-ui/Drawer/atoms.d.mts +58 -0
  194. package/es/base-ui/Drawer/atoms.mjs +262 -0
  195. package/es/base-ui/Drawer/atoms.mjs.map +1 -0
  196. package/es/base-ui/Drawer/constants.d.mts +17 -0
  197. package/es/base-ui/Drawer/constants.mjs +72 -0
  198. package/es/base-ui/Drawer/constants.mjs.map +1 -0
  199. package/es/base-ui/Drawer/index.d.mts +5 -0
  200. package/es/base-ui/Drawer/style.mjs +295 -0
  201. package/es/base-ui/Drawer/style.mjs.map +1 -0
  202. package/es/base-ui/Drawer/type.d.mts +65 -0
  203. package/es/base-ui/DropdownMenu/DropdownMenu.mjs +2 -1
  204. package/es/base-ui/DropdownMenu/DropdownMenu.mjs.map +1 -1
  205. package/es/base-ui/DropdownMenu/atoms.mjs +2 -1
  206. package/es/base-ui/DropdownMenu/atoms.mjs.map +1 -1
  207. package/es/base-ui/DropdownMenu/renderItems.mjs +2 -1
  208. package/es/base-ui/DropdownMenu/renderItems.mjs.map +1 -1
  209. package/es/base-ui/DropdownMenu/sharedStyle.mjs +3 -0
  210. package/es/base-ui/DropdownMenu/sharedStyle.mjs.map +1 -1
  211. package/es/base-ui/FloatingPanel/FloatingPanel.mjs.map +1 -1
  212. package/es/base-ui/FloatingSheet/FloatingSheet.mjs +4 -1
  213. package/es/base-ui/FloatingSheet/FloatingSheet.mjs.map +1 -1
  214. package/es/base-ui/FloatingSheet/FloatingSheetHeader.mjs.map +1 -1
  215. package/es/base-ui/Form/Form.mjs.map +1 -1
  216. package/es/base-ui/Form/components/FormField.mjs.map +1 -1
  217. package/es/base-ui/Form/components/FormGroup.mjs.map +1 -1
  218. package/es/base-ui/Form/components/FormSubmitFooter.mjs.map +1 -1
  219. package/es/base-ui/Form/components/FormTitle.mjs.map +1 -1
  220. package/es/base-ui/Input/Input.mjs.map +1 -1
  221. package/es/base-ui/Input/InputNumber.mjs.map +1 -1
  222. package/es/base-ui/Input/InputOTP.mjs.map +1 -1
  223. package/es/base-ui/Input/InputPassword.mjs.map +1 -1
  224. package/es/base-ui/Input/TextArea.mjs.map +1 -1
  225. package/es/base-ui/Modal/Modal.mjs.map +1 -1
  226. package/es/base-ui/Modal/atoms.mjs +7 -5
  227. package/es/base-ui/Modal/atoms.mjs.map +1 -1
  228. package/es/base-ui/Modal/imperative.mjs +2 -1
  229. package/es/base-ui/Modal/imperative.mjs.map +1 -1
  230. package/es/base-ui/Popover/ArrowIcon.mjs.map +1 -1
  231. package/es/base-ui/Popover/PopoverGroup.mjs.map +1 -1
  232. package/es/base-ui/Popover/PopoverStandalone.mjs.map +1 -1
  233. package/es/base-ui/Popover/atoms.mjs +2 -1
  234. package/es/base-ui/Popover/atoms.mjs.map +1 -1
  235. package/es/base-ui/Popover/context.mjs +4 -2
  236. package/es/base-ui/Popover/context.mjs.map +1 -1
  237. package/es/base-ui/Radio/Radio.mjs.map +1 -1
  238. package/es/base-ui/Radio/RadioGroup.mjs.map +1 -1
  239. package/es/base-ui/ScrollArea/ScrollArea.mjs.map +1 -1
  240. package/es/base-ui/Segmented/Segmented.mjs.map +1 -1
  241. package/es/base-ui/Select/Select.mjs.map +1 -1
  242. package/es/base-ui/Select/atoms.mjs +2 -1
  243. package/es/base-ui/Select/atoms.mjs.map +1 -1
  244. package/es/base-ui/Select/parts.mjs.map +1 -1
  245. package/es/base-ui/Select/renderOptions.mjs.map +1 -1
  246. package/es/base-ui/Slider/Slider.mjs.map +1 -1
  247. package/es/base-ui/Slider/SliderWithInput.mjs.map +1 -1
  248. package/es/base-ui/SubmenuArrowIcon.mjs.map +1 -1
  249. package/es/base-ui/Switch/Switch.mjs.map +1 -1
  250. package/es/base-ui/Switch/atoms.d.mts +3 -3
  251. package/es/base-ui/Switch/atoms.mjs +99 -50
  252. package/es/base-ui/Switch/atoms.mjs.map +1 -1
  253. package/es/base-ui/Switch/style.mjs +44 -1
  254. package/es/base-ui/Switch/style.mjs.map +1 -1
  255. package/es/base-ui/Switch/type.d.mts +3 -7
  256. package/es/base-ui/Tabs/Tabs.mjs.map +1 -1
  257. package/es/base-ui/Tabs/atoms.mjs.map +1 -1
  258. package/es/base-ui/Toast/Toast.mjs.map +1 -1
  259. package/es/base-ui/Toast/imperative.mjs.map +1 -1
  260. package/es/base-ui/Tooltip/ArrowIcon.mjs.map +1 -1
  261. package/es/base-ui/Tooltip/TooltipGroup.mjs.map +1 -1
  262. package/es/base-ui/Tooltip/TooltipStandalone.mjs.map +1 -1
  263. package/es/base-ui/index.d.mts +7 -2
  264. package/es/base-ui/index.mjs +5 -2
  265. package/es/brand/LobeChat/index.mjs +0 -1
  266. package/es/brand/LobeChat/index.mjs.map +1 -1
  267. package/es/brand/LobeChatText/index.mjs.map +1 -1
  268. package/es/brand/LobeHub/index.mjs +0 -1
  269. package/es/brand/LobeHub/index.mjs.map +1 -1
  270. package/es/brand/LobeHubText/index.mjs.map +1 -1
  271. package/es/brand/Logo3d/index.mjs +2 -1
  272. package/es/brand/Logo3d/index.mjs.map +1 -1
  273. package/es/brand/LogoThree/Loading.mjs.map +1 -1
  274. package/es/brand/LogoThree/LogoSpline.mjs.map +1 -1
  275. package/es/brand/LogoThree/index.mjs.map +1 -1
  276. package/es/brand/components/Divider.mjs.map +1 -1
  277. package/es/chat/BackBottom/BackBottom.mjs.map +1 -1
  278. package/es/chat/ChatHeader/ChatHeader.mjs.map +1 -1
  279. package/es/chat/ChatHeader/ChatHeaderTitle.mjs.map +1 -1
  280. package/es/chat/ChatInputArea/ChatInputArea.mjs.map +1 -1
  281. package/es/chat/ChatInputArea/components/ChatInputActionBar.mjs.map +1 -1
  282. package/es/chat/ChatInputArea/components/ChatSendButton.mjs.map +1 -1
  283. package/es/chat/ChatItem/ChatItem.mjs.map +1 -1
  284. package/es/chat/ChatItem/components/Actions.mjs +5 -4
  285. package/es/chat/ChatItem/components/Actions.mjs.map +1 -1
  286. package/es/chat/ChatItem/components/Avatar.mjs.map +1 -1
  287. package/es/chat/ChatItem/components/ErrorContent.mjs.map +1 -1
  288. package/es/chat/ChatItem/components/Loading.mjs.map +1 -1
  289. package/es/chat/ChatItem/components/MessageContent.mjs.map +1 -1
  290. package/es/chat/ChatItem/components/Title.mjs.map +1 -1
  291. package/es/chat/ChatList/ChatList.mjs +2 -1
  292. package/es/chat/ChatList/ChatList.mjs.map +1 -1
  293. package/es/chat/ChatList/components/HistoryDivider.mjs.map +1 -1
  294. package/es/chat/EditableMessage/EditableMessage.mjs.map +1 -1
  295. package/es/chat/EditableMessageList/EditableMessageList.mjs.map +1 -1
  296. package/es/chat/LoadingDots/LoadingDots.mjs.map +1 -1
  297. package/es/chat/MessageInput/MessageInput.mjs.map +1 -1
  298. package/es/chat/MessageModal/MessageModal.mjs.map +1 -1
  299. package/es/color/ColorScales/ScaleRow.mjs +0 -2
  300. package/es/color/ColorScales/ScaleRow.mjs.map +1 -1
  301. package/es/color/ColorScales/index.mjs.map +1 -1
  302. package/es/color/CssVar/ScaleRow.mjs.map +1 -1
  303. package/es/color/CssVar/VarRow.mjs.map +1 -1
  304. package/es/color/CssVar/index.mjs.map +1 -1
  305. package/es/hooks/useMarkdown/latex.mjs.map +1 -1
  306. package/es/hooks/useMarkdown/useMarkdownContent.mjs.map +1 -1
  307. package/es/hooks/useMermaid.mjs +81 -116
  308. package/es/hooks/useMermaid.mjs.map +1 -1
  309. package/es/hooks/useMermaidCdn.d.mts +10 -0
  310. package/es/hooks/useMermaidCdn.mjs +97 -0
  311. package/es/hooks/useMermaidCdn.mjs.map +1 -0
  312. package/es/hooks/useStreamMermaid.mjs +19 -70
  313. package/es/hooks/useStreamMermaid.mjs.map +1 -1
  314. package/es/icons/Auth0/components/Mono.mjs.map +1 -1
  315. package/es/icons/Authelia/components/Color.mjs.map +1 -1
  316. package/es/icons/Authelia/components/Mono.mjs.map +1 -1
  317. package/es/icons/Authentik/components/Color.mjs.map +1 -1
  318. package/es/icons/Authentik/components/Mono.mjs.map +1 -1
  319. package/es/icons/Casdoor/components/Color.mjs.map +1 -1
  320. package/es/icons/Casdoor/components/Mono.mjs.map +1 -1
  321. package/es/icons/Clerk/components/Color.mjs.map +1 -1
  322. package/es/icons/Clerk/components/Mono.mjs.map +1 -1
  323. package/es/icons/DingTalk/components/Color.mjs.map +1 -1
  324. package/es/icons/DingTalk/components/Mono.mjs.map +1 -1
  325. package/es/icons/Discord/components/Color.mjs.map +1 -1
  326. package/es/icons/Discord/components/Mono.mjs.map +1 -1
  327. package/es/icons/GoogleChat/components/Color.mjs.map +1 -1
  328. package/es/icons/GoogleChat/components/Mono.mjs.map +1 -1
  329. package/es/icons/IMessage/components/Color.mjs.map +1 -1
  330. package/es/icons/IMessage/components/Inner.mjs.map +1 -1
  331. package/es/icons/IMessage/components/Mono.mjs.map +1 -1
  332. package/es/icons/Lark/components/Color.mjs.map +1 -1
  333. package/es/icons/Lark/components/Mono.mjs.map +1 -1
  334. package/es/icons/Line/components/Color.mjs.map +1 -1
  335. package/es/icons/Line/components/Mono.mjs.map +1 -1
  336. package/es/icons/Logto/components/Color.mjs.map +1 -1
  337. package/es/icons/Logto/components/Mono.mjs.map +1 -1
  338. package/es/icons/MicrosoftEntra/components/Color.mjs.map +1 -1
  339. package/es/icons/MicrosoftEntra/components/Mono.mjs.map +1 -1
  340. package/es/icons/MicrosoftTeams/components/Color.mjs.map +1 -1
  341. package/es/icons/MicrosoftTeams/components/Mono.mjs.map +1 -1
  342. package/es/icons/NextAuth/components/Color.mjs.map +1 -1
  343. package/es/icons/NextAuth/components/Mono.mjs.map +1 -1
  344. package/es/icons/QQ/components/Color.mjs.map +1 -1
  345. package/es/icons/QQ/components/Mono.mjs.map +1 -1
  346. package/es/icons/Slack/components/Color.mjs.map +1 -1
  347. package/es/icons/Slack/components/Mono.mjs.map +1 -1
  348. package/es/icons/Telegram/components/Color.mjs.map +1 -1
  349. package/es/icons/Telegram/components/Inner.mjs.map +1 -1
  350. package/es/icons/Telegram/components/Mono.mjs.map +1 -1
  351. package/es/icons/WeChat/components/Color.mjs.map +1 -1
  352. package/es/icons/WeChat/components/Mono.mjs.map +1 -1
  353. package/es/icons/WhatsApp/components/Color.mjs.map +1 -1
  354. package/es/icons/WhatsApp/components/Mono.mjs.map +1 -1
  355. package/es/icons/Zitadel/components/Color.mjs.map +1 -1
  356. package/es/icons/Zitadel/components/Mono.mjs.map +1 -1
  357. package/es/index.d.mts +2 -2
  358. package/es/index.mjs +2 -2
  359. package/es/mdx/Callout/index.mjs.map +1 -1
  360. package/es/mdx/Cards/Card.mjs.map +1 -1
  361. package/es/mdx/FileTree/File.mjs.map +1 -1
  362. package/es/mdx/FileTree/Folder.mjs.map +1 -1
  363. package/es/mdx/Mdx/index.mjs.map +1 -1
  364. package/es/mdx/Tabs/Tab.mjs.map +1 -1
  365. package/es/mdx/Tabs/index.mjs.map +1 -1
  366. package/es/mdx/mdxComponents/Citation/PopoverPanel.mjs.map +1 -1
  367. package/es/mdx/mdxComponents/Citation/index.mjs.map +1 -1
  368. package/es/mdx/mdxComponents/CodeBlock.mjs.map +1 -1
  369. package/es/mdx/mdxComponents/Link.mjs.map +1 -1
  370. package/es/mobile/ChatHeader/ChatHeader.mjs.map +1 -1
  371. package/es/mobile/ChatHeader/ChatHeaderTitle.mjs.map +1 -1
  372. package/es/mobile/ChatInputArea/ChatInputArea.mjs.map +1 -1
  373. package/es/mobile/TabBar/TabBar.mjs.map +1 -1
  374. package/es/storybook/StoryBook/index.mjs.map +1 -1
  375. package/package.json +3 -4
@@ -1 +1 @@
1
- {"version":3,"file":"ScaleRow.mjs","names":["Flexbox"],"sources":["../../../src/color/ColorScales/ScaleRow.tsx"],"sourcesContent":["import { message, Space } from 'antd';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport { copyToClipboard } from '@/utils/copyToClipboard';\n\nimport { alphaBg, styles } from './style';\n\nexport interface IScaleRow {\n name: string;\n scale: string[];\n title: 'light' | 'lightA' | 'dark' | 'darkA';\n}\n\nconst ScaleRow = memo<IScaleRow>(({ name, title, scale }) => {\n let style = {};\n let isAlpha = false;\n\n switch (title) {\n case 'lightA': {\n style = { background: alphaBg.light, backgroundColor: '#fff' };\n isAlpha = true;\n break;\n }\n case 'darkA': {\n style = { background: alphaBg.dark, backgroundColor: '#000' };\n isAlpha = true;\n break;\n }\n default: {\n break;\n }\n }\n\n return (\n <Space size={2}>\n <div className={styles.scaleRowTitle} key={title}>\n <div className={styles.text}>{title}</div>\n </div>\n {scale.map((color, index) => {\n if (index === 0 || index === 12) return false;\n\n return (\n <div\n className={styles.scaleBox}\n key={index}\n style={style}\n title={color}\n onClick={async () => {\n const content = `token.${name}${index}${isAlpha ? 'A' : ''} /* ${color} */`;\n\n await copyToClipboard(content);\n message.success(content);\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{ backgroundColor: color }}\n />\n </div>\n );\n })}\n </Space>\n );\n});\n\nexport default ScaleRow;\n"],"mappings":";;;;;;;AAcA,MAAM,WAAW,MAAiB,EAAE,MAAM,OAAO,YAAY;CAC3D,IAAI,QAAQ,CAAC;CACb,IAAI,UAAU;CAEd,QAAQ,OAAR;EACE,KAAK;GACH,QAAQ;IAAE,YAAY,QAAQ;IAAO,iBAAiB;GAAO;GAC7D,UAAU;GACV;EAEF,KAAK;GACH,QAAQ;IAAE,YAAY,QAAQ;IAAM,iBAAiB;GAAO;GAC5D,UAAU;GACV;EAEF,SACE;CAEJ;CAEA,OACE,qBAAC,OAAD;EAAO,MAAM;YAAb,CACE,oBAAC,OAAD;GAAK,WAAW,OAAO;aACrB,oBAAC,OAAD;IAAK,WAAW,OAAO;cAAO;GAAW,CAAA;EACtC,GAFsC,KAEtC,GACJ,MAAM,KAAK,OAAO,UAAU;GAC3B,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;GAExC,OACE,oBAAC,OAAD;IACE,WAAW,OAAO;IAEX;IACP,OAAO;IACP,SAAS,YAAY;KACnB,MAAM,UAAU,SAAS,OAAO,QAAQ,UAAU,MAAM,GAAG,MAAM,MAAM;KAEvE,MAAM,gBAAgB,OAAO;KAC7B,QAAQ,QAAQ,OAAO;IACzB;cAEA,oBAACA,mBAAD;KACE,YAAA;KACA,OAAO;KACP,WAAW,OAAO;KAClB,SAAS;KACT,OAAO,EAAE,iBAAiB,MAAM;IACjC,CAAA;GACE,GAjBE,KAiBF;EAET,CAAC,CACI;;AAEX,CAAC"}
1
+ {"version":3,"file":"ScaleRow.mjs","names":["Flexbox"],"sources":["../../../src/color/ColorScales/ScaleRow.tsx"],"sourcesContent":["import { message, Space } from 'antd';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport { copyToClipboard } from '@/utils/copyToClipboard';\n\nimport { alphaBg, styles } from './style';\n\nexport interface IScaleRow {\n name: string;\n scale: string[];\n title: 'light' | 'lightA' | 'dark' | 'darkA';\n}\n\nconst ScaleRow = memo<IScaleRow>(({ name, title, scale }) => {\n let style = {};\n let isAlpha = false;\n\n switch (title) {\n case 'lightA': {\n style = { background: alphaBg.light, backgroundColor: '#fff' };\n isAlpha = true;\n break;\n }\n case 'darkA': {\n style = { background: alphaBg.dark, backgroundColor: '#000' };\n isAlpha = true;\n break;\n }\n default: {\n break;\n }\n }\n\n return (\n <Space size={2}>\n <div className={styles.scaleRowTitle} key={title}>\n <div className={styles.text}>{title}</div>\n </div>\n {scale.map((color, index) => {\n if (index === 0 || index === 12) return false;\n\n return (\n <div\n className={styles.scaleBox}\n key={index}\n style={style}\n title={color}\n onClick={async () => {\n const content = `token.${name}${index}${isAlpha ? 'A' : ''} /* ${color} */`;\n\n await copyToClipboard(content);\n message.success(content);\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{ backgroundColor: color }}\n />\n </div>\n );\n })}\n </Space>\n );\n});\n\nexport default ScaleRow;\n"],"mappings":";;;;;;;AAcA,MAAM,WAAW,MAAiB,EAAE,MAAM,OAAO,YAAY;CAC3D,IAAI,QAAQ,CAAC;CACb,IAAI,UAAU;CAEd,QAAQ,OAAR;EACE,KAAK;GACH,QAAQ;IAAE,YAAY,QAAQ;IAAO,iBAAiB;GAAO;GAC7D,UAAU;GACV;EAEF,KAAK;GACH,QAAQ;IAAE,YAAY,QAAQ;IAAM,iBAAiB;GAAO;GAC5D,UAAU;CAMd;CAEA,OACE,qBAAC,OAAD;EAAO,MAAM;EAAb,UAAA,CACE,oBAAC,OAAD;GAAK,WAAW,OAAO;GACrB,UAAA,oBAAC,OAAD;IAAK,WAAW,OAAO;IAAO,UAAA;GAAW,CAAA;EACtC,GAFsC,KAEtC,GACJ,MAAM,KAAK,OAAO,UAAU;GAC3B,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;GAExC,OACE,oBAAC,OAAD;IACE,WAAW,OAAO;IAEX;IACP,OAAO;IACP,SAAS,YAAY;KACnB,MAAM,UAAU,SAAS,OAAO,QAAQ,UAAU,MAAM,GAAG,MAAM,MAAM;KAEvE,MAAM,gBAAgB,OAAO;KAC7B,QAAQ,QAAQ,OAAO;IACzB;IAEA,UAAA,oBAACA,mBAAD;KACE,YAAA;KACA,OAAO;KACP,WAAW,OAAO;KAClB,SAAS;KACT,OAAO,EAAE,iBAAiB,MAAM;IACjC,CAAA;GACE,GAjBE,KAiBF;EAET,CAAC,CACI;;AAEX,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["Flexbox"],"sources":["../../../src/color/ColorScales/index.tsx"],"sourcesContent":["'use client';\n\nimport { Space } from 'antd';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport type { ColorScaleItem } from '../types';\nimport ScaleRow from './ScaleRow';\nimport { styles } from './style';\n\nexport interface ColorScalesProps {\n /**\n * @description Index of the mid highlight color in the scale\n */\n midHighLight: number;\n /**\n * @description Name of the color scale\n */\n name: string;\n /**\n * @description Color scale item object\n */\n scale: ColorScaleItem;\n}\n\nconst ColorScales = memo<ColorScalesProps>(({ name, scale, midHighLight }) => {\n return (\n <Flexbox horizontal align={'center'} flex={1} justify={'center'}>\n <div style={{ padding: '8px 16px 32px 0' }}>\n <Space direction={'vertical'} size={2}>\n <Space key=\"scale-title\" size={2}>\n <Flexbox horizontal align={'center'} className={styles.scaleRowTitle} key=\"scale-num\" />\n {Array.from({ length: scale.light.length })\n .fill('')\n .map((_, index) => {\n if (index === 0 || index === 12) return false;\n\n const isMidHighlight = midHighLight === index;\n\n return (\n <div className={styles.scaleBox} key={`num${index}`}>\n <div className={styles.scaleBox}>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{\n fontWeight: isMidHighlight ? 700 : 400,\n opacity: 0.5,\n }}\n >\n {index}\n </Flexbox>\n </div>\n </div>\n );\n })}\n </Space>\n <ScaleRow key=\"light\" name={name} scale={scale.light} title=\"light\" />\n <ScaleRow key=\"lightA\" name={name} scale={scale.lightA} title=\"lightA\" />\n <ScaleRow key=\"dark\" name={name} scale={scale.dark} title=\"dark\" />\n <ScaleRow key=\"darkA\" name={name} scale={scale.darkA} title=\"darkA\" />\n </Space>\n </div>\n </Flexbox>\n );\n});\n\nexport default ColorScales;\n"],"mappings":";;;;;;;;AA0BA,MAAM,cAAc,MAAwB,EAAE,MAAM,OAAO,mBAAmB;CAC5E,OACE,oBAACA,mBAAD;EAAS,YAAA;EAAW,OAAO;EAAU,MAAM;EAAG,SAAS;YACrD,oBAAC,OAAD;GAAK,OAAO,EAAE,SAAS,kBAAkB;aACvC,qBAAC,OAAD;IAAO,WAAW;IAAY,MAAM;cAApC;KACE,qBAAC,OAAD;MAAyB,MAAM;gBAA/B,CACE,oBAACA,mBAAD;OAAS,YAAA;OAAW,OAAO;OAAU,WAAW,OAAO;MAAgC,GAAb,WAAa,GACtF,MAAM,KAAK,EAAE,QAAQ,MAAM,MAAM,OAAO,CAAC,CAAC,CACxC,KAAK,EAAE,CAAC,CACR,KAAK,GAAG,UAAU;OACjB,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;OAExC,MAAM,iBAAiB,iBAAiB;OAExC,OACE,oBAAC,OAAD;QAAK,WAAW,OAAO;kBACrB,oBAAC,OAAD;SAAK,WAAW,OAAO;mBACrB,oBAACA,mBAAD;UACE,YAAA;UACA,OAAO;UACP,WAAW,OAAO;UAClB,SAAS;UACT,OAAO;WACL,YAAY,iBAAiB,MAAM;WACnC,SAAS;UACX;oBAEC;SACM,CAAA;QACN,CAAA;OACF,GAfiC,MAAM,OAevC;MAET,CAAC,CACE;QA5BI,aA4BJ;KACP,oBAAC,UAAD;MAA4B;MAAM,OAAO,MAAM;MAAO,OAAM;KAAS,GAAvD,OAAuD;KACrE,oBAAC,UAAD;MAA6B;MAAM,OAAO,MAAM;MAAQ,OAAM;KAAU,GAA1D,QAA0D;KACxE,oBAAC,UAAD;MAA2B;MAAM,OAAO,MAAM;MAAM,OAAM;KAAQ,GAApD,MAAoD;KAClE,oBAAC,UAAD;MAA4B;MAAM,OAAO,MAAM;MAAO,OAAM;KAAS,GAAvD,OAAuD;IAChE;;EACJ,CAAA;CACE,CAAA;AAEb,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":["Flexbox"],"sources":["../../../src/color/ColorScales/index.tsx"],"sourcesContent":["'use client';\n\nimport { Space } from 'antd';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport type { ColorScaleItem } from '../types';\nimport ScaleRow from './ScaleRow';\nimport { styles } from './style';\n\nexport interface ColorScalesProps {\n /**\n * @description Index of the mid highlight color in the scale\n */\n midHighLight: number;\n /**\n * @description Name of the color scale\n */\n name: string;\n /**\n * @description Color scale item object\n */\n scale: ColorScaleItem;\n}\n\nconst ColorScales = memo<ColorScalesProps>(({ name, scale, midHighLight }) => {\n return (\n <Flexbox horizontal align={'center'} flex={1} justify={'center'}>\n <div style={{ padding: '8px 16px 32px 0' }}>\n <Space direction={'vertical'} size={2}>\n <Space key=\"scale-title\" size={2}>\n <Flexbox horizontal align={'center'} className={styles.scaleRowTitle} key=\"scale-num\" />\n {Array.from({ length: scale.light.length })\n .fill('')\n .map((_, index) => {\n if (index === 0 || index === 12) return false;\n\n const isMidHighlight = midHighLight === index;\n\n return (\n <div className={styles.scaleBox} key={`num${index}`}>\n <div className={styles.scaleBox}>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{\n fontWeight: isMidHighlight ? 700 : 400,\n opacity: 0.5,\n }}\n >\n {index}\n </Flexbox>\n </div>\n </div>\n );\n })}\n </Space>\n <ScaleRow key=\"light\" name={name} scale={scale.light} title=\"light\" />\n <ScaleRow key=\"lightA\" name={name} scale={scale.lightA} title=\"lightA\" />\n <ScaleRow key=\"dark\" name={name} scale={scale.dark} title=\"dark\" />\n <ScaleRow key=\"darkA\" name={name} scale={scale.darkA} title=\"darkA\" />\n </Space>\n </div>\n </Flexbox>\n );\n});\n\nexport default ColorScales;\n"],"mappings":";;;;;;;;AA0BA,MAAM,cAAc,MAAwB,EAAE,MAAM,OAAO,mBAAmB;CAC5E,OACE,oBAACA,mBAAD;EAAS,YAAA;EAAW,OAAO;EAAU,MAAM;EAAG,SAAS;EACrD,UAAA,oBAAC,OAAD;GAAK,OAAO,EAAE,SAAS,kBAAkB;GACvC,UAAA,qBAAC,OAAD;IAAO,WAAW;IAAY,MAAM;IAApC,UAAA;KACE,qBAAC,OAAD;MAAyB,MAAM;MAA/B,UAAA,CACE,oBAACA,mBAAD;OAAS,YAAA;OAAW,OAAO;OAAU,WAAW,OAAO;MAAgC,GAAb,WAAa,GACtF,MAAM,KAAK,EAAE,QAAQ,MAAM,MAAM,OAAO,CAAC,CAAC,CACxC,KAAK,EAAE,CAAC,CACR,KAAK,GAAG,UAAU;OACjB,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;OAExC,MAAM,iBAAiB,iBAAiB;OAExC,OACE,oBAAC,OAAD;QAAK,WAAW,OAAO;QACrB,UAAA,oBAAC,OAAD;SAAK,WAAW,OAAO;SACrB,UAAA,oBAACA,mBAAD;UACE,YAAA;UACA,OAAO;UACP,WAAW,OAAO;UAClB,SAAS;UACT,OAAO;WACL,YAAY,iBAAiB,MAAM;WACnC,SAAS;UACX;UAEC,UAAA;SACM,CAAA;QACN,CAAA;OACF,GAfiC,MAAM,OAevC;MAET,CAAC,CACE;KA5BI,GAAA,aA4BJ;KACP,oBAAC,UAAD;MAA4B;MAAM,OAAO,MAAM;MAAO,OAAM;KAAS,GAAvD,OAAuD;KACrE,oBAAC,UAAD;MAA6B;MAAM,OAAO,MAAM;MAAQ,OAAM;KAAU,GAA1D,QAA0D;KACxE,oBAAC,UAAD;MAA2B;MAAM,OAAO,MAAM;MAAM,OAAM;KAAQ,GAApD,MAAoD;KAClE,oBAAC,UAAD;MAA4B;MAAM,OAAO,MAAM;MAAO,OAAM;KAAS,GAAvD,OAAuD;IAChE;;EACJ,CAAA;CACE,CAAA;AAEb,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ScaleRow.mjs","names":["Flexbox"],"sources":["../../../src/color/CssVar/ScaleRow.tsx"],"sourcesContent":["import { message, Space } from 'antd';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport { copyToClipboard } from '@/utils/copyToClipboard';\n\nimport { styles } from './style';\n\nexport interface IScaleRow {\n name: string;\n scale: string[];\n title: 'light' | 'dark';\n}\n\nconst ScaleRow = memo<IScaleRow>(({ name, title, scale }) => {\n const style = {};\n const isAlpha = false;\n\n return (\n <Space size={2}>\n <div className={styles.scaleRowTitle} key={title}>\n <div className={styles.text}>{title}</div>\n </div>\n {scale.map((color, index) => {\n if (index === 0 || index === 12) return false;\n\n return (\n <div\n className={styles.scaleBox}\n key={index}\n style={style}\n title={color}\n onClick={async () => {\n const content = `token.${name}${index}${isAlpha ? 'A' : ''} /* ${color} */`;\n\n await copyToClipboard(content);\n message.success(content);\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{ backgroundColor: color }}\n />\n </div>\n );\n })}\n </Space>\n );\n});\n\nexport default ScaleRow;\n"],"mappings":";;;;;;;AAcA,MAAM,WAAW,MAAiB,EAAE,MAAM,OAAO,YAAY;CAC3D,MAAM,QAAQ,CAAC;CAGf,OACE,qBAAC,OAAD;EAAO,MAAM;YAAb,CACE,oBAAC,OAAD;GAAK,WAAW,OAAO;aACrB,oBAAC,OAAD;IAAK,WAAW,OAAO;cAAO;GAAW,CAAA;EACtC,GAFsC,KAEtC,GACJ,MAAM,KAAK,OAAO,UAAU;GAC3B,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;GAExC,OACE,oBAAC,OAAD;IACE,WAAW,OAAO;IAEX;IACP,OAAO;IACP,SAAS,YAAY;KACnB,MAAM,UAAU,SAAS,OAAO,MAAA,MAAiC,MAAM;KAEvE,MAAM,gBAAgB,OAAO;KAC7B,QAAQ,QAAQ,OAAO;IACzB;cAEA,oBAACA,mBAAD;KACE,YAAA;KACA,OAAO;KACP,WAAW,OAAO;KAClB,SAAS;KACT,OAAO,EAAE,iBAAiB,MAAM;IACjC,CAAA;GACE,GAjBE,KAiBF;EAET,CAAC,CACI;;AAEX,CAAC"}
1
+ {"version":3,"file":"ScaleRow.mjs","names":["Flexbox"],"sources":["../../../src/color/CssVar/ScaleRow.tsx"],"sourcesContent":["import { message, Space } from 'antd';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport { copyToClipboard } from '@/utils/copyToClipboard';\n\nimport { styles } from './style';\n\nexport interface IScaleRow {\n name: string;\n scale: string[];\n title: 'light' | 'dark';\n}\n\nconst ScaleRow = memo<IScaleRow>(({ name, title, scale }) => {\n const style = {};\n const isAlpha = false;\n\n return (\n <Space size={2}>\n <div className={styles.scaleRowTitle} key={title}>\n <div className={styles.text}>{title}</div>\n </div>\n {scale.map((color, index) => {\n if (index === 0 || index === 12) return false;\n\n return (\n <div\n className={styles.scaleBox}\n key={index}\n style={style}\n title={color}\n onClick={async () => {\n const content = `token.${name}${index}${isAlpha ? 'A' : ''} /* ${color} */`;\n\n await copyToClipboard(content);\n message.success(content);\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{ backgroundColor: color }}\n />\n </div>\n );\n })}\n </Space>\n );\n});\n\nexport default ScaleRow;\n"],"mappings":";;;;;;;AAcA,MAAM,WAAW,MAAiB,EAAE,MAAM,OAAO,YAAY;CAC3D,MAAM,QAAQ,CAAC;CAGf,OACE,qBAAC,OAAD;EAAO,MAAM;EAAb,UAAA,CACE,oBAAC,OAAD;GAAK,WAAW,OAAO;GACrB,UAAA,oBAAC,OAAD;IAAK,WAAW,OAAO;IAAO,UAAA;GAAW,CAAA;EACtC,GAFsC,KAEtC,GACJ,MAAM,KAAK,OAAO,UAAU;GAC3B,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;GAExC,OACE,oBAAC,OAAD;IACE,WAAW,OAAO;IAEX;IACP,OAAO;IACP,SAAS,YAAY;KACnB,MAAM,UAAU,SAAS,OAAO,MAAA,MAAiC,MAAM;KAEvE,MAAM,gBAAgB,OAAO;KAC7B,QAAQ,QAAQ,OAAO;IACzB;IAEA,UAAA,oBAACA,mBAAD;KACE,YAAA;KACA,OAAO;KACP,WAAW,OAAO;KAClB,SAAS;KACT,OAAO,EAAE,iBAAiB,MAAM;IACjC,CAAA;GACE,GAjBE,KAiBF;EAET,CAAC,CACI;;AAEX,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"VarRow.mjs","names":["Flexbox"],"sources":["../../../src/color/CssVar/VarRow.tsx"],"sourcesContent":["import { message, Space } from 'antd';\nimport { cssVar } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport { copyToClipboard } from '@/utils/copyToClipboard';\n\nimport { styles } from './style';\n\nexport interface IScaleRow {\n name: string;\n}\n\nconst ScaleRow = memo<IScaleRow>(({ name }) => {\n return (\n <Space size={2}>\n <div className={styles.scaleRowTitle} key={name}>\n <div className={styles.text}>cssVar</div>\n </div>\n {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((color) => {\n return (\n <div\n className={styles.scaleBox}\n key={color}\n title={(cssVar as any)[`${name}${color}`] as any}\n onClick={async () => {\n const content = (cssVar as any)[`${name}${color}`] as any;\n\n await copyToClipboard(content);\n message.success(content);\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{ backgroundColor: (cssVar as any)[`${name}${color}`] as any }}\n />\n </div>\n );\n })}\n </Space>\n );\n});\n\nexport default ScaleRow;\n"],"mappings":";;;;;;;;AAaA,MAAM,WAAW,MAAiB,EAAE,WAAW;CAC7C,OACE,qBAAC,OAAD;EAAO,MAAM;YAAb,CACE,oBAAC,OAAD;GAAK,WAAW,OAAO;aACrB,oBAAC,OAAD;IAAK,WAAW,OAAO;cAAM;GAAW,CAAA;EACrC,GAFsC,IAEtC,GACJ;GAAC;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;EAAE,CAAC,CAAC,KAAK,UAAU;GAC9C,OACE,oBAAC,OAAD;IACE,WAAW,OAAO;IAElB,OAAQ,OAAe,GAAG,OAAO;IACjC,SAAS,YAAY;KACnB,MAAM,UAAW,OAAe,GAAG,OAAO;KAE1C,MAAM,gBAAgB,OAAO;KAC7B,QAAQ,QAAQ,OAAO;IACzB;cAEA,oBAACA,mBAAD;KACE,YAAA;KACA,OAAO;KACP,WAAW,OAAO;KAClB,SAAS;KACT,OAAO,EAAE,iBAAkB,OAAe,GAAG,OAAO,SAAgB;IACrE,CAAA;GACE,GAhBE,KAgBF;EAET,CAAC,CACI;;AAEX,CAAC"}
1
+ {"version":3,"file":"VarRow.mjs","names":["Flexbox"],"sources":["../../../src/color/CssVar/VarRow.tsx"],"sourcesContent":["import { message, Space } from 'antd';\nimport { cssVar } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\nimport { copyToClipboard } from '@/utils/copyToClipboard';\n\nimport { styles } from './style';\n\nexport interface IScaleRow {\n name: string;\n}\n\nconst ScaleRow = memo<IScaleRow>(({ name }) => {\n return (\n <Space size={2}>\n <div className={styles.scaleRowTitle} key={name}>\n <div className={styles.text}>cssVar</div>\n </div>\n {[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((color) => {\n return (\n <div\n className={styles.scaleBox}\n key={color}\n title={(cssVar as any)[`${name}${color}`] as any}\n onClick={async () => {\n const content = (cssVar as any)[`${name}${color}`] as any;\n\n await copyToClipboard(content);\n message.success(content);\n }}\n >\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{ backgroundColor: (cssVar as any)[`${name}${color}`] as any }}\n />\n </div>\n );\n })}\n </Space>\n );\n});\n\nexport default ScaleRow;\n"],"mappings":";;;;;;;;AAaA,MAAM,WAAW,MAAiB,EAAE,WAAW;CAC7C,OACE,qBAAC,OAAD;EAAO,MAAM;EAAb,UAAA,CACE,oBAAC,OAAD;GAAK,WAAW,OAAO;GACrB,UAAA,oBAAC,OAAD;IAAK,WAAW,OAAO;IAAM,UAAA;GAAW,CAAA;EACrC,GAFsC,IAEtC,GACJ;GAAC;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;GAAG;EAAE,CAAC,CAAC,KAAK,UAAU;GAC9C,OACE,oBAAC,OAAD;IACE,WAAW,OAAO;IAElB,OAAQ,OAAe,GAAG,OAAO;IACjC,SAAS,YAAY;KACnB,MAAM,UAAW,OAAe,GAAG,OAAO;KAE1C,MAAM,gBAAgB,OAAO;KAC7B,QAAQ,QAAQ,OAAO;IACzB;IAEA,UAAA,oBAACA,mBAAD;KACE,YAAA;KACA,OAAO;KACP,WAAW,OAAO;KAClB,SAAS;KACT,OAAO,EAAE,iBAAkB,OAAe,GAAG,OAAO,SAAgB;IACrE,CAAA;GACE,GAhBE,KAgBF;EAET,CAAC,CACI;;AAEX,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["Flexbox","VarRow"],"sources":["../../../src/color/CssVar/index.tsx"],"sourcesContent":["'use client';\n\nimport { Space } from 'antd';\nimport { useThemeMode } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport { type ColorScaleItem } from '../types';\nimport ScaleRow from './ScaleRow';\nimport { styles } from './style';\nimport VarRow from './VarRow';\n\nexport interface ColorScalesProps {\n /**\n * @description Index of the mid highlight color in the scale\n */\n midHighLight: number;\n /**\n * @description Name of the color scale\n */\n name: string;\n /**\n * @description Color scale item object\n */\n scale: ColorScaleItem;\n}\n\nconst ColorScales = memo<ColorScalesProps>(({ name, scale, midHighLight }) => {\n const { isDarkMode } = useThemeMode();\n return (\n <Flexbox horizontal align={'center'} flex={1} justify={'center'}>\n <div style={{ padding: '8px 16px 32px 0' }}>\n <Space direction={'vertical'} size={2}>\n <Space key=\"scale-title\" size={2}>\n <Flexbox horizontal align={'center'} className={styles.scaleRowTitle} key=\"scale-num\" />\n {Array.from({ length: scale.light.length })\n .fill('')\n .map((_, index) => {\n if (index === 0 || index === 12) return false;\n\n const isMidHighlight = midHighLight === index;\n\n return (\n <div className={styles.scaleBox} key={`num${index}`}>\n <div className={styles.scaleBox}>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{\n fontWeight: isMidHighlight ? 700 : 400,\n opacity: 0.5,\n }}\n >\n {index}\n </Flexbox>\n </div>\n </div>\n );\n })}\n </Space>\n <VarRow name={name} />\n {isDarkMode ? (\n <>\n <ScaleRow key=\"dark\" name={name} scale={scale.dark} title=\"dark\" />\n <ScaleRow key=\"light\" name={name} scale={scale.light} title=\"light\" />\n </>\n ) : (\n <>\n {' '}\n <ScaleRow key=\"light\" name={name} scale={scale.light} title=\"light\" />\n <ScaleRow key=\"dark\" name={name} scale={scale.dark} title=\"dark\" />\n </>\n )}\n </Space>\n </div>\n </Flexbox>\n );\n});\n\nexport default ColorScales;\n"],"mappings":";;;;;;;;;;AA4BA,MAAM,cAAc,MAAwB,EAAE,MAAM,OAAO,mBAAmB;CAC5E,MAAM,EAAE,eAAe,aAAa;CACpC,OACE,oBAACA,mBAAD;EAAS,YAAA;EAAW,OAAO;EAAU,MAAM;EAAG,SAAS;YACrD,oBAAC,OAAD;GAAK,OAAO,EAAE,SAAS,kBAAkB;aACvC,qBAAC,OAAD;IAAO,WAAW;IAAY,MAAM;cAApC;KACE,qBAAC,OAAD;MAAyB,MAAM;gBAA/B,CACE,oBAACA,mBAAD;OAAS,YAAA;OAAW,OAAO;OAAU,WAAW,OAAO;MAAgC,GAAb,WAAa,GACtF,MAAM,KAAK,EAAE,QAAQ,MAAM,MAAM,OAAO,CAAC,CAAC,CACxC,KAAK,EAAE,CAAC,CACR,KAAK,GAAG,UAAU;OACjB,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;OAExC,MAAM,iBAAiB,iBAAiB;OAExC,OACE,oBAAC,OAAD;QAAK,WAAW,OAAO;kBACrB,oBAAC,OAAD;SAAK,WAAW,OAAO;mBACrB,oBAACA,mBAAD;UACE,YAAA;UACA,OAAO;UACP,WAAW,OAAO;UAClB,SAAS;UACT,OAAO;WACL,YAAY,iBAAiB,MAAM;WACnC,SAAS;UACX;oBAEC;SACM,CAAA;QACN,CAAA;OACF,GAfiC,MAAM,OAevC;MAET,CAAC,CACE;QA5BI,aA4BJ;KACP,oBAACC,YAAD,EAAc,KAAO,CAAA;KACpB,aACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,UAAD;MAA2B;MAAM,OAAO,MAAM;MAAM,OAAM;KAAQ,GAApD,MAAoD,GAClE,oBAAC,UAAD;MAA4B;MAAM,OAAO,MAAM;MAAO,OAAM;KAAS,GAAvD,OAAuD,CACrE,EAAA,CAAA,IAEF,qBAAA,YAAA,EAAA,UAAA;MACG;MACD,oBAAC,UAAD;OAA4B;OAAM,OAAO,MAAM;OAAO,OAAM;MAAS,GAAvD,OAAuD;MACrE,oBAAC,UAAD;OAA2B;OAAM,OAAO,MAAM;OAAM,OAAM;MAAQ,GAApD,MAAoD;KAClE,EAAA,CAAA;IAEC;;EACJ,CAAA;CACE,CAAA;AAEb,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":["Flexbox","VarRow"],"sources":["../../../src/color/CssVar/index.tsx"],"sourcesContent":["'use client';\n\nimport { Space } from 'antd';\nimport { useThemeMode } from 'antd-style';\nimport { memo } from 'react';\n\nimport { Flexbox } from '@/Flex';\n\nimport { type ColorScaleItem } from '../types';\nimport ScaleRow from './ScaleRow';\nimport { styles } from './style';\nimport VarRow from './VarRow';\n\nexport interface ColorScalesProps {\n /**\n * @description Index of the mid highlight color in the scale\n */\n midHighLight: number;\n /**\n * @description Name of the color scale\n */\n name: string;\n /**\n * @description Color scale item object\n */\n scale: ColorScaleItem;\n}\n\nconst ColorScales = memo<ColorScalesProps>(({ name, scale, midHighLight }) => {\n const { isDarkMode } = useThemeMode();\n return (\n <Flexbox horizontal align={'center'} flex={1} justify={'center'}>\n <div style={{ padding: '8px 16px 32px 0' }}>\n <Space direction={'vertical'} size={2}>\n <Space key=\"scale-title\" size={2}>\n <Flexbox horizontal align={'center'} className={styles.scaleRowTitle} key=\"scale-num\" />\n {Array.from({ length: scale.light.length })\n .fill('')\n .map((_, index) => {\n if (index === 0 || index === 12) return false;\n\n const isMidHighlight = midHighLight === index;\n\n return (\n <div className={styles.scaleBox} key={`num${index}`}>\n <div className={styles.scaleBox}>\n <Flexbox\n horizontal\n align={'center'}\n className={styles.scaleItem}\n justify={'center'}\n style={{\n fontWeight: isMidHighlight ? 700 : 400,\n opacity: 0.5,\n }}\n >\n {index}\n </Flexbox>\n </div>\n </div>\n );\n })}\n </Space>\n <VarRow name={name} />\n {isDarkMode ? (\n <>\n <ScaleRow key=\"dark\" name={name} scale={scale.dark} title=\"dark\" />\n <ScaleRow key=\"light\" name={name} scale={scale.light} title=\"light\" />\n </>\n ) : (\n <>\n {' '}\n <ScaleRow key=\"light\" name={name} scale={scale.light} title=\"light\" />\n <ScaleRow key=\"dark\" name={name} scale={scale.dark} title=\"dark\" />\n </>\n )}\n </Space>\n </div>\n </Flexbox>\n );\n});\n\nexport default ColorScales;\n"],"mappings":";;;;;;;;;;AA4BA,MAAM,cAAc,MAAwB,EAAE,MAAM,OAAO,mBAAmB;CAC5E,MAAM,EAAE,eAAe,aAAa;CACpC,OACE,oBAACA,mBAAD;EAAS,YAAA;EAAW,OAAO;EAAU,MAAM;EAAG,SAAS;EACrD,UAAA,oBAAC,OAAD;GAAK,OAAO,EAAE,SAAS,kBAAkB;GACvC,UAAA,qBAAC,OAAD;IAAO,WAAW;IAAY,MAAM;IAApC,UAAA;KACE,qBAAC,OAAD;MAAyB,MAAM;MAA/B,UAAA,CACE,oBAACA,mBAAD;OAAS,YAAA;OAAW,OAAO;OAAU,WAAW,OAAO;MAAgC,GAAb,WAAa,GACtF,MAAM,KAAK,EAAE,QAAQ,MAAM,MAAM,OAAO,CAAC,CAAC,CACxC,KAAK,EAAE,CAAC,CACR,KAAK,GAAG,UAAU;OACjB,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;OAExC,MAAM,iBAAiB,iBAAiB;OAExC,OACE,oBAAC,OAAD;QAAK,WAAW,OAAO;QACrB,UAAA,oBAAC,OAAD;SAAK,WAAW,OAAO;SACrB,UAAA,oBAACA,mBAAD;UACE,YAAA;UACA,OAAO;UACP,WAAW,OAAO;UAClB,SAAS;UACT,OAAO;WACL,YAAY,iBAAiB,MAAM;WACnC,SAAS;UACX;UAEC,UAAA;SACM,CAAA;QACN,CAAA;OACF,GAfiC,MAAM,OAevC;MAET,CAAC,CACE;KA5BI,GAAA,aA4BJ;KACP,oBAACC,YAAD,EAAc,KAAO,CAAA;KACpB,aACC,qBAAA,YAAA,EAAA,UAAA,CACE,oBAAC,UAAD;MAA2B;MAAM,OAAO,MAAM;MAAM,OAAM;KAAQ,GAApD,MAAoD,GAClE,oBAAC,UAAD;MAA4B;MAAM,OAAO,MAAM;MAAO,OAAM;KAAS,GAAvD,OAAuD,CACrE,EAAA,CAAA,IAEF,qBAAA,YAAA,EAAA,UAAA;MACG;MACD,oBAAC,UAAD;OAA4B;OAAM,OAAO,MAAM;OAAO,OAAM;MAAS,GAAvD,OAAuD;MACrE,oBAAC,UAAD;OAA2B;OAAM,OAAO,MAAM;OAAM,OAAM;MAAQ,GAApD,MAAoD;KAClE,EAAA,CAAA;IAEC;;EACJ,CAAA;CACE,CAAA;AAEb,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"latex.mjs","names":[],"sources":["../../../src/hooks/useMarkdown/latex.ts"],"sourcesContent":["import { renderToString } from 'katex';\n\n// ============================================================================\n// Utility Classes\n// ============================================================================\n\n/**\n * PlaceholderManager - Manages temporary replacement and restoration of protected content\n * Used to protect code blocks and LaTeX expressions during preprocessing\n */\nclass PlaceholderManager {\n private placeholders: string[] = [];\n private prefix: string;\n\n constructor(prefix = 'PROTECTED') {\n this.prefix = prefix;\n }\n\n add(content: string): string {\n const index = this.placeholders.length;\n this.placeholders.push(content);\n return `<<${this.prefix}_${index}>>`;\n }\n\n restore(text: string): string {\n return text.replaceAll(new RegExp(`<<${this.prefix}_(\\\\d+)>>`, 'g'), (_, index) => {\n return this.placeholders[Number.parseInt(index)] || '';\n });\n }\n\n clear(): void {\n this.placeholders = [];\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n// Helper: replace unescaped pipes with \\vert within a LaTeX math fragment\nconst replaceUnescapedPipes = (formula: string): string =>\n // Use \\vert{} so the control sequence terminates before the next token\n formula.replaceAll(/(?<!\\\\)\\|/g, '\\\\vert{}');\n\n/**\n * Converts LaTeX bracket delimiters to dollar sign delimiters.\n * Converts \\[...\\] to $$...$$ and \\(...\\) to $...$\n * Preserves code blocks during the conversion.\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with LaTeX bracket delimiters converted to dollar sign delimiters\n */\nexport function convertLatexDelimiters(text: string): string {\n const pattern = /(```[\\s\\S]*?```|`.*?`)|\\\\\\[([\\s\\S]*?[^\\\\])\\\\\\]|\\\\\\((.*?)\\\\\\)/g;\n return text.replaceAll(\n pattern,\n (\n match: string,\n codeBlock: string | undefined,\n squareBracket: string | undefined,\n roundBracket: string | undefined,\n ): string => {\n if (codeBlock !== undefined) {\n return codeBlock;\n } else if (squareBracket !== undefined) {\n return `$$${squareBracket}$$`;\n } else if (roundBracket !== undefined) {\n return `$${roundBracket}$`;\n }\n return match;\n },\n );\n}\n\n/**\n * Escapes mhchem commands in LaTeX expressions to ensure proper rendering.\n *\n * @param text The input string containing LaTeX expressions with mhchem commands\n * @returns The string with escaped mhchem commands\n */\nexport function escapeMhchemCommands(text: string) {\n return text.replaceAll('$\\\\ce{', '$\\\\\\\\ce{').replaceAll('$\\\\pu{', '$\\\\\\\\pu{');\n}\n\n/**\n * Escapes pipe characters within LaTeX expressions to prevent them from being interpreted\n * as table column separators in markdown tables.\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with pipe characters escaped in LaTeX expressions\n */\nexport function escapeLatexPipes(text: string): string {\n // Replace unescaped '|' inside LaTeX math spans with '\\vert' so that\n // remark-gfm table parsing won't treat them as column separators.\n // Leave code blocks/inline code untouched.\n // Also ignore escaped dollars (\\$) which are currency symbols\n\n // Process code blocks first to protect them\n const codeBlocks: string[] = [];\n let content = text.replaceAll(/(```[\\s\\S]*?```|`[^\\n`]*`)/g, (match) => {\n codeBlocks.push(match);\n return `<<CODE_${codeBlocks.length - 1}>>`;\n });\n\n // For display math, allow multiline\n content = content.replaceAll(/\\$\\$([\\s\\S]*?)\\$\\$/g, (match, display) => {\n return `$$${replaceUnescapedPipes(display)}$$`;\n });\n\n // For inline math, use non-greedy match that DOES NOT cross newlines\n // This prevents issues in tables where $ might appear in different cells\n content = content.replaceAll(/(?<!\\\\)\\$(?!\\$)([^\\n$]*)(?<!\\\\)\\$(?!\\$)/g, (match, inline) => {\n return `$${replaceUnescapedPipes(inline)}$`;\n });\n\n // Restore code blocks\n content = content.replaceAll(/<<CODE_(\\d+)>>/g, (_, index) => {\n return codeBlocks[Number.parseInt(index)];\n });\n\n return content;\n}\n\n/**\n * Escapes underscores within \\text{...} commands in LaTeX expressions\n * that are not already escaped.\n * For example, \\text{node_domain} becomes \\text{node\\_domain},\n * but \\text{node\\_domain} remains \\text{node\\_domain}.\n *\n * @param text The input string potentially containing LaTeX expressions\n * @returns The string with unescaped underscores escaped within \\text{...} commands\n */\nexport function escapeTextUnderscores(text: string): string {\n return text.replaceAll(/\\\\text\\{([^}]*)\\}/g, (match, textContent: string) => {\n // textContent is the content within the braces, e.g., \"node_domain\" or \"already\\_escaped\"\n // Replace underscores '_' with '\\_' only if they are NOT preceded by a backslash '\\'.\n // The (?<!\\\\) is a negative lookbehind assertion that ensures the character before '_' is not a '\\'.\n const escapedTextContent = textContent.replaceAll(/(?<!\\\\)_/g, '\\\\_');\n return `\\\\text{${escapedTextContent}}`;\n });\n}\n\n/**\n * Escapes dollar signs that appear to be currency symbols to prevent them from being\n * interpreted as LaTeX math delimiters.\n *\n * This function identifies currency patterns such as:\n * - $20, $100, $1,000\n * - $20-50, $100+\n * - Patterns within markdown tables\n *\n * @param text The input string containing potential currency symbols\n * @returns The string with currency dollar signs escaped\n */\nexport function escapeCurrencyDollars(text: string): string {\n // Protect code blocks and existing LaTeX expressions from processing\n const manager = new PlaceholderManager('PROTECTED');\n\n let content = text.replaceAll(\n // Match patterns to protect (in order):\n // 1. Code blocks: ```...```\n // 2. Inline code: `...`\n // 3. Display math: $$...$$\n // 4. Inline math with LaTeX commands: $...\\...$ (must contain backslash to distinguish from currency)\n // 5. Simple number formulas: $1$, $10$, $100$ (pure digits in math mode)\n // 6. Number lists in math mode: $1,-1,0$ or $1,2,3$ (comma-separated numbers, possibly negative)\n // 7. LaTeX bracket notation: \\[...\\]\n // 8. LaTeX parenthesis notation: \\(...\\)\n /(```[\\s\\S]*?```|`[^\\n`]*`|\\$\\$[\\s\\S]*?\\$\\$|(?<!\\\\)\\$(?!\\$)(?=[\\s\\S]*?\\\\)[\\s\\S]*?(?<!\\\\)\\$(?!\\$)|\\$\\d+\\$|\\$-?\\d+(?:,-?\\d+)+\\$|\\\\\\[[\\s\\S]*?\\\\\\]|\\\\\\(.*?\\\\\\))/g,\n (match) => manager.add(match),\n );\n\n // Escape dollar signs that are clearly currency:\n // - $ followed by a digit\n // - Not preceded by another $ (to avoid breaking $$)\n // - Not followed immediately by another $ (to avoid breaking $1$ LaTeX)\n // - Followed by number patterns with optional commas, decimals, ranges, or plus signs\n // Match patterns like: $20, $1,000, $19.99, $20-50, $300+, $1,000-2,000+\n // But NOT: $1$, $2$ (these are LaTeX formulas)\n // In the replacement: \\\\ = backslash, $$ = literal $, $1 = capture group 1\n content = content.replaceAll(\n /(?<!\\$)\\$(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?(?:-\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?)?\\+?)(?!\\$)/g,\n '\\\\$$$1',\n );\n\n // Restore protected content\n content = manager.restore(content);\n\n return content;\n}\n\n// Old simple preprocessLaTeX has been replaced by the comprehensive version below\n// The new preprocessLaTeX provides the same default behavior with optional advanced featuresgit\n\n/**\n * Extracts the LaTeX formula after the last $$ delimiter if there's an odd number of $$ delimiters.\n *\n * @param text The input string containing LaTeX formulas\n * @returns The content after the last $$ if there's an odd number of $$, otherwise an empty string\n */\nconst extractIncompleteFormula = (text: string) => {\n // Count the number of $$ delimiters\n const dollarsCount = (text.match(/\\$\\$/g) || []).length;\n\n // If odd number of $$ delimiters, extract content after the last $$\n if (dollarsCount % 2 === 1) {\n const match = text.match(/\\$\\$([\\s\\S]*)$/);\n return match ? match[1] : '';\n }\n\n // If even number of $$ delimiters, return empty string\n return '';\n};\n\n/**\n * Checks if the last LaTeX formula in the text is renderable.\n * Only validates the formula after the last $$ if there's an odd number of $$.\n *\n * @param text The input string containing LaTeX formulas\n * @returns True if the last formula is renderable or if there's no incomplete formula\n */\nexport const isLastFormulaRenderable = (text: string) => {\n const formula = extractIncompleteFormula(text);\n\n // If no incomplete formula, return true\n if (!formula) return true;\n\n // Try to render the last formula\n try {\n renderToString(formula, {\n displayMode: true,\n throwOnError: true,\n });\n return true;\n } catch (error) {\n console.error(`LaTeX formula rendering error: ${error}`);\n return false;\n }\n};\n\n// ============================================================================\n// Advanced Preprocessing Functions\n// ============================================================================\n\n/**\n * Fixes common LaTeX syntax errors automatically\n * - Balances unmatched braces\n * - Balances \\left and \\right delimiters\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with fixed LaTeX expressions\n */\nexport function fixCommonLaTeXErrors(text: string): string {\n return text.replaceAll(/(\\$\\$[\\s\\S]*?\\$\\$|\\$[\\s\\S]*?\\$)/g, (match) => {\n let fixed = match;\n\n // Fix unbalanced braces\n const openBraces = (fixed.match(/(?<!\\\\)\\{/g) || []).length;\n const closeBraces = (fixed.match(/(?<!\\\\)\\}/g) || []).length;\n if (openBraces > closeBraces) {\n const diff = openBraces - closeBraces;\n const closingBraces = '}'.repeat(diff);\n // Insert before the closing delimiter\n fixed = fixed.replace(/(\\$\\$?)$/, closingBraces + '$1');\n }\n\n // Fix unbalanced \\left and \\right\n const leftDelims = (fixed.match(/\\\\left[(.<[{|]/g) || []).length;\n const rightDelims = (fixed.match(/\\\\right[).>\\]|}]/g) || []).length;\n if (leftDelims > rightDelims) {\n const diff = leftDelims - rightDelims;\n const rightDots = '\\\\right.'.repeat(diff);\n fixed = fixed.replace(/(\\$\\$?)$/, rightDots + '$1');\n }\n\n return fixed;\n });\n}\n\n/**\n * Normalizes whitespace in LaTeX expressions\n * - Removes extra spaces around $ delimiters\n * - Normalizes multiple spaces to single space inside formulas\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with normalized whitespace\n */\nexport function normalizeLatexSpacing(text: string): string {\n let result = text;\n\n // Remove spaces inside $ delimiters (at the edges)\n result = result.replaceAll(/\\$\\s+/g, '$');\n result = result.replaceAll(/\\s+\\$/g, '$');\n result = result.replaceAll(/\\$\\$\\s+/g, '$$');\n result = result.replaceAll(/\\s+\\$\\$/g, '$$');\n\n // Normalize multiple spaces inside formulas to single space\n result = result.replaceAll(/(\\$\\$[\\s\\S]*?\\$\\$|\\$[\\s\\S]*?\\$)/g, (match) => {\n return match.replaceAll(/\\s{2,}/g, ' ');\n });\n\n return result;\n}\n\n/**\n * Validates all LaTeX expressions in the text\n * Returns detailed information about validation results\n *\n * @param text The input string containing LaTeX expressions\n * @returns Validation results with errors if any\n */\nexport function validateLatexExpressions(text: string): {\n errors: Array<{\n formula: string;\n message: string;\n position: number;\n type: 'display' | 'inline';\n }>;\n totalExpressions: number;\n valid: boolean;\n} {\n const errors: Array<{\n formula: string;\n message: string;\n position: number;\n type: 'display' | 'inline';\n }> = [];\n\n let totalExpressions = 0;\n const pattern = /\\$\\$([\\s\\S]*?)\\$\\$|(?<!\\\\)\\$(?!\\$)([\\s\\S]*?)(?<!\\\\)\\$(?!\\$)/g;\n let match;\n\n while ((match = pattern.exec(text)) !== null) {\n totalExpressions++;\n const formula = match[1] || match[2];\n const isDisplay = match[0].startsWith('$$');\n\n try {\n renderToString(formula, {\n displayMode: isDisplay,\n strict: 'warn',\n throwOnError: true,\n trust: false,\n });\n } catch (error) {\n errors.push({\n formula: formula.slice(0, 50) + (formula.length > 50 ? '...' : ''),\n message: error instanceof Error ? error.message : String(error),\n position: match.index,\n type: isDisplay ? 'display' : 'inline',\n });\n }\n }\n\n return {\n errors,\n totalExpressions,\n valid: errors.length === 0,\n };\n}\n\n/**\n * Handles CJK (Chinese, Japanese, Korean) characters mixed with LaTeX\n * Optionally adds spaces between CJK characters and LaTeX expressions for better rendering\n *\n * @param text The input string\n * @param addSpaces Whether to add spaces between CJK and LaTeX (default: false)\n * @returns The processed string\n */\nexport function handleCJKWithLatex(text: string, addSpaces = false): string {\n if (!addSpaces) return text;\n\n let result = text;\n\n // Add space between CJK character and opening $\n result = result.replaceAll(/([\\u3040-\\u30FF\\u4E00-\\u9FA5])(\\$)/g, '$1 $2');\n\n // Add space between closing $ and CJK character\n result = result.replaceAll(/(\\$)([\\u3040-\\u30FF\\u4E00-\\u9FA5])/g, '$1 $2');\n\n return result;\n}\n\n// ============================================================================\n// Advanced Preprocessing Options\n// ============================================================================\n\nexport interface AdvancedPreprocessOptions {\n /** Add spaces between CJK and LaTeX (default: false, requires handleCJK: true) */\n addCJKSpaces?: boolean;\n /** Convert bracket notation \\[...\\] to $$...$$ (default: true) */\n convertBrackets?: boolean;\n /** Enable currency escaping (default: true) */\n escapeCurrency?: boolean;\n /** Escape mhchem commands (default: true) */\n escapeMhchem?: boolean;\n /** Escape pipe symbols in LaTeX (default: true) */\n escapePipes?: boolean;\n /** Escape underscores in \\text{} (default: true) */\n escapeUnderscores?: boolean;\n /** Automatically fix common LaTeX errors (default: false) */\n fixErrors?: boolean;\n /** Handle CJK characters (default: false) */\n handleCJK?: boolean;\n /** Normalize whitespace (default: false) */\n normalizeSpacing?: boolean;\n /** Throw error on validation failure (default: false, requires validate: true) */\n throwOnValidationError?: boolean;\n /** Validate LaTeX syntax (default: false) */\n validate?: boolean;\n}\n\n/**\n * Comprehensive LaTeX preprocessing with configurable options\n *\n * This is the main preprocessing function that handles:\n * - Currency symbol escaping (e.g., $20 → \\$20)\n * - LaTeX delimiter conversion (\\[...\\] → $$...$$)\n * - Special character escaping (pipes, underscores, mhchem)\n * - Optional error fixing and validation\n * - Optional CJK character handling\n *\n * @param text The input string containing LaTeX and Markdown\n * @param options Configuration options for fine-grained control\n * @returns The preprocessed string\n *\n * @example\n * ```ts\n * // Default behavior (same as old preprocessLaTeX)\n * preprocessLaTeX('向量$90^\\\\circ$,非 $0^\\\\circ$ 和 $180^\\\\circ$')\n *\n * // With custom options\n * preprocessLaTeX(text, {\n * fixErrors: true,\n * validate: true,\n * handleCJK: true\n * })\n * ```\n */\nexport function preprocessLaTeX(text: string, options: AdvancedPreprocessOptions = {}): string {\n const {\n addCJKSpaces = false,\n convertBrackets = true,\n escapeCurrency = true,\n escapeMhchem = true,\n escapePipes = true,\n escapeUnderscores = true,\n fixErrors = false,\n handleCJK = false,\n normalizeSpacing = false,\n throwOnValidationError = false,\n validate = false,\n } = options;\n\n let content = text;\n\n // Phase 1: Currency escaping (if enabled)\n if (escapeCurrency) {\n content = escapeCurrencyDollars(content);\n }\n\n // Phase 2: Bracket conversion (if enabled)\n if (convertBrackets) {\n content = convertLatexDelimiters(content);\n }\n\n // Phase 3: LaTeX-specific escaping\n if (escapeMhchem) {\n content = escapeMhchemCommands(content);\n }\n\n if (escapePipes) {\n content = escapeLatexPipes(content);\n }\n\n if (escapeUnderscores) {\n content = escapeTextUnderscores(content);\n }\n\n // Phase 4: Error fixing (if enabled)\n if (fixErrors) {\n content = fixCommonLaTeXErrors(content);\n }\n\n // Phase 5: Whitespace normalization (if enabled)\n if (normalizeSpacing) {\n content = normalizeLatexSpacing(content);\n }\n\n // Phase 6: CJK handling (if enabled)\n if (handleCJK) {\n content = handleCJKWithLatex(content, addCJKSpaces);\n }\n\n // Phase 7: Validation (if enabled)\n if (validate) {\n const validation = validateLatexExpressions(content);\n if (!validation.valid) {\n const errorMessage = `LaTeX validation failed (${validation.errors.length}/${validation.totalExpressions} expressions have errors):\\n${validation.errors.map((e) => ` - [${e.type}] at position ${e.position}: ${e.message}\\n Formula: ${e.formula}`).join('\\n')}`;\n\n if (throwOnValidationError) {\n throw new Error(errorMessage);\n } else {\n console.warn(errorMessage);\n }\n }\n }\n\n return content;\n}\n\n/**\n * Strict preprocessing mode - enables all safety features and validations\n * Use this when you want maximum correctness and are willing to accept the performance cost\n *\n * @param text The input string\n * @returns The preprocessed string with all features enabled\n *\n * @example\n * ```ts\n * const processed = preprocessLaTeXStrict(userInput)\n * // Enables: error fixing, validation, CJK handling, space normalization\n * ```\n */\nexport function preprocessLaTeXStrict(text: string): string {\n return preprocessLaTeX(text, {\n addCJKSpaces: false, // Usually don't want extra spaces\n convertBrackets: true,\n escapeCurrency: true,\n escapeMhchem: true,\n escapePipes: true,\n escapeUnderscores: true,\n fixErrors: true,\n handleCJK: true,\n normalizeSpacing: true,\n throwOnValidationError: false, // Warn but don't throw\n validate: true,\n });\n}\n\n/**\n * Minimal preprocessing mode - only essential operations\n * Use this for better performance when you control the input\n *\n * @param text The input string\n * @returns The preprocessed string with minimal processing\n *\n * @example\n * ```ts\n * const processed = preprocessLaTeXMinimal(trustedInput)\n * // Only escapes currency and converts brackets\n * ```\n */\nexport function preprocessLaTeXMinimal(text: string): string {\n return preprocessLaTeX(text, {\n convertBrackets: true,\n escapeCurrency: true,\n escapeMhchem: false,\n escapePipes: false,\n escapeUnderscores: false,\n fixErrors: false,\n handleCJK: false,\n normalizeSpacing: false,\n validate: false,\n });\n}\n"],"mappings":";;;;;;AAUA,IAAM,qBAAN,MAAyB;CAIvB,YAAY,SAAS,aAAa;sBAHD,CAAC;EAIhC,KAAK,SAAS;CAChB;CAEA,IAAI,SAAyB;EAC3B,MAAM,QAAQ,KAAK,aAAa;EAChC,KAAK,aAAa,KAAK,OAAO;EAC9B,OAAO,KAAK,KAAK,OAAO,GAAG,MAAM;CACnC;CAEA,QAAQ,MAAsB;EAC5B,OAAO,KAAK,WAAW,IAAI,OAAO,KAAK,KAAK,OAAO,YAAY,GAAG,IAAI,GAAG,UAAU;GACjF,OAAO,KAAK,aAAa,OAAO,SAAS,KAAK,MAAM;EACtD,CAAC;CACH;CAEA,QAAc;EACZ,KAAK,eAAe,CAAC;CACvB;AACF;AAOA,MAAM,yBAAyB,YAE7B,QAAQ,WAAW,cAAc,UAAU;;;;;;;;;AAU7C,SAAgB,uBAAuB,MAAsB;CAE3D,OAAO,KAAK,WACV,kEAEE,OACA,WACA,eACA,iBACW;EACX,IAAI,cAAc,KAAA,GAChB,OAAO;OACF,IAAI,kBAAkB,KAAA,GAC3B,OAAO,KAAK,cAAc;OACrB,IAAI,iBAAiB,KAAA,GAC1B,OAAO,IAAI,aAAa;EAE1B,OAAO;CACT,CACF;AACF;;;;;;;AAQA,SAAgB,qBAAqB,MAAc;CACjD,OAAO,KAAK,WAAW,UAAU,UAAU,CAAC,CAAC,WAAW,UAAU,UAAU;AAC9E;;;;;;;;AASA,SAAgB,iBAAiB,MAAsB;CAOrD,MAAM,aAAuB,CAAC;CAC9B,IAAI,UAAU,KAAK,WAAW,gCAAgC,UAAU;EACtE,WAAW,KAAK,KAAK;EACrB,OAAO,UAAU,WAAW,SAAS,EAAE;CACzC,CAAC;CAGD,UAAU,QAAQ,WAAW,wBAAwB,OAAO,YAAY;EACtE,OAAO,KAAK,sBAAsB,OAAO,EAAE;CAC7C,CAAC;CAID,UAAU,QAAQ,WAAW,6CAA6C,OAAO,WAAW;EAC1F,OAAO,IAAI,sBAAsB,MAAM,EAAE;CAC3C,CAAC;CAGD,UAAU,QAAQ,WAAW,oBAAoB,GAAG,UAAU;EAC5D,OAAO,WAAW,OAAO,SAAS,KAAK;CACzC,CAAC;CAED,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,sBAAsB,MAAsB;CAC1D,OAAO,KAAK,WAAW,uBAAuB,OAAO,gBAAwB;EAK3E,OAAO,UADoB,YAAY,WAAW,aAAa,KAC7B,EAAE;CACtC,CAAC;AACH;;;;;;;;;;;;;AAcA,SAAgB,sBAAsB,MAAsB;CAE1D,MAAM,UAAU,IAAI,mBAAmB,WAAW;CAElD,IAAI,UAAU,KAAK,WAUjB,gKACC,UAAU,QAAQ,IAAI,KAAK,CAC9B;CAUA,UAAU,QAAQ,WAChB,uFACA,QACF;CAGA,UAAU,QAAQ,QAAQ,OAAO;CAEjC,OAAO;AACT;;;;;;;AAWA,MAAM,4BAA4B,SAAiB;CAKjD,KAHsB,KAAK,MAAM,OAAO,KAAK,CAAC,EAAA,CAAG,SAG9B,MAAM,GAAG;EAC1B,MAAM,QAAQ,KAAK,MAAM,gBAAgB;EACzC,OAAO,QAAQ,MAAM,KAAK;CAC5B;CAGA,OAAO;AACT;;;;;;;;AASA,MAAa,2BAA2B,SAAiB;CACvD,MAAM,UAAU,yBAAyB,IAAI;CAG7C,IAAI,CAAC,SAAS,OAAO;CAGrB,IAAI;EACF,eAAe,SAAS;GACtB,aAAa;GACb,cAAc;EAChB,CAAC;EACD,OAAO;CACT,SAAS,OAAO;EACd,QAAQ,MAAM,kCAAkC,OAAO;EACvD,OAAO;CACT;AACF;;;;;;;;;AAcA,SAAgB,qBAAqB,MAAsB;CACzD,OAAO,KAAK,WAAW,qCAAqC,UAAU;EACpE,IAAI,QAAQ;EAGZ,MAAM,cAAc,MAAM,MAAM,YAAY,KAAK,CAAC,EAAA,CAAG;EACrD,MAAM,eAAe,MAAM,MAAM,YAAY,KAAK,CAAC,EAAA,CAAG;EACtD,IAAI,aAAa,aAAa;GAC5B,MAAM,OAAO,aAAa;GAC1B,MAAM,gBAAgB,IAAI,OAAO,IAAI;GAErC,QAAQ,MAAM,QAAQ,YAAY,gBAAgB,IAAI;EACxD;EAGA,MAAM,cAAc,MAAM,MAAM,iBAAiB,KAAK,CAAC,EAAA,CAAG;EAC1D,MAAM,eAAe,MAAM,MAAM,mBAAmB,KAAK,CAAC,EAAA,CAAG;EAC7D,IAAI,aAAa,aAAa;GAC5B,MAAM,OAAO,aAAa;GAC1B,MAAM,YAAY,WAAW,OAAO,IAAI;GACxC,QAAQ,MAAM,QAAQ,YAAY,YAAY,IAAI;EACpD;EAEA,OAAO;CACT,CAAC;AACH;;;;;;;;;AAUA,SAAgB,sBAAsB,MAAsB;CAC1D,IAAI,SAAS;CAGb,SAAS,OAAO,WAAW,UAAU,GAAG;CACxC,SAAS,OAAO,WAAW,UAAU,GAAG;CACxC,SAAS,OAAO,WAAW,YAAY,IAAI;CAC3C,SAAS,OAAO,WAAW,YAAY,IAAI;CAG3C,SAAS,OAAO,WAAW,qCAAqC,UAAU;EACxE,OAAO,MAAM,WAAW,WAAW,GAAG;CACxC,CAAC;CAED,OAAO;AACT;;;;;;;;AASA,SAAgB,yBAAyB,MASvC;CACA,MAAM,SAKD,CAAC;CAEN,IAAI,mBAAmB;CACvB,MAAM,UAAU;CAChB,IAAI;CAEJ,QAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;EAC5C;EACA,MAAM,UAAU,MAAM,MAAM,MAAM;EAClC,MAAM,YAAY,MAAM,EAAE,CAAC,WAAW,IAAI;EAE1C,IAAI;GACF,eAAe,SAAS;IACtB,aAAa;IACb,QAAQ;IACR,cAAc;IACd,OAAO;GACT,CAAC;EACH,SAAS,OAAO;GACd,OAAO,KAAK;IACV,SAAS,QAAQ,MAAM,GAAG,EAAE,KAAK,QAAQ,SAAS,KAAK,QAAQ;IAC/D,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC9D,UAAU,MAAM;IAChB,MAAM,YAAY,YAAY;GAChC,CAAC;EACH;CACF;CAEA,OAAO;EACL;EACA;EACA,OAAO,OAAO,WAAW;CAC3B;AACF;;;;;;;;;AAUA,SAAgB,mBAAmB,MAAc,YAAY,OAAe;CAC1E,IAAI,CAAC,WAAW,OAAO;CAEvB,IAAI,SAAS;CAGb,SAAS,OAAO,WAAW,uCAAuC,OAAO;CAGzE,SAAS,OAAO,WAAW,uCAAuC,OAAO;CAEzE,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0DA,SAAgB,gBAAgB,MAAc,UAAqC,CAAC,GAAW;CAC7F,MAAM,EACJ,eAAe,OACf,kBAAkB,MAClB,iBAAiB,MACjB,eAAe,MACf,cAAc,MACd,oBAAoB,MACpB,YAAY,OACZ,YAAY,OACZ,mBAAmB,OACnB,yBAAyB,OACzB,WAAW,UACT;CAEJ,IAAI,UAAU;CAGd,IAAI,gBACF,UAAU,sBAAsB,OAAO;CAIzC,IAAI,iBACF,UAAU,uBAAuB,OAAO;CAI1C,IAAI,cACF,UAAU,qBAAqB,OAAO;CAGxC,IAAI,aACF,UAAU,iBAAiB,OAAO;CAGpC,IAAI,mBACF,UAAU,sBAAsB,OAAO;CAIzC,IAAI,WACF,UAAU,qBAAqB,OAAO;CAIxC,IAAI,kBACF,UAAU,sBAAsB,OAAO;CAIzC,IAAI,WACF,UAAU,mBAAmB,SAAS,YAAY;CAIpD,IAAI,UAAU;EACZ,MAAM,aAAa,yBAAyB,OAAO;EACnD,IAAI,CAAC,WAAW,OAAO;GACrB,MAAM,eAAe,4BAA4B,WAAW,OAAO,OAAO,GAAG,WAAW,iBAAiB,8BAA8B,WAAW,OAAO,KAAK,MAAM,QAAQ,EAAE,KAAK,gBAAgB,EAAE,SAAS,IAAI,EAAE,QAAQ,iBAAiB,EAAE,SAAS,CAAC,CAAC,KAAK,IAAI;GAEnQ,IAAI,wBACF,MAAM,IAAI,MAAM,YAAY;QAE5B,QAAQ,KAAK,YAAY;EAE7B;CACF;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"latex.mjs","names":[],"sources":["../../../src/hooks/useMarkdown/latex.ts"],"sourcesContent":["import { renderToString } from 'katex';\n\n// ============================================================================\n// Utility Classes\n// ============================================================================\n\n/**\n * PlaceholderManager - Manages temporary replacement and restoration of protected content\n * Used to protect code blocks and LaTeX expressions during preprocessing\n */\nclass PlaceholderManager {\n private placeholders: string[] = [];\n private prefix: string;\n\n constructor(prefix = 'PROTECTED') {\n this.prefix = prefix;\n }\n\n add(content: string): string {\n const index = this.placeholders.length;\n this.placeholders.push(content);\n return `<<${this.prefix}_${index}>>`;\n }\n\n restore(text: string): string {\n return text.replaceAll(new RegExp(`<<${this.prefix}_(\\\\d+)>>`, 'g'), (_, index) => {\n return this.placeholders[Number.parseInt(index)] || '';\n });\n }\n\n clear(): void {\n this.placeholders = [];\n }\n}\n\n// ============================================================================\n// Helper Functions\n// ============================================================================\n\n// Helper: replace unescaped pipes with \\vert within a LaTeX math fragment\nconst replaceUnescapedPipes = (formula: string): string =>\n // Use \\vert{} so the control sequence terminates before the next token\n formula.replaceAll(/(?<!\\\\)\\|/g, '\\\\vert{}');\n\n/**\n * Converts LaTeX bracket delimiters to dollar sign delimiters.\n * Converts \\[...\\] to $$...$$ and \\(...\\) to $...$\n * Preserves code blocks during the conversion.\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with LaTeX bracket delimiters converted to dollar sign delimiters\n */\nexport function convertLatexDelimiters(text: string): string {\n const pattern = /(```[\\s\\S]*?```|`.*?`)|\\\\\\[([\\s\\S]*?[^\\\\])\\\\\\]|\\\\\\((.*?)\\\\\\)/g;\n return text.replaceAll(\n pattern,\n (\n match: string,\n codeBlock: string | undefined,\n squareBracket: string | undefined,\n roundBracket: string | undefined,\n ): string => {\n if (codeBlock !== undefined) {\n return codeBlock;\n } else if (squareBracket !== undefined) {\n return `$$${squareBracket}$$`;\n } else if (roundBracket !== undefined) {\n return `$${roundBracket}$`;\n }\n return match;\n },\n );\n}\n\n/**\n * Escapes mhchem commands in LaTeX expressions to ensure proper rendering.\n *\n * @param text The input string containing LaTeX expressions with mhchem commands\n * @returns The string with escaped mhchem commands\n */\nexport function escapeMhchemCommands(text: string) {\n return text.replaceAll('$\\\\ce{', '$\\\\\\\\ce{').replaceAll('$\\\\pu{', '$\\\\\\\\pu{');\n}\n\n/**\n * Escapes pipe characters within LaTeX expressions to prevent them from being interpreted\n * as table column separators in markdown tables.\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with pipe characters escaped in LaTeX expressions\n */\nexport function escapeLatexPipes(text: string): string {\n // Replace unescaped '|' inside LaTeX math spans with '\\vert' so that\n // remark-gfm table parsing won't treat them as column separators.\n // Leave code blocks/inline code untouched.\n // Also ignore escaped dollars (\\$) which are currency symbols\n\n // Process code blocks first to protect them\n const codeBlocks: string[] = [];\n let content = text.replaceAll(/(```[\\s\\S]*?```|`[^\\n`]*`)/g, (match) => {\n codeBlocks.push(match);\n return `<<CODE_${codeBlocks.length - 1}>>`;\n });\n\n // For display math, allow multiline\n content = content.replaceAll(/\\$\\$([\\s\\S]*?)\\$\\$/g, (match, display) => {\n return `$$${replaceUnescapedPipes(display)}$$`;\n });\n\n // For inline math, use non-greedy match that DOES NOT cross newlines\n // This prevents issues in tables where $ might appear in different cells\n content = content.replaceAll(/(?<!\\\\)\\$(?!\\$)([^\\n$]*)(?<!\\\\)\\$(?!\\$)/g, (match, inline) => {\n return `$${replaceUnescapedPipes(inline)}$`;\n });\n\n // Restore code blocks\n content = content.replaceAll(/<<CODE_(\\d+)>>/g, (_, index) => {\n return codeBlocks[Number.parseInt(index)];\n });\n\n return content;\n}\n\n/**\n * Escapes underscores within \\text{...} commands in LaTeX expressions\n * that are not already escaped.\n * For example, \\text{node_domain} becomes \\text{node\\_domain},\n * but \\text{node\\_domain} remains \\text{node\\_domain}.\n *\n * @param text The input string potentially containing LaTeX expressions\n * @returns The string with unescaped underscores escaped within \\text{...} commands\n */\nexport function escapeTextUnderscores(text: string): string {\n return text.replaceAll(/\\\\text\\{([^}]*)\\}/g, (match, textContent: string) => {\n // textContent is the content within the braces, e.g., \"node_domain\" or \"already\\_escaped\"\n // Replace underscores '_' with '\\_' only if they are NOT preceded by a backslash '\\'.\n // The (?<!\\\\) is a negative lookbehind assertion that ensures the character before '_' is not a '\\'.\n const escapedTextContent = textContent.replaceAll(/(?<!\\\\)_/g, '\\\\_');\n return `\\\\text{${escapedTextContent}}`;\n });\n}\n\n/**\n * Escapes dollar signs that appear to be currency symbols to prevent them from being\n * interpreted as LaTeX math delimiters.\n *\n * This function identifies currency patterns such as:\n * - $20, $100, $1,000\n * - $20-50, $100+\n * - Patterns within markdown tables\n *\n * @param text The input string containing potential currency symbols\n * @returns The string with currency dollar signs escaped\n */\nexport function escapeCurrencyDollars(text: string): string {\n // Protect code blocks and existing LaTeX expressions from processing\n const manager = new PlaceholderManager('PROTECTED');\n\n let content = text.replaceAll(\n // Match patterns to protect (in order):\n // 1. Code blocks: ```...```\n // 2. Inline code: `...`\n // 3. Display math: $$...$$\n // 4. Inline math with LaTeX commands: $...\\...$ (must contain backslash to distinguish from currency)\n // 5. Simple number formulas: $1$, $10$, $100$ (pure digits in math mode)\n // 6. Number lists in math mode: $1,-1,0$ or $1,2,3$ (comma-separated numbers, possibly negative)\n // 7. LaTeX bracket notation: \\[...\\]\n // 8. LaTeX parenthesis notation: \\(...\\)\n /(```[\\s\\S]*?```|`[^\\n`]*`|\\$\\$[\\s\\S]*?\\$\\$|(?<!\\\\)\\$(?!\\$)(?=[\\s\\S]*?\\\\)[\\s\\S]*?(?<!\\\\)\\$(?!\\$)|\\$\\d+\\$|\\$-?\\d+(?:,-?\\d+)+\\$|\\\\\\[[\\s\\S]*?\\\\\\]|\\\\\\(.*?\\\\\\))/g,\n (match) => manager.add(match),\n );\n\n // Escape dollar signs that are clearly currency:\n // - $ followed by a digit\n // - Not preceded by another $ (to avoid breaking $$)\n // - Not followed immediately by another $ (to avoid breaking $1$ LaTeX)\n // - Followed by number patterns with optional commas, decimals, ranges, or plus signs\n // Match patterns like: $20, $1,000, $19.99, $20-50, $300+, $1,000-2,000+\n // But NOT: $1$, $2$ (these are LaTeX formulas)\n // In the replacement: \\\\ = backslash, $$ = literal $, $1 = capture group 1\n content = content.replaceAll(\n /(?<!\\$)\\$(\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?(?:-\\d{1,3}(?:,\\d{3})*(?:\\.\\d+)?)?\\+?)(?!\\$)/g,\n '\\\\$$$1',\n );\n\n // Restore protected content\n content = manager.restore(content);\n\n return content;\n}\n\n// Old simple preprocessLaTeX has been replaced by the comprehensive version below\n// The new preprocessLaTeX provides the same default behavior with optional advanced featuresgit\n\n/**\n * Extracts the LaTeX formula after the last $$ delimiter if there's an odd number of $$ delimiters.\n *\n * @param text The input string containing LaTeX formulas\n * @returns The content after the last $$ if there's an odd number of $$, otherwise an empty string\n */\nconst extractIncompleteFormula = (text: string) => {\n // Count the number of $$ delimiters\n const dollarsCount = (text.match(/\\$\\$/g) || []).length;\n\n // If odd number of $$ delimiters, extract content after the last $$\n if (dollarsCount % 2 === 1) {\n const match = text.match(/\\$\\$([\\s\\S]*)$/);\n return match ? match[1] : '';\n }\n\n // If even number of $$ delimiters, return empty string\n return '';\n};\n\n/**\n * Checks if the last LaTeX formula in the text is renderable.\n * Only validates the formula after the last $$ if there's an odd number of $$.\n *\n * @param text The input string containing LaTeX formulas\n * @returns True if the last formula is renderable or if there's no incomplete formula\n */\nexport const isLastFormulaRenderable = (text: string) => {\n const formula = extractIncompleteFormula(text);\n\n // If no incomplete formula, return true\n if (!formula) return true;\n\n // Try to render the last formula\n try {\n renderToString(formula, {\n displayMode: true,\n throwOnError: true,\n });\n return true;\n } catch (error) {\n console.error(`LaTeX formula rendering error: ${error}`);\n return false;\n }\n};\n\n// ============================================================================\n// Advanced Preprocessing Functions\n// ============================================================================\n\n/**\n * Fixes common LaTeX syntax errors automatically\n * - Balances unmatched braces\n * - Balances \\left and \\right delimiters\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with fixed LaTeX expressions\n */\nexport function fixCommonLaTeXErrors(text: string): string {\n return text.replaceAll(/(\\$\\$[\\s\\S]*?\\$\\$|\\$[\\s\\S]*?\\$)/g, (match) => {\n let fixed = match;\n\n // Fix unbalanced braces\n const openBraces = (fixed.match(/(?<!\\\\)\\{/g) || []).length;\n const closeBraces = (fixed.match(/(?<!\\\\)\\}/g) || []).length;\n if (openBraces > closeBraces) {\n const diff = openBraces - closeBraces;\n const closingBraces = '}'.repeat(diff);\n // Insert before the closing delimiter\n fixed = fixed.replace(/(\\$\\$?)$/, closingBraces + '$1');\n }\n\n // Fix unbalanced \\left and \\right\n const leftDelims = (fixed.match(/\\\\left[(.<[{|]/g) || []).length;\n const rightDelims = (fixed.match(/\\\\right[).>\\]|}]/g) || []).length;\n if (leftDelims > rightDelims) {\n const diff = leftDelims - rightDelims;\n const rightDots = '\\\\right.'.repeat(diff);\n fixed = fixed.replace(/(\\$\\$?)$/, rightDots + '$1');\n }\n\n return fixed;\n });\n}\n\n/**\n * Normalizes whitespace in LaTeX expressions\n * - Removes extra spaces around $ delimiters\n * - Normalizes multiple spaces to single space inside formulas\n *\n * @param text The input string containing LaTeX expressions\n * @returns The string with normalized whitespace\n */\nexport function normalizeLatexSpacing(text: string): string {\n let result = text;\n\n // Remove spaces inside $ delimiters (at the edges)\n result = result.replaceAll(/\\$\\s+/g, '$');\n result = result.replaceAll(/\\s+\\$/g, '$');\n result = result.replaceAll(/\\$\\$\\s+/g, '$$');\n result = result.replaceAll(/\\s+\\$\\$/g, '$$');\n\n // Normalize multiple spaces inside formulas to single space\n result = result.replaceAll(/(\\$\\$[\\s\\S]*?\\$\\$|\\$[\\s\\S]*?\\$)/g, (match) => {\n return match.replaceAll(/\\s{2,}/g, ' ');\n });\n\n return result;\n}\n\n/**\n * Validates all LaTeX expressions in the text\n * Returns detailed information about validation results\n *\n * @param text The input string containing LaTeX expressions\n * @returns Validation results with errors if any\n */\nexport function validateLatexExpressions(text: string): {\n errors: Array<{\n formula: string;\n message: string;\n position: number;\n type: 'display' | 'inline';\n }>;\n totalExpressions: number;\n valid: boolean;\n} {\n const errors: Array<{\n formula: string;\n message: string;\n position: number;\n type: 'display' | 'inline';\n }> = [];\n\n let totalExpressions = 0;\n const pattern = /\\$\\$([\\s\\S]*?)\\$\\$|(?<!\\\\)\\$(?!\\$)([\\s\\S]*?)(?<!\\\\)\\$(?!\\$)/g;\n let match;\n\n while ((match = pattern.exec(text)) !== null) {\n totalExpressions++;\n const formula = match[1] || match[2];\n const isDisplay = match[0].startsWith('$$');\n\n try {\n renderToString(formula, {\n displayMode: isDisplay,\n strict: 'warn',\n throwOnError: true,\n trust: false,\n });\n } catch (error) {\n errors.push({\n formula: formula.slice(0, 50) + (formula.length > 50 ? '...' : ''),\n message: error instanceof Error ? error.message : String(error),\n position: match.index,\n type: isDisplay ? 'display' : 'inline',\n });\n }\n }\n\n return {\n errors,\n totalExpressions,\n valid: errors.length === 0,\n };\n}\n\n/**\n * Handles CJK (Chinese, Japanese, Korean) characters mixed with LaTeX\n * Optionally adds spaces between CJK characters and LaTeX expressions for better rendering\n *\n * @param text The input string\n * @param addSpaces Whether to add spaces between CJK and LaTeX (default: false)\n * @returns The processed string\n */\nexport function handleCJKWithLatex(text: string, addSpaces = false): string {\n if (!addSpaces) return text;\n\n let result = text;\n\n // Add space between CJK character and opening $\n result = result.replaceAll(/([\\u3040-\\u30FF\\u4E00-\\u9FA5])(\\$)/g, '$1 $2');\n\n // Add space between closing $ and CJK character\n result = result.replaceAll(/(\\$)([\\u3040-\\u30FF\\u4E00-\\u9FA5])/g, '$1 $2');\n\n return result;\n}\n\n// ============================================================================\n// Advanced Preprocessing Options\n// ============================================================================\n\nexport interface AdvancedPreprocessOptions {\n /** Add spaces between CJK and LaTeX (default: false, requires handleCJK: true) */\n addCJKSpaces?: boolean;\n /** Convert bracket notation \\[...\\] to $$...$$ (default: true) */\n convertBrackets?: boolean;\n /** Enable currency escaping (default: true) */\n escapeCurrency?: boolean;\n /** Escape mhchem commands (default: true) */\n escapeMhchem?: boolean;\n /** Escape pipe symbols in LaTeX (default: true) */\n escapePipes?: boolean;\n /** Escape underscores in \\text{} (default: true) */\n escapeUnderscores?: boolean;\n /** Automatically fix common LaTeX errors (default: false) */\n fixErrors?: boolean;\n /** Handle CJK characters (default: false) */\n handleCJK?: boolean;\n /** Normalize whitespace (default: false) */\n normalizeSpacing?: boolean;\n /** Throw error on validation failure (default: false, requires validate: true) */\n throwOnValidationError?: boolean;\n /** Validate LaTeX syntax (default: false) */\n validate?: boolean;\n}\n\n/**\n * Comprehensive LaTeX preprocessing with configurable options\n *\n * This is the main preprocessing function that handles:\n * - Currency symbol escaping (e.g., $20 → \\$20)\n * - LaTeX delimiter conversion (\\[...\\] → $$...$$)\n * - Special character escaping (pipes, underscores, mhchem)\n * - Optional error fixing and validation\n * - Optional CJK character handling\n *\n * @param text The input string containing LaTeX and Markdown\n * @param options Configuration options for fine-grained control\n * @returns The preprocessed string\n *\n * @example\n * ```ts\n * // Default behavior (same as old preprocessLaTeX)\n * preprocessLaTeX('向量$90^\\\\circ$,非 $0^\\\\circ$ 和 $180^\\\\circ$')\n *\n * // With custom options\n * preprocessLaTeX(text, {\n * fixErrors: true,\n * validate: true,\n * handleCJK: true\n * })\n * ```\n */\nexport function preprocessLaTeX(text: string, options: AdvancedPreprocessOptions = {}): string {\n const {\n addCJKSpaces = false,\n convertBrackets = true,\n escapeCurrency = true,\n escapeMhchem = true,\n escapePipes = true,\n escapeUnderscores = true,\n fixErrors = false,\n handleCJK = false,\n normalizeSpacing = false,\n throwOnValidationError = false,\n validate = false,\n } = options;\n\n let content = text;\n\n // Phase 1: Currency escaping (if enabled)\n if (escapeCurrency) {\n content = escapeCurrencyDollars(content);\n }\n\n // Phase 2: Bracket conversion (if enabled)\n if (convertBrackets) {\n content = convertLatexDelimiters(content);\n }\n\n // Phase 3: LaTeX-specific escaping\n if (escapeMhchem) {\n content = escapeMhchemCommands(content);\n }\n\n if (escapePipes) {\n content = escapeLatexPipes(content);\n }\n\n if (escapeUnderscores) {\n content = escapeTextUnderscores(content);\n }\n\n // Phase 4: Error fixing (if enabled)\n if (fixErrors) {\n content = fixCommonLaTeXErrors(content);\n }\n\n // Phase 5: Whitespace normalization (if enabled)\n if (normalizeSpacing) {\n content = normalizeLatexSpacing(content);\n }\n\n // Phase 6: CJK handling (if enabled)\n if (handleCJK) {\n content = handleCJKWithLatex(content, addCJKSpaces);\n }\n\n // Phase 7: Validation (if enabled)\n if (validate) {\n const validation = validateLatexExpressions(content);\n if (!validation.valid) {\n const errorMessage = `LaTeX validation failed (${validation.errors.length}/${validation.totalExpressions} expressions have errors):\\n${validation.errors.map((e) => ` - [${e.type}] at position ${e.position}: ${e.message}\\n Formula: ${e.formula}`).join('\\n')}`;\n\n if (throwOnValidationError) {\n throw new Error(errorMessage);\n } else {\n console.warn(errorMessage);\n }\n }\n }\n\n return content;\n}\n\n/**\n * Strict preprocessing mode - enables all safety features and validations\n * Use this when you want maximum correctness and are willing to accept the performance cost\n *\n * @param text The input string\n * @returns The preprocessed string with all features enabled\n *\n * @example\n * ```ts\n * const processed = preprocessLaTeXStrict(userInput)\n * // Enables: error fixing, validation, CJK handling, space normalization\n * ```\n */\nexport function preprocessLaTeXStrict(text: string): string {\n return preprocessLaTeX(text, {\n addCJKSpaces: false, // Usually don't want extra spaces\n convertBrackets: true,\n escapeCurrency: true,\n escapeMhchem: true,\n escapePipes: true,\n escapeUnderscores: true,\n fixErrors: true,\n handleCJK: true,\n normalizeSpacing: true,\n throwOnValidationError: false, // Warn but don't throw\n validate: true,\n });\n}\n\n/**\n * Minimal preprocessing mode - only essential operations\n * Use this for better performance when you control the input\n *\n * @param text The input string\n * @returns The preprocessed string with minimal processing\n *\n * @example\n * ```ts\n * const processed = preprocessLaTeXMinimal(trustedInput)\n * // Only escapes currency and converts brackets\n * ```\n */\nexport function preprocessLaTeXMinimal(text: string): string {\n return preprocessLaTeX(text, {\n convertBrackets: true,\n escapeCurrency: true,\n escapeMhchem: false,\n escapePipes: false,\n escapeUnderscores: false,\n fixErrors: false,\n handleCJK: false,\n normalizeSpacing: false,\n validate: false,\n });\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useMarkdownContent.mjs","names":[],"sources":["../../../src/hooks/useMarkdown/useMarkdownContent.ts"],"sourcesContent":["'use client';\n\nimport { useMemo, useRef, useState } from 'react';\n\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\n\nimport { isLastFormulaRenderable } from './latex';\nimport { addToCache, contentCache, preprocessMarkdownContent } from './utils';\n\nexport const useMarkdownContent = (children: string): string | undefined => {\n const { animated, enableLatex = true, enableCustomFootnotes, citations } = useMarkdownContext();\n const [validContent, setValidContent] = useState<string>('');\n const prevProcessedContent = useRef<string>('');\n\n const citationsLength = citations?.length || 0;\n\n // Calculate cache key with fewer string concatenations and better performance\n const cacheKey = useMemo(\n () => `${children}|${enableLatex ? 1 : 0}|${enableCustomFootnotes ? 1 : 0}|${citationsLength}`,\n [children, enableLatex, enableCustomFootnotes, citationsLength],\n );\n\n // Process content and use cache to avoid repeated calculations\n return useMemo(() => {\n // Try to get from cache first for best performance\n if (contentCache.has(cacheKey)) {\n return contentCache.get(cacheKey);\n }\n\n // Process new content only if needed\n let processedContent = preprocessMarkdownContent(children, {\n citationsLength,\n enableCustomFootnotes,\n enableLatex,\n });\n\n // Special handling for LaTeX content when animated\n if (animated && enableLatex) {\n const isRenderable = isLastFormulaRenderable(processedContent);\n if (!isRenderable && validContent) {\n processedContent = validContent;\n }\n }\n\n // Only update state if content changed (prevents unnecessary re-renders)\n if (processedContent !== prevProcessedContent.current) {\n setValidContent(processedContent);\n prevProcessedContent.current = processedContent;\n }\n\n // Cache the processed result\n addToCache(cacheKey, processedContent);\n return processedContent;\n }, [\n cacheKey,\n children,\n enableLatex,\n enableCustomFootnotes,\n citationsLength,\n animated,\n validContent,\n ]);\n};\n"],"mappings":";;;;;;AASA,MAAa,sBAAsB,aAAyC;CAC1E,MAAM,EAAE,UAAU,cAAc,MAAM,uBAAuB,cAAc,mBAAmB;CAC9F,MAAM,CAAC,cAAc,mBAAmB,SAAiB,EAAE;CAC3D,MAAM,uBAAuB,OAAe,EAAE;CAE9C,MAAM,kBAAkB,WAAW,UAAU;CAG7C,MAAM,WAAW,cACT,GAAG,SAAS,GAAG,cAAc,IAAI,EAAE,GAAG,wBAAwB,IAAI,EAAE,GAAG,mBAC7E;EAAC;EAAU;EAAa;EAAuB;CAAe,CAChE;CAGA,OAAO,cAAc;EAEnB,IAAI,aAAa,IAAI,QAAQ,GAC3B,OAAO,aAAa,IAAI,QAAQ;EAIlC,IAAI,mBAAmB,0BAA0B,UAAU;GACzD;GACA;GACA;EACF,CAAC;EAGD,IAAI,YAAY;OAEV,CADiB,wBAAwB,gBAC7B,KAAK,cACnB,mBAAmB;EAAA;EAKvB,IAAI,qBAAqB,qBAAqB,SAAS;GACrD,gBAAgB,gBAAgB;GAChC,qBAAqB,UAAU;EACjC;EAGA,WAAW,UAAU,gBAAgB;EACrC,OAAO;CACT,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH"}
1
+ {"version":3,"file":"useMarkdownContent.mjs","names":[],"sources":["../../../src/hooks/useMarkdown/useMarkdownContent.ts"],"sourcesContent":["'use client';\n\nimport { useMemo, useRef, useState } from 'react';\n\nimport { useMarkdownContext } from '@/Markdown/components/MarkdownProvider';\n\nimport { isLastFormulaRenderable } from './latex';\nimport { addToCache, contentCache, preprocessMarkdownContent } from './utils';\n\nexport const useMarkdownContent = (children: string): string | undefined => {\n const { animated, enableLatex = true, enableCustomFootnotes, citations } = useMarkdownContext();\n const [validContent, setValidContent] = useState<string>('');\n const prevProcessedContent = useRef<string>('');\n\n const citationsLength = citations?.length || 0;\n\n // Calculate cache key with fewer string concatenations and better performance\n const cacheKey = useMemo(\n () => `${children}|${enableLatex ? 1 : 0}|${enableCustomFootnotes ? 1 : 0}|${citationsLength}`,\n [children, enableLatex, enableCustomFootnotes, citationsLength],\n );\n\n // Process content and use cache to avoid repeated calculations\n return useMemo(() => {\n // Try to get from cache first for best performance\n if (contentCache.has(cacheKey)) {\n return contentCache.get(cacheKey);\n }\n\n // Process new content only if needed\n let processedContent = preprocessMarkdownContent(children, {\n citationsLength,\n enableCustomFootnotes,\n enableLatex,\n });\n\n // Special handling for LaTeX content when animated\n if (animated && enableLatex) {\n const isRenderable = isLastFormulaRenderable(processedContent);\n if (!isRenderable && validContent) {\n processedContent = validContent;\n }\n }\n\n // Only update state if content changed (prevents unnecessary re-renders)\n if (processedContent !== prevProcessedContent.current) {\n setValidContent(processedContent);\n prevProcessedContent.current = processedContent;\n }\n\n // Cache the processed result\n addToCache(cacheKey, processedContent);\n return processedContent;\n }, [\n cacheKey,\n children,\n enableLatex,\n enableCustomFootnotes,\n citationsLength,\n animated,\n validContent,\n ]);\n};\n"],"mappings":";;;;;;AASA,MAAa,sBAAsB,aAAyC;CAC1E,MAAM,EAAE,UAAU,cAAc,MAAM,uBAAuB,cAAc,mBAAmB;CAC9F,MAAM,CAAC,cAAc,mBAAmB,SAAiB,EAAE;CAC3D,MAAM,uBAAuB,OAAe,EAAE;CAE9C,MAAM,kBAAkB,WAAW,UAAU;CAG7C,MAAM,WAAW,cACT,GAAG,SAAS,GAAG,cAAc,IAAI,EAAE,GAAG,wBAAwB,IAAI,EAAE,GAAG,mBAC7E;EAAC;EAAU;EAAa;EAAuB;CAAe,CAChE;CAGA,OAAO,cAAc;EAEnB,IAAI,aAAa,IAAI,QAAQ,GAC3B,OAAO,aAAa,IAAI,QAAQ;EAIlC,IAAI,mBAAmB,0BAA0B,UAAU;GACzD;GACA;GACA;EACF,CAAC;EAGD,IAAI,YAAY,aAEV;OAAA,CADiB,wBAAwB,gBAC7B,KAAK,cACnB,mBAAmB;EAAA;EAKvB,IAAI,qBAAqB,qBAAqB,SAAS;GACrD,gBAAgB,gBAAgB;GAChC,qBAAqB,UAAU;EACjC;EAGA,WAAW,UAAU,gBAAgB;EACrC,OAAO;CACT,GAAG;EACD;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH"}
@@ -1,133 +1,98 @@
1
1
  "use client";
2
- import { useEffect, useMemo, useState } from "react";
3
- import { useTheme } from "antd-style";
4
- import { Md5 } from "ts-md5";
2
+ import { prepareInlineMermaidSvg } from "../Mermaid/SyntaxMermaid/prepareInlineSvg.mjs";
3
+ import { createCdnMermaidConfig, renderWithCdnMermaid } from "./useMermaidCdn.mjs";
4
+ import { useEffect, useId, useMemo, useState } from "react";
5
+ import { useThemeMode } from "antd-style";
6
+ import { THEMES, renderMermaidSVG } from "beautiful-mermaid";
5
7
  //#region src/hooks/useMermaid.ts
6
- const MD5_LENGTH_THRESHOLD = 1e4;
7
- const mermaidCache = /* @__PURE__ */ new Map();
8
- const MAX_CACHE_SIZE = 500;
9
- const cleanupCache = () => {
10
- if (mermaidCache.size > MAX_CACHE_SIZE) {
11
- const entriesToRemove = Math.floor(MAX_CACHE_SIZE * .2);
12
- const keysToRemove = Array.from(mermaidCache.keys()).slice(0, entriesToRemove);
13
- for (const key of keysToRemove) mermaidCache.delete(key);
14
- }
15
- };
16
- let mermaidPromise = null;
17
- const loadMermaid = () => {
18
- if (typeof window === "undefined") return Promise.resolve(null);
19
- if (!mermaidPromise) mermaidPromise = import("mermaid").then((mod) => mod.default);
20
- return mermaidPromise;
8
+ /**
9
+ * beautiful-mermaid emits these as CSS custom properties on the SVG root and
10
+ * derives the rest with color-mix(), so pointing them at antd's variables lets
11
+ * the diagram follow the theme through CSS alone — no token subscription, and
12
+ * no re-render (or re-layout) when the appearance changes.
13
+ */
14
+ const LOBE_THEME_OPTIONS = {
15
+ accent: "var(--ant-color-primary)",
16
+ bg: "var(--ant-color-bg-container)",
17
+ border: "var(--ant-color-border)",
18
+ fg: "var(--ant-color-text)",
19
+ line: "var(--ant-color-text-secondary)",
20
+ muted: "var(--ant-color-text-description)",
21
+ surface: "var(--ant-color-fill-tertiary)",
22
+ transparent: true
21
23
  };
22
- const createMermaidConfig = (theme, customTheme, securityLevel = "strict") => ({
23
- fontFamily: theme.fontFamilyCode,
24
- gantt: { useWidth: 1920 },
25
- securityLevel,
26
- startOnLoad: false,
27
- theme: customTheme || (theme.isDarkMode ? "dark" : "neutral"),
28
- themeVariables: customTheme ? void 0 : {
29
- errorBkgColor: theme.colorTextDescription,
30
- errorTextColor: theme.colorTextDescription,
31
- fontFamily: theme.fontFamily,
32
- lineColor: theme.colorTextSecondary,
33
- mainBkg: theme.colorBgContainer,
34
- noteBkgColor: theme.colorInfoBg,
35
- noteTextColor: theme.colorInfoText,
36
- pie1: theme.geekblue,
37
- pie2: theme.colorWarning,
38
- pie3: theme.colorSuccess,
39
- pie4: theme.colorError,
40
- primaryBorderColor: theme.colorBorder,
41
- primaryColor: theme.colorBgContainer,
42
- primaryTextColor: theme.colorText,
43
- secondaryBorderColor: theme.colorInfoBorder,
44
- secondaryColor: theme.colorInfoBg,
45
- secondaryTextColor: theme.colorInfoText,
46
- tertiaryBorderColor: theme.colorSuccessBorder,
47
- tertiaryColor: theme.colorSuccessBg,
48
- tertiaryTextColor: theme.colorSuccessText,
49
- textColor: theme.colorText
50
- }
51
- });
24
+ const isNamedTheme = (theme) => !!theme && theme !== "lobe-theme" && theme in THEMES;
25
+ const createMermaidOptions = (customTheme) => isNamedTheme(customTheme) ? THEMES[customTheme] : LOBE_THEME_OPTIONS;
52
26
  /**
53
- * 验证并处理 Mermaid 图表内容 - 优化版本(移除 SWR)
27
+ * beautiful-mermaid covers six diagram types; anything else throws here and is
28
+ * handed to the CDN-loaded upstream mermaid instead.
54
29
  */
55
- const useMermaid = (content, { id, theme: customTheme, securityLevel }) => {
56
- const theme = useTheme();
57
- const [data, setData] = useState("");
58
- const mermaidConfig = useMemo(() => createMermaidConfig(theme, customTheme, securityLevel), [
59
- theme.fontFamilyCode,
60
- theme.isDarkMode,
61
- theme.colorTextDescription,
62
- theme.fontFamily,
63
- theme.colorTextSecondary,
64
- theme.colorBgContainer,
65
- theme.colorInfoBg,
66
- theme.colorInfoText,
67
- theme.geekblue,
68
- theme.colorWarning,
69
- theme.colorSuccess,
70
- theme.colorError,
71
- theme.colorBorder,
72
- theme.colorInfoBorder,
73
- theme.colorSuccessBorder,
74
- theme.colorSuccessBg,
75
- theme.colorSuccessText,
76
- theme.colorText,
77
- customTheme,
78
- securityLevel
79
- ]);
80
- const cacheKey = useMemo(() => {
81
- const hash = content.length < 1e4 ? content : Md5.hashStr(content);
82
- return [
83
- id,
84
- customTheme || (theme.isDarkMode ? "d" : "l"),
85
- hash
86
- ].filter(Boolean).join("-");
87
- }, [
88
- content,
89
- id,
90
- theme.isDarkMode,
91
- customTheme
92
- ]);
30
+ const renderMermaid = (content, scopeId, customTheme) => {
31
+ if (!content) return { svg: "" };
32
+ try {
33
+ const svg = renderMermaidSVG(content, createMermaidOptions(customTheme));
34
+ return { svg: prepareInlineMermaidSvg(svg, scopeId) };
35
+ } catch {
36
+ return {
37
+ error: "unsupported",
38
+ svg: ""
39
+ };
40
+ }
41
+ };
42
+ const useCdnMermaidFallback = (content, { enabled, theme: customTheme }) => {
43
+ const { isDarkMode } = useThemeMode();
44
+ const reactId = useId();
45
+ const [result, setResult] = useState({ svg: "" });
93
46
  useEffect(() => {
94
- const cachedPromise = mermaidCache.get(cacheKey);
95
- if (cachedPromise) {
96
- cachedPromise.then((svg) => {
97
- setData(svg);
98
- }).catch(() => {});
47
+ if (!enabled || !content) {
48
+ setResult({ svg: "" });
99
49
  return;
100
50
  }
101
- const renderPromise = (async () => {
102
- try {
103
- const mermaidInstance = await loadMermaid();
104
- if (!mermaidInstance) return "";
105
- if (await mermaidInstance.parse(content)) {
106
- mermaidInstance.initialize(mermaidConfig);
107
- const { svg } = await mermaidInstance.render(id, content);
108
- return svg;
109
- } else throw new Error("Mermaid 语法无效");
110
- } catch (error_) {
111
- console.error("Mermaid 解析错误:", error_);
112
- return "";
113
- }
114
- })();
115
- mermaidCache.set(cacheKey, renderPromise);
116
- cleanupCache();
117
- renderPromise.then((svg) => {
118
- if (mermaidCache.get(cacheKey) === renderPromise) setData(svg);
51
+ let active = true;
52
+ setResult({
53
+ loading: true,
54
+ svg: ""
55
+ });
56
+ const config = createCdnMermaidConfig(isDarkMode, isNamedTheme(customTheme) ? customTheme : void 0);
57
+ renderWithCdnMermaid(content, `mermaid-cdn-${reactId.replaceAll(":", "")}`, config).then((svg) => {
58
+ if (!active) return;
59
+ setResult(svg ? { svg } : {
60
+ error: "Failed to render diagram",
61
+ svg: ""
62
+ });
119
63
  }).catch(() => {
120
- if (mermaidCache.get(cacheKey) === renderPromise) mermaidCache.delete(cacheKey);
64
+ if (active) setResult({
65
+ error: "Failed to render diagram",
66
+ svg: ""
67
+ });
121
68
  });
69
+ return () => {
70
+ active = false;
71
+ };
122
72
  }, [
123
- cacheKey,
73
+ enabled,
124
74
  content,
125
- id,
126
- mermaidConfig
75
+ isDarkMode,
76
+ customTheme,
77
+ reactId
78
+ ]);
79
+ return result;
80
+ };
81
+ const useMermaid = (content, { theme: customTheme } = {}) => {
82
+ const reactId = useId();
83
+ const scopeId = useMemo(() => `mermaid-${reactId.replaceAll(":", "")}`, [reactId]);
84
+ const primary = useMemo(() => renderMermaid(content, scopeId, customTheme), [
85
+ content,
86
+ scopeId,
87
+ customTheme
127
88
  ]);
128
- return data;
89
+ const fallback = useCdnMermaidFallback(content, {
90
+ enabled: Boolean(primary.error),
91
+ theme: customTheme
92
+ });
93
+ return primary.error ? fallback : primary;
129
94
  };
130
95
  //#endregion
131
- export { MD5_LENGTH_THRESHOLD, createMermaidConfig, loadMermaid, useMermaid };
96
+ export { createMermaidOptions, renderMermaid, useCdnMermaidFallback, useMermaid };
132
97
 
133
98
  //# sourceMappingURL=useMermaid.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useMermaid.mjs","names":[],"sources":["../../src/hooks/useMermaid.ts"],"sourcesContent":["'use client';\n\nimport { useTheme } from 'antd-style';\nimport type { MermaidConfig } from 'mermaid';\nimport { useEffect, useMemo, useState } from 'react';\nimport { Md5 } from 'ts-md5';\n\n// 缓存已验证的图表内容\nexport const MD5_LENGTH_THRESHOLD = 10_000;\n\n// Application-level cache for rendered Mermaid SVG\n// Key: cacheKey string, Value: Promise<string>\nconst mermaidCache = new Map<string, Promise<string>>();\n\n// Maximum cache size to prevent memory leaks\nconst MAX_CACHE_SIZE = 500;\n\n// Clean up old cache entries when limit is reached\nconst cleanupCache = () => {\n if (mermaidCache.size > MAX_CACHE_SIZE) {\n // Remove oldest 20% of entries\n const entriesToRemove = Math.floor(MAX_CACHE_SIZE * 0.2);\n const keysToRemove = Array.from(mermaidCache.keys()).slice(0, entriesToRemove);\n for (const key of keysToRemove) {\n mermaidCache.delete(key);\n }\n }\n};\n\n// 懒加载 mermaid 实例\nlet mermaidPromise: Promise<typeof import('mermaid').default | null> | null = null;\n\nexport const loadMermaid = (): Promise<typeof import('mermaid').default | null> => {\n if (typeof window === 'undefined') return Promise.resolve(null);\n\n if (!mermaidPromise) {\n mermaidPromise = import('mermaid').then((mod) => mod.default);\n }\n\n return mermaidPromise;\n};\n\n// Helper to create mermaid config\nexport const createMermaidConfig = (\n theme: ReturnType<typeof useTheme>,\n customTheme?: MermaidConfig['theme'],\n // SECURITY: Keep 'strict' as the default. Using 'loose' causes Mermaid to render\n // node labels via innerHTML, enabling XSS when diagram content is user-controlled.\n // Only pass 'loose' if your use case explicitly requires HTML labels and you control\n // the diagram source entirely.\n securityLevel: MermaidConfig['securityLevel'] = 'strict',\n): MermaidConfig => ({\n fontFamily: theme.fontFamilyCode,\n gantt: {\n useWidth: 1920,\n },\n securityLevel,\n startOnLoad: false,\n theme: customTheme || (theme.isDarkMode ? 'dark' : 'neutral'),\n themeVariables: customTheme\n ? undefined\n : {\n errorBkgColor: theme.colorTextDescription,\n errorTextColor: theme.colorTextDescription,\n fontFamily: theme.fontFamily,\n lineColor: theme.colorTextSecondary,\n mainBkg: theme.colorBgContainer,\n noteBkgColor: theme.colorInfoBg,\n noteTextColor: theme.colorInfoText,\n pie1: theme.geekblue,\n pie2: theme.colorWarning,\n pie3: theme.colorSuccess,\n pie4: theme.colorError,\n primaryBorderColor: theme.colorBorder,\n primaryColor: theme.colorBgContainer,\n primaryTextColor: theme.colorText,\n secondaryBorderColor: theme.colorInfoBorder,\n secondaryColor: theme.colorInfoBg,\n secondaryTextColor: theme.colorInfoText,\n tertiaryBorderColor: theme.colorSuccessBorder,\n tertiaryColor: theme.colorSuccessBg,\n tertiaryTextColor: theme.colorSuccessText,\n textColor: theme.colorText,\n },\n});\n\n/**\n * 验证并处理 Mermaid 图表内容 - 优化版本(移除 SWR)\n */\nexport const useMermaid = (\n content: string,\n {\n id,\n theme: customTheme,\n securityLevel,\n }: {\n id: string;\n // SECURITY: Defaults to 'strict'. Set to 'loose' only when you fully control\n // the diagram source and intentionally need HTML rendering in node labels.\n securityLevel?: MermaidConfig['securityLevel'];\n theme?: MermaidConfig['theme'];\n },\n): string => {\n const theme = useTheme();\n const [data, setData] = useState<string>('');\n\n // 提取主题相关配置到 useMemo - 只依赖实际使用的 theme 属性\n const mermaidConfig = useMemo(\n () => createMermaidConfig(theme, customTheme, securityLevel),\n [\n theme.fontFamilyCode,\n theme.isDarkMode,\n theme.colorTextDescription,\n theme.fontFamily,\n theme.colorTextSecondary,\n theme.colorBgContainer,\n theme.colorInfoBg,\n theme.colorInfoText,\n theme.geekblue,\n theme.colorWarning,\n theme.colorSuccess,\n theme.colorError,\n theme.colorBorder,\n theme.colorInfoBorder,\n theme.colorSuccessBorder,\n theme.colorSuccessBg,\n theme.colorSuccessText,\n theme.colorText,\n customTheme,\n securityLevel,\n ],\n );\n\n // 为长内容生成哈希键\n const cacheKey = useMemo((): string => {\n const hash = content.length < MD5_LENGTH_THRESHOLD ? content : Md5.hashStr(content);\n return [id, customTheme || (theme.isDarkMode ? 'd' : 'l'), hash].filter(Boolean).join('-');\n }, [content, id, theme.isDarkMode, customTheme]);\n\n useEffect(() => {\n // Check cache first\n const cachedPromise = mermaidCache.get(cacheKey);\n if (cachedPromise) {\n cachedPromise\n .then((svg) => {\n setData(svg);\n })\n .catch(() => {\n // Silently handle errors, fallback will be handled in the promise\n });\n return;\n }\n\n // Create new promise for rendering\n const renderPromise = (async (): Promise<string> => {\n try {\n const mermaidInstance = await loadMermaid();\n if (!mermaidInstance) return '';\n\n // 验证语法\n const isValid = await mermaidInstance.parse(content);\n\n if (isValid) {\n // 初始化并渲染\n mermaidInstance.initialize(mermaidConfig);\n const { svg } = await mermaidInstance.render(id, content);\n return svg;\n } else {\n throw new Error('Mermaid 语法无效');\n }\n } catch (error_) {\n console.error('Mermaid 解析错误:', error_);\n return '';\n }\n })();\n\n // Cache the promise\n mermaidCache.set(cacheKey, renderPromise);\n cleanupCache();\n\n // Handle promise result\n renderPromise\n .then((svg) => {\n // Only update if this is still the current cache key\n if (mermaidCache.get(cacheKey) === renderPromise) {\n setData(svg);\n }\n })\n .catch(() => {\n // Remove failed promise from cache\n if (mermaidCache.get(cacheKey) === renderPromise) {\n mermaidCache.delete(cacheKey);\n }\n });\n }, [cacheKey, content, id, mermaidConfig]);\n\n return data;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useMermaid.mjs","names":[],"sources":["../../src/hooks/useMermaid.ts"],"sourcesContent":["'use client';\n\nimport { useThemeMode } from 'antd-style';\nimport { renderMermaidSVG, type RenderOptions, type ThemeName, THEMES } from 'beautiful-mermaid';\nimport { useEffect, useId, useMemo, useState } from 'react';\n\nimport { prepareInlineMermaidSvg } from '@/Mermaid/SyntaxMermaid/prepareInlineSvg';\n\nimport { createCdnMermaidConfig, renderWithCdnMermaid } from './useMermaidCdn';\n\nexport type MermaidThemeName = 'lobe-theme' | ThemeName;\n\nexport interface MermaidRenderResult {\n error?: string;\n loading?: boolean;\n svg: string;\n}\n\n/**\n * beautiful-mermaid emits these as CSS custom properties on the SVG root and\n * derives the rest with color-mix(), so pointing them at antd's variables lets\n * the diagram follow the theme through CSS alone no token subscription, and\n * no re-render (or re-layout) when the appearance changes.\n */\nconst LOBE_THEME_OPTIONS: RenderOptions = {\n accent: 'var(--ant-color-primary)',\n bg: 'var(--ant-color-bg-container)',\n border: 'var(--ant-color-border)',\n fg: 'var(--ant-color-text)',\n line: 'var(--ant-color-text-secondary)',\n muted: 'var(--ant-color-text-description)',\n surface: 'var(--ant-color-fill-tertiary)',\n transparent: true,\n};\n\nconst isNamedTheme = (theme?: MermaidThemeName): theme is ThemeName =>\n !!theme && theme !== 'lobe-theme' && theme in THEMES;\n\nexport const createMermaidOptions = (customTheme?: MermaidThemeName): RenderOptions =>\n isNamedTheme(customTheme) ? THEMES[customTheme]! : LOBE_THEME_OPTIONS;\n\n/**\n * beautiful-mermaid covers six diagram types; anything else throws here and is\n * handed to the CDN-loaded upstream mermaid instead.\n */\nexport const renderMermaid = (\n content: string,\n scopeId: string,\n customTheme?: MermaidThemeName,\n): MermaidRenderResult => {\n if (!content) return { svg: '' };\n try {\n const svg = renderMermaidSVG(content, createMermaidOptions(customTheme));\n return { svg: prepareInlineMermaidSvg(svg, scopeId) };\n } catch {\n return { error: 'unsupported', svg: '' };\n }\n};\n\nexport const useCdnMermaidFallback = (\n content: string,\n { enabled, theme: customTheme }: { enabled: boolean; theme?: MermaidThemeName },\n): MermaidRenderResult => {\n const { isDarkMode } = useThemeMode();\n const reactId = useId();\n const [result, setResult] = useState<MermaidRenderResult>({ svg: '' });\n\n useEffect(() => {\n if (!enabled || !content) {\n setResult({ svg: '' });\n return;\n }\n\n let active = true;\n setResult({ loading: true, svg: '' });\n\n const config = createCdnMermaidConfig(\n isDarkMode,\n isNamedTheme(customTheme) ? customTheme : undefined,\n );\n\n renderWithCdnMermaid(content, `mermaid-cdn-${reactId.replaceAll(':', '')}`, config)\n .then((svg) => {\n if (!active) return;\n setResult(svg ? { svg } : { error: 'Failed to render diagram', svg: '' });\n })\n .catch(() => {\n if (active) setResult({ error: 'Failed to render diagram', svg: '' });\n });\n\n return () => {\n active = false;\n };\n }, [enabled, content, isDarkMode, customTheme, reactId]);\n\n return result;\n};\n\nexport const useMermaid = (\n content: string,\n { theme: customTheme }: { theme?: MermaidThemeName } = {},\n): MermaidRenderResult => {\n const reactId = useId();\n const scopeId = useMemo(() => `mermaid-${reactId.replaceAll(':', '')}`, [reactId]);\n\n const primary = useMemo(\n () => renderMermaid(content, scopeId, customTheme),\n [content, scopeId, customTheme],\n );\n\n const fallback = useCdnMermaidFallback(content, {\n enabled: Boolean(primary.error),\n theme: customTheme,\n });\n\n return primary.error ? fallback : primary;\n};\n"],"mappings":";;;;;;;;;;;;;AAwBA,MAAM,qBAAoC;CACxC,QAAQ;CACR,IAAI;CACJ,QAAQ;CACR,IAAI;CACJ,MAAM;CACN,OAAO;CACP,SAAS;CACT,aAAa;AACf;AAEA,MAAM,gBAAgB,UACpB,CAAC,CAAC,SAAS,UAAU,gBAAgB,SAAS;AAEhD,MAAa,wBAAwB,gBACnC,aAAa,WAAW,IAAI,OAAO,eAAgB;;;;;AAMrD,MAAa,iBACX,SACA,SACA,gBACwB;CACxB,IAAI,CAAC,SAAS,OAAO,EAAE,KAAK,GAAG;CAC/B,IAAI;EACF,MAAM,MAAM,iBAAiB,SAAS,qBAAqB,WAAW,CAAC;EACvE,OAAO,EAAE,KAAK,wBAAwB,KAAK,OAAO,EAAE;CACtD,QAAQ;EACN,OAAO;GAAE,OAAO;GAAe,KAAK;EAAG;CACzC;AACF;AAEA,MAAa,yBACX,SACA,EAAE,SAAS,OAAO,kBACM;CACxB,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,UAAU,MAAM;CACtB,MAAM,CAAC,QAAQ,aAAa,SAA8B,EAAE,KAAK,GAAG,CAAC;CAErE,gBAAgB;EACd,IAAI,CAAC,WAAW,CAAC,SAAS;GACxB,UAAU,EAAE,KAAK,GAAG,CAAC;GACrB;EACF;EAEA,IAAI,SAAS;EACb,UAAU;GAAE,SAAS;GAAM,KAAK;EAAG,CAAC;EAEpC,MAAM,SAAS,uBACb,YACA,aAAa,WAAW,IAAI,cAAc,KAAA,CAC5C;EAEA,qBAAqB,SAAS,eAAe,QAAQ,WAAW,KAAK,EAAE,KAAK,MAAM,CAAC,CAChF,MAAM,QAAQ;GACb,IAAI,CAAC,QAAQ;GACb,UAAU,MAAM,EAAE,IAAI,IAAI;IAAE,OAAO;IAA4B,KAAK;GAAG,CAAC;EAC1E,CAAC,CAAC,CACD,YAAY;GACX,IAAI,QAAQ,UAAU;IAAE,OAAO;IAA4B,KAAK;GAAG,CAAC;EACtE,CAAC;EAEH,aAAa;GACX,SAAS;EACX;CACF,GAAG;EAAC;EAAS;EAAS;EAAY;EAAa;CAAO,CAAC;CAEvD,OAAO;AACT;AAEA,MAAa,cACX,SACA,EAAE,OAAO,gBAA8C,CAAC,MAChC;CACxB,MAAM,UAAU,MAAM;CACtB,MAAM,UAAU,cAAc,WAAW,QAAQ,WAAW,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC;CAEjF,MAAM,UAAU,cACR,cAAc,SAAS,SAAS,WAAW,GACjD;EAAC;EAAS;EAAS;CAAW,CAChC;CAEA,MAAM,WAAW,sBAAsB,SAAS;EAC9C,SAAS,QAAQ,QAAQ,KAAK;EAC9B,OAAO;CACT,CAAC;CAED,OAAO,QAAQ,QAAQ,WAAW;AACpC"}
@@ -0,0 +1,10 @@
1
+ //#region src/hooks/useMermaidCdn.d.ts
2
+ /**
3
+ * Point the fallback loader at a mirror, or at a self-hosted copy for offline
4
+ * and strict-CSP deployments. Resets any in-flight load.
5
+ */
6
+ declare const setMermaidCdnUrl: (url: string) => void;
7
+ declare const getMermaidCdnUrl: () => string;
8
+ //#endregion
9
+ export { getMermaidCdnUrl, setMermaidCdnUrl };
10
+ //# sourceMappingURL=useMermaidCdn.d.mts.map
@@ -0,0 +1,97 @@
1
+ "use client";
2
+ //#region src/hooks/useMermaidCdn.ts
3
+ let mermaidCdnUrl = "https://esm.sh/mermaid@11";
4
+ let mermaidPromise = null;
5
+ /**
6
+ * Point the fallback loader at a mirror, or at a self-hosted copy for offline
7
+ * and strict-CSP deployments. Resets any in-flight load.
8
+ */
9
+ const setMermaidCdnUrl = (url) => {
10
+ if (url === mermaidCdnUrl) return;
11
+ mermaidCdnUrl = url;
12
+ mermaidPromise = null;
13
+ };
14
+ const getMermaidCdnUrl = () => mermaidCdnUrl;
15
+ const loadCdnMermaid = () => {
16
+ if (typeof window === "undefined") return Promise.resolve(null);
17
+ mermaidPromise ??= import(
18
+ /* @vite-ignore */
19
+ mermaidCdnUrl
20
+ ).then((mod) => mod.default ?? mod).catch(() => null);
21
+ return mermaidPromise;
22
+ };
23
+ /**
24
+ * Upstream mermaid runs colour maths over themeVariables, so it needs literal
25
+ * values rather than var() references. Reading antd's CSS variables here keeps
26
+ * the cost off the render path — no theme context subscription, and it only
27
+ * runs for the diagram types that actually fall back to the CDN.
28
+ */
29
+ const readCssVars = (names) => {
30
+ const result = {};
31
+ if (typeof document === "undefined") return result;
32
+ const computed = globalThis.getComputedStyle(document.documentElement);
33
+ for (const [key, variable] of Object.entries(names)) result[key] = computed.getPropertyValue(variable).trim() || void 0;
34
+ return result;
35
+ };
36
+ const createCdnMermaidConfig = (isDarkMode, customTheme) => {
37
+ const token = readCssVars({
38
+ border: "--ant-color-border",
39
+ error: "--ant-color-error",
40
+ fontFamily: "--ant-font-family",
41
+ fontFamilyCode: "--ant-font-family-code",
42
+ infoBg: "--ant-color-info-bg",
43
+ infoBorder: "--ant-color-info-border",
44
+ infoText: "--ant-color-info-text",
45
+ primary: "--ant-color-primary",
46
+ success: "--ant-color-success",
47
+ successBg: "--ant-color-success-bg",
48
+ successBorder: "--ant-color-success-border",
49
+ successText: "--ant-color-success-text",
50
+ text: "--ant-color-text",
51
+ textDescription: "--ant-color-text-description",
52
+ textSecondary: "--ant-color-text-secondary",
53
+ bgContainer: "--ant-color-bg-container",
54
+ warning: "--ant-color-warning"
55
+ });
56
+ return {
57
+ fontFamily: token.fontFamilyCode,
58
+ gantt: { useWidth: 1920 },
59
+ securityLevel: "strict",
60
+ startOnLoad: false,
61
+ theme: customTheme || (isDarkMode ? "dark" : "neutral"),
62
+ themeVariables: customTheme ? void 0 : {
63
+ errorBkgColor: token.textDescription,
64
+ errorTextColor: token.textDescription,
65
+ fontFamily: token.fontFamily,
66
+ lineColor: token.textSecondary,
67
+ mainBkg: token.bgContainer,
68
+ noteBkgColor: token.infoBg,
69
+ noteTextColor: token.infoText,
70
+ pie1: token.primary,
71
+ pie2: token.warning,
72
+ pie3: token.success,
73
+ pie4: token.error,
74
+ primaryBorderColor: token.border,
75
+ primaryColor: token.bgContainer,
76
+ primaryTextColor: token.text,
77
+ secondaryBorderColor: token.infoBorder,
78
+ secondaryColor: token.infoBg,
79
+ secondaryTextColor: token.infoText,
80
+ tertiaryBorderColor: token.successBorder,
81
+ tertiaryColor: token.successBg,
82
+ tertiaryTextColor: token.successText,
83
+ textColor: token.text
84
+ }
85
+ };
86
+ };
87
+ const renderWithCdnMermaid = async (content, id, config) => {
88
+ const mermaid = await loadCdnMermaid();
89
+ if (!mermaid) return "";
90
+ mermaid.initialize(config);
91
+ const { svg } = await mermaid.render(id, content);
92
+ return svg;
93
+ };
94
+ //#endregion
95
+ export { createCdnMermaidConfig, getMermaidCdnUrl, loadCdnMermaid, renderWithCdnMermaid, setMermaidCdnUrl };
96
+
97
+ //# sourceMappingURL=useMermaidCdn.mjs.map