markstream-svelte 0.0.1-beta.1

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 (233) hide show
  1. package/README.md +77 -0
  2. package/dist/components/AdmonitionNode.svelte +8 -0
  3. package/dist/components/AdmonitionNode.svelte.d.ts +23 -0
  4. package/dist/components/AdmonitionNode.svelte.d.ts.map +1 -0
  5. package/dist/components/BlockquoteNode.svelte +10 -0
  6. package/dist/components/BlockquoteNode.svelte.d.ts +24 -0
  7. package/dist/components/BlockquoteNode.svelte.d.ts.map +1 -0
  8. package/dist/components/CheckboxNode.svelte +5 -0
  9. package/dist/components/CheckboxNode.svelte.d.ts +22 -0
  10. package/dist/components/CheckboxNode.svelte.d.ts.map +1 -0
  11. package/dist/components/CodeBlockNode.svelte +944 -0
  12. package/dist/components/CodeBlockNode.svelte.d.ts +43 -0
  13. package/dist/components/CodeBlockNode.svelte.d.ts.map +1 -0
  14. package/dist/components/D2BlockNode.svelte +272 -0
  15. package/dist/components/D2BlockNode.svelte.d.ts +33 -0
  16. package/dist/components/D2BlockNode.svelte.d.ts.map +1 -0
  17. package/dist/components/DefinitionListNode.svelte +8 -0
  18. package/dist/components/DefinitionListNode.svelte.d.ts +23 -0
  19. package/dist/components/DefinitionListNode.svelte.d.ts.map +1 -0
  20. package/dist/components/EmojiNode.svelte +7 -0
  21. package/dist/components/EmojiNode.svelte.d.ts +22 -0
  22. package/dist/components/EmojiNode.svelte.d.ts.map +1 -0
  23. package/dist/components/EmphasisNode.svelte +8 -0
  24. package/dist/components/EmphasisNode.svelte.d.ts +24 -0
  25. package/dist/components/EmphasisNode.svelte.d.ts.map +1 -0
  26. package/dist/components/FallbackComponent.svelte +8 -0
  27. package/dist/components/FallbackComponent.svelte.d.ts +23 -0
  28. package/dist/components/FallbackComponent.svelte.d.ts.map +1 -0
  29. package/dist/components/FootnoteAnchorNode.svelte +21 -0
  30. package/dist/components/FootnoteAnchorNode.svelte.d.ts +22 -0
  31. package/dist/components/FootnoteAnchorNode.svelte.d.ts.map +1 -0
  32. package/dist/components/FootnoteNode.svelte +19 -0
  33. package/dist/components/FootnoteNode.svelte.d.ts +24 -0
  34. package/dist/components/FootnoteNode.svelte.d.ts.map +1 -0
  35. package/dist/components/FootnoteReferenceNode.svelte +26 -0
  36. package/dist/components/FootnoteReferenceNode.svelte.d.ts +22 -0
  37. package/dist/components/FootnoteReferenceNode.svelte.d.ts.map +1 -0
  38. package/dist/components/HardBreakNode.svelte +1 -0
  39. package/dist/components/HardBreakNode.svelte.d.ts +27 -0
  40. package/dist/components/HardBreakNode.svelte.d.ts.map +1 -0
  41. package/dist/components/HeadingNode.svelte +15 -0
  42. package/dist/components/HeadingNode.svelte.d.ts +24 -0
  43. package/dist/components/HeadingNode.svelte.d.ts.map +1 -0
  44. package/dist/components/HighlightNode.svelte +8 -0
  45. package/dist/components/HighlightNode.svelte.d.ts +24 -0
  46. package/dist/components/HighlightNode.svelte.d.ts.map +1 -0
  47. package/dist/components/HtmlBlockNode.svelte +8 -0
  48. package/dist/components/HtmlBlockNode.svelte.d.ts +23 -0
  49. package/dist/components/HtmlBlockNode.svelte.d.ts.map +1 -0
  50. package/dist/components/HtmlInlineNode.svelte +8 -0
  51. package/dist/components/HtmlInlineNode.svelte.d.ts +23 -0
  52. package/dist/components/HtmlInlineNode.svelte.d.ts.map +1 -0
  53. package/dist/components/HtmlPreviewFrame.svelte +13 -0
  54. package/dist/components/HtmlPreviewFrame.svelte.d.ts +26 -0
  55. package/dist/components/HtmlPreviewFrame.svelte.d.ts.map +1 -0
  56. package/dist/components/ImageNode.svelte +86 -0
  57. package/dist/components/ImageNode.svelte.d.ts +25 -0
  58. package/dist/components/ImageNode.svelte.d.ts.map +1 -0
  59. package/dist/components/InfographicBlockNode.svelte +429 -0
  60. package/dist/components/InfographicBlockNode.svelte.d.ts +34 -0
  61. package/dist/components/InfographicBlockNode.svelte.d.ts.map +1 -0
  62. package/dist/components/InlineCodeNode.svelte +7 -0
  63. package/dist/components/InlineCodeNode.svelte.d.ts +22 -0
  64. package/dist/components/InlineCodeNode.svelte.d.ts.map +1 -0
  65. package/dist/components/InlineWrapNode.svelte +10 -0
  66. package/dist/components/InlineWrapNode.svelte.d.ts +25 -0
  67. package/dist/components/InlineWrapNode.svelte.d.ts.map +1 -0
  68. package/dist/components/InsertNode.svelte +8 -0
  69. package/dist/components/InsertNode.svelte.d.ts +24 -0
  70. package/dist/components/InsertNode.svelte.d.ts.map +1 -0
  71. package/dist/components/LinkNode.svelte +41 -0
  72. package/dist/components/LinkNode.svelte.d.ts +25 -0
  73. package/dist/components/LinkNode.svelte.d.ts.map +1 -0
  74. package/dist/components/ListItemNode.svelte +9 -0
  75. package/dist/components/ListItemNode.svelte.d.ts +24 -0
  76. package/dist/components/ListItemNode.svelte.d.ts.map +1 -0
  77. package/dist/components/ListNode.svelte +16 -0
  78. package/dist/components/ListNode.svelte.d.ts +24 -0
  79. package/dist/components/ListNode.svelte.d.ts.map +1 -0
  80. package/dist/components/MarkdownCodeBlockNode.svelte +7 -0
  81. package/dist/components/MarkdownCodeBlockNode.svelte.d.ts +23 -0
  82. package/dist/components/MarkdownCodeBlockNode.svelte.d.ts.map +1 -0
  83. package/dist/components/MathBlockNode.svelte +96 -0
  84. package/dist/components/MathBlockNode.svelte.d.ts +22 -0
  85. package/dist/components/MathBlockNode.svelte.d.ts.map +1 -0
  86. package/dist/components/MathInlineNode.svelte +103 -0
  87. package/dist/components/MathInlineNode.svelte.d.ts +22 -0
  88. package/dist/components/MathInlineNode.svelte.d.ts.map +1 -0
  89. package/dist/components/MermaidBlockNode.svelte +557 -0
  90. package/dist/components/MermaidBlockNode.svelte.d.ts +40 -0
  91. package/dist/components/MermaidBlockNode.svelte.d.ts.map +1 -0
  92. package/dist/components/NodeOutlet.svelte +192 -0
  93. package/dist/components/NodeOutlet.svelte.d.ts +24 -0
  94. package/dist/components/NodeOutlet.svelte.d.ts.map +1 -0
  95. package/dist/components/NodeRenderer.svelte +349 -0
  96. package/dist/components/NodeRenderer.svelte.d.ts +64 -0
  97. package/dist/components/NodeRenderer.svelte.d.ts.map +1 -0
  98. package/dist/components/ParagraphNode.svelte +21 -0
  99. package/dist/components/ParagraphNode.svelte.d.ts +24 -0
  100. package/dist/components/ParagraphNode.svelte.d.ts.map +1 -0
  101. package/dist/components/PreCodeNode.svelte +13 -0
  102. package/dist/components/PreCodeNode.svelte.d.ts +22 -0
  103. package/dist/components/PreCodeNode.svelte.d.ts.map +1 -0
  104. package/dist/components/ReferenceNode.svelte +8 -0
  105. package/dist/components/ReferenceNode.svelte.d.ts +23 -0
  106. package/dist/components/ReferenceNode.svelte.d.ts.map +1 -0
  107. package/dist/components/RenderChildren.svelte +12 -0
  108. package/dist/components/RenderChildren.svelte.d.ts +24 -0
  109. package/dist/components/RenderChildren.svelte.d.ts.map +1 -0
  110. package/dist/components/StrikethroughNode.svelte +8 -0
  111. package/dist/components/StrikethroughNode.svelte.d.ts +24 -0
  112. package/dist/components/StrikethroughNode.svelte.d.ts.map +1 -0
  113. package/dist/components/StrongNode.svelte +8 -0
  114. package/dist/components/StrongNode.svelte.d.ts +24 -0
  115. package/dist/components/StrongNode.svelte.d.ts.map +1 -0
  116. package/dist/components/SubscriptNode.svelte +8 -0
  117. package/dist/components/SubscriptNode.svelte.d.ts +24 -0
  118. package/dist/components/SubscriptNode.svelte.d.ts.map +1 -0
  119. package/dist/components/SuperscriptNode.svelte +8 -0
  120. package/dist/components/SuperscriptNode.svelte.d.ts +24 -0
  121. package/dist/components/SuperscriptNode.svelte.d.ts.map +1 -0
  122. package/dist/components/TableNode.svelte +8 -0
  123. package/dist/components/TableNode.svelte.d.ts +23 -0
  124. package/dist/components/TableNode.svelte.d.ts.map +1 -0
  125. package/dist/components/TextNode.svelte +37 -0
  126. package/dist/components/TextNode.svelte.d.ts +25 -0
  127. package/dist/components/TextNode.svelte.d.ts.map +1 -0
  128. package/dist/components/ThematicBreakNode.svelte +1 -0
  129. package/dist/components/ThematicBreakNode.svelte.d.ts +27 -0
  130. package/dist/components/ThematicBreakNode.svelte.d.ts.map +1 -0
  131. package/dist/components/Tooltip.svelte +4 -0
  132. package/dist/components/Tooltip.svelte.d.ts +21 -0
  133. package/dist/components/Tooltip.svelte.d.ts.map +1 -0
  134. package/dist/components/VmrContainerNode.svelte +8 -0
  135. package/dist/components/VmrContainerNode.svelte.d.ts +23 -0
  136. package/dist/components/VmrContainerNode.svelte.d.ts.map +1 -0
  137. package/dist/components/shared/diagram-height.d.ts +10 -0
  138. package/dist/components/shared/diagram-height.d.ts.map +1 -0
  139. package/dist/components/shared/diagram-height.js +52 -0
  140. package/dist/components/shared/node-helpers.d.ts +108 -0
  141. package/dist/components/shared/node-helpers.d.ts.map +1 -0
  142. package/dist/components/shared/node-helpers.js +220 -0
  143. package/dist/components/shared/node-outlet-helpers.d.ts +9 -0
  144. package/dist/components/shared/node-outlet-helpers.d.ts.map +1 -0
  145. package/dist/components/shared/node-outlet-helpers.js +92 -0
  146. package/dist/components/shared/render-window.d.ts +19 -0
  147. package/dist/components/shared/render-window.d.ts.map +1 -0
  148. package/dist/components/shared/render-window.js +63 -0
  149. package/dist/components/shared/renderNodeHtml.d.ts +4 -0
  150. package/dist/components/shared/renderNodeHtml.d.ts.map +1 -0
  151. package/dist/components/shared/renderNodeHtml.js +19 -0
  152. package/dist/components/shared/rich-block-helpers.d.ts +7 -0
  153. package/dist/components/shared/rich-block-helpers.d.ts.map +1 -0
  154. package/dist/components/shared/rich-block-helpers.js +76 -0
  155. package/dist/customComponents.d.ts +10 -0
  156. package/dist/customComponents.d.ts.map +1 -0
  157. package/dist/customComponents.js +66 -0
  158. package/dist/enhanceRenderedHtml.d.ts +21 -0
  159. package/dist/enhanceRenderedHtml.d.ts.map +1 -0
  160. package/dist/enhanceRenderedHtml.js +768 -0
  161. package/dist/hydrateCustomTagContent.d.ts +3 -0
  162. package/dist/hydrateCustomTagContent.d.ts.map +1 -0
  163. package/dist/hydrateCustomTagContent.js +130 -0
  164. package/dist/i18n/useSafeI18n.d.ts +5 -0
  165. package/dist/i18n/useSafeI18n.d.ts.map +1 -0
  166. package/dist/i18n/useSafeI18n.js +42 -0
  167. package/dist/index.css +2009 -0
  168. package/dist/index.d.ts +78 -0
  169. package/dist/index.d.ts.map +1 -0
  170. package/dist/index.js +66 -0
  171. package/dist/index.px.css +2009 -0
  172. package/dist/index.tailwind.css +2009 -0
  173. package/dist/optional/d2.d.ts +7 -0
  174. package/dist/optional/d2.d.ts.map +1 -0
  175. package/dist/optional/d2.js +67 -0
  176. package/dist/optional/infographic.d.ts +2 -0
  177. package/dist/optional/infographic.d.ts.map +1 -0
  178. package/dist/optional/infographic.js +29 -0
  179. package/dist/optional/katex.d.ts +7 -0
  180. package/dist/optional/katex.d.ts.map +1 -0
  181. package/dist/optional/katex.js +93 -0
  182. package/dist/optional/mermaid.d.ts +7 -0
  183. package/dist/optional/mermaid.d.ts.map +1 -0
  184. package/dist/optional/mermaid.js +171 -0
  185. package/dist/optional/monaco.d.ts +5 -0
  186. package/dist/optional/monaco.d.ts.map +1 -0
  187. package/dist/optional/monaco.js +70 -0
  188. package/dist/parseNestedMarkdownToNodes.d.ts +15 -0
  189. package/dist/parseNestedMarkdownToNodes.d.ts.map +1 -0
  190. package/dist/parseNestedMarkdownToNodes.js +66 -0
  191. package/dist/renderMarkdownHtml.d.ts +31 -0
  192. package/dist/renderMarkdownHtml.d.ts.map +1 -0
  193. package/dist/renderMarkdownHtml.js +465 -0
  194. package/dist/sanitizeHtmlContent.d.ts +3 -0
  195. package/dist/sanitizeHtmlContent.d.ts.map +1 -0
  196. package/dist/sanitizeHtmlContent.js +175 -0
  197. package/dist/sanitizeSvg.d.ts +3 -0
  198. package/dist/sanitizeSvg.d.ts.map +1 -0
  199. package/dist/sanitizeSvg.js +76 -0
  200. package/dist/tailwind-entry.d.ts +2 -0
  201. package/dist/tailwind-entry.d.ts.map +1 -0
  202. package/dist/tailwind-entry.js +1 -0
  203. package/dist/tooltip/singletonTooltip.d.ts +8 -0
  204. package/dist/tooltip/singletonTooltip.d.ts.map +1 -0
  205. package/dist/tooltip/singletonTooltip.js +124 -0
  206. package/dist/types/monaco.d.ts +66 -0
  207. package/dist/types/monaco.d.ts.map +1 -0
  208. package/dist/types/monaco.js +1 -0
  209. package/dist/utils/languageIcon.d.ts +8 -0
  210. package/dist/utils/languageIcon.d.ts.map +1 -0
  211. package/dist/utils/languageIcon.js +182 -0
  212. package/dist/utils/normalizeKaTeXRenderInput.d.ts +2 -0
  213. package/dist/utils/normalizeKaTeXRenderInput.d.ts.map +1 -0
  214. package/dist/utils/normalizeKaTeXRenderInput.js +7 -0
  215. package/dist/workers/katexCdnWorker.d.ts +21 -0
  216. package/dist/workers/katexCdnWorker.d.ts.map +1 -0
  217. package/dist/workers/katexCdnWorker.js +193 -0
  218. package/dist/workers/katexRenderer.worker.d.ts +2 -0
  219. package/dist/workers/katexRenderer.worker.d.ts.map +1 -0
  220. package/dist/workers/katexRenderer.worker.js +55 -0
  221. package/dist/workers/katexWorkerClient.d.ts +36 -0
  222. package/dist/workers/katexWorkerClient.d.ts.map +1 -0
  223. package/dist/workers/katexWorkerClient.js +270 -0
  224. package/dist/workers/mermaidCdnWorker.d.ts +16 -0
  225. package/dist/workers/mermaidCdnWorker.d.ts.map +1 -0
  226. package/dist/workers/mermaidCdnWorker.js +235 -0
  227. package/dist/workers/mermaidParser.worker.d.ts +2 -0
  228. package/dist/workers/mermaidParser.worker.d.ts.map +1 -0
  229. package/dist/workers/mermaidParser.worker.js +85 -0
  230. package/dist/workers/mermaidWorkerClient.d.ts +16 -0
  231. package/dist/workers/mermaidWorkerClient.d.ts.map +1 -0
  232. package/dist/workers/mermaidWorkerClient.js +170 -0
  233. package/package.json +95 -0
