@ai-react-markdown/core 1.2.9 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +87 -25
- package/dist/index.cjs +2293 -848
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +336 -19
- package/dist/index.d.ts +336 -19
- package/dist/index.js +2301 -858
- package/dist/index.js.map +1 -1
- package/package.json +20 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
-
import { ComponentType, PropsWithChildren, CSSProperties } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import { JSX, ComponentType, PropsWithChildren, CSSProperties, FC } from 'react';
|
|
3
|
+
import { Element, ElementContent } from 'hast';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Public types for the local Markdown wrapper. Ported 1:1 from react-markdown
|
|
7
|
+
* v10's lib/index.js JSDoc, restructured as TypeScript declarations.
|
|
8
|
+
*
|
|
9
|
+
* @module components/markdown/types
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/** Extra fields the wrapper passes to user-supplied tag components. */
|
|
13
|
+
interface ExtraProps {
|
|
14
|
+
node?: Element | undefined;
|
|
15
|
+
}
|
|
16
|
+
/** Map tag names to user components or other tag names. */
|
|
17
|
+
type Components = {
|
|
18
|
+
[Key in keyof JSX.IntrinsicElements]?: ComponentType<JSX.IntrinsicElements[Key] & ExtraProps> | keyof JSX.IntrinsicElements;
|
|
19
|
+
};
|
|
4
20
|
|
|
5
21
|
/**
|
|
6
22
|
* Core type definitions, enums, and default configuration for ai-react-markdown.
|
|
@@ -14,9 +30,10 @@ import { Components } from 'react-markdown';
|
|
|
14
30
|
|
|
15
31
|
/**
|
|
16
32
|
* Custom component overrides for the markdown renderer.
|
|
17
|
-
* Alias for
|
|
18
|
-
* library's `AIMarkdown` naming
|
|
19
|
-
* direct `react-markdown` dependency
|
|
33
|
+
* Alias for the local Markdown wrapper's `Components` type (a vendored fork of
|
|
34
|
+
* react-markdown's), re-exported under the library's `AIMarkdown` naming
|
|
35
|
+
* convention so consumers don't need a direct `react-markdown` dependency
|
|
36
|
+
* for type imports.
|
|
20
37
|
*/
|
|
21
38
|
type AIMarkdownCustomComponents = Components;
|
|
22
39
|
/**
|
|
@@ -27,9 +44,7 @@ declare enum AIMarkdownRenderExtraSyntax {
|
|
|
27
44
|
/** `==Highlight==` syntax support. */
|
|
28
45
|
HIGHLIGHT = "HIGHLIGHT",
|
|
29
46
|
/** Definition list syntax. @see https://michelf.ca/projects/php-markdown/extra/#def-list */
|
|
30
|
-
DEFINITION_LIST = "DEFINITION_LIST"
|
|
31
|
-
/** Superscript (`^text^`) and subscript (`~text~`) syntax. */
|
|
32
|
-
SUBSCRIPT = "SUBSCRIPT"
|
|
47
|
+
DEFINITION_LIST = "DEFINITION_LIST"
|
|
33
48
|
}
|
|
34
49
|
/**
|
|
35
50
|
* Display optimization abilities applied during markdown processing.
|
|
@@ -46,18 +61,62 @@ declare enum AIMarkdownRenderDisplayOptimizeAbility {
|
|
|
46
61
|
/**
|
|
47
62
|
* Configuration object controlling which markdown extensions and
|
|
48
63
|
* display optimizations are active during rendering.
|
|
64
|
+
*
|
|
65
|
+
* Arrays are typed `readonly` so the interface is assignable from the frozen
|
|
66
|
+
* {@link defaultAIMarkdownRenderConfig}. Consumers can still pass mutable
|
|
67
|
+
* arrays since `readonly T[]` is assignable from `T[]`. Note: this is a
|
|
68
|
+
* compile-time hint only — user-supplied configs are not deep-frozen at
|
|
69
|
+
* runtime, so the library does not guarantee the object remains unchanged
|
|
70
|
+
* after it is passed in.
|
|
49
71
|
*/
|
|
50
72
|
interface AIMarkdownRenderConfig {
|
|
51
73
|
/** Extra syntax extensions to enable. */
|
|
52
|
-
extraSyntaxSupported: AIMarkdownRenderExtraSyntax[];
|
|
74
|
+
readonly extraSyntaxSupported: readonly AIMarkdownRenderExtraSyntax[];
|
|
53
75
|
/** Display optimization abilities to enable. */
|
|
54
|
-
displayOptimizeAbilities: AIMarkdownRenderDisplayOptimizeAbility[];
|
|
76
|
+
readonly displayOptimizeAbilities: readonly AIMarkdownRenderDisplayOptimizeAbility[];
|
|
77
|
+
/**
|
|
78
|
+
* Whether to enable block-level memoization across renders.
|
|
79
|
+
*
|
|
80
|
+
* When `true` (default), the renderer splits each rendered document into
|
|
81
|
+
* per-block units and memoizes the React subtree of each block by its
|
|
82
|
+
* source identity (`raw + occurrence + ctx + position`). Unchanged blocks
|
|
83
|
+
* during streaming skip `toJsxRuntime` and React reconcile work, reducing
|
|
84
|
+
* per-frame cost roughly proportional to the unchanged fraction of the
|
|
85
|
+
* document. Output is byte-identical to the disabled path.
|
|
86
|
+
*
|
|
87
|
+
* When `false`, the renderer falls back to the legacy bare `<Markdown>`
|
|
88
|
+
* flow — every render runs the full pipeline end-to-end with no
|
|
89
|
+
* cross-frame reuse. Useful for debugging, for environments where the
|
|
90
|
+
* extra `useRef`-backed cache is undesirable, or as an escape hatch if a
|
|
91
|
+
* future custom rehype plugin interacts badly with the plan abstraction.
|
|
92
|
+
*
|
|
93
|
+
* @default true
|
|
94
|
+
*/
|
|
95
|
+
readonly blockMemoEnabled: boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Default `true`. Controls Direction A: whether `<AIMarkdown>` (standalone
|
|
98
|
+
* mode) protects orphan `footnoteDefinition` nodes from being silently
|
|
99
|
+
* dropped by `mdast-util-to-hast` when no corresponding `footnoteReference`
|
|
100
|
+
* exists. Implemented via a custom `footnoteDefinition` handler that
|
|
101
|
+
* proactively registers the label in `state.footnoteOrder`.
|
|
102
|
+
*
|
|
103
|
+
* When `<AIMarkdown>` is wrapped in `<AIMarkdownDocuments>`, this field
|
|
104
|
+
* is ignored — the wrapper's `preserveOrphanReferences` prop overrides
|
|
105
|
+
* unconditionally for all chunks under it.
|
|
106
|
+
*/
|
|
107
|
+
readonly preserveOrphanReferences: boolean;
|
|
55
108
|
}
|
|
56
109
|
/**
|
|
57
110
|
* Sensible default configuration with all extensions and optimizations enabled.
|
|
58
|
-
* Frozen
|
|
111
|
+
* Frozen at both the top level and the inner arrays so this shared singleton
|
|
112
|
+
* cannot be mutated by any consumer.
|
|
59
113
|
*/
|
|
60
|
-
declare const defaultAIMarkdownRenderConfig:
|
|
114
|
+
declare const defaultAIMarkdownRenderConfig: Readonly<{
|
|
115
|
+
extraSyntaxSupported: readonly AIMarkdownRenderExtraSyntax[];
|
|
116
|
+
displayOptimizeAbilities: readonly AIMarkdownRenderDisplayOptimizeAbility[];
|
|
117
|
+
blockMemoEnabled: true;
|
|
118
|
+
preserveOrphanReferences: true;
|
|
119
|
+
}>;
|
|
61
120
|
/**
|
|
62
121
|
* Arbitrary metadata that consumers can pass through a dedicated React context.
|
|
63
122
|
* Custom renderers can access this via the {@link useAIMarkdownMetadata} hook.
|
|
@@ -140,6 +199,30 @@ interface AIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig = AIMarkd
|
|
|
140
199
|
variant: AIMarkdownVariant;
|
|
141
200
|
/** Active color scheme. */
|
|
142
201
|
colorScheme: AIMarkdownColorScheme;
|
|
202
|
+
/**
|
|
203
|
+
* Stable identifier unique to this *logical markdown document*. Used as
|
|
204
|
+
* the id namespace for clobberable attributes (`id`, hash hrefs) so two
|
|
205
|
+
* documents on the same page don't cross-link — e.g. clicking a footnote
|
|
206
|
+
* `[^1]` in message A won't scroll to the `[^1]` definition in message B.
|
|
207
|
+
*
|
|
208
|
+
* Named `documentId` (not `instanceId`) intentionally: when one logical
|
|
209
|
+
* markdown document is split into multiple `<AIMarkdown>` instances
|
|
210
|
+
* (chunked / streamed rendering), every chunk SHOULD share the same value
|
|
211
|
+
* so id-prefixes align across the chunks.
|
|
212
|
+
*
|
|
213
|
+
* Auto-generated via React's `useId()` (SSR-safe, stable across
|
|
214
|
+
* re-renders) when not provided by the consumer; consumer-supplied values
|
|
215
|
+
* always win.
|
|
216
|
+
*/
|
|
217
|
+
documentId: string;
|
|
218
|
+
/**
|
|
219
|
+
* Per-document URI-safe id prefix used by all clobberable attributes
|
|
220
|
+
* (`id="…"` / `href="#…"`). Derived once by the provider as
|
|
221
|
+
* `${encodeURIComponent(documentId)}-user-content-` and exposed here so
|
|
222
|
+
* downstream consumers (placeholder components, cross-chunk anchor logic)
|
|
223
|
+
* read a single canonical source instead of recomputing locally.
|
|
224
|
+
*/
|
|
225
|
+
clobberPrefix: string;
|
|
143
226
|
/** Active render configuration. */
|
|
144
227
|
config: TConfig;
|
|
145
228
|
}
|
|
@@ -494,16 +577,59 @@ type PartialObjectDeep<ObjectType extends object, Options extends Required<Parti
|
|
|
494
577
|
* Must be called inside a component rendered as a descendant of `<AIMarkdown>`.
|
|
495
578
|
* Throws if called outside the provider boundary.
|
|
496
579
|
*
|
|
497
|
-
*
|
|
498
|
-
* @returns The current render state (does not include metadata — use {@link useAIMarkdownMetadata} for that).
|
|
580
|
+
* ### `TConfig` is a caller-asserted type, not a derived one
|
|
499
581
|
*
|
|
500
|
-
*
|
|
582
|
+
* The generic parameter is **an assertion the caller makes about the provider
|
|
583
|
+
* above it** — TypeScript cannot verify that the actual `<AIMarkdown>` in the
|
|
584
|
+
* tree was configured with a matching `defaultConfig: TConfig`. If you pass a
|
|
585
|
+
* wider `TConfig` than what the provider actually carries, field access at
|
|
586
|
+
* compile time will look fine but resolve to `undefined` at runtime.
|
|
587
|
+
*
|
|
588
|
+
* The intended pattern is that extension packages (e.g. `@ai-react-markdown/mantine`)
|
|
589
|
+
* ship their own narrow wrapper hook alongside a matching `defaultConfig`, so the
|
|
590
|
+
* assertion is made *once* next to the provider configuration and consumers of the
|
|
591
|
+
* wrapper never touch the raw generic.
|
|
592
|
+
*
|
|
593
|
+
* @typeParam TConfig - Caller-asserted configuration shape (defaults to
|
|
594
|
+
* {@link AIMarkdownRenderConfig}). Must be aligned with the provider's
|
|
595
|
+
* `defaultConfig` — the library does not check this at runtime.
|
|
596
|
+
* @returns The current render state (does not include metadata — use
|
|
597
|
+
* {@link useAIMarkdownMetadata} for that).
|
|
598
|
+
* @throws If called outside an `<AIMarkdown>` provider tree.
|
|
599
|
+
*
|
|
600
|
+
* @example Base usage — no generic, always safe:
|
|
501
601
|
* ```tsx
|
|
502
602
|
* function CustomCodeBlock({ children }: PropsWithChildren) {
|
|
503
603
|
* const { streaming, config } = useAIMarkdownRenderState();
|
|
504
|
-
* //
|
|
604
|
+
* // config: AIMarkdownRenderConfig — guaranteed shape
|
|
505
605
|
* }
|
|
506
606
|
* ```
|
|
607
|
+
*
|
|
608
|
+
* @example Wrapper-hook pattern — the intended way to use an extended TConfig:
|
|
609
|
+
* ```tsx
|
|
610
|
+
* // In your extension package (pin the assertion in one place):
|
|
611
|
+
* interface ExtendedConfig extends AIMarkdownRenderConfig {
|
|
612
|
+
* themeMode: 'light' | 'dark' | 'auto';
|
|
613
|
+
* }
|
|
614
|
+
* export const extendedDefaultConfig: ExtendedConfig = {
|
|
615
|
+
* ...defaultAIMarkdownRenderConfig,
|
|
616
|
+
* themeMode: 'auto',
|
|
617
|
+
* };
|
|
618
|
+
* export const useExtendedRenderState = () =>
|
|
619
|
+
* useAIMarkdownRenderState<ExtendedConfig>();
|
|
620
|
+
*
|
|
621
|
+
* // Provider is always configured with the matching defaultConfig:
|
|
622
|
+
* <AIMarkdown defaultConfig={extendedDefaultConfig} ...>{children}</AIMarkdown>
|
|
623
|
+
*
|
|
624
|
+
* // Consumers use the narrow wrapper — no raw generic anywhere:
|
|
625
|
+
* const { config } = useExtendedRenderState();
|
|
626
|
+
* config.themeMode; // correctly typed and present at runtime
|
|
627
|
+
* ```
|
|
628
|
+
*
|
|
629
|
+
* @see `@ai-react-markdown/mantine` — real-world reference. Its
|
|
630
|
+
* `MantineAIMarkdownRenderConfig`, `defaultMantineAIMarkdownRenderConfig`,
|
|
631
|
+
* `<MantineAIMarkdown>` (which passes `defaultConfig` by default), and
|
|
632
|
+
* `useMantineAIMarkdownRenderState` implement this exact pattern.
|
|
507
633
|
*/
|
|
508
634
|
declare function useAIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig>(): AIMarkdownRenderState<TConfig>;
|
|
509
635
|
/**
|
|
@@ -513,8 +639,24 @@ declare function useAIMarkdownRenderState<TConfig extends AIMarkdownRenderConfig
|
|
|
513
639
|
* do not cause re-renders in components that only consume render state
|
|
514
640
|
* (e.g. {@link MarkdownContent}).
|
|
515
641
|
*
|
|
516
|
-
*
|
|
642
|
+
* ### `TMetadata` is a caller-asserted type
|
|
643
|
+
*
|
|
644
|
+
* Same contract as {@link useAIMarkdownRenderState} — the generic is an
|
|
645
|
+
* assertion about the `metadata` prop passed to the provider above, not a
|
|
646
|
+
* value TypeScript can derive. Unlike render-state config, metadata has no
|
|
647
|
+
* runtime fallback: if the provider received no `metadata`, the hook returns
|
|
648
|
+
* `undefined` regardless of the asserted type. Prefer wrapping this hook in
|
|
649
|
+
* a project-local hook that pins `TMetadata` next to the call site that
|
|
650
|
+
* actually provides the metadata.
|
|
651
|
+
*
|
|
652
|
+
* @typeParam TMetadata - Caller-asserted metadata shape (defaults to
|
|
653
|
+
* {@link AIMarkdownMetadata}). Caller is responsible for ensuring the
|
|
654
|
+
* provider's `metadata` prop matches this shape.
|
|
517
655
|
* @returns The current metadata, or `undefined` if none was provided.
|
|
656
|
+
*
|
|
657
|
+
* @see `@ai-react-markdown/mantine` — `useMantineAIMarkdownMetadata` applies
|
|
658
|
+
* the wrapper pattern to this hook, pinning `MantineAIMarkdownMetadata` in
|
|
659
|
+
* a single location.
|
|
518
660
|
*/
|
|
519
661
|
declare function useAIMarkdownMetadata<TMetadata extends AIMarkdownMetadata = AIMarkdownMetadata>(): TMetadata | undefined;
|
|
520
662
|
/** Props for {@link AIMarkdownRenderStateProvider}. */
|
|
@@ -523,6 +665,19 @@ interface AIMarkdownRenderStateProviderProps<TConfig extends AIMarkdownRenderCon
|
|
|
523
665
|
fontSize: string;
|
|
524
666
|
variant: AIMarkdownVariant;
|
|
525
667
|
colorScheme: AIMarkdownColorScheme;
|
|
668
|
+
/**
|
|
669
|
+
* Logical-document identifier used as the id namespace for clobberable
|
|
670
|
+
* attributes (id / hash hrefs). Optional — when omitted, the provider
|
|
671
|
+
* auto-generates one via {@link useId} so the provider stays drop-in
|
|
672
|
+
* usable for direct consumers (e.g. extension packages that don't go
|
|
673
|
+
* through `<AIMarkdown>`).
|
|
674
|
+
*
|
|
675
|
+
* Pass the SAME value to multiple providers / `<AIMarkdown>` instances
|
|
676
|
+
* when they render chunks of the same logical document — their id
|
|
677
|
+
* prefixes will align so cross-chunk anchors and (once the parser sees
|
|
678
|
+
* the full doc) footnote navigation work.
|
|
679
|
+
*/
|
|
680
|
+
documentId?: string;
|
|
526
681
|
/**
|
|
527
682
|
* Base default config to merge against. When omitted, falls back to
|
|
528
683
|
* {@link defaultAIMarkdownRenderConfig}. Sub-packages (e.g. mantine) can
|
|
@@ -572,6 +727,14 @@ type AIMDContentPreprocessor = (content: string) => string;
|
|
|
572
727
|
* returned, preventing unnecessary re-renders in downstream `useMemo` / `useEffect`
|
|
573
728
|
* consumers that depend on reference equality.
|
|
574
729
|
*
|
|
730
|
+
* The ref is updated in a layout effect (not during render) so that the cached
|
|
731
|
+
* reference only advances on COMMITTED renders. In concurrent mode a render
|
|
732
|
+
* may be discarded (e.g. by Suspense); writing to the ref during render would
|
|
733
|
+
* let values from discarded renders pollute the cache and leak into subsequent
|
|
734
|
+
* committed renders. Layout effects run synchronously right after commit, which
|
|
735
|
+
* closes the window where a same-tick re-render could otherwise observe a stale
|
|
736
|
+
* `ref.current` and hand back an outdated reference.
|
|
737
|
+
*
|
|
575
738
|
* @typeParam T - The value type.
|
|
576
739
|
* @param value - The potentially new value to stabilize.
|
|
577
740
|
* @returns The previous reference when deep-equal, otherwise the new value.
|
|
@@ -584,6 +747,138 @@ type AIMDContentPreprocessor = (content: string) => string;
|
|
|
584
747
|
*/
|
|
585
748
|
declare function useStableValue<T>(value: T): T;
|
|
586
749
|
|
|
750
|
+
/**
|
|
751
|
+
* Cross-chunk shared state. Holds per-chunk contributions (refs, defs,
|
|
752
|
+
* linkDefs) keyed by Symbol identity allocated via useId reactId, with
|
|
753
|
+
* refcount + microtask-deferred reclamation for React Strict Mode safety.
|
|
754
|
+
*
|
|
755
|
+
* @module components/documentRegistry
|
|
756
|
+
*/
|
|
757
|
+
|
|
758
|
+
interface FootnoteDef {
|
|
759
|
+
/** Already-normalized identifier (uppercase). Used as dictionary key for
|
|
760
|
+
* case-insensitive cross-chunk lookups. */
|
|
761
|
+
identifier: string;
|
|
762
|
+
/** mdast's case-folded identifier — the exact string mdast-util-to-hast
|
|
763
|
+
* emits in `<li id="${clobberPrefix}fn-${sourceIdentifier}">` and that
|
|
764
|
+
* `FootnoteSupNumber` mirrors in its anchor href. Needed so the aggregate
|
|
765
|
+
* footer's `<li id>` and backref href match the inline `<sup>`'s href
|
|
766
|
+
* exactly (otherwise hash navigation breaks). Optional so unit-test
|
|
767
|
+
* fixtures don't need to fabricate it; production data always supplies it. */
|
|
768
|
+
sourceIdentifier?: string;
|
|
769
|
+
/** Content extracted from the source markdown footnote definition. */
|
|
770
|
+
contentSource: string;
|
|
771
|
+
/** Per-def hast body (the def's mdast children after mdast-util-to-hast
|
|
772
|
+
* conversion). Drives AggregateFootnotesIfLast to render the consolidated
|
|
773
|
+
* footer at the end of each document's last chunk. Optional so unit-test
|
|
774
|
+
* fixtures can build minimal FootnoteDef objects without producing hast. */
|
|
775
|
+
bodyHast?: ElementContent[];
|
|
776
|
+
}
|
|
777
|
+
interface LinkDef {
|
|
778
|
+
/** Already-normalized identifier (uppercase). */
|
|
779
|
+
identifier: string;
|
|
780
|
+
url: string;
|
|
781
|
+
title?: string;
|
|
782
|
+
}
|
|
783
|
+
type RefKind = 'footnote' | 'link' | 'image';
|
|
784
|
+
interface RefRecord {
|
|
785
|
+
/** Already-normalized identifier (uppercase). */
|
|
786
|
+
label: string;
|
|
787
|
+
/** Which markdown reference space this entry belongs to. Footnote refs,
|
|
788
|
+
* link refs, and image refs occupy disjoint namespaces in GFM, so they
|
|
789
|
+
* must be filtered separately when computing footnote numbers / refcounts. */
|
|
790
|
+
kind: RefKind;
|
|
791
|
+
referenceType?: 'full' | 'collapsed' | 'shortcut';
|
|
792
|
+
}
|
|
793
|
+
interface ChunkData {
|
|
794
|
+
refs: RefRecord[];
|
|
795
|
+
defs: Map<string, FootnoteDef>;
|
|
796
|
+
linkDefs: Map<string, LinkDef>;
|
|
797
|
+
ownFootnoteLabels: Set<string>;
|
|
798
|
+
ownLinkLabels: Set<string>;
|
|
799
|
+
}
|
|
800
|
+
interface Registry {
|
|
801
|
+
/** Chunk mount-order Symbol list. **Read-only from outside the registry.**
|
|
802
|
+
* Direct mutation (`.push`, `.splice`, index assignment) corrupts
|
|
803
|
+
* footnote numbering, "last chunk" detection, and eviction. Use the
|
|
804
|
+
* `allocateSymbol` / `releaseSymbol` / `registerChunk` API instead. */
|
|
805
|
+
readonly chunkOrder: readonly symbol[];
|
|
806
|
+
/** Chunk Symbol → contribution payload. **Read-only from outside.**
|
|
807
|
+
* Use `contributeChunkData` / `contributeLabels` / `registerChunk` to
|
|
808
|
+
* publish; direct `.set` / `.delete` bypasses version bumps and
|
|
809
|
+
* subscriber wake-ups. */
|
|
810
|
+
readonly chunkData: ReadonlyMap<symbol, ChunkData>;
|
|
811
|
+
/** Union of own-def labels across all chunks. PASS 0.5 phantom-injection
|
|
812
|
+
* driver. **Read-only from outside.** The registry derives this from
|
|
813
|
+
* per-chunk contributions; direct mutation breaks the derivation. */
|
|
814
|
+
readonly labelSet: {
|
|
815
|
+
readonly footnoteLabels: ReadonlySet<string>;
|
|
816
|
+
readonly linkLabels: ReadonlySet<string>;
|
|
817
|
+
};
|
|
818
|
+
/** Monotonic version counter bumped by every mutation. **Read-only from
|
|
819
|
+
* outside** — consumers should observe via `subscribe`, not by writing. */
|
|
820
|
+
readonly version: number;
|
|
821
|
+
/** Allocate (or reuse, for Strict Mode remount) the chunk Symbol for
|
|
822
|
+
* `reactId` AND publish this chunk's own def labels (footnotes + links)
|
|
823
|
+
* in one call. Canonical pair API used by `MarkdownContent`'s allocate
|
|
824
|
+
* effect — combining the two reduces the pair to a single registry
|
|
825
|
+
* version step, which downstream consumers see as one wake-up rather
|
|
826
|
+
* than two (the second was already coalesced by microtask, but this
|
|
827
|
+
* keeps the version monotonic-by-1-per-mount which makes debugging
|
|
828
|
+
* easier). The granular `allocateSymbol` / `contributeLabels` methods
|
|
829
|
+
* remain available for tests that need to exercise each step. */
|
|
830
|
+
registerChunk(reactId: string, footnotes: Set<string>, links: Set<string>): symbol;
|
|
831
|
+
allocateSymbol(reactId: string): symbol;
|
|
832
|
+
releaseSymbol(reactId: string): void;
|
|
833
|
+
contributeLabels(symbol: symbol, footnotes: Set<string>, links: Set<string>): void;
|
|
834
|
+
contributeChunkData(symbol: symbol, data: ChunkData): void;
|
|
835
|
+
subscribe(cb: () => void): () => void;
|
|
836
|
+
canonicalFootnoteFor(label: string): symbol | null;
|
|
837
|
+
canonicalLinkFor(label: string): symbol | null;
|
|
838
|
+
globalNumber(label: string): number | null;
|
|
839
|
+
resolveLinkDef(label: string): LinkDef | null;
|
|
840
|
+
getRefsForLabel(label: string): number;
|
|
841
|
+
/** Map a chunk-local footnote-ref occurrence index (1-based, as emitted by
|
|
842
|
+
* `customMdastHandlers`) to the corresponding document-wide occurrence
|
|
843
|
+
* index across all chunks. Used by `FootnoteSupNumber` to build a unique
|
|
844
|
+
* `id="fnref-X-N"` for each ref instance and by `AggregateFootnotesIfLast`
|
|
845
|
+
* to enumerate per-occurrence backrefs. Returns `null` if the ref isn't
|
|
846
|
+
* registered yet (registry mid-flight). */
|
|
847
|
+
globalOccurrenceForRef(chunkSym: symbol, label: string, localOccurrence: number): number | null;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
/**
|
|
851
|
+
* Optional outer wrapper enabling cross-chunk coordination for any
|
|
852
|
+
* `<AIMarkdown>` instances rendered as descendants. Each unique
|
|
853
|
+
* `documentId` partitions its own Registry.
|
|
854
|
+
*
|
|
855
|
+
* Without this wrapper, `<AIMarkdown>` instances render independently
|
|
856
|
+
* (current behavior). With it, multiple chunks sharing a `documentId`
|
|
857
|
+
* coordinate footnote numbering, linkReference/imageReference resolution,
|
|
858
|
+
* and anchor jumps across chunks.
|
|
859
|
+
*
|
|
860
|
+
* @module components/AIMarkdownDocuments
|
|
861
|
+
*/
|
|
862
|
+
|
|
863
|
+
interface AIMarkdownDocumentsProps extends PropsWithChildren {
|
|
864
|
+
/**
|
|
865
|
+
* Default `true`. Unconditionally controls orphan-reference protection
|
|
866
|
+
* for all chunks under this wrapper, overriding their individual
|
|
867
|
+
* `config.preserveOrphanReferences`. Does not control cross-chunk
|
|
868
|
+
* coordination itself (that's gated by wrapper presence + `documentId`).
|
|
869
|
+
*/
|
|
870
|
+
preserveOrphanReferences?: boolean;
|
|
871
|
+
}
|
|
872
|
+
declare const AIMarkdownDocuments: FC<AIMarkdownDocumentsProps>;
|
|
873
|
+
/**
|
|
874
|
+
* Returns the registry for the given `documentId`, or `null` if:
|
|
875
|
+
* - `<AIMarkdown>` is not inside an `<AIMarkdownDocuments>` wrapper, OR
|
|
876
|
+
* - `documentId` is undefined / empty string.
|
|
877
|
+
*
|
|
878
|
+
* Callers should treat `null` as "no coordination; run standalone path."
|
|
879
|
+
*/
|
|
880
|
+
declare function useDocumentRegistry(documentId: string | undefined): Registry | null;
|
|
881
|
+
|
|
587
882
|
/**
|
|
588
883
|
* Props for the `<AIMarkdown>` component.
|
|
589
884
|
*
|
|
@@ -632,12 +927,34 @@ interface AIMarkdownProps<TConfig extends AIMarkdownRenderConfig = AIMarkdownRen
|
|
|
632
927
|
variant?: AIMarkdownVariant;
|
|
633
928
|
/** Color scheme name. Defaults to `'light'`. */
|
|
634
929
|
colorScheme?: AIMarkdownColorScheme;
|
|
930
|
+
/**
|
|
931
|
+
* Stable identifier for the *logical markdown document* this `<AIMarkdown>`
|
|
932
|
+
* is rendering. Used as the id namespace for all clobberable attributes
|
|
933
|
+
* (`id`, hash hrefs) so two documents on the same page do not cross-link —
|
|
934
|
+
* e.g. clicking a footnote `[^1]` in message A will not scroll to the
|
|
935
|
+
* `[^1]` definition in message B.
|
|
936
|
+
*
|
|
937
|
+
* Why `documentId` and not `instanceId`: when one logical document is
|
|
938
|
+
* split across multiple `<AIMarkdown>` instances (chunked / streamed
|
|
939
|
+
* rendering), every chunk should share the SAME `documentId` so their
|
|
940
|
+
* id-prefixes line up. The id is per-document, not per-React-instance.
|
|
941
|
+
*
|
|
942
|
+
* When omitted, an id is auto-generated via React's `useId()` (SSR-safe
|
|
943
|
+
* and stable across re-renders). Pass an explicit value when you need
|
|
944
|
+
* deterministic ids (snapshot tests, cross-component deep links) or when
|
|
945
|
+
* multiple instances render the same logical document.
|
|
946
|
+
*
|
|
947
|
+
* Consumer-supplied values pass through `encodeURIComponent` at the prefix
|
|
948
|
+
* construction site, so any string is safe — including ids with reserved
|
|
949
|
+
* characters like `:`, `/`, or spaces.
|
|
950
|
+
*/
|
|
951
|
+
documentId?: string;
|
|
635
952
|
}
|
|
636
953
|
/**
|
|
637
954
|
* Root component that preprocesses markdown content and renders it through
|
|
638
955
|
* a configurable remark/rehype pipeline wrapped in typography and style layers.
|
|
639
956
|
*/
|
|
640
|
-
declare const AIMarkdownComponent: <TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig, TRenderData extends AIMarkdownMetadata = AIMarkdownMetadata>({ streaming, content, fontSize, contentPreprocessors, customComponents, defaultConfig, config, metadata, Typography, ExtraStyles, variant, colorScheme, }: AIMarkdownProps<TConfig, TRenderData>) => react_jsx_runtime.JSX.Element;
|
|
957
|
+
declare const AIMarkdownComponent: <TConfig extends AIMarkdownRenderConfig = AIMarkdownRenderConfig, TRenderData extends AIMarkdownMetadata = AIMarkdownMetadata>({ streaming, content, fontSize, contentPreprocessors, customComponents, defaultConfig, config, metadata, Typography, ExtraStyles, variant, colorScheme, documentId, }: AIMarkdownProps<TConfig, TRenderData>) => react_jsx_runtime.JSX.Element;
|
|
641
958
|
declare const _default: typeof AIMarkdownComponent;
|
|
642
959
|
|
|
643
|
-
export { type AIMDContentPreprocessor, type AIMarkdownColorScheme, type AIMarkdownCustomComponents, type AIMarkdownExtraStylesComponent, type AIMarkdownExtraStylesProps, type AIMarkdownMetadata, type AIMarkdownProps, type AIMarkdownRenderConfig, AIMarkdownRenderDisplayOptimizeAbility, AIMarkdownRenderExtraSyntax, type AIMarkdownRenderState, type AIMarkdownTypographyComponent, type AIMarkdownTypographyProps, type AIMarkdownVariant, type PartialDeep, _default as default, defaultAIMarkdownRenderConfig, useAIMarkdownMetadata, useAIMarkdownRenderState, useStableValue };
|
|
960
|
+
export { type AIMDContentPreprocessor, type AIMarkdownColorScheme, type AIMarkdownCustomComponents, AIMarkdownDocuments, type AIMarkdownDocumentsProps, type AIMarkdownExtraStylesComponent, type AIMarkdownExtraStylesProps, type AIMarkdownMetadata, type AIMarkdownProps, type AIMarkdownRenderConfig, AIMarkdownRenderDisplayOptimizeAbility, AIMarkdownRenderExtraSyntax, type AIMarkdownRenderState, type AIMarkdownTypographyComponent, type AIMarkdownTypographyProps, type AIMarkdownVariant, type ChunkData, type FootnoteDef, type LinkDef, type PartialDeep, type RefKind, type RefRecord, type Registry, _default as default, defaultAIMarkdownRenderConfig, useAIMarkdownMetadata, useAIMarkdownRenderState, useDocumentRegistry, useStableValue };
|