@incremark/svelte 0.2.6 → 0.3.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 (58) hide show
  1. package/README.en.md +274 -0
  2. package/dist/ThemeProvider.svelte +4 -1
  3. package/dist/ThemeProvider.svelte.d.ts.map +1 -1
  4. package/dist/components/AutoScrollContainer.svelte +18 -18
  5. package/dist/components/ConfigProvider.svelte +18 -0
  6. package/dist/components/ConfigProvider.svelte.d.ts +9 -0
  7. package/dist/components/ConfigProvider.svelte.d.ts.map +1 -0
  8. package/dist/components/Incremark.svelte +63 -72
  9. package/dist/components/Incremark.svelte.d.ts +5 -7
  10. package/dist/components/Incremark.svelte.d.ts.map +1 -1
  11. package/dist/components/IncremarkCode.svelte +28 -251
  12. package/dist/components/IncremarkCode.svelte.d.ts +4 -1
  13. package/dist/components/IncremarkCode.svelte.d.ts.map +1 -1
  14. package/dist/components/IncremarkCodeDefault.svelte +115 -0
  15. package/dist/components/IncremarkCodeDefault.svelte.d.ts +18 -0
  16. package/dist/components/IncremarkCodeDefault.svelte.d.ts.map +1 -0
  17. package/dist/components/IncremarkCodeMermaid.svelte +148 -0
  18. package/dist/components/IncremarkCodeMermaid.svelte.d.ts +14 -0
  19. package/dist/components/IncremarkCodeMermaid.svelte.d.ts.map +1 -0
  20. package/dist/components/IncremarkContent.svelte +115 -0
  21. package/dist/components/IncremarkContent.svelte.d.ts +5 -0
  22. package/dist/components/IncremarkContent.svelte.d.ts.map +1 -0
  23. package/dist/components/IncremarkFootnotes.svelte +4 -8
  24. package/dist/components/IncremarkFootnotes.svelte.d.ts.map +1 -1
  25. package/dist/components/IncremarkInline.svelte +3 -3
  26. package/dist/components/IncremarkList.svelte +1 -0
  27. package/dist/components/IncremarkRenderer.svelte +4 -0
  28. package/dist/components/IncremarkRenderer.svelte.d.ts +2 -0
  29. package/dist/components/IncremarkRenderer.svelte.d.ts.map +1 -1
  30. package/dist/components/IncremarkTable.svelte +6 -9
  31. package/dist/components/IncremarkTable.svelte.d.ts.map +1 -1
  32. package/dist/components/SvgIcon.svelte +25 -0
  33. package/dist/components/SvgIcon.svelte.d.ts +12 -0
  34. package/dist/components/SvgIcon.svelte.d.ts.map +1 -0
  35. package/dist/components/index.d.ts +2 -1
  36. package/dist/components/index.d.ts.map +1 -1
  37. package/dist/components/index.js +1 -0
  38. package/dist/components/types.d.ts +29 -3
  39. package/dist/components/types.d.ts.map +1 -1
  40. package/dist/index.d.ts +8 -2
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +7 -2
  43. package/dist/stores/{useDevTools.d.ts → useDevTools.svelte.d.ts} +1 -1
  44. package/dist/stores/useDevTools.svelte.d.ts.map +1 -0
  45. package/dist/stores/{useDevTools.js → useDevTools.svelte.js} +10 -9
  46. package/dist/stores/useIncremark.d.ts +4 -4
  47. package/dist/stores/useIncremark.d.ts.map +1 -1
  48. package/dist/stores/useLocale.svelte.d.ts +29 -0
  49. package/dist/stores/useLocale.svelte.d.ts.map +1 -0
  50. package/dist/stores/useLocale.svelte.js +32 -0
  51. package/dist/stores/useShiki.svelte.d.ts +9 -0
  52. package/dist/stores/useShiki.svelte.d.ts.map +1 -0
  53. package/dist/stores/useShiki.svelte.js +110 -0
  54. package/dist/stores/useTypewriter.d.ts +0 -1
  55. package/dist/stores/useTypewriter.d.ts.map +1 -1
  56. package/dist/stores/useTypewriter.js +1 -3
  57. package/package.json +13 -7
  58. package/dist/stores/useDevTools.d.ts.map +0 -1