@@ -0,0 +1,944 @@
1
+ <script lang="ts">
2
+ import type { CodeBlockMonacoOptions, CodeBlockMonacoTheme } from '../types/monaco'
3
+ import type { SvelteRenderableNode, SvelteRenderContext } from './shared/node-helpers'
4
+ import { onDestroy, onMount, tick } from 'svelte'
5
+ import { useSafeI18n } from '../i18n/useSafeI18n'
6
+ import { getUseMonaco } from '../optional/monaco'
7
+ import { hideTooltip, showTooltipForAnchor } from '../tooltip/singletonTooltip'
8
+ import { getLanguageIcon, isLikelyIncompleteLanguageIdentifier, languageMap, normalizeLanguageIdentifier, resolveMonacoLanguageId } from '../utils/languageIcon'
9
+ import HtmlPreviewFrame from './HtmlPreviewFrame.svelte'
10
+ import { copyTextToClipboard, resolveCssSize } from './shared/rich-block-helpers'
11
+ import { getString, sanitizeClassToken } from './shared/node-helpers'
12
+
13
+ export let node: SvelteRenderableNode
14
+ export let context: SvelteRenderContext | undefined = undefined
15
+ export let isDark: boolean | undefined = undefined
16
+ export let loading: boolean | undefined = undefined
17
+ export let stream: boolean | undefined = undefined
18
+ export let darkTheme: CodeBlockMonacoTheme | undefined = undefined
19
+ export let lightTheme: CodeBlockMonacoTheme | undefined = undefined
20
+ export let themes: CodeBlockMonacoTheme[] | undefined = undefined
21
+ export let monacoOptions: CodeBlockMonacoOptions | undefined = undefined
22
+ export let minWidth: string | number | undefined = undefined
23
+ export let maxWidth: string | number | undefined = undefined
24
+ export let isShowPreview = true
25
+ export let enableFontSizeControl = true
26
+ export let showHeader = true
27
+ export let showCopyButton = true
28
+ export let showExpandButton = true
29
+ export let showPreviewButton = true
30
+ export let showCollapseButton = true
31
+ export let showFontSizeButtons = true
32
+ export let htmlPreviewAllowScripts = false
33
+ export let htmlPreviewSandbox: string | undefined = undefined
34
+
35
+ const { t } = useSafeI18n()
36
+ const defaultDiffHideUnchangedRegions = Object.freeze({
37
+ enabled: true,
38
+ contextLineCount: 2,
39
+ minimumLineCount: 4,
40
+ revealLineCount: 5,
41
+ })
42
+ const disabledDiffHideUnchangedRegions = Object.freeze({
43
+ enabled: false,
44
+ contextLineCount: 0,
45
+ minimumLineCount: Number.POSITIVE_INFINITY,
46
+ revealLineCount: 0,
47
+ })
48
+ const streamingLanguageTokens = ['javascript', 'plaintext', 'shellscript', 'typescript']
49
+
50
+ function resolveRecoverableFallbackLanguage(error: unknown) {
51
+ const message = error instanceof Error ? error.message : String(error ?? '')
52
+ const missingLanguage = message.match(/Language `([^`]+)` is not included/)?.[1]
53
+ return missingLanguage && isLikelyIncompleteLanguageIdentifier(missingLanguage)
54
+ ? missingLanguage
55
+ : ''
56
+ }
57
+
58
+ function markEditorFallback(error: unknown) {
59
+ const recoverableLanguage = resolveRecoverableFallbackLanguage(error)
60
+ if (recoverableLanguage) {
61
+ fallbackLanguage = recoverableLanguage
62
+ useFallback = false
63
+ queueRecoverableLanguageRetry(recoverableLanguage)
64
+ return
65
+ }
66
+ fallbackLanguage = rawLanguage
67
+ useFallback = true
68
+ }
69
+
70
+ function isStreamingLanguagePrefix(lang: string) {
71
+ const token = lang.trim().split(/\s+/)[0]?.split(':')[0]?.toLowerCase() || ''
72
+ return token.length >= 3 && streamingLanguageTokens.some(candidate => candidate !== token && candidate.startsWith(token))
73
+ }
74
+
75
+ function queueRecoverableLanguageRetry(recoverableLanguage: string) {
76
+ if (languageRetryTimer)
77
+ return
78
+ const retry = () => {
79
+ languageRetryTimer = null
80
+ if (!mounted)
81
+ return
82
+ if (
83
+ rawLanguage !== recoverableLanguage
84
+ && !isLikelyIncompleteLanguageIdentifier(rawLanguage)
85
+ && !isStreamingLanguagePrefix(rawLanguage)
86
+ && !shouldDelayEditor
87
+ && !shouldDeferStreamingLanguage
88
+ ) {
89
+ fallbackLanguage = ''
90
+ void syncEditor()
91
+ return
92
+ }
93
+ languageRetryTimer = setTimeout(retry, 50)
94
+ }
95
+ languageRetryTimer = setTimeout(retry, 50)
96
+ }
97
+
98
+ let editorHost: HTMLDivElement | null = null
99
+ let helpers: any = null
100
+ let runtimeMonacoOptions: Record<string, any> | null = null
101
+ let ensureMonacoPromise: Promise<void> | null = null
102
+ let editorReady = false
103
+ let useFallback = false
104
+ let fallbackLanguage = ''
105
+ let editorKind: 'single' | 'diff' | null = null
106
+ let createEditorPromise: Promise<void> | null = null
107
+ let mounted = false
108
+ let collapsed = false
109
+ let expanded = false
110
+ let copied = false
111
+ let previewOpen = false
112
+ let codeFontSize = 13
113
+ let copyTimer: ReturnType<typeof setTimeout> | null = null
114
+ let lifecycleId = 0
115
+ let heightSyncRaf: number | null = null
116
+ let heightSyncDisposables: Array<{ dispose?: () => void } | (() => void)> = []
117
+ let lastLayoutWidth: number | null = null
118
+ let lastLayoutHeight: number | null = null
119
+ let lastThemeRequest = ''
120
+ let languageRetryTimer: ReturnType<typeof setTimeout> | null = null
121
+ let loadingSettledRefreshPromise: Promise<void> | null = null
122
+ let loadingSettledRefreshTimer: ReturnType<typeof setTimeout> | null = null
123
+ let lastSettledRefreshSignature = ''
124
+ let tokenizeTimer: ReturnType<typeof setTimeout> | null = null
125
+ let tokenizeRaf: number | null = null
126
+ let tokenizeShouldRefreshModelValue = false
127
+
128
+ $: rawLanguage = getString((node as any)?.language).trim()
129
+ $: canonicalLanguage = normalizeLanguageIdentifier(rawLanguage)
130
+ $: monacoLanguage = resolveMonacoLanguageId(canonicalLanguage || rawLanguage || 'plaintext')
131
+ $: code = getResolvedCode(node)
132
+ $: diff = Boolean((node as any)?.diff)
133
+ $: originalCode = getString((node as any)?.originalCode)
134
+ $: updatedCode = getString((node as any)?.updatedCode)
135
+ $: nodeLoading = (node as any)?.loading === true
136
+ $: resolvedLoading = loading ?? nodeLoading
137
+ $: resolvedStream = stream ?? context?.codeBlockStream ?? true
138
+ $: resolvedIsDark = isDark ?? context?.isDark ?? false
139
+ $: resolvedThemes = context?.codeBlockThemes
140
+ $: mergedMonacoOptions = { ...(resolvedThemes?.monacoOptions || {}), ...(monacoOptions || {}) }
141
+ $: resolvedMonacoOptions = buildResolvedMonacoOptions()
142
+ $: requestedTheme = getThemeName(
143
+ resolvedIsDark
144
+ ? darkTheme ?? resolvedThemes?.darkTheme
145
+ : lightTheme ?? resolvedThemes?.lightTheme,
146
+ resolvedIsDark ? 'vitesse-dark' : 'vitesse-light',
147
+ )
148
+ $: defaultCodeFontSize = Number(mergedMonacoOptions.fontSize) || 13
149
+ $: minWidthValue = resolveCssSize(minWidth ?? resolvedThemes?.minWidth)
150
+ $: maxWidthValue = resolveCssSize(maxWidth ?? resolvedThemes?.maxWidth)
151
+ $: containerStyle = [
152
+ minWidthValue ? `min-width: ${minWidthValue}` : '',
153
+ maxWidthValue ? `max-width: ${maxWidthValue}` : '',
154
+ ].filter(Boolean).join('; ')
155
+ $: languageIcon = getLanguageIcon(canonicalLanguage || rawLanguage || 'plain')
156
+ $: displayLanguage = languageMap[canonicalLanguage] || (rawLanguage ? rawLanguage.toUpperCase() : languageMap[''])
157
+ $: isPreviewable = isShowPreview !== false && (canonicalLanguage === 'html' || canonicalLanguage === 'svg')
158
+ $: previewTitle = canonicalLanguage === 'svg' ? t('artifacts.svgPreviewTitle') : t('artifacts.htmlPreviewTitle')
159
+ $: shouldDelayEditor = resolvedStream === false && resolvedLoading
160
+ $: documentStreaming = context?.final === false || resolvedLoading
161
+ $: shouldDeferStreamingLanguage = resolvedStream !== false && documentStreaming && (isLikelyIncompleteLanguageIdentifier(rawLanguage) || isStreamingLanguagePrefix(rawLanguage))
162
+ $: shouldRender = !(resolvedLoading && !code.trim())
163
+ $: preLanguageClass = sanitizeClassToken(rawLanguage || monacoLanguage)
164
+ $: showPreWhileMonacoLoads = !useFallback && !shouldDelayEditor && !shouldDeferStreamingLanguage && !editorReady
165
+ $: showPreFallback = useFallback || shouldDelayEditor || shouldDeferStreamingLanguage || showPreWhileMonacoLoads
166
+ $: settledRefreshSignature = diff
167
+ ? `${monacoLanguage}\0${originalCode}\0${updatedCode || code}`
168
+ : `${monacoLanguage}\0${code}`
169
+ $: if (useFallback && fallbackLanguage && rawLanguage !== fallbackLanguage && isLikelyIncompleteLanguageIdentifier(fallbackLanguage)) {
170
+ useFallback = false
171
+ fallbackLanguage = ''
172
+ }
173
+ $: {
174
+ void mounted
175
+ void resolvedLoading
176
+ void settledRefreshSignature
177
+ void shouldDelayEditor
178
+ void shouldDeferStreamingLanguage
179
+ if (mounted && resolvedLoading === false && !shouldDelayEditor && !shouldDeferStreamingLanguage) {
180
+ if (settledRefreshSignature !== lastSettledRefreshSignature) {
181
+ lastSettledRefreshSignature = settledRefreshSignature
182
+ queueLoadingSettledRefresh()
183
+ }
184
+ }
185
+ }
186
+ $: {
187
+ void mounted
188
+ void editorHost
189
+ void shouldRender
190
+ void collapsed
191
+ void shouldDelayEditor
192
+ void shouldDeferStreamingLanguage
193
+ void diff
194
+ void code
195
+ void originalCode
196
+ void updatedCode
197
+ void monacoLanguage
198
+ void requestedTheme
199
+ void resolvedMonacoOptions
200
+ void codeFontSize
201
+ void expanded
202
+ if (mounted)
203
+ void syncEditor()
204
+ }
205
+
206
+ onMount(() => {
207
+ mounted = true
208
+ codeFontSize = defaultCodeFontSize
209
+ })
210
+
211
+ onDestroy(() => {
212
+ mounted = false
213
+ lifecycleId += 1
214
+ if (copyTimer)
215
+ clearTimeout(copyTimer)
216
+ if (languageRetryTimer)
217
+ clearTimeout(languageRetryTimer)
218
+ if (loadingSettledRefreshTimer)
219
+ clearTimeout(loadingSettledRefreshTimer)
220
+ cancelEditorTokenization()
221
+ cleanupEditor()
222
+ })
223
+
224
+ function getResolvedCode(sourceNode: SvelteRenderableNode) {
225
+ if ((sourceNode as any)?.diff)
226
+ return getString((sourceNode as any)?.updatedCode ?? (sourceNode as any)?.code)
227
+ return getString((sourceNode as any)?.code)
228
+ }
229
+
230
+ function getThemeName(theme: CodeBlockMonacoTheme | undefined, fallback: string) {
231
+ if (typeof theme === 'string' && theme)
232
+ return theme
233
+ if (theme && typeof theme === 'object' && typeof (theme as any).name === 'string')
234
+ return String((theme as any).name)
235
+ return fallback
236
+ }
237
+
238
+ function buildThemeList() {
239
+ const list: CodeBlockMonacoTheme[] = ['vitesse-dark', 'vitesse-light']
240
+ const add = (item: CodeBlockMonacoTheme | undefined) => {
241
+ if (item)
242
+ list.push(item)
243
+ }
244
+ add(darkTheme ?? resolvedThemes?.darkTheme)
245
+ add(lightTheme ?? resolvedThemes?.lightTheme)
246
+ for (const item of resolvedThemes?.themes || [])
247
+ add(item)
248
+ for (const item of themes || [])
249
+ add(item)
250
+ return list
251
+ }
252
+
253
+ function resolveDiffHideUnchangedRegionsOption(value: unknown) {
254
+ if (typeof value === 'boolean')
255
+ return value
256
+ if (value && typeof value === 'object') {
257
+ const raw = value as Record<string, unknown>
258
+ return {
259
+ ...defaultDiffHideUnchangedRegions,
260
+ ...raw,
261
+ enabled: raw.enabled ?? true,
262
+ }
263
+ }
264
+ return { ...defaultDiffHideUnchangedRegions }
265
+ }
266
+
267
+ function buildResolvedMonacoOptions() {
268
+ const raw = { ...mergedMonacoOptions } as Record<string, any>
269
+ const maxHeight = expanded ? 900 : (raw.MAX_HEIGHT ?? 500)
270
+ const baseOptions = {
271
+ readOnly: true,
272
+ minimap: { enabled: false },
273
+ lineNumbers: 'on',
274
+ wordWrap: 'on',
275
+ wrappingIndent: 'same',
276
+ revealDebounceMs: 75,
277
+ }
278
+ const finalOptions = {
279
+ MAX_HEIGHT: maxHeight,
280
+ fontSize: codeFontSize,
281
+ themes: buildThemeList(),
282
+ }
283
+
284
+ if (!diff) {
285
+ return {
286
+ ...baseOptions,
287
+ ...raw,
288
+ ...finalOptions,
289
+ }
290
+ }
291
+
292
+ const diffHideUnchangedRegions = raw.diffHideUnchangedRegions === undefined
293
+ ? { ...defaultDiffHideUnchangedRegions }
294
+ : resolveDiffHideUnchangedRegionsOption(raw.diffHideUnchangedRegions)
295
+ const hideUnchangedRegions = raw.hideUnchangedRegions === undefined
296
+ ? undefined
297
+ : resolveDiffHideUnchangedRegionsOption(raw.hideUnchangedRegions)
298
+ const streamPreviewDiff = resolvedStream !== false && resolvedLoading !== false
299
+ const activeDiffHideUnchangedRegions = streamPreviewDiff
300
+ ? { ...disabledDiffHideUnchangedRegions }
301
+ : diffHideUnchangedRegions
302
+ const activeHideUnchangedRegions = streamPreviewDiff
303
+ ? { ...disabledDiffHideUnchangedRegions }
304
+ : hideUnchangedRegions
305
+ const experimental = {
306
+ ...((raw.experimental as Record<string, unknown> | undefined) ?? {}),
307
+ }
308
+ const diffUnchangedRegionStyle = raw.diffUnchangedRegionStyle ?? 'line-info'
309
+ const diffDefaults = {
310
+ maxComputationTime: 0,
311
+ diffAlgorithm: 'legacy',
312
+ ignoreTrimWhitespace: false,
313
+ renderIndicators: true,
314
+ diffUpdateThrottleMs: 120,
315
+ renderLineHighlight: 'none',
316
+ renderLineHighlightOnlyWhenFocus: true,
317
+ selectionHighlight: false,
318
+ occurrencesHighlight: 'off',
319
+ matchBrackets: 'never',
320
+ lineDecorationsWidth: 4,
321
+ lineNumbersMinChars: 2,
322
+ glyphMargin: false,
323
+ renderOverviewRuler: false,
324
+ overviewRulerBorder: false,
325
+ hideCursorInOverviewRuler: true,
326
+ scrollBeyondLastLine: false,
327
+ diffHideUnchangedRegions: activeDiffHideUnchangedRegions,
328
+ useInlineViewWhenSpaceIsLimited: raw.useInlineViewWhenSpaceIsLimited ?? false,
329
+ diffLineStyle: 'background',
330
+ diffAppearance: 'auto',
331
+ diffUnchangedRegionStyle,
332
+ diffHunkActionsOnHover: false,
333
+ experimental,
334
+ }
335
+
336
+ return {
337
+ ...baseOptions,
338
+ ...diffDefaults,
339
+ ...raw,
340
+ experimental,
341
+ ...(activeHideUnchangedRegions === undefined ? {} : { hideUnchangedRegions: activeHideUnchangedRegions }),
342
+ diffHideUnchangedRegions: activeDiffHideUnchangedRegions,
343
+ ...finalOptions,
344
+ }
345
+ }
346
+
347
+ function syncRuntimeMonacoOptions() {
348
+ const nextOptions = {
349
+ ...resolvedMonacoOptions,
350
+ theme: requestedTheme,
351
+ }
352
+ if (!runtimeMonacoOptions) {
353
+ runtimeMonacoOptions = nextOptions
354
+ return runtimeMonacoOptions
355
+ }
356
+ for (const key of Object.keys(runtimeMonacoOptions)) {
357
+ if (!(key in nextOptions))
358
+ delete runtimeMonacoOptions[key]
359
+ }
360
+ Object.assign(runtimeMonacoOptions, nextOptions)
361
+ return runtimeMonacoOptions
362
+ }
363
+
364
+ async function ensureMonaco() {
365
+ if (helpers || useFallback || typeof window === 'undefined')
366
+ return
367
+ if (ensureMonacoPromise)
368
+ return ensureMonacoPromise
369
+
370
+ ensureMonacoPromise = (async () => {
371
+ const mod = await getUseMonaco()
372
+ if (!mounted)
373
+ return
374
+ if (!mod || typeof mod.useMonaco !== 'function') {
375
+ useFallback = true
376
+ return
377
+ }
378
+
379
+ helpers = mod.useMonaco(syncRuntimeMonacoOptions())
380
+ lastThemeRequest = requestedTheme
381
+ })().finally(() => {
382
+ ensureMonacoPromise = null
383
+ })
384
+ return ensureMonacoPromise
385
+ }
386
+
387
+ function queueThemeSync() {
388
+ if (!helpers || !requestedTheme || requestedTheme === lastThemeRequest)
389
+ return
390
+ lastThemeRequest = requestedTheme
391
+ void Promise.resolve(helpers.setTheme?.(requestedTheme)).catch((error) => {
392
+ if (typeof console !== 'undefined')
393
+ console.warn('[markstream-svelte] Failed to apply Monaco theme:', error)
394
+ })
395
+ }
396
+
397
+ async function syncEditor() {
398
+ if (!mounted || !shouldRender || !editorHost || collapsed || shouldDelayEditor || shouldDeferStreamingLanguage)
399
+ return
400
+
401
+ await ensureMonaco()
402
+ if (!mounted || useFallback || !helpers)
403
+ return
404
+ syncRuntimeMonacoOptions()
405
+
406
+ const desiredKind: 'single' | 'diff' = diff ? 'diff' : 'single'
407
+ const hasEditorView = desiredKind === 'diff'
408
+ ? Boolean(helpers.getDiffEditorView?.())
409
+ : Boolean(helpers.getEditorView?.())
410
+ const hasEditor = hasEditorView && hasRenderedEditorDom(desiredKind)
411
+
412
+ if (!hasEditor || editorKind !== desiredKind) {
413
+ await recreateEditor(desiredKind)
414
+ if (!mounted || useFallback || !helpers)
415
+ return
416
+ if (!hasRenderedEditorDom(desiredKind) || editorKind !== desiredKind)
417
+ return
418
+ }
419
+
420
+ try {
421
+ if (diff && typeof helpers.updateDiff === 'function')
422
+ await Promise.resolve(helpers.updateDiff(originalCode, updatedCode || code, monacoLanguage))
423
+ else if (typeof helpers.updateCode === 'function') {
424
+ await Promise.resolve(helpers.updateCode(code, monacoLanguage))
425
+ scheduleEditorTokenization()
426
+ }
427
+ queueThemeSync()
428
+ applyEditorOptions()
429
+ scheduleEditorHeightSync()
430
+ }
431
+ catch (error) {
432
+ markEditorFallback(error)
433
+ }
434
+ }
435
+
436
+ function hasRenderedEditorDom(kind: 'single' | 'diff') {
437
+ if (!editorHost)
438
+ return false
439
+ return kind === 'diff'
440
+ ? Boolean(editorHost.querySelector('.monaco-diff-editor'))
441
+ : Boolean(editorHost.querySelector('.monaco-editor'))
442
+ }
443
+
444
+ async function recreateEditor(kind: 'single' | 'diff') {
445
+ if (!editorHost || !helpers || createEditorPromise)
446
+ return createEditorPromise
447
+
448
+ const creationId = ++lifecycleId
449
+ editorReady = false
450
+ createEditorPromise = (async () => {
451
+ try {
452
+ cleanupEditor(false)
453
+ if (!mounted || !editorHost || lifecycleId !== creationId)
454
+ return
455
+ editorHost.replaceChildren()
456
+ lastLayoutWidth = null
457
+ lastLayoutHeight = null
458
+
459
+ if (kind === 'diff' && typeof helpers.createDiffEditor === 'function') {
460
+ await helpers.createDiffEditor(editorHost, originalCode, updatedCode || code, monacoLanguage)
461
+ await Promise.resolve(helpers.updateDiff?.(originalCode, updatedCode || code, monacoLanguage))
462
+ editorKind = 'diff'
463
+ }
464
+ else {
465
+ await helpers.createEditor(editorHost, code, monacoLanguage)
466
+ await Promise.resolve(helpers.updateCode?.(code, monacoLanguage))
467
+ editorKind = 'single'
468
+ }
469
+ applyEditorOptions()
470
+ editorReady = true
471
+ bindEditorHeightSync()
472
+ scheduleEditorHeightSync()
473
+ queueThemeSync()
474
+ }
475
+ catch (error) {
476
+ if (mounted) {
477
+ markEditorFallback(error)
478
+ }
479
+ }
480
+ })().finally(() => {
481
+ createEditorPromise = null
482
+ })
483
+
484
+ return createEditorPromise
485
+ }
486
+
487
+ function refreshEditorAfterLoadingSettled() {
488
+ if (loadingSettledRefreshPromise)
489
+ return loadingSettledRefreshPromise
490
+
491
+ loadingSettledRefreshPromise = (async () => {
492
+ await tick()
493
+ await nextAnimationFrame()
494
+ if (createEditorPromise) {
495
+ try {
496
+ await createEditorPromise
497
+ }
498
+ catch {}
499
+ }
500
+ if (!mounted || !shouldRender || !editorHost || collapsed || shouldDelayEditor || shouldDeferStreamingLanguage)
501
+ return
502
+ await ensureMonaco()
503
+ if (!mounted || useFallback || !helpers)
504
+ return
505
+ syncRuntimeMonacoOptions()
506
+ const desiredKind: 'single' | 'diff' = diff ? 'diff' : 'single'
507
+ if (!hasRenderedEditorDom(desiredKind) || editorKind !== desiredKind)
508
+ await recreateEditor(desiredKind)
509
+ if (!mounted || useFallback || !helpers || !hasRenderedEditorDom(desiredKind) || editorKind !== desiredKind)
510
+ return
511
+ if (diff) {
512
+ await Promise.resolve(helpers.updateDiff?.(originalCode, updatedCode || code, monacoLanguage))
513
+ helpers.refreshDiffPresentation?.()
514
+ applyEditorOptions()
515
+ scheduleEditorHeightSync()
516
+ return
517
+ }
518
+ await Promise.resolve(helpers.updateCode?.(code, monacoLanguage))
519
+ scheduleEditorTokenization(140, true)
520
+ applyEditorOptions()
521
+ scheduleEditorHeightSync()
522
+ })().finally(() => {
523
+ loadingSettledRefreshPromise = null
524
+ })
525
+
526
+ return loadingSettledRefreshPromise
527
+ }
528
+
529
+ function queueLoadingSettledRefresh() {
530
+ if (loadingSettledRefreshTimer)
531
+ clearTimeout(loadingSettledRefreshTimer)
532
+ loadingSettledRefreshTimer = setTimeout(() => {
533
+ loadingSettledRefreshTimer = null
534
+ void refreshEditorAfterLoadingSettled()
535
+ }, 80)
536
+ }
537
+
538
+ function nextAnimationFrame() {
539
+ if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function')
540
+ return Promise.resolve()
541
+ return new Promise<void>(resolve => window.requestAnimationFrame(() => resolve()))
542
+ }
543
+
544
+ function cleanupEditor(disposeHelpers = true) {
545
+ clearEditorHeightSyncBindings()
546
+ cancelEditorHeightSync()
547
+ try {
548
+ if (disposeHelpers)
549
+ helpers?.cleanupEditor?.()
550
+ else
551
+ (helpers?.safeClean || helpers?.cleanupEditor)?.()
552
+ }
553
+ catch {}
554
+ editorKind = null
555
+ editorReady = false
556
+ lastLayoutWidth = null
557
+ lastLayoutHeight = null
558
+ if (disposeHelpers) {
559
+ helpers = null
560
+ runtimeMonacoOptions = null
561
+ ensureMonacoPromise = null
562
+ lastThemeRequest = ''
563
+ }
564
+ }
565
+
566
+ function applyEditorOptions() {
567
+ const target = diff ? helpers?.getDiffEditorView?.() : helpers?.getEditorView?.()
568
+ target?.updateOptions?.({ fontSize: codeFontSize, automaticLayout: false })
569
+ scheduleEditorHeightSync()
570
+ }
571
+
572
+ function getMaxHeightValue() {
573
+ const raw = resolvedMonacoOptions.MAX_HEIGHT
574
+ if (raw === 'none' || raw == null)
575
+ return Number.POSITIVE_INFINITY
576
+ const value = typeof raw === 'number' ? raw : Number.parseFloat(String(raw))
577
+ return Number.isFinite(value) && value > 0 ? value : 500
578
+ }
579
+
580
+ function scheduleEditorHeightSync() {
581
+ if (typeof window === 'undefined' || !editorHost || !editorReady)
582
+ return
583
+ if (heightSyncRaf != null)
584
+ return
585
+ heightSyncRaf = window.requestAnimationFrame(() => {
586
+ heightSyncRaf = null
587
+ window.requestAnimationFrame(() => syncEditorHostHeight())
588
+ })
589
+ }
590
+
591
+ function cancelEditorHeightSync() {
592
+ if (heightSyncRaf == null || typeof window === 'undefined')
593
+ return
594
+ window.cancelAnimationFrame(heightSyncRaf)
595
+ heightSyncRaf = null
596
+ }
597
+
598
+ function scheduleEditorTokenization(delay = 140, refreshModelValue = false) {
599
+ if (typeof window === 'undefined')
600
+ return
601
+ tokenizeShouldRefreshModelValue = tokenizeShouldRefreshModelValue || refreshModelValue
602
+ if (tokenizeTimer)
603
+ clearTimeout(tokenizeTimer)
604
+ tokenizeTimer = setTimeout(() => {
605
+ tokenizeTimer = null
606
+ if (tokenizeRaf != null)
607
+ return
608
+ tokenizeRaf = window.requestAnimationFrame(() => {
609
+ const shouldRefreshModelValue = tokenizeShouldRefreshModelValue
610
+ tokenizeShouldRefreshModelValue = false
611
+ tokenizeRaf = null
612
+ forceTokenizeEditorModel(shouldRefreshModelValue)
613
+ })
614
+ }, delay)
615
+ }
616
+
617
+ function cancelEditorTokenization() {
618
+ if (tokenizeTimer) {
619
+ clearTimeout(tokenizeTimer)
620
+ tokenizeTimer = null
621
+ }
622
+ tokenizeShouldRefreshModelValue = false
623
+ if (tokenizeRaf == null || typeof window === 'undefined')
624
+ return
625
+ window.cancelAnimationFrame(tokenizeRaf)
626
+ tokenizeRaf = null
627
+ }
628
+
629
+ function forceTokenizeEditorModel(refreshModelValue = false) {
630
+ try {
631
+ const editor = diff
632
+ ? helpers?.getDiffEditorView?.()?.getModifiedEditor?.()
633
+ : helpers?.getEditorView?.()
634
+ const model = editor?.getModel?.()
635
+ const forceTokenization = model?.forceTokenization
636
+ if (refreshModelValue && !diff && typeof model?.setValue === 'function') {
637
+ const scrollTop = Number(editor?.getScrollTop?.() || 0)
638
+ const scrollLeft = Number(editor?.getScrollLeft?.() || 0)
639
+ const selection = editor?.getSelection?.()
640
+ model.setValue(code)
641
+ if (selection)
642
+ editor?.setSelection?.(selection)
643
+ if (Number.isFinite(scrollTop))
644
+ editor?.setScrollTop?.(scrollTop)
645
+ if (Number.isFinite(scrollLeft))
646
+ editor?.setScrollLeft?.(scrollLeft)
647
+ }
648
+ const lineCount = Number(model?.getLineCount?.() || 0)
649
+ if (typeof forceTokenization !== 'function' || !Number.isFinite(lineCount) || lineCount <= 0)
650
+ return
651
+ for (let line = 1; line <= lineCount; line += 1)
652
+ forceTokenization.call(model, line)
653
+ editor?.render?.(true)
654
+ }
655
+ catch {}
656
+ }
657
+
658
+ function bindEditorHeightSync() {
659
+ clearEditorHeightSyncBindings()
660
+ const bind = (source: any, eventName: 'onDidContentSizeChange' | 'onDidLayoutChange') => {
661
+ try {
662
+ const subscribe = source?.[eventName]
663
+ if (typeof subscribe !== 'function')
664
+ return
665
+ const disposable = subscribe.call(source, () => scheduleEditorHeightSync())
666
+ if (disposable)
667
+ heightSyncDisposables.push(disposable)
668
+ }
669
+ catch {}
670
+ }
671
+
672
+ if (diff) {
673
+ const diffEditor = helpers?.getDiffEditorView?.()
674
+ const originalEditor = diffEditor?.getOriginalEditor?.()
675
+ const modifiedEditor = diffEditor?.getModifiedEditor?.()
676
+ try {
677
+ const disposable = diffEditor?.onDidUpdateDiff?.(() => scheduleEditorHeightSync())
678
+ if (disposable)
679
+ heightSyncDisposables.push(disposable)
680
+ }
681
+ catch {}
682
+ bind(originalEditor, 'onDidContentSizeChange')
683
+ bind(modifiedEditor, 'onDidContentSizeChange')
684
+ bind(originalEditor, 'onDidLayoutChange')
685
+ bind(modifiedEditor, 'onDidLayoutChange')
686
+ return
687
+ }
688
+
689
+ const editor = helpers?.getEditorView?.()
690
+ bind(editor, 'onDidContentSizeChange')
691
+ bind(editor, 'onDidLayoutChange')
692
+ }
693
+
694
+ function clearEditorHeightSyncBindings() {
695
+ for (const disposable of heightSyncDisposables) {
696
+ try {
697
+ if (typeof disposable === 'function')
698
+ disposable()
699
+ else
700
+ disposable?.dispose?.()
701
+ }
702
+ catch {}
703
+ }
704
+ heightSyncDisposables = []
705
+ }
706
+
707
+ function syncEditorHostHeight() {
708
+ if (!editorHost || !helpers || !editorReady || collapsed)
709
+ return
710
+
711
+ const maxHeight = getMaxHeightValue()
712
+ const contentHeight = diff
713
+ ? measureRenderedDiffHeight(editorHost) ?? computeEditorContentHeight()
714
+ : computeEditorContentHeight()
715
+ if (!contentHeight || contentHeight <= 0)
716
+ return
717
+
718
+ const minHeight = getEditorHostMinHeight()
719
+ const cappedHeight = expanded || !Number.isFinite(maxHeight)
720
+ ? Math.ceil(contentHeight)
721
+ : Math.ceil(Math.min(contentHeight, maxHeight))
722
+ const nextHeight = Math.max(minHeight, cappedHeight)
723
+ editorHost.style.height = `${nextHeight}px`
724
+ editorHost.style.minHeight = `${nextHeight}px`
725
+ editorHost.style.maxHeight = expanded || !Number.isFinite(maxHeight) ? 'none' : `${Math.ceil(maxHeight)}px`
726
+ editorHost.style.overflow = diff ? 'hidden' : (contentHeight > nextHeight ? 'auto' : 'hidden')
727
+ layoutEditor(nextHeight)
728
+ }
729
+
730
+ function getEditorHostMinHeight() {
731
+ if (!editorHost || typeof window === 'undefined')
732
+ return 0
733
+ const values = [
734
+ window.getComputedStyle(editorHost.parentElement || editorHost).minHeight,
735
+ window.getComputedStyle(editorHost).minHeight,
736
+ ]
737
+ for (const value of values) {
738
+ const parsed = Number.parseFloat(value)
739
+ if (Number.isFinite(parsed) && parsed > 0)
740
+ return Math.ceil(parsed)
741
+ }
742
+ return 0
743
+ }
744
+
745
+ function layoutEditor(height: number) {
746
+ const width = Math.max(0, editorHost?.clientWidth || 0)
747
+ const roundedWidth = Math.ceil(width)
748
+ const roundedHeight = Math.ceil(height)
749
+ if (lastLayoutWidth === roundedWidth && lastLayoutHeight === roundedHeight)
750
+ return
751
+ lastLayoutWidth = roundedWidth
752
+ lastLayoutHeight = roundedHeight
753
+ try {
754
+ if (diff)
755
+ helpers?.getDiffEditorView?.()?.layout?.(width > 0 ? { width: roundedWidth, height: roundedHeight } : undefined)
756
+ else
757
+ helpers?.getEditorView?.()?.layout?.(width > 0 ? { width: roundedWidth, height: roundedHeight } : undefined)
758
+ }
759
+ catch {}
760
+ }
761
+
762
+ function computeEditorContentHeight() {
763
+ try {
764
+ if (diff) {
765
+ const diffEditor = helpers?.getDiffEditorView?.()
766
+ const originalEditor = diffEditor?.getOriginalEditor?.()
767
+ const modifiedEditor = diffEditor?.getModifiedEditor?.()
768
+ const originalHeight = Number(originalEditor?.getContentHeight?.() || 0)
769
+ const modifiedHeight = Number(modifiedEditor?.getContentHeight?.() || 0)
770
+ const height = Math.max(originalHeight, modifiedHeight)
771
+ if (height > 0)
772
+ return Math.ceil(height + 1)
773
+ }
774
+ const editor = helpers?.getEditorView?.()
775
+ const height = Number(editor?.getContentHeight?.() || 0)
776
+ if (height > 0)
777
+ return Math.ceil(height + 1)
778
+ }
779
+ catch {}
780
+ return null
781
+ }
782
+
783
+ function measureRenderedDiffHeight(container: HTMLElement) {
784
+ if (typeof window === 'undefined')
785
+ return null
786
+ try {
787
+ const hostRect = container.getBoundingClientRect()
788
+ if (hostRect.height <= 0)
789
+ return null
790
+
791
+ const selectors = [
792
+ '.editor.original .view-lines .view-line',
793
+ '.editor.modified .view-lines .view-line',
794
+ '.editor.original .view-zones > div',
795
+ '.editor.modified .view-zones > div',
796
+ '.editor.original .margin-view-zones > div',
797
+ '.editor.modified .margin-view-zones > div',
798
+ '.editor.original .diff-hidden-lines',
799
+ '.editor.modified .diff-hidden-lines',
800
+ '.stream-monaco-diff-unchanged-bridge',
801
+ ]
802
+
803
+ let bottom = 0
804
+ for (const node of Array.from(container.querySelectorAll<HTMLElement>(selectors.join(',')))) {
805
+ const style = window.getComputedStyle(node)
806
+ if (style.display === 'none' || style.visibility === 'hidden')
807
+ continue
808
+ if (Number.parseFloat(style.opacity || '1') <= 0.01)
809
+ continue
810
+ const rect = node.getBoundingClientRect()
811
+ if (rect.height <= 0 || rect.bottom <= hostRect.top)
812
+ continue
813
+ bottom = Math.max(bottom, rect.bottom - hostRect.top)
814
+ }
815
+
816
+ if (bottom > 0)
817
+ return Math.ceil(bottom + 1)
818
+
819
+ const diffRoot = container.querySelector<HTMLElement>('.monaco-diff-editor')
820
+ const diffHeight = diffRoot?.getBoundingClientRect?.().height ?? 0
821
+ return diffHeight > 0 ? Math.ceil(diffHeight + 1) : null
822
+ }
823
+ catch {
824
+ return null
825
+ }
826
+ }
827
+
828
+ async function copy() {
829
+ await copyTextToClipboard(code)
830
+ context?.events?.onCopy?.(code)
831
+ copied = true
832
+ if (copyTimer)
833
+ clearTimeout(copyTimer)
834
+ copyTimer = setTimeout(() => {
835
+ copied = false
836
+ }, 1000)
837
+ }
838
+
839
+ function decreaseFont() {
840
+ if (!enableFontSizeControl)
841
+ return
842
+ codeFontSize = Math.max(10, codeFontSize - 1)
843
+ applyEditorOptions()
844
+ }
845
+
846
+ function resetFont() {
847
+ if (!enableFontSizeControl)
848
+ return
849
+ codeFontSize = defaultCodeFontSize
850
+ applyEditorOptions()
851
+ }
852
+
853
+ function increaseFont() {
854
+ if (!enableFontSizeControl)
855
+ return
856
+ codeFontSize = Math.min(24, codeFontSize + 1)
857
+ applyEditorOptions()
858
+ }
859
+
860
+ function showButtonTooltip(event: MouseEvent | FocusEvent, text: string) {
861
+ const target = event.currentTarget as HTMLElement | null
862
+ if (!target || (target instanceof HTMLButtonElement && target.disabled))
863
+ return
864
+ showTooltipForAnchor(target, text, 'top', false, undefined, resolvedIsDark)
865
+ }
866
+
867
+ function showCopyTooltip(event: MouseEvent | FocusEvent) {
868
+ showButtonTooltip(event, copied ? (t('common.copied') || 'Copied') : (t('common.copy') || 'Copy'))
869
+ }
870
+ </script>
871
+
872
+ {#if shouldRender}
873
+ <div
874
+ class:is-dark={resolvedIsDark}
875
+ class:is-plain-text={monacoLanguage === 'plaintext'}
876
+ class:is-rendering={resolvedLoading}
877
+ class:is-diff={diff}
878
+ class="code-block-container"
879
+ data-markstream-code-block="1"
880
+ data-markstream-enhanced={editorReady && !useFallback ? 'true' : 'false'}
881
+ style={containerStyle}
882
+ >
883
+ {#if showHeader}
884
+ <div class="code-block-header">
885
+ <div class="code-block-header__meta">
886
+ <span class="code-block-language-icon" aria-hidden="true">{@html languageIcon}</span>
887
+ <span class="code-block-header__label">{diff ? `Diff / ${displayLanguage}` : displayLanguage}</span>
888
+ </div>
889
+ <div class="code-block-header__actions">
890
+ {#if showCopyButton}
891
+ <button type="button" class="code-action-btn" aria-label={copied ? t('common.copied') : t('common.copy')} onblur={() => hideTooltip()} onclick={copy} onfocus={showCopyTooltip} onmouseleave={() => hideTooltip()} onmouseenter={showCopyTooltip}>
892
+ {#if copied}
893
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 6L9 17l-5-5" /></svg>
894
+ {:else}
895
+ <svg viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></g></svg>
896
+ {/if}
897
+ </button>
898
+ {/if}
899
+ {#if showFontSizeButtons && enableFontSizeControl}
900
+ <button type="button" class="code-action-btn" aria-label={t('common.decrease')} onblur={() => hideTooltip()} onclick={decreaseFont} onfocus={(event) => showButtonTooltip(event, t('common.decrease') || 'Decrease')} onmouseleave={() => hideTooltip()} onmouseenter={(event) => showButtonTooltip(event, t('common.decrease') || 'Decrease')}>
901
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14" /></svg>
902
+ </button>
903
+ <button type="button" class="code-action-btn" aria-label={t('common.reset')} onblur={() => hideTooltip()} onclick={resetFont} onfocus={(event) => showButtonTooltip(event, t('common.reset') || 'Reset')} onmouseleave={() => hideTooltip()} onmouseenter={(event) => showButtonTooltip(event, t('common.reset') || 'Reset')}>
904
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12a9 9 0 1 0 9-9a9.75 9.75 0 0 0-6.74 2.74L3 8m0-5v5h5" /></svg>
905
+ </button>
906
+ <button type="button" class="code-action-btn" aria-label={t('common.increase')} onblur={() => hideTooltip()} onclick={increaseFont} onfocus={(event) => showButtonTooltip(event, t('common.increase') || 'Increase')} onmouseleave={() => hideTooltip()} onmouseenter={(event) => showButtonTooltip(event, t('common.increase') || 'Increase')}>
907
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14m-7-7v14" /></svg>
908
+ </button>
909
+ {/if}
910
+ {#if isPreviewable && showPreviewButton}
911
+ <button type="button" class="code-action-btn" aria-label={t('common.preview')} onblur={() => hideTooltip()} onclick={() => (previewOpen = !previewOpen)} onfocus={(event) => showButtonTooltip(event, t('common.preview') || 'Preview')} onmouseleave={() => hideTooltip()} onmouseenter={(event) => showButtonTooltip(event, t('common.preview') || 'Preview')}>
912
+ <svg viewBox="0 0 24 24" aria-hidden="true"><g fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M2.062 12.348a1 1 0 0 1 0-.696a10.75 10.75 0 0 1 19.876 0a1 1 0 0 1 0 .696a10.75 10.75 0 0 1-19.876 0" /><circle cx="12" cy="12" r="3" /></g></svg>
913
+ </button>
914
+ {/if}
915
+ {#if showExpandButton}
916
+ <button type="button" class="code-action-btn" aria-pressed={expanded} aria-label={expanded ? t('common.collapse') : t('common.expand')} onblur={() => hideTooltip()} onclick={() => (expanded = !expanded)} onfocus={(event) => showButtonTooltip(event, expanded ? (t('common.collapse') || 'Collapse') : (t('common.expand') || 'Expand'))} onmouseleave={() => hideTooltip()} onmouseenter={(event) => showButtonTooltip(event, expanded ? (t('common.collapse') || 'Collapse') : (t('common.expand') || 'Expand'))}>
917
+ <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d={expanded ? 'm14 10l7-7m-1 7h-6V4M3 21l7-7m-6 0h6v6' : 'M15 3h6v6m0-6l-7 7M3 21l7-7m-1 7H3v-6'} /></svg>
918
+ </button>
919
+ {/if}
920
+ {#if showCollapseButton}
921
+ <button type="button" class="code-action-btn" aria-pressed={collapsed} aria-label={collapsed ? t('common.expand') : t('common.collapse')} onblur={() => hideTooltip()} onclick={() => (collapsed = !collapsed)} onfocus={(event) => showButtonTooltip(event, collapsed ? (t('common.expand') || 'Expand') : (t('common.collapse') || 'Collapse'))} onmouseleave={() => hideTooltip()} onmouseenter={(event) => showButtonTooltip(event, collapsed ? (t('common.expand') || 'Expand') : (t('common.collapse') || 'Collapse'))}>
922
+ <svg style:rotate={collapsed ? '0deg' : '90deg'} viewBox="0 0 24 24" aria-hidden="true"><path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m9 18l6-6l-6-6" /></svg>
923
+ </button>
924
+ {/if}
925
+ </div>
926
+ </div>
927
+ {/if}
928
+
929
+ {#if !collapsed}
930
+ <div class:code-block-body--expanded={expanded} class="code-block-body">
931
+ {#if !shouldDelayEditor}
932
+ <div bind:this={editorHost} class:is-hidden={showPreFallback} class="code-editor-container"></div>
933
+ {/if}
934
+ {#if showPreFallback}
935
+ <pre class="code-pre-fallback"><code class={preLanguageClass ? `language-${preLanguageClass}` : undefined}>{code}</code></pre>
936
+ {/if}
937
+ </div>
938
+ {/if}
939
+
940
+ {#if previewOpen && isPreviewable}
941
+ <HtmlPreviewFrame code={code} title={previewTitle} isDark={resolvedIsDark} {htmlPreviewAllowScripts} {htmlPreviewSandbox} onClose={() => (previewOpen = false)} />
942
+ {/if}
943
+ </div>
944
+ {/if}