svelte-streamdown 2.4.5 → 2.5.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.
@@ -2,18 +2,12 @@
2
2
  import { useStreamdown } from '../context.svelte.js';
3
3
  import Slot from './Slot.svelte';
4
4
  import type { FootnoteRef } from '../marked/marked-footnotes.js';
5
- import {
6
- autoPlacement,
7
- computePosition,
8
- autoUpdate,
9
- hide,
10
- offset,
11
- shift
12
- } from '@floating-ui/dom';
5
+
13
6
  import { useClickOutside } from '../utils/useClickOutside.svelte.js';
14
7
  import { scale } from 'svelte/transition';
15
8
  import Block from '../Block.svelte';
16
9
  import { useKeyDown } from '../utils/useKeyDown.svelte.js';
10
+ import { Popover } from './popover.svelte.js';
17
11
 
18
12
  const streamdown = useStreamdown();
19
13
 
@@ -24,106 +18,62 @@
24
18
  } = $props();
25
19
 
26
20
  const id = $props.id();
27
- let isOpen = $state(false);
28
-
29
- let reference = $state<HTMLButtonElement>();
30
- let content = $state<HTMLDialogElement>();
21
+ const popover = new Popover();
31
22
 
32
- const clickOutside = useClickOutside({
23
+ useKeyDown({
24
+ keys: ['Escape'],
33
25
  get isActive() {
34
- return isOpen;
26
+ return popover.isOpen;
35
27
  },
36
28
  callback: () => {
37
- isOpen = false;
29
+ popover.isOpen = false;
38
30
  }
39
31
  });
40
-
41
- useKeyDown({
42
- keys: ['Escape'],
32
+ const clickOutside = useClickOutside({
43
33
  get isActive() {
44
- return isOpen;
34
+ return popover.isOpen;
45
35
  },
46
36
  callback: () => {
47
- isOpen = false;
37
+ popover.isOpen = false;
48
38
  }
49
39
  });
50
-
51
- const place = async (node: HTMLElement) => {
52
- const middleware = [
53
- hide(),
54
- offset(0),
55
- shift({
56
- mainAxis: true
57
- }),
58
- autoPlacement({
59
- allowedPlacements: ['top', 'top-end', 'top-start', 'bottom', 'bottom-end', 'bottom-start']
60
- })
61
- ];
62
- const { x, y, strategy, placement, middlewareData } = await computePosition(reference!, node, {
63
- strategy: 'fixed',
64
- middleware
65
- });
66
-
67
- Object.assign(node.style, {
68
- position: strategy,
69
- left: `${x}px`,
70
- top: `${y}px`
71
- });
72
- };
73
-
74
- const popoverAttachment = (node: HTMLDialogElement) => {
75
- content = node;
76
- void place(node);
77
- const off = autoUpdate(reference!, node, () => place(node));
78
- return () => {
79
- off();
80
- };
81
- };
82
40
  </script>
83
41
 
84
- {#if isOpen}
85
- <Slot
86
- props={{
87
- token,
88
- isOpen
89
- }}
90
- render={streamdown.snippets.footnotePopover}
42
+ {#if popover.isOpen}
43
+ <dialog
44
+ id={'footnote-popover-' + id}
45
+ aria-modal="false"
46
+ transition:scale|global={{ start: 0.95, duration: 100 }}
47
+ {@attach clickOutside.attachment}
48
+ {@attach popover.popoverAttachment}
49
+ open
50
+ class={`${streamdown.theme.components.popover}`}
91
51
  >
92
- <dialog
93
- style="z-index: 1000; position: fixed;"
94
- id={'footnote-popover-' + id}
95
- aria-modal="false"
96
- transition:scale|global={{ start: 0.95, duration: 100 }}
97
- {@attach clickOutside.attachment}
98
- {@attach popoverAttachment}
99
- open
100
- class={`${streamdown.theme.footnotePopover.base}`}
52
+ <Slot
53
+ props={{
54
+ token,
55
+ isOpen: popover.isOpen
56
+ }}
57
+ render={streamdown.snippets.footnotePopover}
101
58
  >
102
59
  {#each token.content.lines as line}
103
- <Block insideFootnote block={line} />
60
+ <Block block={line} />
104
61
  {/each}
105
- </dialog>
106
- </Slot>
62
+ </Slot>
63
+ </dialog>
107
64
  {/if}
108
65
 
109
66
  {#if token.label !== 'streamdown:footnote'}
110
- <Slot
111
- props={{
112
- token
113
- }}
114
- render={streamdown.snippets.footnoteRef}
67
+ <button
68
+ style={streamdown.animationBlockStyle}
69
+ bind:this={popover.reference}
70
+ class={streamdown.theme.footnoteRef.base}
71
+ onclick={() => (popover.isOpen = !popover.isOpen)}
72
+ aria-expanded={popover.isOpen}
73
+ aria-haspopup="dialog"
74
+ aria-controls={'footnote-popover-' + id}
75
+ {@attach clickOutside.attachment}
115
76
  >
116
- <button
117
- style={streamdown.animationBlockStyle}
118
- bind:this={reference}
119
- class={streamdown.theme.footnoteRef.base}
120
- onclick={() => (isOpen = !isOpen)}
121
- aria-expanded={isOpen}
122
- aria-haspopup="dialog"
123
- aria-controls={'footnote-popover-' + id}
124
- {@attach clickOutside.attachment}
125
- >
126
- {token.label.replace('^', '')}
127
- </button>
128
- </Slot>
77
+ {token.label.replace('^', '')}
78
+ </button>
129
79
  {/if}
@@ -200,60 +200,63 @@
200
200
  };
201
201
  </script>
202
202
 
203
- {#if mermaid}
204
- <div
205
- style={streamdown.isMounted ? streamdown.animationBlockStyle : ''}
206
- class={streamdown.theme.mermaid.base}
207
- {@attach (node) => renderMermaid(token.text, node)}
208
- {@attach insider.attach}
209
- data-expanded={'false'}
210
- >
211
- {#if streamdown.controls.mermaid}
212
- <div class={streamdown.theme.mermaid.buttons}>
213
- <button
214
- class={streamdown.theme.mermaid.button}
215
- aria-label="Zoom to fit"
216
- onclick={() => panzoom.zoomToFit()}
217
- data-panzoom-ignore
218
- >
219
- {@render (streamdown.icons?.fitView || fitViewIcon)()}
220
- </button>
221
- <button
222
- class={streamdown.theme.mermaid.button}
223
- aria-label="Zoom in"
224
- onclick={() => panzoom.zoomIn()}
225
- data-panzoom-ignore
226
- >
227
- {@render (streamdown.icons?.zoomIn || zoomInIcon)()}
228
- </button>
229
- <button
230
- class={streamdown.theme.mermaid.button}
231
- aria-label="Zoom out"
232
- onclick={() => panzoom.zoomOut()}
233
- data-panzoom-ignore
234
- >
235
- {@render (streamdown.icons?.zoomOut || zoomOutIcon)()}
236
- </button>
237
- <button
238
- class={streamdown.theme.mermaid.button}
239
- aria-label="Toggle expand"
240
- onclick={() => panzoom.toggleExpand()}
241
- data-panzoom-ignore
242
- >
243
- {@render (streamdown.icons?.fullscreen || fullscreenIcon)()}
244
- </button>
245
- </div>
246
- {/if}
247
- <svg {@attach panzoom.attach} data-mermaid-svg></svg>
248
- </div>
249
- {:else}
250
- <div class={streamdown.theme.mermaid.base}></div>
251
- {/if}
252
-
203
+ <div>
204
+ {#if mermaid}
205
+ <div
206
+ style={streamdown.isMounted ? streamdown.animationBlockStyle : ''}
207
+ class={streamdown.theme.mermaid.base}
208
+ {@attach (node) => renderMermaid(token.text, node)}
209
+ {@attach insider.attach}
210
+ data-expanded={'false'}
211
+ >
212
+ {#if streamdown.controls.mermaid}
213
+ <div class={streamdown.theme.mermaid.buttons}>
214
+ <button
215
+ class={streamdown.theme.components.button}
216
+ aria-label="Zoom to fit"
217
+ onclick={() => panzoom.zoomToFit()}
218
+ data-panzoom-ignore
219
+ >
220
+ {@render (streamdown.icons?.fitView || fitViewIcon)()}
221
+ </button>
222
+ <button
223
+ class={streamdown.theme.components.button}
224
+ aria-label="Zoom in"
225
+ onclick={() => panzoom.zoomIn()}
226
+ data-panzoom-ignore
227
+ >
228
+ {@render (streamdown.icons?.zoomIn || zoomInIcon)()}
229
+ </button>
230
+ <button
231
+ class={streamdown.theme.components.button}
232
+ aria-label="Zoom out"
233
+ onclick={() => panzoom.zoomOut()}
234
+ data-panzoom-ignore
235
+ >
236
+ {@render (streamdown.icons?.zoomOut || zoomOutIcon)()}
237
+ </button>
238
+ <button
239
+ class={streamdown.theme.components.button}
240
+ aria-label="Toggle expand"
241
+ onclick={() => panzoom.toggleExpand()}
242
+ data-panzoom-ignore
243
+ >
244
+ {@render (streamdown.icons?.fullscreen || fullscreenIcon)()}
245
+ </button>
246
+ </div>
247
+ {/if}
248
+ <svg {@attach panzoom.attach} data-mermaid-svg></svg>
249
+ </div>
250
+ {:else}
251
+ <div class={streamdown.theme.mermaid.base}></div>
252
+ {/if}
253
+ </div>
253
254
  {#snippet zoomInIcon()}
254
255
  <svg
255
256
  class={streamdown.theme.mermaid.icon}
256
257
  xmlns="http://www.w3.org/2000/svg"
258
+ width="100%"
259
+ height="100%"
257
260
  viewBox="0 0 24 24"
258
261
  fill="none"
259
262
  stroke="currentColor"
@@ -271,6 +274,8 @@
271
274
  <svg
272
275
  class={streamdown.theme.mermaid.icon}
273
276
  xmlns="http://www.w3.org/2000/svg"
277
+ width="100%"
278
+ height="100%"
274
279
  viewBox="0 0 24 24"
275
280
  fill="none"
276
281
  stroke="currentColor"
@@ -321,47 +326,7 @@
321
326
  {/snippet}
322
327
 
323
328
  <style>
324
- /* View Transition styles for zoom effect */
325
- ::view-transition-old(panzoom-element),
326
- ::view-transition-new(panzoom-element) {
327
- /* Animate both scale and opacity for smooth zoom */
328
- animation-duration: 0.3s;
329
- animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
330
- }
331
-
332
- /* Zoom in animation (expand) */
333
- ::view-transition-old(panzoom-element) {
334
- animation-name: zoom-out;
335
- }
336
-
337
- ::view-transition-new(panzoom-element) {
338
- animation-name: zoom-in;
339
- }
340
-
341
- @keyframes zoom-out {
342
- from {
343
- transform: scale(1);
344
- }
345
- to {
346
- transform: scale(0.8);
347
- }
348
- }
349
-
350
- @keyframes zoom-in {
351
- from {
352
- transform: scale(1.2);
353
- }
354
- to {
355
- transform: scale(1);
356
- }
357
- }
358
-
359
329
  :global([data-expanded='true']) {
360
- ::view-transition-old(panzoom-element),
361
- ::view-transition-new(panzoom-element) {
362
- animation-duration: 0.3s;
363
- animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
364
- }
365
330
  position: fixed;
366
331
  top: 16px;
367
332
  left: 16px;
@@ -0,0 +1,8 @@
1
+ export declare class Popover {
2
+ isOpen: boolean;
3
+ content: HTMLDialogElement | undefined;
4
+ reference: HTMLButtonElement | undefined;
5
+ constructor();
6
+ place: (node: HTMLElement) => Promise<void>;
7
+ popoverAttachment: (node: HTMLDialogElement) => () => void;
8
+ }
@@ -0,0 +1,40 @@
1
+ import { useClickOutside } from '../utils/useClickOutside.svelte.js';
2
+ import { autoPlacement, computePosition, autoUpdate, hide, offset, shift } from '@floating-ui/dom';
3
+ import { setContext } from 'svelte';
4
+ export class Popover {
5
+ isOpen = $state(false);
6
+ content = $state();
7
+ reference = $state();
8
+ constructor() {
9
+ setContext('POPOVER', true);
10
+ }
11
+ place = async (node) => {
12
+ const middleware = [
13
+ hide(),
14
+ offset(10),
15
+ shift({
16
+ mainAxis: true
17
+ }),
18
+ autoPlacement({
19
+ allowedPlacements: ['top', 'top-end', 'top-start', 'bottom', 'bottom-end', 'bottom-start']
20
+ })
21
+ ];
22
+ const { x, y, strategy, placement, middlewareData } = await computePosition(this.reference, node, {
23
+ strategy: 'fixed',
24
+ middleware
25
+ });
26
+ Object.assign(node.style, {
27
+ position: strategy,
28
+ left: `${x}px`,
29
+ top: `${y}px`
30
+ });
31
+ };
32
+ popoverAttachment = (node) => {
33
+ this.content = node;
34
+ void this.place(node);
35
+ const off = autoUpdate(this.reference, node, () => this.place(node));
36
+ return () => {
37
+ off();
38
+ };
39
+ };
40
+ }
@@ -0,0 +1,35 @@
1
+ type KeyFramesOptions = {
2
+ duration: number;
3
+ easing: string;
4
+ fill: 'auto' | 'backwards' | 'both' | 'forwards' | 'none';
5
+ };
6
+ export declare const bind: (ref: Record<string, any>, props: Record<string, any>) => void;
7
+ export interface StepperState<Item> {
8
+ items: Item[];
9
+ keyFramesOptions: KeyFramesOptions;
10
+ }
11
+ export declare class StepperState<Item> {
12
+ activeStep: number;
13
+ destinationOffset: number;
14
+ stepAnimation: Animation | undefined;
15
+ offsets: number[];
16
+ stepHeights: number[];
17
+ stepContainer: HTMLElement | null;
18
+ isAnimating: boolean;
19
+ constructor(props: {
20
+ items: Item[];
21
+ keyFramesOptions: KeyFramesOptions;
22
+ });
23
+ translate: () => void;
24
+ setActiveStep: (i: number) => () => void;
25
+ scroller: (node: HTMLElement) => {
26
+ destroy: () => void;
27
+ };
28
+ next: () => void;
29
+ previous: () => void;
30
+ goTo: (i: number) => void;
31
+ get canGoNext(): boolean;
32
+ get canGoPrevious(): boolean;
33
+ canGoToStep: (targetStep: number) => boolean;
34
+ }
35
+ export {};
@@ -0,0 +1,98 @@
1
+ import { tick } from 'svelte';
2
+ export const bind = (ref, props) => {
3
+ const descriptors = Object.getOwnPropertyDescriptors(props);
4
+ for (const key in descriptors) {
5
+ Object.defineProperty(ref, key, descriptors[key]);
6
+ }
7
+ };
8
+ export class StepperState {
9
+ activeStep = $state(0);
10
+ destinationOffset = $state(0);
11
+ stepAnimation = $state();
12
+ offsets = $state([]);
13
+ stepHeights = $state([]);
14
+ stepContainer = null;
15
+ isAnimating = $state(false);
16
+ constructor(props) {
17
+ bind(this, props);
18
+ }
19
+ translate = () => {
20
+ if (this.destinationOffset !== this.offsets[this.activeStep] && this.stepContainer) {
21
+ this.destinationOffset = this.offsets[this.activeStep];
22
+ this.stepAnimation?.cancel();
23
+ this.stepAnimation = this.stepContainer.animate({
24
+ transform: `translateX(-${this.offsets[this.activeStep]}px)`
25
+ }, this.keyFramesOptions);
26
+ this.stepAnimation.onfinish = () => {
27
+ this.stepAnimation = undefined;
28
+ };
29
+ }
30
+ };
31
+ setActiveStep = (i) => () => {
32
+ if (!this.canGoToStep(i) || !this.stepContainer)
33
+ return;
34
+ const previousStep = this.stepContainer.children[this.activeStep];
35
+ const nextStep = this.stepContainer.children[i];
36
+ if (!previousStep || !nextStep)
37
+ return;
38
+ this.activeStep = i;
39
+ this.translate();
40
+ previousStep.animate({
41
+ opacity: `0`
42
+ }, this.keyFramesOptions);
43
+ nextStep.animate({
44
+ opacity: `1`
45
+ }, this.keyFramesOptions);
46
+ };
47
+ scroller = (node) => {
48
+ const onScroll = (e) => {
49
+ e.preventDefault();
50
+ node.scrollTo(0, 0);
51
+ };
52
+ node.addEventListener('scroll', onScroll);
53
+ node.scrollTo(0, 0);
54
+ const steps = node.querySelectorAll('[data-step]');
55
+ const setOffsets = () => {
56
+ steps.forEach((step, i) => {
57
+ this.offsets[i] = step.offsetLeft;
58
+ this.translate();
59
+ });
60
+ };
61
+ const resizeObserver = new ResizeObserver(setOffsets);
62
+ resizeObserver.observe(node);
63
+ setOffsets();
64
+ return {
65
+ destroy: () => {
66
+ resizeObserver.unobserve(node);
67
+ node.removeEventListener('scroll', onScroll);
68
+ this.activeStep = 0;
69
+ this.offsets = [];
70
+ this.destinationOffset = 0;
71
+ }
72
+ };
73
+ };
74
+ next = () => {
75
+ if (this.activeStep < this.items.length - 1) {
76
+ this.setActiveStep(this.activeStep + 1)();
77
+ }
78
+ };
79
+ previous = () => {
80
+ if (this.activeStep > 0) {
81
+ this.setActiveStep(this.activeStep - 1)();
82
+ }
83
+ };
84
+ goTo = (i) => {
85
+ if (this.canGoToStep(i)) {
86
+ this.setActiveStep(i)();
87
+ }
88
+ };
89
+ get canGoNext() {
90
+ return this.activeStep < this.items.length - 1;
91
+ }
92
+ get canGoPrevious() {
93
+ return this.activeStep > 0;
94
+ }
95
+ canGoToStep = (targetStep) => {
96
+ return targetStep >= 0 && targetStep < this.items.length;
97
+ };
98
+ }
@@ -1,4 +1,4 @@
1
- <script lang="ts">
1
+ <script lang="ts" generics="Source extends Record<string, any> = Record<string, any>">
2
2
  import Block from './Block.svelte';
3
3
  import { StreamdownContext, type StreamdownProps } from './context.svelte.js';
4
4
  import { mergeTheme, shadcnTheme } from './theme.js';
@@ -27,8 +27,10 @@
27
27
  icons,
28
28
  children,
29
29
  extensions,
30
+ sources,
31
+ inlineCitationsMode = 'carousel',
30
32
  ...snippets
31
- }: StreamdownProps = $props();
33
+ }: StreamdownProps<Source> = $props();
32
34
 
33
35
  streamdown = new StreamdownContext({
34
36
  get element() {
@@ -78,7 +80,12 @@
78
80
  get shikiPreloadThemes() {
79
81
  return shikiPreloadThemes;
80
82
  },
81
-
83
+ get sources() {
84
+ return sources;
85
+ },
86
+ get inlineCitationsMode() {
87
+ return inlineCitationsMode;
88
+ },
82
89
  get animation() {
83
90
  if (!animation?.enabled)
84
91
  return {
@@ -1,4 +1,25 @@
1
1
  import { type StreamdownProps } from './context.svelte.js';
2
- declare const Streamdown: import("svelte").Component<StreamdownProps, {}, "streamdown" | "element">;
3
- type Streamdown = ReturnType<typeof Streamdown>;
2
+ declare function $$render<Source extends Record<string, any> = Record<string, any>>(): {
3
+ props: StreamdownProps<Source>;
4
+ exports: {};
5
+ bindings: "streamdown" | "element";
6
+ slots: {};
7
+ events: {};
8
+ };
9
+ declare class __sveltets_Render<Source extends Record<string, any> = Record<string, any>> {
10
+ props(): ReturnType<typeof $$render<Source>>['props'];
11
+ events(): ReturnType<typeof $$render<Source>>['events'];
12
+ slots(): ReturnType<typeof $$render<Source>>['slots'];
13
+ bindings(): "streamdown" | "element";
14
+ exports(): {};
15
+ }
16
+ interface $$IsomorphicComponent {
17
+ new <Source extends Record<string, any> = Record<string, any>>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<Source>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<Source>['props']>, ReturnType<__sveltets_Render<Source>['events']>, ReturnType<__sveltets_Render<Source>['slots']>> & {
18
+ $$bindings?: ReturnType<__sveltets_Render<Source>['bindings']>;
19
+ } & ReturnType<__sveltets_Render<Source>['exports']>;
20
+ <Source extends Record<string, any> = Record<string, any>>(internal: unknown, props: ReturnType<__sveltets_Render<Source>['props']> & {}): ReturnType<__sveltets_Render<Source>['exports']>;
21
+ z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
22
+ }
23
+ declare const Streamdown: $$IsomorphicComponent;
24
+ type Streamdown<Source extends Record<string, any> = Record<string, any>> = InstanceType<typeof Streamdown<Source>>;
4
25
  export default Streamdown;
@@ -3,7 +3,7 @@ import type { DeepPartialTheme, Theme } from './theme.js';
3
3
  import type { MermaidConfig } from 'mermaid';
4
4
  import type { KatexOptions } from 'katex';
5
5
  import type { BundledTheme } from 'shiki';
6
- export interface StreamdownContext extends Omit<StreamdownProps, keyof Snippets | 'class' | 'theme' | 'shikiTheme'> {
6
+ export interface StreamdownContext extends Omit<StreamdownProps, keyof Snippets | 'class' | 'theme' | 'shikiTheme' | 'inlineCitationsMode'> {
7
7
  snippets: Snippets;
8
8
  shikiTheme: BundledTheme;
9
9
  theme: Theme;
@@ -11,24 +11,25 @@ export interface StreamdownContext extends Omit<StreamdownProps, keyof Snippets
11
11
  code: boolean;
12
12
  mermaid: boolean;
13
13
  };
14
+ inlineCitationsMode: 'list' | 'carousel';
14
15
  animation: {
15
16
  enabled: boolean;
16
17
  } & StreamdownProps['animation'];
17
18
  }
18
- export declare class StreamdownContext {
19
+ export declare class StreamdownContext<Source extends Record<string, any> = Record<string, any>> {
19
20
  footnotes: {
20
21
  refs: Map<string, FootnoteRef>;
21
22
  footnotes: Map<string, Footnote>;
22
23
  };
23
24
  isMounted: boolean;
24
- animationTextStyle: string | undefined;
25
- animationBlockStyle: string | undefined;
25
+ get animationTextStyle(): string | undefined;
26
+ get animationBlockStyle(): string | undefined;
26
27
  constructor(props: Omit<StreamdownProps, keyof Snippets | 'class'> & {
27
- snippets: Snippets;
28
+ snippets: Snippets<Source>;
28
29
  });
29
30
  }
30
- export declare const useStreamdown: () => StreamdownContext;
31
- import type { AlertToken, MathToken, SubSupToken, TableToken, THead, TBody, TFoot, THeadRow, TRow, TD, TH, Extension, GenericToken } from './marked/index.js';
31
+ export declare const useStreamdown: () => StreamdownContext<Record<string, any>>;
32
+ import type { AlertToken, MathToken, SubSupToken, TableToken, THead, TBody, TFoot, THeadRow, TRow, TD, TH, Extension, GenericToken, CitationToken } from './marked/index.js';
32
33
  import type { Tokens } from 'marked';
33
34
  import type { ListItemToken, ListToken } from './marked/marked-list.js';
34
35
  import type { Footnote, FootnoteRef, FootnoteToken } from './marked/marked-footnotes.js';
@@ -67,18 +68,29 @@ type TokenSnippet = {
67
68
  description: DescriptionToken;
68
69
  descriptionTerm: DescriptionTermToken;
69
70
  descriptionDetail: DescriptionDetailToken;
71
+ inlineCitation: CitationToken;
72
+ inlineCitationPopover: CitationToken;
73
+ inlineCitationContent: CitationToken;
74
+ inlineCitationPreview: CitationToken;
70
75
  };
71
76
  type PredefinedElements = keyof TokenSnippet;
72
- export type Snippets = {
77
+ export type Snippets<Source extends Record<string, any> = Record<string, any>> = {
73
78
  [K in PredefinedElements]?: Snippet<[
74
79
  {
75
80
  children: Snippet;
76
81
  token: TokenSnippet[K];
77
- }
82
+ } & (K extends 'inlineCitationContent' ? {
83
+ source: Source;
84
+ key: string;
85
+ } : {})
78
86
  ]>;
79
87
  };
80
- export type StreamdownProps = {
88
+ export type StreamdownProps<Source extends Record<string, any> = Record<string, any>> = {
81
89
  streamdown?: StreamdownContext;
90
+ sources?: {
91
+ [key: string]: Source;
92
+ };
93
+ inlineCitationsMode?: 'list' | 'carousel';
82
94
  element?: HTMLElement;
83
95
  content: string;
84
96
  class?: string;
@@ -127,6 +139,8 @@ export type StreamdownProps = {
127
139
  warning?: Snippet;
128
140
  caution?: Snippet;
129
141
  important?: Snippet;
142
+ chevronLeft?: Snippet;
143
+ chevronRight?: Snippet;
130
144
  };
131
145
  extensions?: Extension[];
132
146
  children?: Snippet<[{
@@ -134,5 +148,5 @@ export type StreamdownProps = {
134
148
  token: GenericToken;
135
149
  children: Snippet;
136
150
  }]>;
137
- } & Partial<Snippets>;
151
+ } & Partial<Snippets<Source>>;
138
152
  export {};