@ai-matrx/rich-content 0.0.0-stage → 0.2.2

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 (247) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/LICENSE +21 -0
  3. package/README.md +61 -2
  4. package/dist/display/blocks/csv/CsvBlock.d.ts +10 -0
  5. package/dist/display/blocks/csv/CsvBlock.js +245 -0
  6. package/dist/display/blocks/table/parseMarkdownTable.d.ts +20 -0
  7. package/dist/display/blocks/table/parseMarkdownTable.js +35 -0
  8. package/dist/display/chat-markdown/citations/remarkMatrxCite.d.ts +33 -0
  9. package/dist/display/chat-markdown/citations/remarkMatrxCite.js +71 -0
  10. package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.d.ts +29 -0
  11. package/dist/display/chat-markdown/matrx-variables/remarkMatrxVariable.js +71 -0
  12. package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.d.ts +55 -0
  13. package/dist/display/chat-markdown/page-break/remarkMatrxPageBreak.js +108 -0
  14. package/dist/display/chat-markdown/rehypeSafeRawHtml.d.ts +59 -0
  15. package/dist/display/chat-markdown/rehypeSafeRawHtml.js +140 -0
  16. package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.d.ts +14 -0
  17. package/dist/display/markdown-classification/processors/bock-processors/parse-markdown-table.js +171 -0
  18. package/dist/display/markdown-classification/processors/types.d.ts +120 -0
  19. package/dist/display/markdown-classification/processors/types.js +10 -0
  20. package/dist/display/markdown-classification/processors/utils/client-blocks.d.ts +169 -0
  21. package/dist/display/markdown-classification/processors/utils/client-blocks.js +0 -0
  22. package/dist/display/markdown-classification/processors/utils/content-splitter-core.d.ts +223 -0
  23. package/dist/display/markdown-classification/processors/utils/content-splitter-core.js +1791 -0
  24. package/dist/display/markdown-classification/processors/utils/content-splitter-v2.d.ts +15 -0
  25. package/dist/display/markdown-classification/processors/utils/content-splitter-v2.js +19 -0
  26. package/dist/display/markdown-classification/processors/utils/expand-text-blocks.d.ts +9 -0
  27. package/dist/display/markdown-classification/processors/utils/expand-text-blocks.js +36 -0
  28. package/dist/display/markdown-classification/processors/utils/gfm-table-lines.d.ts +5 -0
  29. package/dist/display/markdown-classification/processors/utils/gfm-table-lines.js +40 -0
  30. package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.d.ts +16 -0
  31. package/dist/display/markdown-classification/processors/utils/gfm-table-vector-inputs.js +385 -0
  32. package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.d.ts +43 -0
  33. package/dist/display/markdown-classification/processors/utils/gfm-table-vectors.js +33 -0
  34. package/dist/display/markdown-classification/processors/utils/table-data-parser.d.ts +9 -0
  35. package/dist/display/markdown-classification/processors/utils/table-data-parser.js +30 -0
  36. package/dist/display/markdown-classification/processors/utils/thinking-parser.d.ts +7 -0
  37. package/dist/display/markdown-classification/processors/utils/thinking-parser.js +70 -0
  38. package/dist/display/render-block.d.ts +23 -0
  39. package/dist/display/render-block.js +0 -0
  40. package/dist/display/themes.d.ts +1023 -0
  41. package/dist/display/themes.js +1105 -0
  42. package/dist/display/types.d.ts +32 -0
  43. package/dist/display/types.js +0 -0
  44. package/dist/host/ContentIrHostBoundary.d.ts +8 -0
  45. package/dist/host/ContentIrHostBoundary.js +15 -0
  46. package/dist/host/ErrorActions.d.ts +4 -0
  47. package/dist/host/ErrorActions.js +11 -0
  48. package/dist/host/NestedContent.d.ts +3 -0
  49. package/dist/host/NestedContent.js +12 -0
  50. package/dist/host/ResourcePeek.d.ts +6 -0
  51. package/dist/host/ResourcePeek.js +14 -0
  52. package/dist/host/component-registry.d.ts +2 -0
  53. package/dist/host/component-registry.js +25 -0
  54. package/dist/host/diagnostics.d.ts +2 -0
  55. package/dist/host/diagnostics.js +15 -0
  56. package/dist/host/index.d.ts +3 -0
  57. package/dist/host/index.js +18 -0
  58. package/dist/host/kind-incident.d.ts +3 -0
  59. package/dist/host/kind-incident.js +12 -0
  60. package/dist/host/kind-registry.d.ts +2 -0
  61. package/dist/host/kind-registry.js +35 -0
  62. package/dist/host/people.d.ts +3 -0
  63. package/dist/host/people.js +12 -0
  64. package/dist/host/registry.d.ts +27 -0
  65. package/dist/host/registry.js +55 -0
  66. package/dist/host/splitter-envelopes.d.ts +2 -0
  67. package/dist/host/splitter-envelopes.js +7 -0
  68. package/dist/host/tables.d.ts +6 -0
  69. package/dist/host/tables.js +8 -0
  70. package/dist/host/toast.d.ts +2 -0
  71. package/dist/host/toast.js +57 -0
  72. package/dist/host/types.d.ts +157 -0
  73. package/dist/host/types.js +0 -0
  74. package/dist/host/wikilinks.d.ts +15 -0
  75. package/dist/host/wikilinks.js +23 -0
  76. package/dist/kinds/host/route-env.d.ts +33 -0
  77. package/dist/kinds/host/route-env.js +16 -0
  78. package/dist/kinds/react/KindEscapedNotice.d.ts +14 -0
  79. package/dist/kinds/react/KindEscapedNotice.js +72 -0
  80. package/dist/kinds/react/ProvisionalKindBoundary.d.ts +19 -0
  81. package/dist/kinds/react/ProvisionalKindBoundary.js +17 -0
  82. package/dist/kinds/react/ensure-kind-renderable.d.ts +14 -0
  83. package/dist/kinds/react/ensure-kind-renderable.js +45 -0
  84. package/dist/kinds/react/kind-problems.d.ts +62 -0
  85. package/dist/kinds/react/kind-problems.js +134 -0
  86. package/dist/kinds/react/kind-route.d.ts +23 -0
  87. package/dist/kinds/react/kind-route.js +24 -0
  88. package/dist/kinds/react/loading/infer-loading-slug.d.ts +58 -0
  89. package/dist/kinds/react/loading/infer-loading-slug.js +100 -0
  90. package/dist/kinds/react/loading/kind-loading-components.d.ts +48 -0
  91. package/dist/kinds/react/loading/kind-loading-components.js +447 -0
  92. package/dist/kinds/react/loading/kind-loading-registry.d.ts +21 -0
  93. package/dist/kinds/react/loading/kind-loading-registry.js +62 -0
  94. package/dist/kinds/react/loading/kind-loading-slugs.d.ts +18 -0
  95. package/dist/kinds/react/loading/kind-loading-slugs.js +34 -0
  96. package/dist/kinds/react/loading/kind-loading.types.d.ts +79 -0
  97. package/dist/kinds/react/loading/kind-loading.types.js +31 -0
  98. package/dist/kinds/react/loading/resolve-loading-slug.d.ts +29 -0
  99. package/dist/kinds/react/loading/resolve-loading-slug.js +51 -0
  100. package/dist/kinds/react/partial-kind-route.d.ts +32 -0
  101. package/dist/kinds/react/partial-kind-route.js +27 -0
  102. package/dist/kinds/react/registry-versioned.d.ts +54 -0
  103. package/dist/kinds/react/registry-versioned.js +18 -0
  104. package/dist/kinds/react/route-at-version.d.ts +38 -0
  105. package/dist/kinds/react/route-at-version.js +78 -0
  106. package/dist/kinds/react/slot/KindSlot.d.ts +87 -0
  107. package/dist/kinds/react/slot/KindSlot.js +65 -0
  108. package/dist/kinds/react/use-registry-repaint.d.ts +6 -0
  109. package/dist/kinds/react/use-registry-repaint.js +36 -0
  110. package/dist/kinds/react/useIrNode.d.ts +9 -0
  111. package/dist/kinds/react/useIrNode.js +46 -0
  112. package/dist/kinds/react/useLiveJsonRegion.d.ts +15 -0
  113. package/dist/kinds/react/useLiveJsonRegion.js +84 -0
  114. package/dist/kinds/redux/render-block-envelope.d.ts +14 -0
  115. package/dist/kinds/redux/render-block-envelope.js +26 -0
  116. package/dist/kinds/registry/kind-correctors.d.ts +63 -0
  117. package/dist/kinds/registry/kind-correctors.js +94 -0
  118. package/dist/kinds/registry/legacy-quiz-envelope.d.ts +1 -0
  119. package/dist/kinds/registry/legacy-quiz-envelope.js +1 -0
  120. package/dist/kinds/registry/region-envelope-memo.d.ts +45 -0
  121. package/dist/kinds/registry/region-envelope-memo.js +94 -0
  122. package/dist/kinds/registry/registry-debug.d.ts +38 -0
  123. package/dist/kinds/registry/registry-debug.js +39 -0
  124. package/dist/markdown-core/MarkdownCore.d.ts +6 -0
  125. package/dist/markdown-core/MarkdownCore.js +32 -0
  126. package/dist/markdown-core/MarkdownCoreImpl.d.ts +3 -0
  127. package/dist/markdown-core/MarkdownCoreImpl.js +27 -0
  128. package/dist/markdown-core/MarkdownCoreServer.d.ts +4 -0
  129. package/dist/markdown-core/MarkdownCoreServer.js +26 -0
  130. package/dist/markdown-core/heading-anchors-context.d.ts +2 -0
  131. package/dist/markdown-core/heading-anchors-context.js +11 -0
  132. package/dist/markdown-core/heading-anchors-props.d.ts +2 -0
  133. package/dist/markdown-core/heading-anchors-props.js +6 -0
  134. package/dist/markdown-core/markdown-core-html.d.ts +3 -0
  135. package/dist/markdown-core/markdown-core-html.js +33 -0
  136. package/dist/markdown-core/markdown-core-presets.d.ts +22 -0
  137. package/dist/markdown-core/markdown-core-presets.js +118 -0
  138. package/dist/markdown-core/markdown-core-types.d.ts +43 -0
  139. package/dist/markdown-core/markdown-core-types.js +0 -0
  140. package/dist/markdown-core/math/vendor/micromark-math-math-flow.d.ts +15 -0
  141. package/dist/markdown-core/math/vendor/micromark-math-math-flow.js +143 -0
  142. package/dist/markdown-core/math/vendor/micromark-math-math-text.d.ts +24 -0
  143. package/dist/markdown-core/math/vendor/micromark-math-math-text.js +127 -0
  144. package/dist/markdown-core/math/vendor/micromark-math-syntax.d.ts +30 -0
  145. package/dist/markdown-core/math/vendor/micromark-math-syntax.js +15 -0
  146. package/dist/markdown-core/math/vendor/rehype-katex.d.ts +15 -0
  147. package/dist/markdown-core/math/vendor/rehype-katex.js +83 -0
  148. package/dist/markdown-core/math/vendor/remark-math.d.ts +9 -0
  149. package/dist/markdown-core/math/vendor/remark-math.js +20 -0
  150. package/dist/markdown-core/math-normalizer.d.ts +57 -0
  151. package/dist/markdown-core/math-normalizer.js +315 -0
  152. package/dist/markdown-core/plain-title.d.ts +2 -0
  153. package/dist/markdown-core/plain-title.js +1 -0
  154. package/dist/markdown-core/stream-heal.d.ts +2 -0
  155. package/dist/markdown-core/stream-heal.js +184 -0
  156. package/dist/markdown-core/streaming-context.d.ts +2 -0
  157. package/dist/markdown-core/streaming-context.js +11 -0
  158. package/dist/markdown-core/syntax/callout-types.d.ts +9 -0
  159. package/dist/markdown-core/syntax/callout-types.js +101 -0
  160. package/dist/markdown-core/syntax/containers.d.ts +17 -0
  161. package/dist/markdown-core/syntax/containers.js +353 -0
  162. package/dist/markdown-core/syntax/document-numbering.d.ts +52 -0
  163. package/dist/markdown-core/syntax/document-numbering.js +184 -0
  164. package/dist/markdown-core/syntax/elements/CalloutIcon.d.ts +3 -0
  165. package/dist/markdown-core/syntax/elements/CalloutIcon.js +41 -0
  166. package/dist/markdown-core/syntax/elements/CrossRef.d.ts +12 -0
  167. package/dist/markdown-core/syntax/elements/CrossRef.js +57 -0
  168. package/dist/markdown-core/syntax/elements/CsvFence.d.ts +4 -0
  169. package/dist/markdown-core/syntax/elements/CsvFence.js +18 -0
  170. package/dist/markdown-core/syntax/elements/DetailsElements.d.ts +12 -0
  171. package/dist/markdown-core/syntax/elements/DetailsElements.js +38 -0
  172. package/dist/markdown-core/syntax/elements/DocumentNumbering.d.ts +20 -0
  173. package/dist/markdown-core/syntax/elements/DocumentNumbering.js +37 -0
  174. package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.d.ts +4 -0
  175. package/dist/markdown-core/syntax/elements/DocumentPropertiesPanel.js +46 -0
  176. package/dist/markdown-core/syntax/elements/InDocAnchor.d.ts +11 -0
  177. package/dist/markdown-core/syntax/elements/InDocAnchor.js +87 -0
  178. package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.d.ts +24 -0
  179. package/dist/markdown-core/syntax/elements/MarkdownSourceEdit.js +28 -0
  180. package/dist/markdown-core/syntax/elements/MatrxTabs.d.ts +10 -0
  181. package/dist/markdown-core/syntax/elements/MatrxTabs.js +59 -0
  182. package/dist/markdown-core/syntax/elements/MentionChip.d.ts +7 -0
  183. package/dist/markdown-core/syntax/elements/MentionChip.js +69 -0
  184. package/dist/markdown-core/syntax/elements/NestedBody.d.ts +3 -0
  185. package/dist/markdown-core/syntax/elements/NestedBody.js +13 -0
  186. package/dist/markdown-core/syntax/elements/TableOfContents.d.ts +5 -0
  187. package/dist/markdown-core/syntax/elements/TableOfContents.js +44 -0
  188. package/dist/markdown-core/syntax/elements/TaskCheckbox.d.ts +7 -0
  189. package/dist/markdown-core/syntax/elements/TaskCheckbox.js +63 -0
  190. package/dist/markdown-core/syntax/elements/WikiEmbed.d.ts +7 -0
  191. package/dist/markdown-core/syntax/elements/WikiEmbed.js +68 -0
  192. package/dist/markdown-core/syntax/elements/WikiLink.d.ts +10 -0
  193. package/dist/markdown-core/syntax/elements/WikiLink.js +114 -0
  194. package/dist/markdown-core/syntax/elements/core-syntax-elements.d.ts +22 -0
  195. package/dist/markdown-core/syntax/elements/core-syntax-elements.js +70 -0
  196. package/dist/markdown-core/syntax/elements/find-in-document.d.ts +3 -0
  197. package/dist/markdown-core/syntax/elements/find-in-document.js +20 -0
  198. package/dist/markdown-core/syntax/elements/wiki-target.d.ts +5 -0
  199. package/dist/markdown-core/syntax/elements/wiki-target.js +8 -0
  200. package/dist/markdown-core/syntax/frontmatter.d.ts +26 -0
  201. package/dist/markdown-core/syntax/frontmatter.js +72 -0
  202. package/dist/markdown-core/syntax/gfm-cell-pipes.d.ts +11 -0
  203. package/dist/markdown-core/syntax/gfm-cell-pipes.js +4 -0
  204. package/dist/markdown-core/syntax/inline-syntax.d.ts +26 -0
  205. package/dist/markdown-core/syntax/inline-syntax.js +163 -0
  206. package/dist/markdown-core/syntax/linear-scan.d.ts +46 -0
  207. package/dist/markdown-core/syntax/linear-scan.js +129 -0
  208. package/dist/markdown-core/syntax/mdast-helpers.d.ts +48 -0
  209. package/dist/markdown-core/syntax/mdast-helpers.js +48 -0
  210. package/dist/markdown-core/syntax/mentions.d.ts +2 -0
  211. package/dist/markdown-core/syntax/mentions.js +42 -0
  212. package/dist/markdown-core/syntax/names.d.ts +6 -0
  213. package/dist/markdown-core/syntax/names.js +18 -0
  214. package/dist/markdown-core/syntax/prepare-syntax-source.d.ts +1 -0
  215. package/dist/markdown-core/syntax/prepare-syntax-source.js +78 -0
  216. package/dist/markdown-core/syntax/rehype-matrx-syntax.d.ts +9 -0
  217. package/dist/markdown-core/syntax/rehype-matrx-syntax.js +180 -0
  218. package/dist/markdown-core/syntax/remark-inline-only.d.ts +23 -0
  219. package/dist/markdown-core/syntax/remark-inline-only.js +25 -0
  220. package/dist/markdown-core/syntax/remark-matrx-syntax.d.ts +7 -0
  221. package/dist/markdown-core/syntax/remark-matrx-syntax.js +351 -0
  222. package/dist/markdown-core/syntax/remark-table-code-pipes.d.ts +7 -0
  223. package/dist/markdown-core/syntax/remark-table-code-pipes.js +23 -0
  224. package/dist/markdown-core/syntax/stream-heal-syntax.d.ts +2 -0
  225. package/dist/markdown-core/syntax/stream-heal-syntax.js +108 -0
  226. package/dist/markdown-core/syntax/task-source.d.ts +10 -0
  227. package/dist/markdown-core/syntax/task-source.js +34 -0
  228. package/dist/markdown-core/syntax/useDocumentProperties.d.ts +3 -0
  229. package/dist/markdown-core/syntax/useDocumentProperties.js +8 -0
  230. package/dist/styles.css +0 -0
  231. package/dist/utils/addressWithoutNavigating.d.ts +68 -0
  232. package/dist/utils/addressWithoutNavigating.js +60 -0
  233. package/dist/utils/client-lazy.d.ts +13 -0
  234. package/dist/utils/client-lazy.js +24 -0
  235. package/dist/utils/decision-options.d.ts +21 -0
  236. package/dist/utils/decision-options.js +32 -0
  237. package/dist/utils/gfm-lexer.d.ts +5 -0
  238. package/dist/utils/gfm-lexer.js +10 -0
  239. package/dist/utils/json.d.ts +63 -0
  240. package/dist/utils/json.js +22 -0
  241. package/dist/utils/plain-title.d.ts +25 -0
  242. package/dist/utils/plain-title.js +51 -0
  243. package/dist/utils/table-source.d.ts +62 -0
  244. package/dist/utils/table-source.js +191 -0
  245. package/dist/utils/youtube.d.ts +52 -0
  246. package/dist/utils/youtube.js +137 -0
  247. package/package.json +134 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,72 @@