package/README.en.md ADDED
@@ -0,0 +1,274 @@
1
+ # @incremark/svelte
2
+
3
+ Svelte 5 integration library for Incremark, providing high-performance streaming Markdown rendering components.
4
+
5
+ **[🇨🇳 中文](./README.md)** | 🇺🇸 English
6
+
7
+ ## Core Advantages
8
+
9
+ - 📦 **Out of the Box** - Provides `IncremarkContent` component and `useIncremark` store
10
+ - ⚡ **Extreme Performance** - Incremental parsing with O(n) complexity, dual-engine support
11
+ - ⌨️ **Typewriter Effect** - Built-in animation effects (fade-in, typing)
12
+ - 🎨 **Highly Customizable** - Custom components, code blocks, containers
13
+ - 🎯 **Svelte 5 Runes** - Uses the latest Svelte 5 syntax
14
+ - 📜 **Auto Scroll** - Built-in AutoScrollContainer component
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ pnpm add @incremark/core @incremark/svelte
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ### Recommended: IncremarkContent Component
25
+
26
+ ```svelte
27
+ <script lang="ts">
28
+ import { IncremarkContent } from '@incremark/svelte'
29
+ import '@incremark/svelte/style.css'
30
+
31
+ let content = $state('')
32
+ let isFinished = $state(false)
33
+
34
+ // Handle AI streaming output
35
+ async function handleStream(stream: AsyncIterable<string>) {
36
+ content = ''
37
+ isFinished = false
38
+
39
+ for await (const chunk of stream) {
40
+ content += chunk
41
+ }
42
+
43
+ isFinished = true
44
+ }
45
+ </script>
46
+
47
+ <button onclick={() => handleStream(stream)}>Start</button>
48
+ <IncremarkContent
49
+ {content}
50
+ {isFinished}
51
+ incremarkOptions={{
52
+ gfm: true,
53
+ math: true,
54
+ containers: true,
55
+ htmlTree: true
56
+ }}
57
+ />
58
+ ```
59
+
60
+ ### Advanced: useIncremark Store
61
+
62
+ ```svelte
63
+ <script lang="ts">
64
+ import { useIncremark, Incremark } from '@incremark/svelte'
65
+ import '@incremark/svelte/style.css'
66
+
67
+ const { blocks, append, finalize, reset } = useIncremark({
68
+ gfm: true,
69
+ math: true
70
+ })
71
+
72
+ async function handleStream(stream: AsyncIterable<string>) {
73
+ reset()
74
+ for await (const chunk of stream) {
75
+ append(chunk)
76
+ }
77
+ finalize()
78
+ }
79
+ </script>
80
+
81
+ <button onclick={() => handleStream(stream)}>Start</button>
82
+ <Incremark blocks={$blocks} />
83
+ ```
84
+
85
+ ## IncremarkContent Component
86
+
87
+ Declarative all-in-one component, recommended for most scenarios.
88
+
89
+ ### Props
90
+
91
+ ```ts
92
+ interface IncremarkContentProps {
93
+ // Input (choose one)
94
+ content?: string // Accumulated Markdown string
95
+ stream?: () => AsyncGenerator<string> // Async generator function
96
+
97
+ // Status
98
+ isFinished?: boolean // Stream finished flag (required for content mode)
99
+
100
+ // Configuration
101
+ incremarkOptions?: {
102
+ gfm?: boolean // GFM support
103
+ math?: boolean // Math formulas
104
+ htmlTree?: boolean // HTML structured parsing
105
+ containers?: boolean // ::: container syntax
106
+ typewriter?: { // Typewriter effect
107
+ enabled?: boolean
108
+ charsPerTick?: number | [number, number]
109
+ tickInterval?: number
110
+ effect?: 'none' | 'fade-in' | 'typing'
111
+ cursor?: string
112
+ }
113
+ }
114
+
115
+ // Custom rendering
116
+ components?: ComponentMap // Custom components
117
+ customContainers?: Record<string, Component> // Custom containers
118
+ customCodeBlocks?: Record<string, Component> // Custom code blocks
119
+ codeBlockConfigs?: Record<string, CodeBlockConfig>
120
+
121
+ // Styling
122
+ showBlockStatus?: boolean // Show block status border
123
+ pendingClass?: string // CSS class for pending blocks
124
+ }
125
+ ```
126
+
127
+ ### Example: Enable Typewriter Effect
128
+
129
+ ```svelte
130
+ <IncremarkContent
131
+ {content}
132
+ {isFinished}
133
+ incremarkOptions={{
134
+ gfm: true,
135
+ typewriter: {
136
+ enabled: true,
137
+ charsPerTick: [1, 3],
138
+ tickInterval: 30,
139
+ effect: 'fade-in'
140
+ }
141
+ }}
142
+ />
143
+ ```
144
+
145
+ ### Example: Custom Components
146
+
147
+ ```svelte
148
+ <script lang="ts">
149
+ import CustomHeading from './CustomHeading.svelte'
150
+ import WarningContainer from './WarningContainer.svelte'
151
+ import EchartsCodeBlock from './EchartsCodeBlock.svelte'
152
+ </script>
153
+
154
+ <IncremarkContent
155
+ {content}
156
+ {isFinished}
157
+ components={{ heading: CustomHeading }}
158
+ customContainers={{ warning: WarningContainer }}
159
+ customCodeBlocks={{ echarts: EchartsCodeBlock }}
160
+ codeBlockConfigs={{ echarts: { takeOver: true } }}
161
+ />
162
+ ```
163
+
164
+ ## Theme System
165
+
166
+ ```svelte
167
+ <script lang="ts">
168
+ import { ThemeProvider, IncremarkContent } from '@incremark/svelte'
169
+ </script>
170
+
171
+ <!-- Built-in theme -->
172
+ <ThemeProvider theme="dark">
173
+ <IncremarkContent {content} {isFinished} />
174
+ </ThemeProvider>
175
+
176
+ <!-- Custom theme -->
177
+ <ThemeProvider theme={{ color: { brand: { primary: '#8b5cf6' } } }}>
178
+ <IncremarkContent {content} {isFinished} />
179
+ </ThemeProvider>
180
+ ```
181
+
182
+ ## Auto Scroll
183
+
184
+ ```svelte
185
+ <script lang="ts">
186
+ import { AutoScrollContainer, IncremarkContent } from '@incremark/svelte'
187
+
188
+ let scrollContainer: { scrollToBottom: () => void }
189
+ let autoScrollEnabled = $state(true)
190
+ </script>
191
+
192
+ <AutoScrollContainer
193
+ bind:this={scrollContainer}
194
+ enabled={autoScrollEnabled}
195
+ threshold={50}
196
+ behavior="smooth"
197
+ >
198
+ <IncremarkContent {content} {isFinished} />
199
+ </AutoScrollContainer>
200
+
201
+ <button onclick={() => scrollContainer?.scrollToBottom()}>
202
+ Scroll to Bottom
203
+ </button>
204
+ ```
205
+
206
+ ## useIncremark API
207
+
208
+ ```ts
209
+ const {
210
+ // State (Svelte stores)
211
+ markdown, // Writable<string> - Complete Markdown
212
+ blocks, // Readable<Block[]> - All blocks
213
+ completedBlocks, // Writable<Block[]> - Completed blocks
214
+ pendingBlocks, // Writable<Block[]> - Pending blocks
215
+ isLoading, // Writable<boolean> - Is loading
216
+ isDisplayComplete, // Readable<boolean> - Is display complete
217
+
218
+ // Methods
219
+ append, // (chunk: string) => IncrementalUpdate
220
+ finalize, // () => IncrementalUpdate
221
+ reset, // () => void
222
+ render, // (content: string) => IncrementalUpdate
223
+
224
+ // Typewriter controls
225
+ typewriter: {
226
+ enabled, // Writable<boolean> - Is enabled
227
+ isProcessing, // Readable<boolean> - Is processing
228
+ skip, // () => void - Skip animation
229
+ setOptions // (options) => void - Update config
230
+ }
231
+ } = useIncremark(options)
232
+ ```
233
+
234
+ ## Svelte 5 Runes Syntax
235
+
236
+ This library uses Svelte 5 Runes syntax:
237
+
238
+ ```svelte
239
+ <script lang="ts">
240
+ import { IncremarkContent } from '@incremark/svelte'
241
+
242
+ // Use $state for reactive state
243
+ let content = $state('')
244
+ let isFinished = $state(false)
245
+
246
+ // Use $derived for computed values
247
+ let charCount = $derived(content.length)
248
+ </script>
249
+
250
+ <IncremarkContent {content} {isFinished} />
251
+ <p>Character count: {charCount}</p>
252
+ ```
253
+
254
+ ## Math Formula Support
255
+
256
+ Built-in support, just enable `math: true`:
257
+
258
+ ```svelte
259
+ <IncremarkContent
260
+ {content}
261
+ {isFinished}
262
+ incremarkOptions={{ math: true }}
263
+ />
264
+ ```
265
+
266
+ Import KaTeX styles:
267
+
268
+ ```ts
269
+ import 'katex/dist/katex.min.css'
270
+ ```
271
+
272
+ ## License
273
+
274
+ MIT
@@ -6,6 +6,7 @@
6
6
  <script lang="ts">
