@elabs-ai/components-editor 4.0.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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +149 -0
  3. package/dist/chunk-LBC5VJBD.js +3748 -0
  4. package/dist/chunk-LBC5VJBD.js.map +1 -0
  5. package/dist/index.css +233 -0
  6. package/dist/index.css.map +1 -0
  7. package/dist/index.d.ts +199 -0
  8. package/dist/index.js +362 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/lib/monaco-environment.d.ts +2 -0
  11. package/dist/lib/monaco-environment.js +44 -0
  12. package/dist/lib/monaco-environment.js.map +1 -0
  13. package/dist/markdown/frontmatter.d.ts +11 -0
  14. package/dist/markdown/frontmatter.js +33 -0
  15. package/dist/markdown/frontmatter.js.map +1 -0
  16. package/dist/markdown/index.css +233 -0
  17. package/dist/markdown/index.css.map +1 -0
  18. package/dist/markdown/index.d.ts +1486 -0
  19. package/dist/markdown/index.js +4882 -0
  20. package/dist/markdown/index.js.map +1 -0
  21. package/dist/markdown/parse.d.ts +25 -0
  22. package/dist/markdown/parse.js +14 -0
  23. package/dist/markdown/parse.js.map +1 -0
  24. package/dist/markdown-editor-DfBZibAn.d.ts +702 -0
  25. package/package.json +101 -0
  26. package/src/ai-objects/ai-objects-integration.test.tsx +128 -0
  27. package/src/ai-objects/ai-objects.stories.tsx +233 -0
  28. package/src/ai-objects/ai-objects.test.tsx +205 -0
  29. package/src/ai-objects/decision-card.tsx +178 -0
  30. package/src/ai-objects/directives.ts +136 -0
  31. package/src/ai-objects/entity.tsx +181 -0
  32. package/src/ai-objects/index.ts +34 -0
  33. package/src/ai-objects/knowledge-card.tsx +143 -0
  34. package/src/calc-block/calc-block.stories.tsx +297 -0
  35. package/src/calc-block/calc-block.test.tsx +164 -0
  36. package/src/calc-block/calc-block.tsx +398 -0
  37. package/src/calc-block/calc-editor-monaco.ts +214 -0
  38. package/src/calc-block/calc-editor-prose.ts +128 -0
  39. package/src/calc-block/calc-editor.css +80 -0
  40. package/src/calc-block/calc-editor.stories.tsx +272 -0
  41. package/src/calc-block/calc-editor.test.ts +228 -0
  42. package/src/calc-block/calc-editor.ts +270 -0
  43. package/src/calc-block/calc-inline.stories.tsx +44 -0
  44. package/src/calc-block/calc-inline.test.tsx +44 -0
  45. package/src/calc-block/calc-inline.tsx +75 -0
  46. package/src/calc-block/index.ts +20 -0
  47. package/src/calc-block/types.ts +164 -0
  48. package/src/code-editor/code-editor.stories.tsx +218 -0
  49. package/src/code-editor/code-editor.test.tsx +134 -0
  50. package/src/code-editor/code-editor.tsx +250 -0
  51. package/src/code-editor/index.ts +6 -0
  52. package/src/code-workspace/code-workspace.stories.tsx +51 -0
  53. package/src/code-workspace/code-workspace.test.tsx +146 -0
  54. package/src/code-workspace/code-workspace.tsx +253 -0
  55. package/src/code-workspace/index.ts +6 -0
  56. package/src/copy-button/copy-button.tsx +51 -0
  57. package/src/copy-button/index.ts +1 -0
  58. package/src/css.d.ts +3 -0
  59. package/src/diff-editor/diff-editor.stories.tsx +44 -0
  60. package/src/diff-editor/diff-editor.test.tsx +68 -0
  61. package/src/diff-editor/diff-editor.tsx +151 -0
  62. package/src/diff-editor/index.ts +1 -0
  63. package/src/editor-context-menu/editor-context-menu.tsx +120 -0
  64. package/src/editor-context-menu/index.ts +1 -0
  65. package/src/editor-toolbar/editor-toolbar.tsx +83 -0
  66. package/src/editor-toolbar/index.ts +1 -0
  67. package/src/index.ts +48 -0
  68. package/src/lib/editor-completions-monaco.test.ts +206 -0
  69. package/src/lib/editor-completions-monaco.ts +127 -0
  70. package/src/lib/editor-completions.test.ts +156 -0
  71. package/src/lib/editor-completions.ts +153 -0
  72. package/src/lib/editor-content-access-prose.test.ts +411 -0
  73. package/src/lib/editor-content-access-prose.ts +172 -0
  74. package/src/lib/editor-content-access.test.ts +182 -0
  75. package/src/lib/editor-content-access.ts +109 -0
  76. package/src/lib/languages.ts +32 -0
  77. package/src/lib/markdown/diff.test.ts +80 -0
  78. package/src/lib/markdown/diff.ts +194 -0
  79. package/src/lib/markdown/directives.ts +342 -0
  80. package/src/lib/markdown/frontmatter.ts +50 -0
  81. package/src/lib/markdown/markdown-scale.test.ts +65 -0
  82. package/src/lib/markdown/markdown-scale.ts +62 -0
  83. package/src/lib/markdown/merge.test.ts +64 -0
  84. package/src/lib/markdown/merge.ts +158 -0
  85. package/src/lib/markdown/slugify.test.ts +156 -0
  86. package/src/lib/markdown/slugify.ts +47 -0
  87. package/src/lib/monaco-environment.ts +103 -0
  88. package/src/lib/monaco-theme-bridge.ts +293 -0
  89. package/src/lib/use-data-theme.ts +61 -0
  90. package/src/markdown/frontmatter.ts +14 -0
  91. package/src/markdown/index.ts +323 -0
  92. package/src/markdown/parse.test.ts +60 -0
  93. package/src/markdown/parse.ts +38 -0
  94. package/src/markdown-academic/citations.test.ts +77 -0
  95. package/src/markdown-academic/citations.tsx +442 -0
  96. package/src/markdown-academic/footnotes.tsx +235 -0
  97. package/src/markdown-academic/index.ts +32 -0
  98. package/src/markdown-academic/math.tsx +163 -0
  99. package/src/markdown-academic/toc.tsx +88 -0
  100. package/src/markdown-editor/completions/completions-menu.tsx +96 -0
  101. package/src/markdown-editor/completions/completions-prose.test.ts +356 -0
  102. package/src/markdown-editor/completions/completions-prose.ts +313 -0
  103. package/src/markdown-editor/completions/completions-widget.tsx +75 -0
  104. package/src/markdown-editor/completions/index.ts +37 -0
  105. package/src/markdown-editor/directive-nodes.ts +151 -0
  106. package/src/markdown-editor/directive-views.test.tsx +189 -0
  107. package/src/markdown-editor/directive-views.tsx +795 -0
  108. package/src/markdown-editor/exit-keymap.test.ts +88 -0
  109. package/src/markdown-editor/exit-keymap.ts +87 -0
  110. package/src/markdown-editor/index.ts +6 -0
  111. package/src/markdown-editor/markdown-editor.css +250 -0
  112. package/src/markdown-editor/markdown-editor.directives.test.tsx +105 -0
  113. package/src/markdown-editor/markdown-editor.fill.test.ts +34 -0
  114. package/src/markdown-editor/markdown-editor.paste-embed.test.tsx +297 -0
  115. package/src/markdown-editor/markdown-editor.stories.tsx +560 -0
  116. package/src/markdown-editor/markdown-editor.strictmode.test.tsx +38 -0
  117. package/src/markdown-editor/markdown-editor.table.test.tsx +287 -0
  118. package/src/markdown-editor/markdown-editor.tsx +560 -0
  119. package/src/markdown-editor/milkdown-react/editor.tsx +33 -0
  120. package/src/markdown-editor/milkdown-react/index.ts +8 -0
  121. package/src/markdown-editor/milkdown-react/types.ts +27 -0
  122. package/src/markdown-editor/milkdown-react/use-editor.ts +27 -0
  123. package/src/markdown-editor/milkdown-react/use-get-editor.ts +56 -0
  124. package/src/markdown-editor/milkdown-react/use-instance.ts +23 -0
  125. package/src/markdown-editor/paste-embed.ts +355 -0
  126. package/src/markdown-editor/slash/brand-slash-commands.test.ts +194 -0
  127. package/src/markdown-editor/slash/brand-slash-commands.ts +324 -0
  128. package/src/markdown-editor/slash/brand-slash-plugin.test.ts +254 -0
  129. package/src/markdown-editor/slash/brand-slash-plugin.ts +385 -0
  130. package/src/markdown-editor/slash/index.ts +107 -0
  131. package/src/markdown-editor/slash/insert-directive.test.ts +263 -0
  132. package/src/markdown-editor/slash/insert-directive.ts +345 -0
  133. package/src/markdown-editor/slash/monaco-slash-menu.test.tsx +198 -0
  134. package/src/markdown-editor/slash/monaco-slash-menu.tsx +356 -0
  135. package/src/markdown-editor/slash/shortcut-monaco.ts +69 -0
  136. package/src/markdown-editor/slash/shortcut.test.ts +157 -0
  137. package/src/markdown-editor/slash/shortcut.ts +57 -0
  138. package/src/markdown-editor/slash/slash-menu.stories.tsx +139 -0
  139. package/src/markdown-editor/slash/slash-menu.tsx +115 -0
  140. package/src/markdown-editor/slash/slash-scroll.test.tsx +52 -0
  141. package/src/markdown-editor/slash/slash-widget.tsx +97 -0
  142. package/src/markdown-editor/slash/source-slash-trigger.test.ts +42 -0
  143. package/src/markdown-editor/slash/source-slash-trigger.ts +46 -0
  144. package/src/markdown-editor/table-view.tsx +249 -0
  145. package/src/markdown-iteration/directive.tsx +92 -0
  146. package/src/markdown-iteration/edit-context.ts +56 -0
  147. package/src/markdown-iteration/index.ts +24 -0
  148. package/src/markdown-iteration/iteration-block.test.tsx +138 -0
  149. package/src/markdown-iteration/iteration-builder-dialog.stories.tsx +293 -0
  150. package/src/markdown-iteration/iteration-builder-dialog.tsx +312 -0
  151. package/src/markdown-iteration/iteration-builder.test.ts +252 -0
  152. package/src/markdown-iteration/iteration-builder.ts +303 -0
  153. package/src/markdown-iteration/iteration.test.ts +56 -0
  154. package/src/markdown-iteration/iteration.tsx +333 -0
  155. package/src/markdown-iteration/template-dialog.stories.tsx +63 -0
  156. package/src/markdown-iteration/template-dialog.test.tsx +104 -0
  157. package/src/markdown-iteration/template-dialog.tsx +116 -0
  158. package/src/markdown-outline/document-outline.stories.tsx +76 -0
  159. package/src/markdown-outline/document-outline.tsx +83 -0
  160. package/src/markdown-outline/index.ts +2 -0
  161. package/src/markdown-outline/markdown-outline.test.ts +49 -0
  162. package/src/markdown-outline/markdown-outline.ts +60 -0
  163. package/src/markdown-preview/code-fence.tsx +193 -0
  164. package/src/markdown-preview/index.ts +8 -0
  165. package/src/markdown-preview/markdown-preview-academic.stories.tsx +203 -0
  166. package/src/markdown-preview/markdown-preview-academic.test.tsx +257 -0
  167. package/src/markdown-preview/markdown-preview-iteration-calc.test.tsx +71 -0
  168. package/src/markdown-preview/markdown-preview-iteration-nested.test.tsx +58 -0
  169. package/src/markdown-preview/markdown-preview-iteration.stories.tsx +187 -0
  170. package/src/markdown-preview/markdown-preview-iteration.test.tsx +90 -0
  171. package/src/markdown-preview/markdown-preview-linking.test.tsx +61 -0
  172. package/src/markdown-preview/markdown-preview-transclusion.test.tsx +33 -0
  173. package/src/markdown-preview/markdown-preview.stories.tsx +108 -0
  174. package/src/markdown-preview/markdown-preview.test.tsx +411 -0
  175. package/src/markdown-preview/markdown-preview.tsx +1541 -0
  176. package/src/markdown-toolbar/index.ts +8 -0
  177. package/src/markdown-toolbar/markdown-commands.test.ts +84 -0
  178. package/src/markdown-toolbar/markdown-commands.ts +104 -0
  179. package/src/markdown-toolbar/markdown-toolbar.stories.tsx +56 -0
  180. package/src/markdown-toolbar/markdown-toolbar.tsx +263 -0
  181. package/src/markdown-workspace/focus-writing.test.ts +52 -0
  182. package/src/markdown-workspace/focus-writing.ts +38 -0
  183. package/src/markdown-workspace/index.ts +6 -0
  184. package/src/markdown-workspace/markdown-workspace.stories.tsx +688 -0
  185. package/src/markdown-workspace/markdown-workspace.test.tsx +326 -0
  186. package/src/markdown-workspace/markdown-workspace.tsx +787 -0
  187. package/src/mermaid-diagram/index.ts +1 -0
  188. package/src/mermaid-diagram/mermaid-diagram.stories.tsx +42 -0
  189. package/src/mermaid-diagram/mermaid-diagram.test.tsx +86 -0
  190. package/src/mermaid-diagram/mermaid-diagram.tsx +318 -0
  191. package/src/mermaid-diagram/mermaid-viewer.test.tsx +89 -0
  192. package/src/mermaid-diagram/mermaid-viewer.tsx +367 -0
  193. package/src/mermaid-diagram/real-parse.test.ts +42 -0
  194. package/src/mermaid-diagram/remediate.test.ts +60 -0
  195. package/src/mermaid-diagram/remediate.ts +124 -0
  196. package/src/mermaid-workspace/index.ts +1 -0
  197. package/src/mermaid-workspace/mermaid-workspace.stories.tsx +28 -0
  198. package/src/mermaid-workspace/mermaid-workspace.tsx +71 -0
  199. package/src/metric-block/index.ts +1 -0
  200. package/src/metric-block/metric-block.stories.tsx +40 -0
  201. package/src/metric-block/metric-block.tsx +14 -0
  202. package/src/monaco-workers.d.ts +10 -0
  203. package/src/prose/index.ts +14 -0
  204. package/src/prose/prose.stories.tsx +44 -0
  205. package/src/prose/prose.test.tsx +44 -0
  206. package/src/prose/prose.tsx +21 -0
  207. package/src/timeline/index.ts +18 -0