1
+ # Changelog
2
+
3
+ ## 0.2.2
4
+
5
+ `remark-math`, `rehype-katex` and the syntax half of `micromark-extension-math` are vendored
6
+ (`markdown-core/math/vendor/`, MIT, notice beside them): upstream pins `katex ^0.16`, which
7
+ carries GHSA-238p-pmpm-9mq7 (fixed in 0.18.2), so every npm consumer installed a vulnerable KaTeX
8
+ and the publish audit refused 0.2.1. The only KaTeX in a consumer graph is now this package's
9
+ `katex ^0.18.9` (packed consumer: `npm audit` 0 vulnerabilities; the render canary still draws
10
+ math). Behavior unchanged.
11
+
12
+ ## 0.2.1
13
+
14
+ The adversarial linear-time guard now runs alone before the parallel Jest suite, preserving its
15
+ strict budget while removing unrelated worker contention from its measurement.
16
+
17
+ ## 0.2.0
18
+
19
+ ### The kind runtime (`kinds/*`)
20
+
21
+ Moved from matrx-frontend `features/content-ir` (the app's bindings over content-ir-react): the
22
+ kind route and partial/provisional route, route-at-version, registry repaint, ensure-renderable,
23
+ the loading-skeleton registry and slug inference, kind problems, escaped-kind notice, `KindSlot`,
24
+ `useIrNode`, `useLiveJsonRegion`, the region-envelope memo, kind correctors, render-block envelope
25
+ helpers (with the inbound-envelope sanitizer that lived in the chat package), and the route env.
26
+
27
+ New host capabilities: `kindRegistry`, `componentRegistry` (content-ir-react's resolver plus
28
+ `wasRefused` / `debugSnapshot`), `contentIrHost`, `reportKindComponentIncident`. A bare host knows
29
+ no kinds (announced) and resolves no kind components beyond the compiled floor.
30
+ `registerKindCorrector(kind, fn)` replaces the hard-wired CRM `draft_critique` corrector (the host
31
+ registers its own kinds' correctors).
32
+
33
+ `tsx` is a devDependency (the regex linear-time guard runs its worker through it; CI had none).
34
+
35
+ ### Consumer action
36
+
37
+ - matrx-frontend: register `kindRegistry`, `componentRegistry`, `contentIrHost`,
38
+ `reportKindComponentIncident` and the `draft_critique` corrector in the host setup; import
39
+ `@ai-matrx/rich-content/kinds/...` for the moved modules.
40
+
41
+ ## 0.1.1
42
+
43
+ Same package contents as 0.1.0; the release carries the conformant packed-tarball canary
44
+ (`scripts/verify-tarball.mjs`) the sibling-graph publish gate requires (the 0.1.0 tag predates it).
45
+
46
+ ## 0.1.0
47
+
48
+ First release — the formatted-text engine leaves matrx-frontend (Arman, 2026-10-06: chat depends
49
+ on the engine directly, as a package). This release carries:
50
+
51
+ - `markdown-core/*` — the one markdown renderer: presets, the syntax layer (wikilinks, embeds,
52
+ mentions, footnotes, task lists, directives, document numbering, CSV fences), streaming heal,
53
+ the server renderer and the HTML projection. Moved verbatim from `components/markdown-core`.
54
+ - `display/markdown-classification/processors/utils/*` — the block splitter (core + client
55
+ entry), GFM table lines and vectors, thinking parser, client blocks; `display/render-block`;
56
+ the remark/rehype plugins (cite, variable, page break, safe raw HTML); the CSV block; the
57
+ markdown table parser.
58
+ - `utils/*` — plain titles, decision options, JSON helpers, address-without-navigating, YouTube
59
+ URLs, the GFM table source and lexer, `clientLazy` (replaces `next/dynamic` `ssr:false`).
60
+ - `host` — `configureRichContent` with the capabilities in the README; every default announces
61
+ itself.
62
+
63
+ Changes from the app copies: `next/dynamic` → `clientLazy`; app imports → host capabilities
64
+ (toast, error sink, error actions, nested content, wikilinks, people, record peek, splitter
65
+ envelopes, save-to-table); the wikilink "create" reads the organization on the host side
66
+ (the Redux store read is gone). `remend` is pinned at 1.3.1 (1.4.0 trims trailing whitespace in
67
+ held-back streaming text; the heal tests encode 1.3.1's behavior).
68
+
69
+ ### Consumer action
70
+
71
+ - matrx-frontend: call `configureRichContent` at the root (see README) and import from
72
+ `@ai-matrx/rich-content/<domain>/<module>`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AI Matrix Engine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,62 @@
1
- # Temporary Holding Version
1
+ # @ai-matrx/rich-content
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The AI Matrx formatted-text engine as portable React: the one markdown renderer (GFM, math,
4
+ directives, wikilinks, mentions, footnotes, streaming heal), the block splitter (static and
5
+ streaming), and — as the extraction completes — the block renderer and generic blocks,
6
+ `<RichContent>` levels, the rich-document action registry and menus, copy, and the selection
7
+ toolbar. The editor is the sibling package `@ai-matrx/rich-editor`.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ pnpm add @ai-matrx/rich-content
13
+ ```
14
+
15
+ Peers: `react`, `react-dom` (>= 19). Tailwind consumers add the package's `dist` to their
16
+ content sources (`@source "../node_modules/@ai-matrx/rich-content/dist";`).
17
+
18
+ ## Use
19
+
20
+ Import modules by path — one specifier is one module, so client/server boundaries and lazy
21
+ chunks stay intact:
22
+
23
+ ```tsx
24
+ import MarkdownCore from "@ai-matrx/rich-content/markdown-core/MarkdownCore";
25
+ import { splitContentIntoBlocksV2 } from "@ai-matrx/rich-content/display/markdown-classification/processors/utils/content-splitter-v2";
26
+ ```
27
+
28
+ ## Host
29
+
30
+ The engine renders with no host at all. Every capability it can ask for has a default that
31
+ announces itself once on the console and marks degraded elements `data-rich-content-host="bare"`.
32
+ Configure once at the app root:
33
+
34
+ ```ts
35
+ import { configureRichContent } from "@ai-matrx/rich-content/host";
36
+
37
+ configureRichContent({
38
+ toast, // your toast (structural: success/error/info/warning/loading/dismiss)
39
+ captureError, // your error sink
40
+ ErrorActions, // extra actions beside an error message
41
+ NestedContent, // nested markdown renderer (standard level)
42
+ wikilinks, // { resolve, create, loadBody } against your records
43
+ resolvePerson, // @mentions
44
+ ResourcePeek, // your record peek
45
+ splitterEnvelopes, // content-IR envelope hooks for complete regions
46
+ useOpenSaveToTable, // "save these rows as a table"
47
+ });
48
+ ```
49
+
50
+ | Capability | Default on a bare host |
51
+ |---|---|
52
+ | `toast` | the console |
53
+ | `captureError` | `console.error` |
54
+ | `ErrorActions` | none (the message always shows) |
55
+ | `NestedContent` | the source as plain text |
56
+ | `wikilinks` | every link reads "unavailable" |
57
+ | `resolvePerson` | the mention label as written |
58
+ | `ResourcePeek` | the chip is not clickable |
59
+ | `splitterEnvelopes` | regions carry no `metadata.__ir` |
60
+ | `useOpenSaveToTable` | no "save as table" button |
61
+
62
+ MIT licensed.
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ interface CsvBlockProps {
3
+ content: string;
4
+ delimiter?: string;
5
+ className?: string;
6
+ /** Fires when the user commits an inline cell edit — inner markdown body only (no fence). */
7
+ onInnerContentChange?: (inner: string) => void;
8
+ }
9
+ declare const CsvBlock: React.FC<CsvBlockProps>;
10
+ export default CsvBlock;
@@ -0,0 +1,245 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useState, useEffect } from "react";
4
+ import { cn } from "@ai-matrx/design-system";
5
+ import {
6
+ Copy,
7
+ Check,
8
+ ArrowUpDown,
9
+ ArrowUp,
10
+ ArrowDown,
11
+ Pencil,
12
+ X,
13
+ Check as CheckIcon,
14
+ Table2
15
+ } from "lucide-react";
16
+ import { toast } from "../../../host/toast.js";
17
+ import { useOpenSaveToTable } from "../../../host/tables.js";
18
+ import { Button } from "@ai-matrx/design-system/controls";
19
+ function parseCsv(content, delimiter) {
20
+ const rows = [];
21
+ const lines = content.split("\n");
22
+ for (const line of lines) {
23
+ if (!line.trim()) continue;
24
+ const cells = [];
25
+ let current = "";
26
+ let inQuotes = false;
27
+ for (let i = 0; i < line.length; i++) {
28
+ const ch = line[i];
29
+ if (inQuotes) {
30
+ if (ch === '"' && line[i + 1] === '"') {
31
+ current += '"';
32
+ i++;
33
+ } else if (ch === '"') {
34
+ inQuotes = false;
35
+ } else {
36
+ current += ch;
37
+ }
38
+ } else {
39
+ if (ch === '"') {
40
+ inQuotes = true;
41
+ } else if (ch === delimiter) {
42
+ cells.push(current.trim());
43
+ current = "";
44
+ } else {
45
+ current += ch;
46
+ }
47
+ }
48
+ }
49
+ cells.push(current.trim());
50
+ rows.push(cells);
51
+ }
52
+ return rows;
53
+ }
54
+ function rowsToDelimitedContent(rows, delimiter) {
55
+ return rows.map(
56
+ (row) => row.map((cell) => {
57
+ const needsQuote = cell.includes(delimiter) || cell.includes('"') || cell.includes("\n") || cell.includes("\r");
58
+ const escaped = cell.replace(/"/g, '""');
59
+ return needsQuote ? `"${escaped}"` : escaped;
60
+ }).join(delimiter)
61
+ ).join("\n");
62
+ }
63
+ const CsvBlock = ({
64
+ content,
65
+ delimiter = ",",
66
+ className,
67
+ onInnerContentChange
68
+ }) => {
69
+ const [copied, setCopied] = useState(false);
70
+ const [sortCol, setSortCol] = useState(null);
71
+ const [sortDir, setSortDir] = useState(null);
72
+ const [editCell, setEditCell] = useState(
73
+ null
74
+ );
75
+ const [editValue, setEditValue] = useState("");
76
+ const [data, setData] = useState(() => parseCsv(content, delimiter));
77
+ const openSaveToTable = useOpenSaveToTable();
78
+ useEffect(() => {
79
+ setData(parseCsv(content, delimiter));
80
+ setEditCell(null);
81
+ }, [content, delimiter]);
82
+ const headers = data[0] || [];
83
+ const bodyRows = data.slice(1);
84
+ const handleCopy = async () => {
85
+ await navigator.clipboard.writeText(content);
86
+ setCopied(true);
87
+ setTimeout(() => setCopied(false), 2e3);
88
+ };
89
+ const handleSaveAsTable = () => {
90
+ if (headers.length === 0 || bodyRows.length === 0) {
91
+ toast.error("No CSV rows to save.");
92
+ return;
93
+ }
94
+ openSaveToTable?.({ grid: { headers, rows: bodyRows } });
95
+ };
96
+ const handleSort = (colIdx) => {
97
+ if (sortCol === colIdx) {
98
+ if (sortDir === "asc") setSortDir("desc");
99
+ else if (sortDir === "desc") {
100
+ setSortCol(null);
101
+ setSortDir(null);
102
+ }
103
+ } else {
104
+ setSortCol(colIdx);
105
+ setSortDir("asc");
106
+ }
107
+ };
108
+ const sortedRows = [...bodyRows];
109
+ if (sortCol !== null && sortDir) {
110
+ sortedRows.sort((a, b) => {
111
+ const aVal = a[sortCol] ?? "";
112
+ const bVal = b[sortCol] ?? "";
113
+ const aNum = Number(aVal);
114
+ const bNum = Number(bVal);
115
+ if (!isNaN(aNum) && !isNaN(bNum)) {
116
+ return sortDir === "asc" ? aNum - bNum : bNum - aNum;
117
+ }
118
+ return sortDir === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
119
+ });
120
+ }
121
+ const startEdit = (rowIdx, colIdx) => {
122
+ setEditCell({ row: rowIdx, col: colIdx });
123
+ setEditValue(bodyRows[rowIdx]?.[colIdx] ?? "");
124
+ };
125
+ const commitEdit = () => {
126
+ if (!editCell) return;
127
+ const newData = [...data];
128
+ const actualRow = editCell.row + 1;
129
+ if (!newData[actualRow]) return;
130
+ newData[actualRow] = [...newData[actualRow]];
131
+ newData[actualRow][editCell.col] = editValue;
132
+ setData(newData);
133
+ setEditCell(null);
134
+ const inner = rowsToDelimitedContent(newData, delimiter);
135
+ onInnerContentChange?.(inner);
136
+ };
137
+ const cancelEdit = () => {
138
+ setEditCell(null);
139
+ };
140
+ const getSortIcon = (colIdx) => {
141
+ if (sortCol !== colIdx)
142
+ return /* @__PURE__ */ jsx(ArrowUpDown, { className: "w-3 h-3 opacity-0 group-hover/th:opacity-50" });
143
+ if (sortDir === "asc") return /* @__PURE__ */ jsx(ArrowUp, { className: "w-3 h-3 text-primary" });
144
+ return /* @__PURE__ */ jsx(ArrowDown, { className: "w-3 h-3 text-primary" });
145
+ };
146
+ return /* @__PURE__ */ jsxs(
147
+ "div",
148
+ {
149
+ className: cn(
150
+ "my-3 rounded-lg border border-border bg-card overflow-hidden",
151
+ className
152
+ ),
153
+ children: [
154
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 border-b border-border/50 bg-muted/30", children: [
155
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
156
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-mono font-semibold text-green-600 dark:text-green-400", children: "CSV" }),
157
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
158
+ bodyRows.length,
159
+ " rows x ",
160
+ headers.length,
161
+ " cols"
162
+ ] })
163
+ ] }),
164
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
165
+ openSaveToTable ? /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(Table2, {}), onClick: handleSaveAsTable, title: "Save to a table", children: /* @__PURE__ */ jsx("span", { children: "Save to a table" }) }) : null,
166
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: copied ? /* @__PURE__ */ jsx(Check, {}) : /* @__PURE__ */ jsx(Copy, {}), glyphTone: copied ? "success" : void 0, onClick: handleCopy, "aria-label": "Copy" })
167
+ ] })
168
+ ] }),
169
+ /* @__PURE__ */ jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-sm border-collapse", children: [
170
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-muted/50", children: [
171
+ /* @__PURE__ */ jsx("th", { className: "px-1 py-1 text-center text-xs text-muted-foreground font-mono border-r border-border/30 w-8", children: "#" }),
172
+ headers.map((h, colIdx) => /* @__PURE__ */ jsx(
173
+ "th",
174
+ {
175
+ onClick: () => handleSort(colIdx),
176
+ className: "group/th px-3 py-1.5 text-left text-xs font-semibold text-foreground border-r border-border/30 last:border-r-0 cursor-pointer hover:bg-muted/70 transition-colors select-none",
177
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
178
+ /* @__PURE__ */ jsx("span", { children: h }),
179
+ getSortIcon(colIdx)
180
+ ] })
181
+ },
182
+ colIdx
183
+ ))
184
+ ] }) }),
185
+ /* @__PURE__ */ jsx("tbody", { children: sortedRows.map((row, rowIdx) => /* @__PURE__ */ jsxs(
186
+ "tr",
187
+ {
188
+ className: "border-t border-border/20 hover:bg-muted/20 transition-colors",
189
+ children: [
190
+ /* @__PURE__ */ jsx("td", { className: "px-1 py-1 text-center text-xs text-muted-foreground font-mono border-r border-border/30", children: rowIdx + 1 }),
191
+ headers.map((_, colIdx) => {
192
+ const isEditing = editCell?.row === rowIdx && editCell?.col === colIdx;
193
+ const cellValue = row[colIdx] ?? "";
194
+ return /* @__PURE__ */ jsx(
195
+ "td",
196
+ {
197
+ className: "group/cell px-3 py-1.5 text-foreground border-r border-border/30 last:border-r-0 relative",
198
+ onDoubleClick: () => startEdit(rowIdx, colIdx),
199
+ children: isEditing ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
200
+ /* @__PURE__ */ jsx(
201
+ "input",
202
+ {
203
+ type: "text",
204
+ value: editValue,
205
+ onChange: (e) => setEditValue(e.target.value),
206
+ onKeyDown: (e) => {
207
+ if (e.key === "Enter") commitEdit();
208
+ if (e.key === "Escape") cancelEdit();
209
+ },
210
+ className: "w-full px-1 py-0 text-sm bg-background border border-primary rounded focus:outline-none",
211
+ style: { fontSize: "16px" },
212
+ autoFocus: true
213
+ }
214
+ ),
215
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(CheckIcon, {}), onClick: commitEdit, "aria-label": "Done" }),
216
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(X, {}), removes: true, onClick: cancelEdit, "aria-label": "Close" })
217
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
218
+ /* @__PURE__ */ jsx(
219
+ "span",
220
+ {
221
+ className: cn(
222
+ !isNaN(Number(cellValue)) && cellValue !== "" && "text-purple-600 dark:text-purple-400 font-mono tabular-nums"
223
+ ),
224
+ children: cellValue
225
+ }
226
+ ),
227
+ /* @__PURE__ */ jsx(Button, { variant: "quiet", icon: /* @__PURE__ */ jsx(Pencil, {}), onClick: () => startEdit(rowIdx, colIdx), "aria-label": "Edit", className: "absolute right-1 top-1/2 opacity-0 hover:!opacity-100" })
228
+ ] })
229
+ },
230
+ colIdx
231
+ );
232
+ })
233
+ ]
234
+ },
235
+ rowIdx
236
+ )) })
237
+ ] }) })
238
+ ]
239
+ }
240
+ );
241
+ };
242
+ var CsvBlock_default = CsvBlock;
243
+ export {
244
+ CsvBlock_default as default
245
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * parseMarkdownTable — the ONE markdown-table parser.
3
+ *
4
+ * Extracted from StreamingTableRenderer so the renderer AND the artifact
5
+ * "Convert to table" path parse identically (no forked regex — the doctrine
6
+ * primitive). Returns null for anything that isn't a well-formed markdown table
7
+ * (header row + separator row + data rows); tolerant of streaming (0 data rows
8
+ * yet) and of leading/trailing pipes.
9
+ */
10
+ export interface ParsedTable {
11
+ headers: string[];
12
+ rows: string[][];
13
+ /** Rows keyed by markdown-stripped header — the shape DB save / JSON export want. */
14
+ normalizedData: Array<{
15
+ [key: string]: string;
16
+ }>;
17
+ }
18
+ /** Strip inline markdown from a header so it forms a clean object key. */
19
+ export declare function cleanTableHeaderKey(header: string): string;
20
+ export declare function parseMarkdownTable(content: string): ParsedTable | null;
@@ -0,0 +1,35 @@
1
+ import { unwrapCodeSpans } from "@ai-matrx/content-ir/source";
2
+ import { dataRowIndexes, rowCells } from "../../../utils/table-source.js";
3
+ import { isGfmDelimiterRow } from "../../markdown-classification/processors/utils/gfm-table-lines.js";
4
+ function cleanTableHeaderKey(header) {
5
+ return unwrapCodeSpans(header).replace(/\*\*([^*]+)\*\*/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/(?<![A-Za-z0-9])_([^_\n]+?)_(?![A-Za-z0-9])/g, "$1").replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1|$2").trim();
6
+ }
7
+ function parseMarkdownTable(content) {
8
+ try {
9
+ const lines = content.split("\n").filter((line) => line.trim().length > 0);
10
+ if (lines.length < 2) return null;
11
+ const headerLine = lines[0];
12
+ const separatorLine = lines[1];
13
+ if (!isGfmDelimiterRow(separatorLine)) return null;
14
+ const parseRow = rowCells;
15
+ const headers = parseRow(headerLine);
16
+ if (headers.length === 0) return null;
17
+ const dataLines = lines.slice(2);
18
+ const validRows = dataRowIndexes(dataLines, dataLines.map((_line, index) => index)).map((index) => parseRow(dataLines[index] ?? ""));
19
+ const normalizedData = validRows.map((row) => {
20
+ const rowData = {};
21
+ headers.forEach((header, index) => {
22
+ rowData[cleanTableHeaderKey(header)] = index < row.length ? row[index] : "";
23
+ });
24
+ return rowData;
25
+ });
26
+ return { headers, rows: validRows, normalizedData };
27
+ } catch (error) {
28
+ console.error("[parseMarkdownTable] Parse error:", error);
29
+ return null;
30
+ }
31
+ }
32
+ export {
33
+ cleanTableHeaderKey,
34
+ parseMarkdownTable
35
+ };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Remark plugin: recognizes inline citation markers `<matrxcite n="3" />`
3
+ * inside markdown TEXT nodes and emits inline `matrx-cite` custom elements so
4
+ * `react-markdown` renders them via the `components` map
5
+ * (→ `CitationMarkerInline`).
6
+ *
7
+ * Why text nodes (mirroring `remarkMatrxVariable`), not raw HTML / the block
8
+ * splitter: `preprocessContent` in BasicMarkdownContent escapes every
9
+ * non-allow-listed tag to `&lt;matrxcite …&gt;`, and CommonMark decodes the
10
+ * entities back to literal `<matrxcite n="3" />` inside text nodes — so the
11
+ * marker arrives here as plain text, safely inside the paragraph flow. The
12
+ * splitter path (audiocite-style) would make each marker its OWN vertically
13
+ * stacked block and re-break citation-split sentences mid-line — the exact
14
+ * regression fixed on 2026-07-16.
15
+ *
16
+ * Design rules (same as remarkMatrxVariable):
17
+ * - Runs at render time on the mdast AST — source strings are never mutated.
18
+ * - Only transforms `text` nodes; code spans/fences keep the literal text.
19
+ * - The source number lives on the DOM as `data-n`.
20
+ *
21
+ * Markers are inserted into display text by
22
+ * `features/agents/redux/execution-system/messages/message-citations.ts`
23
+ * (`insertCitationMarkers`) — this plugin is the render-side half.
24
+ */
25
+ interface MdastNode {
26
+ type: string;
27
+ value?: string;
28
+ children?: MdastNode[];
29
+ data?: Record<string, unknown>;
30
+ [key: string]: unknown;
31
+ }
32
+ export default function remarkMatrxCite(): (tree: MdastNode) => void;
33
+ export {};
@@ -0,0 +1,71 @@
1
+ const CITE_PATTERN = /<matrxcite\s+n="(\d+)"\s*\/>/g;
2
+ function expandTextNode(value) {
3
+ CITE_PATTERN.lastIndex = 0;
4
+ const parts = [];
5
+ let lastIdx = 0;
6
+ let match;
7
+ let matched = false;
8
+ while ((match = CITE_PATTERN.exec(value)) !== null) {
9
+ matched = true;
10
+ const start = match.index;
11
+ const end = start + match[0].length;
12
+ const n = match[1];
13
+ if (start > lastIdx) {
14
+ parts.push({ type: "text", value: value.slice(lastIdx, start) });
15
+ }
16
+ parts.push({
17
+ type: "matrxCite",
18
+ data: {
19
+ hName: "matrx-cite",
20
+ hProperties: { "data-n": n }
21
+ }
22
+ });
23
+ lastIdx = end;
24
+ }
25
+ if (!matched) {
26
+ return [{ type: "text", value }];
27
+ }
28
+ if (lastIdx < value.length) {
29
+ parts.push({ type: "text", value: value.slice(lastIdx) });
30
+ }
31
+ return parts;
32
+ }
33
+ const SKIP_TYPES = /* @__PURE__ */ new Set([
34
+ "code",
35
+ "inlineCode",
36
+ "html",
37
+ "yaml",
38
+ "toml",
39
+ "math",
40
+ "inlineMath"
41
+ ]);
42
+ function walk(node) {
43
+ if (!node || SKIP_TYPES.has(node.type)) return;
44
+ const children = node.children;
45
+ if (!Array.isArray(children) || children.length === 0) return;
46
+ const next = [];
47
+ let mutated = false;
48
+ for (const child of children) {
49
+ if (child?.type === "text" && typeof child.value === "string" && child.value.includes("<matrxcite")) {
50
+ const expanded = expandTextNode(child.value);
51
+ if (expanded.length !== 1 || expanded[0].type !== "text") {
52
+ mutated = true;
53
+ }
54
+ next.push(...expanded);
55
+ } else {
56
+ next.push(child);
57
+ walk(child);
58
+ }
59
+ }
60
+ if (mutated) {
61
+ node.children = next;
62
+ }
63
+ }
64
+ function remarkMatrxCite() {
65
+ return (tree) => {
66
+ walk(tree);
67
+ };
68
+ }
69
+ export {
70
+ remarkMatrxCite as default
71
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Remark plugin: recognizes `{{variable_name}}` tokens inside markdown text
3
+ * and emits inline `matrx-variable` custom elements so `react-markdown` can
4
+ * render them via the `components` map.
5
+ *
6
+ * Design rules:
7
+ * - Runs at render time on the mdast AST — the source `content` string is
8
+ * never modified. Redis/Redux/DB copies of the message are untouched.
9
+ * - Only transforms `text` nodes. `inlineCode`, `code` blocks, `link`, etc.
10
+ * are left alone, so `` `{{literal}}` `` and ```` ```js\n{{foo}}\n``` ````
11
+ * stay as plain text. Inside links/headings/emphasis the pattern still
12
+ * applies because those wrap `text` children.
13
+ * - Pattern requires a closed `}}`. Partial tokens during streaming (e.g.
14
+ * `{{user_na`) stay plain text until the closing braces arrive.
15
+ * - Emits a custom element `matrx-variable` with `data-name="..."` so the
16
+ * renderer can look up the raw snake_case key.
17
+ *
18
+ * Pattern: `{{identifier}}` where identifier starts with a letter or underscore,
19
+ * followed by letters, digits, underscores, or dots.
20
+ */
21
+ interface MdastNode {
22
+ type: string;
23
+ value?: string;
24
+ children?: MdastNode[];
25
+ data?: Record<string, unknown>;
26
+ [key: string]: unknown;
27
+ }
28
+ export default function remarkMatrxVariable(): (tree: MdastNode) => void;
29
+ export {};
@@ -0,0 +1,71 @@
1
+ const VARIABLE_PATTERN = /\{\{([a-zA-Z_][a-zA-Z0-9_.]*)\}\}/g;
2
+ function expandTextNode(value) {
3
+ VARIABLE_PATTERN.lastIndex = 0;
4
+ const parts = [];
5
+ let lastIdx = 0;
6
+ let match;
7
+ let matched = false;
8
+ while ((match = VARIABLE_PATTERN.exec(value)) !== null) {
9
+ matched = true;
10
+ const start = match.index;
11
+ const end = start + match[0].length;
12
+ const name = match[1];
13
+ if (start > lastIdx) {
14
+ parts.push({ type: "text", value: value.slice(lastIdx, start) });
15
+ }
16
+ parts.push({
17
+ type: "matrxVariable",
18
+ data: {
19
+ hName: "matrx-variable",
20
+ hProperties: { "data-name": name }
21
+ }
22
+ });
23
+ lastIdx = end;
24
+ }
25
+ if (!matched) {
26
+ return [{ type: "text", value }];
27
+ }
28
+ if (lastIdx < value.length) {
29
+ parts.push({ type: "text", value: value.slice(lastIdx) });
30
+ }
31
+ return parts;
32
+ }
33
+ const SKIP_TYPES = /* @__PURE__ */ new Set([
34
+ "code",
35
+ "inlineCode",
36
+ "html",
37
+ "yaml",
38
+ "toml",
39
+ "math",
40
+ "inlineMath"
41
+ ]);
42
+ function walk(node) {
43
+ if (!node || SKIP_TYPES.has(node.type)) return;
44
+ const children = node.children;
45
+ if (!Array.isArray(children) || children.length === 0) return;
46
+ const next = [];
47
+ let mutated = false;
48
+ for (const child of children) {
49
+ if (child?.type === "text" && typeof child.value === "string" && child.value.includes("{{")) {
50
+ const expanded = expandTextNode(child.value);
51
+ if (expanded.length !== 1 || expanded[0].type !== "text") {
52
+ mutated = true;
53
+ }
54
+ next.push(...expanded);
55
+ } else {
56
+ next.push(child);
57
+ walk(child);
58
+ }
59
+ }
60
+ if (mutated) {
61
+ node.children = next;
62
+ }
63
+ }
64
+ function remarkMatrxVariable() {
65
+ return (tree) => {
66
+ walk(tree);
67
+ };
68
+ }
69
+ export {
70
+ remarkMatrxVariable as default
71
+ };