7
7
  import type { DesignTokens } from '@incremark/theme'
8
8
  import { applyTheme } from '@incremark/theme'
9
+ import { isBrowser } from '@incremark/shared'
9
10
 
10
11
  /**
11
12
  * 组件 Props
@@ -37,7 +38,9 @@
37
38
  // 在 Svelte 5 中,$effect 会自动追踪在 effect 内部访问的响应式值
38
39
  // 直接访问 theme prop 和 containerRef,确保都被追踪
39
40
  $effect(() => {
40
- // effect 内部直接访问 theme prop,确保被追踪
41
+ // SSR 环境检查
42
+ if (!isBrowser()) return
43
+
41
44
  if (containerRef) {
42
45
  applyTheme(containerRef, theme)
43
46
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ThemeProvider.svelte.d.ts","sourceRoot":"","sources":["../src/ThemeProvider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAIlD;;GAEG;AACH,UAAU,KAAK;IACb;;;;;OAKG;IACH,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAChE,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU;IACV,QAAQ,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAA;CACpC;AAqCH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"ThemeProvider.svelte.d.ts","sourceRoot":"","sources":["../src/ThemeProvider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAKlD;;GAEG;AACH,UAAU,KAAK;IACb;;;;;OAKG;IACH,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAChE,iBAAiB;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU;IACV,QAAQ,CAAC,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAA;CACpC;AAwCH,QAAA,MAAM,aAAa,2CAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
@@ -4,7 +4,7 @@
4
4
  -->
5
5
 
6
6
  <script lang="ts">
7
- import { onMount, onDestroy } from 'svelte'
7
+ import { onMount, onDestroy, tick } from 'svelte'
8
8
  import type { HTMLAttributes } from 'svelte/elements';
9
9
 
10
10
  /**
@@ -117,24 +117,24 @@
117
117
  lastScrollTop = containerRef.scrollTop
118
118
  lastScrollHeight = containerRef.scrollHeight
119
119
 
120
- observer = new MutationObserver(() => {
120
+ observer = new MutationObserver(async () => {
121
121
  // 使用 tick 等待 DOM 更新
122
- setTimeout(() => {
123
- if (!containerRef) return
124
-
125
- // 如果没有滚动条,重置状态
126
- if (!hasScrollbar()) {
127
- isUserScrolledUp = false
128
- }
129
-
130
- // 更新 scrollHeight 记录(内容变化后)
131
- lastScrollHeight = containerRef.scrollHeight
132
-
133
- // 自动滚动
134
- if (enabled && !isUserScrolledUp) {
135
- scrollToBottom()
136
- }
137
- }, 0)
122
+ await tick()
123
+
124
+ if (!containerRef) return
125
+
126
+ // 如果没有滚动条,重置状态
127
+ if (!hasScrollbar()) {
128
+ isUserScrolledUp = false
129
+ }
130
+
131
+ // 更新 scrollHeight 记录(内容变化后)
132
+ lastScrollHeight = containerRef.scrollHeight
133
+
134
+ // 自动滚动
135
+ if (enabled && !isUserScrolledUp) {
136
+ scrollToBottom()
137
+ }
138
138
  })
139
139
 
140
140
  observer.observe(containerRef, {
@@ -0,0 +1,18 @@
1
+ <script lang="ts">
2
+ import type { IncremarkLocale } from '@incremark/svelte'
3
+ import { en } from '../index'
4
+ import { provideLocale } from '../stores/useLocale.svelte'
5
+
6
+ interface Props {
7
+ locale?: IncremarkLocale
8
+ children: import('svelte').Snippet
9
+ }
10
+
11
+ const { locale = en, children }: Props = $props()
12
+
13
+ // 在组件初始化时同步设置 context
14
+ // 使用函数返回 locale 以支持响应式更新
15
+ provideLocale(() => locale)
16
+ </script>
17
+
18
+ {@render children()}
@@ -0,0 +1,9 @@
1
+ import type { IncremarkLocale } from '@incremark/svelte';
2
+ interface Props {
3
+ locale?: IncremarkLocale;
4
+ children: import('svelte').Snippet;
5
+ }
6
+ declare const ConfigProvider: import("svelte").Component<Props, {}, "">;
7
+ type ConfigProvider = ReturnType<typeof ConfigProvider>;
8
+ export default ConfigProvider;
9
+ //# sourceMappingURL=ConfigProvider.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigProvider.svelte.d.ts","sourceRoot":"","sources":["../../src/components/ConfigProvider.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAKtD,UAAU,KAAK;IACb,MAAM,CAAC,EAAE,eAAe,CAAA;IACxB,QAAQ,EAAE,OAAO,QAAQ,EAAE,OAAO,CAAA;CACnC;AAkBH,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
@@ -5,33 +5,23 @@
5
5
 
6
6
  <script lang="ts">
7
7
  import type { Component } from 'svelte'
8
- import type { Readable } from 'svelte/store'
9
8
  import type { RootContent, ParsedBlock } from '@incremark/core'
10
- import type { HTML } from 'mdast'
11
9
 
12
10
  import { getDefinitionsContext } from '../context/definitionsContext'
13
11
  import type { UseIncremarkReturn } from '../stores/useIncremark'
14
- import type { ComponentMap, BlockWithStableId } from './types'
12
+ import type { ComponentMap, RenderableBlock } from './types'
15
13
 
16
14
  // 导入组件
17
15
  import IncremarkFootnotes from './IncremarkFootnotes.svelte'
18
16
  import IncremarkRenderer from './IncremarkRenderer.svelte'
19
17
 
20
- /**
21
- * 检查是否是 html 节点
22
- */
23
- function isHtmlNode(node: RootContent): node is HTML {
24
- return node.type === 'html'
25
- }
26
-
27
18
  /**
28
19
  * 组件 Props
29
20
  */