@@ -0,0 +1,323 @@
1
+ /**
2
+ * @elabs-ai/components-editor/markdown — the opt-in markdown suite.
3
+ *
4
+ * Kept on its own subpath so Monaco-only consumers of `@elabs-ai/components-editor` never pull
5
+ * the markdown/WYSIWYG dependency tree (Milkdown, Streamdown, remark). Everything
6
+ * markdown-shaped — the WYSIWYG editor, the branded preview renderer, the prose /
7
+ * timeline / metric primitives the preview composes, and the shared remark
8
+ * pipeline — lives here.
9
+ */
10
+ export {
11
+ MarkdownEditor,
12
+ type MarkdownEditorProps,
13
+ type MarkdownEditorHandle,
14
+ type EmbedAssetFn,
15
+ } from "../markdown-editor";
16
+
17
+ // Engine-agnostic content-access API — re-exported here for convenience so
18
+ // markdown-subpath consumers get the full picture from one import.
19
+ // `monacoContentAccess` is also on the `.` barrel; types are re-exported here
20
+ // for symmetry. The prose adapter is ONLY here (never on the `.` barrel — keeps
21
+ // @milkdown off the Monaco-only graph, #271-inverse).
22
+ export {
23
+ monacoContentAccess,
24
+ type EditorContentAccess,
25
+ type EditorSelection,
26
+ } from "../lib/editor-content-access";
27
+ export {
28
+ proseMirrorContentAccess,
29
+ selectionWatchPlugin,
30
+ type ProseMirrorContentAccessDeps,
31
+ type ProseMirrorContentAccessOptions,
32
+ } from "../lib/editor-content-access-prose";
33
+
34
+ // Declarative completion-provider API (#283) — e.g. `[[wikilink]]` autocomplete
35
+ // wired via the `completions` prop on `MarkdownWorkspace` / `MarkdownEditor`,
36
+ // with ZERO `monaco-editor` imports needed in consumer code. The library owns
37
+ // the Monaco registration lifecycle (registered once, refcounted across
38
+ // mounted workspaces, disposed with the last one) and mirrors providers into a
39
+ // deliberately minimal WYSIWYG popup — see `lib/editor-completions-monaco.ts`
40
+ // and `markdown-editor/completions/completions-prose.ts` for the exact
41
+ // Monaco-vs-WYSIWYG parity boundary. `attachCompletionsMonaco` is exported for
42
+ // advanced consumers composing their own Monaco surfaces (the `attachCalcMonaco`
43
+ // precedent).
44
+ export {
45
+ triggerQueryStart,
46
+ resolveReplaceRange,
47
+ collectCompletions,
48
+ type EditorCompletionItem,
49
+ type EditorCompletionProvider,
50
+ type EditorCompletionContext,
51
+ type CompletionReplaceRange,
52
+ type CompletionMatch,
53
+ } from "../lib/editor-completions";
54
+ export { attachCompletionsMonaco } from "../lib/editor-completions-monaco";
55
+
56
+ // Slash (`/`) command menu for the WYSIWYG editor — the branded at-caret block
57
+ // inserter (card/callout/metric/timeline + basic blocks). Opt in via the
58
+ // `slashMenu` prop on MarkdownEditor / MarkdownWorkspace; these exports let
59
+ // consumers extend the command list or build their own surface.
60
+ export {
61
+ BRAND_SLASH_COMMANDS,
62
+ brandSlashViewPlugins,
63
+ filterSlashCommands,
64
+ groupSlashCommands,
65
+ insertBrandDirective,
66
+ insertBasicBlock,
67
+ insertCalcFence,
68
+ resolveCalcInsert,
69
+ CALC_FENCE_SEED,
70
+ SlashMenu,
71
+ type SlashCommand,
72
+ type SlashInsertContext,
73
+ type SourceSlashContext,
74
+ type SlashMenuProps,
75
+ type BasicBlockId,
76
+ type InsertableDirective,
77
+ type SlashRange,
78
+ type BrandSlashViewOptions,
79
+ } from "../markdown-editor/slash";
80
+ // The Monaco source-pane slash popup (#271) — imported from the file directly
81
+ // (NOT the slash barrel) because it pulls the Monaco runtime; the slash barrel
82
+ // must stay Monaco-free for the Milkdown editor. This subpath already pulls
83
+ // Monaco via MarkdownWorkspace, so it is the right home for the parity export.
84
+ export {
85
+ MonacoSlashMenu,
86
+ type MonacoSlashMenuProps,
87
+ } from "../markdown-editor/slash/monaco-slash-menu";
88
+
89
+ // The hybrid authoring surface (source | wysiwyg | split) + its formatting toolbar.
90
+ export {
91
+ MarkdownWorkspace,
92
+ type MarkdownWorkspaceHandle,
93
+ type MarkdownWorkspaceProps,
94
+ type MarkdownWorkspaceMode,
95
+ } from "../markdown-workspace";
96
+ export {
97
+ MarkdownToolbar,
98
+ type MarkdownToolbarProps,
99
+ wrapSelection,
100
+ toggleLinePrefix,
101
+ insertLink,
102
+ insertHorizontalRule,
103
+ insertDirective,
104
+ } from "../markdown-toolbar";
105
+
106
+ // Shared visual scale — the single source of truth for heading sizes / weight /
107
+ // tracking / measure consumed by BOTH the preview (prose) and the WYSIWYG editor CSS.
108
+ export {
109
+ MARKDOWN_HEADING_REM,
110
+ MARKDOWN_HEADING_WEIGHT,
111
+ MARKDOWN_HEADING_TRACKING,
112
+ MARKDOWN_MEASURE,
113
+ markdownScaleVars,
114
+ type MarkdownHeadingLevel,
115
+ } from "../lib/markdown/markdown-scale";
116
+
117
+ // Rendering primitives (token-driven; composed by the preview + directive views).
118
+ export * from "../prose";
119
+ export { Timeline, type TimelineProps, type TimelineItem } from "../timeline";
120
+ export { MetricBlock, type MetricBlockProps } from "../metric-block";
121
+
122
+ // Branded preview + shared remark pipeline.
123
+ export {
124
+ MarkdownPreview,
125
+ type MarkdownPreviewProps,
126
+ type MarkdownHeadingInfo,
127
+ } from "../markdown-preview";
128
+ export {
129
+ buildMarkdownPlugins,
130
+ remarkBrandDirectives,
131
+ BRAND_DIRECTIVES,
132
+ type BrandDirectiveName,
133
+ type BuildMarkdownPluginsOptions,
134
+ type MarkdownDirectiveKind,
135
+ type MarkdownDirectiveContext,
136
+ type MarkdownDirectiveRenderer,
137
+ type MarkdownFenceContext,
138
+ type MarkdownFenceRenderer,
139
+ type MarkdownExtensions,
140
+ } from "../lib/markdown/directives";
141
+ // Monaco-free markdown parser (gfm + directives + frontmatter). The canonical
142
+ // dependency-light import is `@elabs-ai/components-editor/markdown/parse`; re-exported here for
143
+ // convenience when you're already pulling the full markdown suite.
144
+ export { parseMarkdown } from "./parse";
145
+ // Re-export the frontmatter utils from the `./frontmatter` subpath barrel (NOT
146
+ // directly from `../lib/markdown/frontmatter`) so there is a single canonical
147
+ // module — `lib/markdown/frontmatter` (impl) → `./frontmatter` (public barrel) →
148
+ // here. Importing `ParsedDocument` from either subpath resolves to one emitted
149
+ // module, so its type identity is assignable across import sites (see #39).
150
+ export { parseFrontmatter, serializeFrontmatter, type ParsedDocument } from "./frontmatter";
151
+
152
+ // Mermaid (#L1): branded diagram renderer + the source⇄diagram workspace (#L2).
153
+ export { MermaidDiagram, type MermaidDiagramProps } from "../mermaid-diagram";
154
+ export { MermaidWorkspace, type MermaidWorkspaceProps } from "../mermaid-workspace";
155
+
156
+ // Calc: a ```calc fence → a branded answer-column sheet, and `:calc[expr]` inline
157
+ // → a result chip — both evaluated by a consumer `evaluate` hook (the math engine
158
+ // stays in the app, like `resolveUrl`).
159
+ export { CalcBlock, type CalcBlockProps } from "../calc-block";
160
+ export { CalcInline, type CalcInlineProps } from "../calc-block";
161
+ export type {
162
+ CalcContext,
163
+ CalcLineResult,
164
+ CalcRule,
165
+ CalcSheet,
166
+ CalcTint,
167
+ CalcToken,
168
+ CalcTokenKind,
169
+ CalcValue,
170
+ CalcValueKind,
171
+ EvaluateCalc,
172
+ } from "../calc-block";
173
+
174
+ // Calc AUTHORING (#220): opt-in live highlighting + autocomplete + result inlays
175
+ // inside ```calc fences, wired via the `calc` prop on MarkdownEditor /
176
+ // MarkdownWorkspace. The hook TYPES let consumers type their engine; the wiring
177
+ // functions (`attachCalcMonaco`, `calcProsePlugins`) + `findCalcFences` are for
178
+ // advanced consumers composing their own Monaco / Milkdown surfaces. The library
179
+ // DECORATES, the consumer COMPUTES — no calc engine is bundled.
180
+ export type {
181
+ CalcComplete,
182
+ CalcCompletion,
183
+ CalcCompletionContext,
184
+ CalcCompletionKind,
185
+ CalcEditorHooks,
186
+ CalcTokenize,
187
+ } from "../calc-block";
188
+ export { findCalcFences, calcTokenClassName, type CalcFence } from "../calc-block/calc-editor";
189
+ export { attachCalcMonaco } from "../calc-block/calc-editor-monaco";
190
+ export { calcProsePlugins } from "../calc-block/calc-editor-prose";
191
+
192
+ // Ghost-diff annotations (#L18): line-level markdown diff → preview washes.
193
+ export {
194
+ computeMarkdownAnnotations,
195
+ summarizeAnnotations,
196
+ shiftAnnotations,
197
+ annotationForRange,
198
+ removedMarkerAt,
199
+ type MarkdownAnnotation,
200
+ type MarkdownAnnotationKind,
201
+ } from "../lib/markdown/diff";
202
+ // Normalization-aware WYSIWYG merge (WI-1) — for consumers composing their
203
+ // own editing surfaces on MarkdownEditor.
204
+ export { mergeNormalizedEdit } from "../lib/markdown/merge";
205
+ export type { MarkdownUrlKind } from "../markdown-preview";
206
+
207
+ // Document outline (#L6): heading extraction + the quiet TOC rail.
208
+ export {
209
+ DocumentOutline,
210
+ useMarkdownOutline,
211
+ parseMarkdownOutline,
212
+ type DocumentOutlineProps,
213
+ type MarkdownOutlineItem,
214
+ } from "../markdown-outline";
215
+
216
+ // AI-object directive trio: DecisionCard, EntityCard/Chip, KnowledgeCard +
217
+ // the renderer factories (decisionDirective, entityDirective, knowledgeDirective,
218
+ // aiObjectDirectives) for wiring into MarkdownPreview `extensions.directives`.
219
+ export {
220
+ DecisionCard,
221
+ decisionCardVariants,
222
+ DECISION_STATUSES,
223
+ type DecisionCardProps,
224
+ type DecisionStatus,
225
+ EntityCard,
226
+ EntityChip,
227
+ entityChipVariants,
228
+ ENTITY_KINDS,
229
+ type EntityCardProps,
230
+ type EntityChipProps,
231
+ type EntityKind,
232
+ KnowledgeCard,
233
+ type KnowledgeCardProps,
234
+ type KnowledgeSourceResolved,
235
+ type KnowledgeSourceResolver,
236
+ decisionDirective,
237
+ entityDirective,
238
+ knowledgeDirective,
239
+ aiObjectDirectives,
240
+ type AiObjectDirectivesOptions,
241
+ } from "../ai-objects";
242
+
243
+ // Academic layer — opt-in via MarkdownPreview props (`footnotes` / `resolveCitation`
244
+ // / `math` / `toc`): branded footnotes, Pandoc/Better-BibTeX citations + a generated
245
+ // bibliography, `$…$`/`$$…$$` math (KaTeX), and a generated `::toc`. The standalone
246
+ // components + the public contract types are exported here.
247
+ export {
248
+ Bibliography,
249
+ collectCitations,
250
+ FootnoteList,
251
+ MathBlock,
252
+ MathInline,
253
+ TableOfContents,
254
+ type BibliographyProps,
255
+ type CitationData,
256
+ type CitationStyle,
257
+ type CiteItem,
258
+ type CollectedCitations,
259
+ type FootnoteListProps,
260
+ type MathProps,
261
+ type ResolveCitation,
262
+ type ResolvedCitation,
263
+ type TableOfContentsProps,
264
+ } from "../markdown-academic";
265
+
266
+ // Iteration — opt-in via MarkdownPreview's `evaluateIteration` (+ `interpolate`)
267
+ // props: a `:::iterate` / `:::pivot` repeater that renders a per-cell markdown
268
+ // template over consumer-resolved data (stacked / grid / matrix layouts). The
269
+ // standalone `IterationBlock` + the public contract types are exported here.
270
+ export {
271
+ IterationBlock,
272
+ defaultInterpolate,
273
+ specFromDirective,
274
+ type EvaluateIteration,
275
+ type InterpolateTemplate,
276
+ type IterationBlockProps,
277
+ type IterationCell,
278
+ type IterationData,
279
+ type IterationLayout,
280
+ type IterationSpec,
281
+ } from "../markdown-iteration";
282
+ // The #223 template modal (Dialog + MarkdownWorkspace) + its one-liner wiring —
283
+ // exported from the heavy (Monaco/Milkdown) side, not the render-light
284
+ // `markdown-iteration` barrel. The node-view `⋯` re-edit seam is `IterationEditContext`.
285
+ export {
286
+ IterationTemplateDialog,
287
+ IterationTemplateProvider,
288
+ type IterationTemplateDialogProps,
289
+ } from "../markdown-iteration/template-dialog";
290
+ export {
291
+ IterationEditContext,
292
+ type IterationEditHandler,
293
+ type IterationEditRequest,
294
+ } from "../markdown-iteration/edit-context";
295
+ // The #223 GUIDED builder (A5): collects the DATA (value lists + bind name +
296
+ // layout) as well as the template, writes a fully-bound directive, and renders a
297
+ // populated result with the built-in `evaluateEmbedded`. The `⋯` re-edit reopens
298
+ // it losslessly via `IterationBuilderProvider`.
299
+ export {
300
+ IterationBuilderDialog,
301
+ IterationBuilderProvider,
302
+ type IterationBuilderDialogProps,
303
+ } from "../markdown-iteration/iteration-builder-dialog";
304
+ export {
305
+ serializeIterationDirective,
306
+ parseIterationDirective,
307
+ builderValueFromParts,
308
+ directivePartsFromValue,
309
+ emptyBuilderValue,
310
+ evaluateEmbedded,
311
+ splitList,
312
+ parseAttributes,
313
+ DEFAULT_TEMPLATE,
314
+ type IterationBuilderValue,
315
+ } from "../markdown-iteration/iteration-builder";
316
+ // The #223 node-menu model helpers: "Transpose" (swap a pivot's rows/cols) and
317
+ // "Convert to static" (render the resolved cells as plain markdown, no
318
+ // ProseMirror dependency) — the pure functions behind the iteration node-view's
319
+ // right-click / `⋯` menu actions (see `markdown-editor/directive-views.tsx`).
320
+ export {
321
+ transposeIterationValue,
322
+ staticMarkdownFromValue,
323
+ } from "../markdown-iteration/iteration-builder";
@@ -0,0 +1,60 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { parseMarkdown } from "./parse";
4
+
5
+ /** Minimal recursive mdast shape for walking without pulling the full types. */
6
+ type MdNode = { type: string; name?: string; children?: MdNode[] };
7
+
8
+ function nodeTypes(tree: MdNode): Set<string> {
9
+ const types = new Set<string>();
10
+ const walk = (n: MdNode) => {
11
+ types.add(n.type);
12
+ for (const c of n.children ?? []) walk(c);
13
+ };
14
+ walk(tree);
15
+ return types;
16
+ }
17
+
18
+ describe("parseMarkdown", () => {
19
+ it("parses gfm + directives + frontmatter into one mdast tree", () => {
20
+ const tree = parseMarkdown(
21
+ [
22
+ "---",
23
+ "title: X",
24
+ "---",
25
+ "# Heading",
26
+ "",
27
+ ':::card{title="T"}',
28
+ "body",
29
+ ":::",
30
+ "",
31
+ "| a | b |",
32
+ "| - | - |",
33
+ "| 1 | 2 |",
34
+ ].join("\n"),
35
+ ) as unknown as MdNode;
36
+
37
+ const types = nodeTypes(tree);
38
+ expect(tree.type).toBe("root");
39
+ expect(types.has("yaml")).toBe(true); // frontmatter
40
+ expect(types.has("containerDirective")).toBe(true); // remark-directive
41
+ expect(types.has("table")).toBe(true); // gfm
42
+ });
43
+
44
+ it("parses inline + leaf directives", () => {
45
+ // Inline `:entity` sits mid-sentence; a leaf `::metric` occupies its own line.
46
+ const tree = parseMarkdown(
47
+ "Owner :entity[Acme]{kind=org} ships it.\n\n::metric{value=1}",
48
+ ) as unknown as MdNode;
49
+ const types = nodeTypes(tree);
50
+ expect(types.has("textDirective")).toBe(true);
51
+ expect(types.has("leafDirective")).toBe(true);
52
+ });
53
+
54
+ it("returns RAW directive mdast — it does NOT rewrite to <brand-directive>", () => {
55
+ const tree = parseMarkdown(":::card\nx\n:::") as unknown as MdNode;
56
+ const json = JSON.stringify(tree);
57
+ expect(json).toContain("containerDirective");
58
+ expect(json).not.toContain("brand-directive");
59
+ });
60
+ });
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `@elabs-ai/components-editor/markdown/parse` — a Monaco-free markdown parser.
3
+ *
4
+ * `parseMarkdown(md)` returns the mdast `Root` for the SAME dialect the branded
5
+ * preview parses: GitHub-flavored markdown + `:::`/`::`/`:` directives + YAML
6
+ * frontmatter. Split onto its own leaf subpath (like `./markdown/frontmatter`) so
7
+ * SERVER, RSC, and unit-test consumers can parse markdown WITHOUT pulling the
8
+ * editor engines (Milkdown, Monaco, Streamdown) into their bundle — the whole
9
+ * reason the `.` vs `./markdown` split exists. Depends only on `unified` +
10
+ * `remark-*` (no React, no Monaco).
11
+ *
12
+ * It returns RAW directive mdast (`containerDirective` / `leafDirective` /
13
+ * `textDirective` nodes) — it does NOT run `remarkBrandDirectives` (that rewrites
14
+ * directives into the `<brand-directive>` hast tag, which is a RENDER concern).
15
+ * Walk the tree by `node.type` + `node.name` yourself. The match is at the
16
+ * DIALECT level (same plugins/extensions); it is not byte-identical to the tree
17
+ * Streamdown builds internally (which also applies a streaming block-splitter).
18
+ */
19
+ import type { Root } from "mdast";
20
+ import remarkDirective from "remark-directive";
21
+ import remarkFrontmatter from "remark-frontmatter";
22
+ import remarkGfm from "remark-gfm";
23
+ import remarkParse from "remark-parse";
24
+ import { unified } from "unified";
25
+
26
+ // Built once: a frozen parser-only processor (gfm + frontmatter + directive
27
+ // syntax extensions). `parse()` is stateless per call, so one instance is safe.
28
+ const processor = unified()
29
+ .use(remarkParse)
30
+ .use(remarkGfm)
31
+ .use(remarkFrontmatter, ["yaml"])
32
+ .use(remarkDirective)
33
+ .freeze();
34
+
35
+ /** Parse markdown to mdast (gfm + directives + frontmatter). Monaco-free. */
36
+ export function parseMarkdown(md: string): Root {
37
+ return processor.parse(md) as Root;
38
+ }
@@ -0,0 +1,77 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { collectCitations, parseCitationBracket, type CitationData } from "./citations";
4
+
5
+ describe("parseCitationBracket", () => {
6
+ it("parses a single key", () => {
7
+ expect(parseCitationBracket("@smith2020")).toEqual([{ key: "smith2020" }]);
8
+ });
9
+
10
+ it("parses multiple `;`-separated keys", () => {
11
+ expect(parseCitationBracket("@a; @b")).toEqual([{ key: "a" }, { key: "b" }]);
12
+ });
13
+
14
+ it("captures a locator after the key", () => {
15
+ expect(parseCitationBracket("@smith2020, p. 5")).toEqual([
16
+ { key: "smith2020", locator: "p. 5" },
17
+ ]);
18
+ });
19
+
20
+ it("captures the suppress-author marker", () => {
21
+ expect(parseCitationBracket("-@smith2020")).toEqual([
22
+ { key: "smith2020", suppressAuthor: true },
23
+ ]);
24
+ });
25
+
26
+ it("captures a prefix", () => {
27
+ expect(parseCitationBracket("see @smith2020")).toEqual([{ key: "smith2020", prefix: "see" }]);
28
+ });
29
+
30
+ it("accepts Better-BibTeX keys with separators", () => {
31
+ expect(parseCitationBracket("@smith:2020a")).toEqual([{ key: "smith:2020a" }]);
32
+ });
33
+
34
+ it("returns null for ordinary bracketed prose (no @key)", () => {
35
+ expect(parseCitationBracket("see figure 1")).toBeNull();
36
+ expect(parseCitationBracket("i")).toBeNull();
37
+ });
38
+
39
+ it("returns null when any `;`-part is not a citation", () => {
40
+ expect(parseCitationBracket("@a; not a cite")).toBeNull();
41
+ });
42
+ });
43
+
44
+ describe("collectCitations", () => {
45
+ const DB: Record<string, CitationData> = {
46
+ smith2020: { author: "Smith", year: 2020 },
47
+ jones2019: { author: "Jones", year: 2019 },
48
+ };
49
+ const resolve = (k: string) => DB[k] ?? null;
50
+
51
+ it("numbers resolved citations in first-appearance order", () => {
52
+ const md = "First [@jones2019], then [@smith2020], then [@jones2019] again.";
53
+ const { order, byKey } = collectCitations(md, resolve);
54
+ expect(order.map((e) => e.key)).toEqual(["jones2019", "smith2020"]);
55
+ expect(byKey.get("jones2019")?.n).toBe(1);
56
+ expect(byKey.get("smith2020")?.n).toBe(2);
57
+ });
58
+
59
+ it("records unresolved keys without assigning a number", () => {
60
+ const md = "Known [@smith2020] and unknown [@ghost1999].";
61
+ const { order, byKey } = collectCitations(md, resolve);
62
+ expect(order.map((e) => e.key)).toEqual(["smith2020"]);
63
+ expect(byKey.get("ghost1999")).toEqual({ key: "ghost1999", data: null });
64
+ expect(byKey.get("smith2020")?.n).toBe(1);
65
+ });
66
+
67
+ it("collects every key in a multi-key bracket", () => {
68
+ const { byKey } = collectCitations("[@smith2020; @jones2019]", resolve);
69
+ expect(byKey.get("smith2020")?.n).toBe(1);
70
+ expect(byKey.get("jones2019")?.n).toBe(2);
71
+ });
72
+
73
+ it("ignores non-citation brackets", () => {
74
+ const { order } = collectCitations("An array[index] and a [link](x).", resolve);
75
+ expect(order).toHaveLength(0);
76
+ });
77
+ });