@ai-matrx/rich-content 0.2.18 → 0.2.20

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.20
4
+
5
+ - Readable Markdown copy now uses Content IR's canonical fence opener and closer. Inline code made from four or more backticks remains prose, while closed, unclosed, and nested fenced-code bodies are copied without their outer fence.
6
+
7
+ ### Consumer action
8
+
9
+ - None required. Public imports and host setup are unchanged.
10
+
3
11
  ## 0.2.10
4
12
 
5
13
  - Markdown copy goes through the host's `app.CopyButtons` (the copy menu; matrx-frontend ALC-19).
@@ -133,4 +141,3 @@ held-back streaming text; the heal tests encode 1.3.1's behavior).
133
141
 
134
142
  - matrx-frontend: call `configureRichContent` at the root (see README) and import from
135
143
  `@ai-matrx/rich-content/<domain>/<module>`.
136
-
@@ -1,11 +1,15 @@
1
- import { unwrapKindEnvelopes } from "@ai-matrx/content-ir/source";
1
+ import {
2
+ closeFence,
3
+ fenceOpenerOf,
4
+ fenceParts,
5
+ unwrapKindEnvelopes
6
+ } from "@ai-matrx/content-ir/source";
2
7
  import {
3
8
  findTableEnd,
4
9
  rowCells,
5
10
  tableStartsAt,
6
11
  unescapeCellPipes
7
12
  } from "../display/markdown-classification/processors/utils/gfm-table-lines.js";