30
21
  interface Props {
31
- /** 要渲染的块列表(来自 useIncremark 的 blocks) */
32
- blocks?: BlockWithStableId[] | Readable<BlockWithStableId[]>
33
- /** 内容是否完全显示完成(用于控制脚注等需要在内容完全显示后才出现的元素)
34
- * 如果传入了 incremark,则会自动使用 incremark.isDisplayComplete,此 prop 被忽略 */
22
+ /** 要渲染的块列表数组 */
23
+ blocks?: RenderableBlock[]
24
+ /** 内容是否完全显示完成 */
35
25
  isDisplayComplete?: boolean
36
26
  /** 自定义组件映射,key 为节点类型 */
37
27
  components?: ComponentMap
@@ -47,7 +37,7 @@
47
37
  completedClass?: string
48
38
  /** 是否显示块状态边框 */
49
39
  showBlockStatus?: boolean
50
- /** 可选:useIncremark 返回的对象(用于自动注入数据) */
40
+ /** 可选:useIncremark 返回的对象(用于自动注入数据,优先级高于 blocks/isDisplayComplete) */
51
41
  incremark?: UseIncremarkReturn
52
42
  }
53
43
 
@@ -64,69 +54,70 @@
64
54
  incremark
65
55
  }: Props = $props()
66
56
 
67
- const context = getDefinitionsContext();
68
- const footnoteReferenceOrder = $derived(context?.footnoteReferenceOrder ?? []);
57
+ const context = getDefinitionsContext()
58
+ // 解构 store 以便使用 $ 语法订阅
59
+ const { footnoteReferenceOrder } = context
60
+
61
+ // 获取 incremark 的 stores(使用 getter 访问以保持响应性)
62
+ const blocksStore = $derived(incremark?.blocks)
63
+ const displayCompleteStore = $derived(incremark?.isDisplayComplete)
64
+
65
+ // 订阅 stores 的值
66
+ let blocksFromStore = $state<RenderableBlock[]>([])
67
+ let displayCompleteFromStore = $state(false)
68
+
69
+ // 使用 effect 订阅 blocks store
70
+ $effect(() => {
71
+ if (blocksStore) {
72
+ const unsubscribe = blocksStore.subscribe((value) => {
73
+ blocksFromStore = value
74
+ })
75
+ return unsubscribe
76
+ }
77
+ })
69
78
 
70
- // 当使用 incremark 时,从 incremark 对象中提取 blocks 和 isDisplayComplete
71
- const incremarkBlocks = $derived(
72
- incremark ? (incremark as any).blocks : []
73
- );
74
- const incremarkIsDisplayComplete = $derived(
75
- incremark ? (incremark as any).isDisplayComplete : false
76
- );
79
+ // 使用 effect 订阅 displayComplete store
80
+ $effect(() => {
81
+ if (displayCompleteStore) {
82
+ const unsubscribe = displayCompleteStore.subscribe((value) => {
83
+ displayCompleteFromStore = value
84
+ })
85
+ return unsubscribe
86
+ }
87
+ })
88
+
89
+ // 计算最终要渲染的 blocks
90
+ const renderBlocks = $derived<RenderableBlock[]>(
91
+ blocksStore ? blocksFromStore : (blocks ?? [])
92
+ )
93
+
94
+ // 计算是否显示完成
95
+ const displayComplete = $derived(
96
+ displayCompleteStore ? displayCompleteFromStore : isDisplayComplete
97
+ )
77
98
  </script>