8
- const FENCE = /^( {0,3})(`{3,}|~{3,})/;
9
13
  function readableInline(line) {
10
14
  const codes = [];
11
15
  let out = line.replace(/(`+)([\s\S]*?[^`])\1(?!`)/g, (_m, _ticks, body) => {
@@ -20,18 +24,22 @@ function readableInline(line) {
20
24
  }
21
25
  function markdownToReadableText(markdown) {
22
26
  const lines = unwrapKindEnvelopes(markdown).replace(/\r\n?/g, "\n").split("\n");
27
+ const fenceLines = {
28
+ count: lines.length,
29
+ line: (line) => lines[line] ?? null
30
+ };
23
31
  const out = [];
24
32
  for (let i = 0; i < lines.length; i += 1) {
25
33
  const line = lines[i];
26
- const fence = FENCE.exec(line);
27
- if (fence) {
28
- const marker = fence[2];
29
- let j = i + 1;
30
- while (j < lines.length && !new RegExp(`^ {0,3}${marker[0] === "`" ? "`" : "~"}{${marker.length},}\\s*$`).test(lines[j])) {
31
- out.push(lines[j]);
32
- j += 1;
34
+ const opener = fenceOpenerOf(line);
35
+ if (opener) {
36
+ const end = closeFence(fenceLines, i, opener);
37
+ const parts = fenceParts(lines.slice(i, end.line + 1).join("\n"));
38
+ if (parts) {
39
+ const bodyLineCount = end.line - i - (end.closed ? 1 : 0);
40
+ if (parts.body || bodyLineCount > 0) out.push(...parts.body.split("\n"));
33
41
  }
34
- i = j;
42
+ i = end.line;
35
43
  continue;
36
44
  }
37
45
  if (tableStartsAt(lines, i)) {
@@ -1,14 +1,3 @@
1
- /**
2
- * APP BINDINGS — the host's own windows, records, canvas, menus and kind views that the engine's
3
- * blocks offer when a host has them. Each export keeps the name the engine code used when it
4
- * lived in matrx-frontend, so call sites read the same; each one delegates to
5
- * `configureRichContent({ app: { … } })` and falls back to an honest default (absent control,
6
- * plain rendering, announced once) on a bare host.
7
- *
8
- * Typing debt (recorded in FEATURE.md): these host callables are typed loosely (`HostFn`,
9
- * `HostComponent`) because their real signatures live in the host app. Tighten each one when it
10
- * gets a package-owned contract.
11
- */
12
1
  import { type ComponentType } from "react";
13
2
  export type HostFn = (...args: any[]) => any;
14
3
  export type HostComponent = ComponentType<any>;
@@ -45,6 +34,15 @@ export interface RichContentAppBindings {
45
34
  convertOriginForSource: HostFn;
46
35
  useDocumentDialogsHost: HostFn;
47
36
  RecordAnnotations: HostComponent;
37
+ ConfirmDialog: HostComponent;
38
+ TextInputDialog: HostComponent;
39
+ EditableContextMenu: HostComponent;
40
+ buildApplicationScopeFromMenuContext: HostFn;
41
+ useMicField: HostFn;
42
+ useFileUpload: HostFn;
43
+ fileUrls: HostFn;
44
+ searchKindDefinitions: HostFn;
45
+ kindCanonicalExample: HostFn;
48
46
  annotationRecordOf: HostFn;
49
47
  recordKeyOf: HostFn;
50
48
  useMermaidPreferences: HostFn;
@@ -157,6 +155,15 @@ export declare const useDocumentDialogsHost: HostFn;
157
155
  export declare const RecordAnnotations: HostComponent;
158
156
  export declare const annotationRecordOf: HostFn;
159
157
  export declare const recordKeyOf: HostFn;
158
+ export declare const ConfirmDialog: HostComponent;
159
+ export declare const TextInputDialog: HostComponent;
160
+ export declare const EditableContextMenu: HostComponent;
161
+ export declare const buildApplicationScopeFromMenuContext: HostFn;
162
+ export declare const useMicField: HostFn;
163
+ export declare const useFileUpload: HostFn;
164
+ export declare const fileUrls: HostFn;
165
+ export declare const searchKindDefinitions: HostFn;
166
+ export declare const kindCanonicalExample: HostFn;
160
167
  export declare const MarkdownStream: HostComponent;
161
168
  export declare const CitationMarkerInline: HostComponent;
162
169
  export declare const CopyButtons: HostComponent;
@@ -1,4 +1,5 @@
1
1
  "use client";
2
+ import { ConfirmDialog as DesignSystemConfirmDialog } from "@ai-matrx/design-system";
2
3
  import { createElement } from "react";
3
4
  import { GenericStructuredView } from "@ai-matrx/content-ir-react";
4
5
  import { announceBareHost, BARE_HOST_ATTR, hostCapability } from "./registry.js";
@@ -86,6 +87,28 @@ const useDocumentDialogsHost = fn("useDocumentDialogsHost", () => ({ callbacks:
86
87
  const RecordAnnotations = component("RecordAnnotations", Passthrough, "no reading set on saved records");
87
88
  const annotationRecordOf = fn("annotationRecordOf", () => null, "no saved record is known");
88
89
  const recordKeyOf = fn("recordKeyOf", (r) => `${r.token}:${r.id}`, "records key as token:id");
90
+ const ConfirmDialog = component("ConfirmDialog", DesignSystemConfirmDialog, "confirm dialogs open in the page, not the popout");
91
+ const TextInputDialog = component("TextInputDialog", null, "no text prompt dialog (link insertion is absent)");
92
+ const EditableContextMenu = component("EditableContextMenu", Passthrough, "no editor context menu");
93
+ const buildApplicationScopeFromMenuContext = fn("buildApplicationScopeFromMenuContext", () => ({}), "agents see no application scope");
94
+ const useMicField = fn(
95
+ "useMicField",
96
+ () => ({ available: false, isRecording: false, isTranscribing: false, handleVoiceClick: async () => {
97
+ } }),
98
+ "no dictation"
99
+ );
100
+ const useFileUpload = fn(
101
+ "useFileUpload",
102
+ () => ({
103
+ upload: async () => {
104
+ throw new Error("This app cannot upload files.");
105
+ }
106
+ }),
107
+ "images cannot be uploaded"
108
+ );
109
+ const fileUrls = fn("fileUrls", (id) => ({ inline: id }), "file links are the file id");
110
+ const searchKindDefinitions = fn("searchKindDefinitions", async () => [], "no kinds can be inserted");
111
+ const kindCanonicalExample = fn("kindCanonicalExample", async () => ({}), "an inserted kind starts empty");
89
112
  const MarkdownStream = component("MarkdownStream", null, "the full renderer is not registered");
90
113
  const CitationMarkerInline = component("CitationMarkerInline", TextOnly, "citation markers show as text");
91
114
  const CopyButtons = component("CopyButtons", null, "no copy menu on rendered content");
@@ -129,7 +152,9 @@ export {
129
152
  ArtifactRender,
130
153
  CitationMarkerInline,
131
154
  CodeBlockWithContextAttach,
155
+ ConfirmDialog,
132
156
  CopyButtons,
157
+ EditableContextMenu,
133
158
  EntityRef,
134
159
  IconInputWithValidation,
135
160
  InlineCopyButton,
@@ -146,12 +171,15 @@ export {
146
171
  RawJsonExplorer,
147
172
  RecordAnnotations,
148
173
  StructuredValueView,
174
+ TextInputDialog,
149
175
  annotationRecordOf,
150
176
  announceProposedGoogleWrite,
177
+ buildApplicationScopeFromMenuContext,
151
178
  contentSourceKey,
152
179
  convertOriginForSource,
153
180
  createMermaidEditorScope,
154
181
  ensureOrganizationContext,
182
+ fileUrls,
155
183
  getArtifactDef,
156
184
  hasArtifactRenderer,
157
185
  holdDeliberateIntent,
@@ -161,6 +189,7 @@ export {
161
189
  imageKnobPrincipals,
162
190
  isOrganizationSelectionCancelled,
163
191
  isProposedGoogleWrite,
192
+ kindCanonicalExample,
164
193
  kindHasRecordChrome,
165
194
  loadExportTargets,
166
195
  loadSendToGoogle,
@@ -169,6 +198,7 @@ export {
169
198
  reportCanvasOpenDrop,
170
199
  resolveArtifactDef,
171
200
  sameContentSource,
201
+ searchKindDefinitions,
172
202
  setImageKnobMapEntry,
173
203
  useActiveOrganizationId,
174
204
  useAdvancedMenu,
@@ -177,6 +207,7 @@ export {
177
207
  useCanvasOpenGuard,
178
208
  useDiagramAgents,
179
209
  useDocumentDialogsHost,
210
+ useFileUpload,
180
211
  useHideReasoning,
181
212
  useHideToolResults,
182
213
  useHostDispatch,
@@ -188,6 +219,7 @@ export {
188
219
  useIsSuperAdmin,
189
220
  useMachineFramesVisible,
190
221
  useMermaidPreferences,
222
+ useMicField,
191
223
  useOpenArtifactInCanvas,
192
224
  useOpenConvertToShapeWindow,
193
225
  useOpenOverlay,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/rich-content",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
4
4
  "description": "The AI Matrx formatted-text engine: the one markdown renderer, streaming markdown, the block splitter and renderer, the generic blocks, <RichContent> levels, the rich-document action registry and menus, copy, and the selection toolbar — as portable React.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -130,9 +130,9 @@
130
130
  "unist-util-visit": "^5.1.0",
131
131
  "unist-util-visit-parents": "^6.0.2",
132
132
  "yaml": "^2.9.1",
133
- "@ai-matrx/canvas": "latest",
134
133
  "@ai-matrx/agents": "latest",
135
134
  "@ai-matrx/alchemy": "latest",
135
+ "@ai-matrx/canvas": "latest",
136
136
  "@ai-matrx/content-ir": "latest",
137
137
  "@ai-matrx/content-ir-react": "latest",
138
138
  "@ai-matrx/data": "latest",
@@ -140,9 +140,9 @@
140
140
  "@ai-matrx/diff": "latest",
141
141
  "@ai-matrx/icons": "latest",
142
142
  "@ai-matrx/kit": "latest",
143
+ "@ai-matrx/media": "latest",
143
144
  "@ai-matrx/print": "latest",
144
145
  "@ai-matrx/records": "latest",
145
- "@ai-matrx/media": "latest",
146
146
  "@ai-matrx/records-ui": "latest",
147
147
  "@ai-matrx/tap-target": "latest"
148
148
  },