78
99
 
79
100
  <div class="incremark">
80
101
  <!-- 主要内容块 -->
81
- {#if incremark}
82
- <!-- 使用 incremark blocks store -->
83
- {#each $incremarkBlocks as block (block.stableId)}
84
- {#if (block as ParsedBlock).node.type !== 'definition' && (block as ParsedBlock).node.type !== 'footnoteDefinition'}
85
- <div
86
- class="incremark-block {(block as ParsedBlock).status === 'completed' ? completedClass : pendingClass} {showBlockStatus ? 'incremark-show-status' : ''} {(block as BlockWithStableId).isLastPending ? 'incremark-last-pending' : ''}"
87
- >
88
- <!-- 使用 IncremarkRenderer,传递 customContainers 和 customCodeBlocks -->
89
- <IncremarkRenderer
90
- node={(block as ParsedBlock).node}
91
- customContainers={customContainers}
92
- customCodeBlocks={customCodeBlocks}
93
- codeBlockConfigs={codeBlockConfigs}
94
- blockStatus={(block as ParsedBlock).status}
95
- />
96
- </div>
97
- {/if}
98
- {/each}
99
- {:else}
100
- <!-- 使用传入的 blocks 数组 -->
101
- {#each (Array.isArray(blocks) ? blocks : []) as block (block.stableId)}
102
- {#if (block as ParsedBlock).node.type !== 'definition' && (block as ParsedBlock).node.type !== 'footnoteDefinition'}
103
- <div
104
- class="incremark-block {(block as ParsedBlock).status === 'completed' ? completedClass : pendingClass} {showBlockStatus ? 'incremark-show-status' : ''} {block.isLastPending ? 'incremark-last-pending' : ''}"
105
- >
106
- <!-- 使用 IncremarkRenderer,传递 customContainers 和 customCodeBlocks -->
107
- <IncremarkRenderer
108
- node={(block as ParsedBlock).node}
109
- customContainers={customContainers}
110
- customCodeBlocks={customCodeBlocks}
111
- codeBlockConfigs={codeBlockConfigs}
112
- blockStatus={(block as ParsedBlock).status}
113
- />
114
- </div>
115
- {/if}
116
- {/each}
117
- {/if}
102
+ {#each renderBlocks as block (block.id)}
103
+ {#if block.node.type !== 'definition' && block.node.type !== 'footnoteDefinition'}
104
+ <div
105
+ class="incremark-block {block.status === 'completed' ? completedClass : pendingClass} {showBlockStatus ? 'incremark-show-status' : ''} {block.isLastPending ? 'incremark-last-pending' : ''}"
106
+ >
107
+ <IncremarkRenderer
108
+ node={block.node}
109
+ {components}
110
+ customContainers={customContainers}
111
+ customCodeBlocks={customCodeBlocks}
112
+ codeBlockConfigs={codeBlockConfigs}
113
+ blockStatus={block.status}
114
+ />
115
+ </div>
116
+ {/if}
117
+ {/each}
118
118
 
119
119
  <!-- 脚注列表(仅在内容完全显示后显示) -->
120
- {#if incremark && $incremarkIsDisplayComplete && $footnoteReferenceOrder}
121
- {@const footnoteOrder = $footnoteReferenceOrder ?? []}
122
- {#if footnoteOrder.length > 0}
123
- <IncremarkFootnotes />
124
- {/if}
125
- {:else if !incremark && isDisplayComplete && $footnoteReferenceOrder}
126
- {@const footnoteOrder = $footnoteReferenceOrder ?? []}
127
- {#if footnoteOrder.length > 0}
128
- <IncremarkFootnotes />
129
- {/if}
120
+ {#if displayComplete && $footnoteReferenceOrder.length > 0}
121
+ <IncremarkFootnotes />
130
122
  {/if}
131
123
  </div>
132
-
@@ -1,15 +1,13 @@
1
1
  import type { Component } from 'svelte';
2
- import type { Readable } from 'svelte/store';
3
2
  import type { UseIncremarkReturn } from '../stores/useIncremark';
4
- import type { ComponentMap, BlockWithStableId } from './types';
3
+ import type { ComponentMap, RenderableBlock } from './types';
5
4
  /**
6
5
  * 组件 Props
7
6
  */
8
7
  interface Props {
9
- /** 要渲染的块列表(来自 useIncremark 的 blocks) */
10
- blocks?: BlockWithStableId[] | Readable<BlockWithStableId[]>;
11
- /** 内容是否完全显示完成(用于控制脚注等需要在内容完全显示后才出现的元素)
12
- * 如果传入了 incremark,则会自动使用 incremark.isDisplayComplete,此 prop 被忽略 */
8
+ /** 要渲染的块列表数组 */
9
+ blocks?: RenderableBlock[];
10
+ /** 内容是否完全显示完成 */
13
11
  isDisplayComplete?: boolean;
14
12
  /** 自定义组件映射,key 为节点类型 */
15
13
  components?: ComponentMap;
@@ -27,7 +25,7 @@ interface Props {
27
25
  completedClass?: string;
28
26
  /** 是否显示块状态边框 */
29
27
  showBlockStatus?: boolean;
30
- /** 可选:useIncremark 返回的对象(用于自动注入数据) */
28
+ /** 可选:useIncremark 返回的对象(用于自动注入数据,优先级高于 blocks/isDisplayComplete) */
31
29
  incremark?: UseIncremarkReturn;
32
30
  }
33
31
  declare const Incremark: Component<Props, {}, "">;
@@ -1 +1 @@
1
- {"version":3,"file":"Incremark.svelte.d.ts","sourceRoot":"","sources":["../../src/components/Incremark.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAK5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAM5D;;GAEG;AACH,UAAU,KAAK;IACb,wCAAwC;IACxC,MAAM,CAAC,EAAE,iBAAiB,EAAE,GAAG,QAAQ,CAAC,iBAAiB,EAAE,CAAC,CAAA;IAC5D;uEACmE;IACnE,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,wBAAwB;IACxB,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,0BAA0B;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACzD,gBAAgB;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,sCAAsC;IACtC,SAAS,CAAC,EAAE,kBAAkB,CAAA;CAC/B;AA2FH,QAAA,MAAM,SAAS,0BAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"Incremark.svelte.d.ts","sourceRoot":"","sources":["../../src/components/Incremark.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAIvC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AAChE,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAM1D;;GAEG;AACH,UAAU,KAAK;IACb,gBAAgB;IAChB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAA;IAC1B,iBAAiB;IACjB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,wBAAwB;IACxB,UAAU,CAAC,EAAE,YAAY,CAAA;IACzB,+CAA+C;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,oDAAoD;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;IACjD,0BAA0B;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACzD,gBAAgB;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,qEAAqE;IACrE,SAAS,CAAC,EAAE,kBAAkB,CAAA;CAC/B;AA0FH,QAAA,MAAM,SAAS,0BAAwC,CAAC;AACxD,KAAK,SAAS,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAC9C,eAAe,SAAS,CAAC"}