@ai-matrx/rich-content 0.2.10 → 0.2.16

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 (114) hide show
  1. package/dist/copy/copy-commands.d.ts +42 -0
  2. package/dist/copy/copy-commands.js +119 -0
  3. package/dist/copy/markdown-copy-html.d.ts +3 -0
  4. package/dist/copy/markdown-copy-html.js +8 -0
  5. package/dist/copy/markdown-readable-text.d.ts +4 -0
  6. package/dist/copy/markdown-readable-text.js +62 -0
  7. package/dist/display/chat-markdown/block-registry/BlockComponentRegistry.js +2 -0
  8. package/dist/display/chat-markdown/block-registry/block-dispatch.js +2 -0
  9. package/dist/host/app-bindings.d.ts +30 -0
  10. package/dist/host/app-bindings.js +38 -0
  11. package/dist/host/feedback-subject.d.ts +16 -0
  12. package/dist/host/feedback-subject.js +0 -0
  13. package/dist/host/manual-copy.d.ts +7 -0
  14. package/dist/host/manual-copy.js +11 -0
  15. package/dist/host/registry.d.ts +2 -0
  16. package/dist/host/registry.js +10 -0
  17. package/dist/host/session-knob.d.ts +5 -0
  18. package/dist/host/session-knob.js +7 -0
  19. package/dist/host/types.d.ts +24 -0
  20. package/dist/rich-document/RegistryContextMenu.d.ts +29 -0
  21. package/dist/rich-document/RegistryContextMenu.js +40 -0
  22. package/dist/rich-document/RichDocument.d.ts +78 -0
  23. package/dist/rich-document/RichDocument.js +218 -0
  24. package/dist/rich-document/RichDocumentActionProvider.d.ts +18 -0
  25. package/dist/rich-document/RichDocumentActionProvider.js +18 -0
  26. package/dist/rich-document/RichDocumentActionSurface.d.ts +11 -0
  27. package/dist/rich-document/RichDocumentActionSurface.js +59 -0
  28. package/dist/rich-document/RichDocumentActions.d.ts +12 -0
  29. package/dist/rich-document/RichDocumentActions.js +29 -0
  30. package/dist/rich-document/actions/hostActions.d.ts +5 -0
  31. package/dist/rich-document/actions/hostActions.js +31 -0
  32. package/dist/rich-document/actions/labels.d.ts +9 -0
  33. package/dist/rich-document/actions/labels.js +8 -0
  34. package/dist/rich-document/actions/markdownTable.d.ts +9 -0
  35. package/dist/rich-document/actions/markdownTable.js +39 -0
  36. package/dist/rich-document/actions/provider.d.ts +58 -0
  37. package/dist/rich-document/actions/provider.js +245 -0
  38. package/dist/rich-document/actions/resumePendingAuthAction.d.ts +3 -0
  39. package/dist/rich-document/actions/resumePendingAuthAction.js +31 -0
  40. package/dist/rich-document/actions/sources/index.d.ts +9 -0
  41. package/dist/rich-document/actions/sources/index.js +22 -0
  42. package/dist/rich-document/actions/sources/raw.d.ts +4 -0
  43. package/dist/rich-document/actions/sources/raw.js +35 -0
  44. package/dist/rich-document/actions/useRichDocumentProvider.d.ts +1 -0
  45. package/dist/rich-document/actions/useRichDocumentProvider.js +13 -0
  46. package/dist/rich-document/host-types.d.ts +51 -0
  47. package/dist/rich-document/host-types.js +0 -0
  48. package/dist/rich-document/registrations.d.ts +1 -0
  49. package/dist/rich-document/registrations.js +13 -0
  50. package/dist/rich-document/review/applyTargets.d.ts +16 -0
  51. package/dist/rich-document/review/applyTargets.js +32 -0
  52. package/dist/rich-document/review/proposedEdit.d.ts +22 -0
  53. package/dist/rich-document/review/proposedEdit.js +48 -0
  54. package/dist/rich-document/review/protectedSpans.d.ts +14 -0
  55. package/dist/rich-document/review/protectedSpans.js +61 -0
  56. package/dist/rich-document/runtime/actionSurfacesStore.d.ts +30 -0
  57. package/dist/rich-document/runtime/actionSurfacesStore.js +79 -0
  58. package/dist/rich-document/runtime/contextMenuFor.d.ts +6 -0
  59. package/dist/rich-document/runtime/contextMenuFor.js +7 -0
  60. package/dist/rich-document/runtime/providerBridge.d.ts +20 -0
  61. package/dist/rich-document/runtime/providerBridge.js +23 -0
  62. package/dist/rich-document/runtime/useActionSurfaceProvider.d.ts +33 -0
  63. package/dist/rich-document/runtime/useActionSurfaceProvider.js +214 -0
  64. package/dist/rich-document/search/ContentFindControl.d.ts +8 -0
  65. package/dist/rich-document/search/ContentFindControl.js +46 -0
  66. package/dist/rich-document/search/RenderedFindBar.d.ts +8 -0
  67. package/dist/rich-document/search/RenderedFindBar.js +110 -0
  68. package/dist/rich-document/search/renderedFind.d.ts +1 -0
  69. package/dist/rich-document/search/renderedFind.js +1 -0
  70. package/dist/rich-document/types.d.ts +384 -0
  71. package/dist/rich-document/types.js +0 -0
  72. package/dist/rich-document/variants/ActionBar.d.ts +17 -0
  73. package/dist/rich-document/variants/ActionBar.js +48 -0
  74. package/dist/rich-document/variants/MenuVariant.d.ts +15 -0
  75. package/dist/rich-document/variants/MenuVariant.js +17 -0
  76. package/dist/rich-document/variants/MiniActionBar.d.ts +5 -0
  77. package/dist/rich-document/variants/MiniActionBar.js +11 -0
  78. package/dist/rich-document/variants/RegistryActionList.d.ts +17 -0
  79. package/dist/rich-document/variants/RegistryActionList.js +94 -0
  80. package/dist/rich-document/variants/RegistryActionMenu.d.ts +24 -0
  81. package/dist/rich-document/variants/RegistryActionMenu.js +74 -0
  82. package/dist/rich-document/variants/shared/AlchemyDocumentMenu.d.ts +7 -0
  83. package/dist/rich-document/variants/shared/AlchemyDocumentMenu.js +83 -0
  84. package/dist/rich-document/variants/shared/OpenOneMenuButton.d.ts +9 -0
  85. package/dist/rich-document/variants/shared/OpenOneMenuButton.js +70 -0
  86. package/dist/rich-document/variants/shared/StandaloneOneMenu.d.ts +8 -0
  87. package/dist/rich-document/variants/shared/StandaloneOneMenu.js +32 -0
  88. package/dist/rich-document/variants/shared/categories.d.ts +4 -0
  89. package/dist/rich-document/variants/shared/categories.js +31 -0
  90. package/dist/rich-document/variants/shared/iconMap.d.ts +2 -0
  91. package/dist/rich-document/variants/shared/iconMap.js +73 -0
  92. package/dist/rich-document/variants/shared/menuStructure.d.ts +81 -0
  93. package/dist/rich-document/variants/shared/menuStructure.js +271 -0
  94. package/dist/rich-document/variants/shared/runAction.d.ts +17 -0
  95. package/dist/rich-document/variants/shared/runAction.js +24 -0
  96. package/dist/selection-toolbar/SelectionToolbarFrame.d.ts +64 -0
  97. package/dist/selection-toolbar/SelectionToolbarFrame.js +191 -0
  98. package/dist/selection-toolbar/common-actions.d.ts +2 -0
  99. package/dist/selection-toolbar/common-actions.js +103 -0
  100. package/dist/selection-toolbar/selection-actions.d.ts +126 -0
  101. package/dist/selection-toolbar/selection-actions.js +240 -0
  102. package/dist/selection-toolbar/selection-copy.d.ts +19 -0
  103. package/dist/selection-toolbar/selection-copy.js +98 -0
  104. package/dist/selection-toolbar/selection-shape.d.ts +1 -0
  105. package/dist/selection-toolbar/selection-shape.js +15 -0
  106. package/dist/selection-toolbar/selection-zones.d.ts +90 -0
  107. package/dist/selection-toolbar/selection-zones.js +85 -0
  108. package/dist/selection-toolbar/textarea-caret.d.ts +8 -0
  109. package/dist/selection-toolbar/textarea-caret.js +69 -0
  110. package/dist/utils/alchemy-icon-keys.d.ts +18 -0
  111. package/dist/utils/alchemy-icon-keys.js +29 -0
  112. package/dist/utils/rendered-find.d.ts +9 -0
  113. package/dist/utils/rendered-find.js +68 -0
  114. package/package.json +23 -7
@@ -0,0 +1,42 @@
1
+ import { markdownToReadableText } from "./markdown-readable-text.js";
2
+ interface CopyOptions {
3
+ isMarkdown?: boolean;
4
+ formatForGoogleDocs?: boolean;
5
+ formatForWordPress?: boolean;
6
+ formatJson?: boolean;
7
+ showHtmlPreview?: boolean;
8
+ includeThinking?: boolean;
9
+ onSuccess?: () => void;
10
+ onError?: (err: unknown) => void;
11
+ onShowHtmlPreview?: (html: string) => boolean | void | Promise<boolean | void>;
12
+ }
13
+ /**
14
+ * Copy CONTENT (markdown, text, or any JSON-able value) through Alchemy's serialization and browser transport.
15
+ * Not the plain-string copy — that is `copyToClipboard` in `@/lib/clipboard/copy`.
16
+ */
17
+ export declare function copyContent(content: unknown, options?: CopyOptions): Promise<boolean>;
18
+ export type CopyFlavor = "default" | "markdown" | "text";
19
+ export { markdownToReadableText };
20
+ /** The knob that decides what a single Copy click puts in a plain field. */
21
+ export declare const COPY_DEFAULT_FLAVOR_KNOB: {
22
+ readonly feature: "copy";
23
+ readonly key: "default_flavor";
24
+ };
25
+ /** The plain-text flavor of a single Copy click for this session ("markdown" until the knob answers). */
26
+ export declare function defaultCopyFlavor(): "markdown" | "text";
27
+ export interface RichCopyOptions {
28
+ /** Keep `<thinking>` / reasoning blocks (default: removed). */
29
+ includeThinking?: boolean;
30
+ /** Toast on success: a label, or false for none. Default: the flavor's label. */
31
+ toast?: string | false;
32
+ }
33
+ /** The bytes a flavor writes — pure enough to test; the HTML is loaded at click time. */
34
+ export declare function richCopyPlainText(markdown: string, flavor: CopyFlavor, defaultFlavor?: "markdown" | "text"): string;
35
+ /**
36
+ * Write the plain flavor, or html + plain in one clipboard item (kit's `copyRich`; `html` may be a
37
+ * promise so the item is created inside the click). A refused rich write degrades to plain text and
38
+ * says so; when nothing lands the person is handed the text to copy by hand.
39
+ */
40
+ export declare function writeClipboardFlavors(plain: string, html?: Promise<string> | string): Promise<boolean>;
41
+ /** THE copy of rich content. Returns true when the clipboard holds it. */
42
+ export declare function copyRichContent(markdown: string, flavor?: CopyFlavor, options?: RichCopyOptions): Promise<boolean>;
@@ -0,0 +1,119 @@
1
+ import {
2
+ createBrowserTransport,
3
+ createDraft,
4
+ capture,
5
+ formatAdapter,
6
+ normalizeTransferJson,
7
+ serialize
8
+ } from "@ai-matrx/alchemy/operate";
9
+ import { copyRich, copyText } from "@ai-matrx/kit/clipboard";
10
+ import { showManualCopy } from "../host/manual-copy.js";
11
+ import { toast } from "../host/toast.js";
12
+ import { getSessionKnob } from "../host/session-knob.js";
13
+ import { markdownToReadableText } from "./markdown-readable-text.js";
14
+ import { formattedCopyHtml, removeThinkingContent } from "./markdown-copy-html.js";
15
+ async function copyContent(content, options = {}) {
16
+ let capturedText;
17
+ try {
18
+ let payload;
19
+ if (typeof content === "string") {
20
+ const text = options.includeThinking ? content : removeThinkingContent(content);
21
+ payload = { kind: options.isMarkdown ? "markdown" : "text", text };
22
+ if (options.formatJson !== false) {
23
+ let parsed;
24
+ try {
25
+ parsed = JSON.parse(text);
26
+ } catch {
27
+ parsed = void 0;
28
+ }
29
+ if (parsed !== void 0)
30
+ payload = { kind: "json", value: normalizeTransferJson(parsed) };
31
+ }
32
+ } else {
33
+ payload = { kind: "json", value: normalizeTransferJson(content) };
34
+ }
35
+ const signal = new AbortController().signal;
36
+ const { snapshot } = await capture(payload, signal);
37
+ const draft = createDraft(snapshot);
38
+ const rich = payload.kind === "markdown" && (options.formatForGoogleDocs || options.formatForWordPress);
39
+ const artifact = rich ? await (await formatAdapter("rich-html").load()).build(
40
+ draft,
41
+ { profile: options.formatForGoogleDocs ? "google-docs" : "generic" },
42
+ signal
43
+ ) : serialize(
44
+ draft,
45
+ payload.kind === "json" ? options.formatJson === false ? "compact-json" : "json" : "plain"
46
+ );
47
+ capturedText = artifact.plainText;
48
+ if (options.showHtmlPreview) {
49
+ if (!options.onShowHtmlPreview || !artifact.html)
50
+ throw new Error(
51
+ "HTML preview requires a formatted Markdown source and a preview callback."
52
+ );
53
+ const previewDelivered = await options.onShowHtmlPreview(artifact.html);
54
+ if (previewDelivered === false) return false;
55
+ options.onSuccess?.();
56
+ return true;
57
+ }
58
+ const outcome = await createBrowserTransport().copy(artifact, signal);
59
+ if (outcome.status === "success") {
60
+ options.onSuccess?.();
61
+ return true;
62
+ }
63
+ if (outcome.status === "degraded") {
64
+ toast.info(`Copied as plain text: ${outcome.reason}`);
65
+ return false;
66
+ }
67
+ if (outcome.status === "cancelled") return false;
68
+ throw new Error(outcome.message);
69
+ } catch (error) {
70
+ if (capturedText !== void 0) {
71
+ showManualCopy({ text: capturedText });
72
+ return false;
73
+ }
74
+ options.onError?.(error);
75
+ if (!options.onError)
76
+ toast.error(
77
+ error instanceof Error ? error.message : "Could not copy content"
78
+ );
79
+ return false;
80
+ }
81
+ }
82
+ const COPY_DEFAULT_FLAVOR_KNOB = { feature: "copy", key: "default_flavor" };
83
+ function defaultCopyFlavor() {
84
+ return getSessionKnob(COPY_DEFAULT_FLAVOR_KNOB) === "text" ? "text" : "markdown";
85
+ }
86
+ const FLAVOR_TOAST = {
87
+ default: "Copied",
88
+ markdown: "Markdown copied",
89
+ text: "Text copied"
90
+ };
91
+ function richCopyPlainText(markdown, flavor, defaultFlavor = "markdown") {
92
+ const plainFlavor = flavor === "default" ? defaultFlavor : flavor;
93
+ return plainFlavor === "text" ? markdownToReadableText(markdown) : markdown;
94
+ }
95
+ async function writeClipboardFlavors(plain, html) {
96
+ const landed = html === void 0 ? await copyText(plain) : await copyRich(
97
+ { text: plain, html },
98
+ { onDegraded: (reason) => toast.info(`Copied without formatting: ${reason}.`) }
99
+ );
100
+ if (!landed) showManualCopy({ text: plain });
101
+ return landed;
102
+ }
103
+ async function copyRichContent(markdown, flavor = "default", options = {}) {
104
+ const source = options.includeThinking ? markdown : removeThinkingContent(markdown);
105
+ const plain = richCopyPlainText(source, flavor, defaultCopyFlavor());
106
+ const ok = await writeClipboardFlavors(plain, flavor === "default" ? formattedCopyHtml(source) : void 0);
107
+ const label = options.toast === void 0 ? FLAVOR_TOAST[flavor] : options.toast;
108
+ if (ok && label) toast.success(label);
109
+ return ok;
110
+ }
111
+ export {
112
+ COPY_DEFAULT_FLAVOR_KNOB,
113
+ copyContent,
114
+ copyRichContent,
115
+ defaultCopyFlavor,
116
+ markdownToReadableText,
117
+ richCopyPlainText,
118
+ writeClipboardFlavors
119
+ };
@@ -0,0 +1,3 @@
1
+ export { removeThinkingContent } from "@ai-matrx/print/markdown";
2
+ /** The formatted HTML for a copy (loaded at click time), or `undefined` when this host writes plain text only. */
3
+ export declare function formattedCopyHtml(markdown: string): Promise<string> | undefined;
@@ -0,0 +1,8 @@
1
+ import { removeThinkingContent } from "@ai-matrx/print/markdown";
2
+ function formattedCopyHtml(markdown) {
3
+ return import("@ai-matrx/print/markdown").then(({ markdownToHtml }) => markdownToHtml(markdown));
4
+ }
5
+ export {
6
+ formattedCopyHtml,
7
+ removeThinkingContent
8
+ };
@@ -0,0 +1,4 @@
1
+ /** Inline markup → its words. Code spans are kept as their text. */
2
+ export declare function readableInline(line: string): string;
3
+ /** Markdown → readable plain text (envelopes unwrapped first). */
4
+ export declare function markdownToReadableText(markdown: string): string;
@@ -0,0 +1,62 @@
1
+ import { unwrapKindEnvelopes } from "@ai-matrx/content-ir/source";
2
+ import {
3
+ findTableEnd,
4
+ rowCells,
5
+ tableStartsAt,
6
+ unescapeCellPipes
7
+ } from "../display/markdown-classification/processors/utils/gfm-table-lines.js";
8
+ const FENCE = /^( {0,3})(`{3,}|~{3,})/;
9
+ function readableInline(line) {
10
+ const codes = [];
11
+ let out = line.replace(/(`+)([\s\S]*?[^`])\1(?!`)/g, (_m, _ticks, body) => {
12
+ codes.push(body.replace(/^ (.*) $/, "$1"));
13
+ return `\uE000${codes.length - 1}\uE000`;
14
+ });
15
+ out = out.replace(/!\[([^\]]*)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, (_m, alt, url) => alt ? `${alt} (${url})` : url).replace(/\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g, (_m, text, url) => {
16
+ const bare = url.replace(/^mailto:/, "");
17
+ return text === url || text === bare ? bare : `${text} (${bare})`;
18
+ }).replace(/<((?:https?:\/\/|mailto:)[^>\s]+)>/g, (_m, url) => url.replace(/^mailto:/, "")).replace(/(\*\*\*|___)(?=\S)([\s\S]*?\S)\1/g, "$2").replace(/(\*\*|__)(?=\S)([\s\S]*?\S)\1/g, "$2").replace(/~~(?=\S)([\s\S]*?\S)~~/g, "$1").replace(/(^|[^\w*])\*(?=\S)([^*]*?\S)\*(?!\w)/g, "$1$2").replace(/(^|[^\w])_(?=\S)([^_]*?\S)_(?!\w)/g, "$1$2").replace(/ {2,}$|\\$/g, "").replace(/\\([!-/:-@[-`{-~])/g, "$1");
19
+ return out.replace(/\uE000(\d+)\uE000/g, (_m, i) => codes[Number(i)] ?? "");
20
+ }
21
+ function markdownToReadableText(markdown) {
22
+ const lines = unwrapKindEnvelopes(markdown).replace(/\r\n?/g, "\n").split("\n");
23
+ const out = [];
24
+ for (let i = 0; i < lines.length; i += 1) {
25
+ 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;
33
+ }
34
+ i = j;
35
+ continue;
36
+ }
37
+ if (tableStartsAt(lines, i)) {
38
+ const end = findTableEnd(lines, i);
39
+ for (let j = i; j < end; j += 1) {
40
+ if (j === i + 1) continue;
41
+ out.push(rowCells(lines[j]).map((c) => readableInline(unescapeCellPipes(c).trim())).join(" "));
42
+ }
43
+ i = end - 1;
44
+ continue;
45
+ }
46
+ if (/^ {0,3}([-*_])( *\1){2,} *$/.test(line)) {
47
+ out.push("");
48
+ continue;
49
+ }
50
+ if (/^ {0,3}(=+|-+) *$/.test(line) && out.length && out[out.length - 1].trim()) continue;
51
+ let rest = line;
52
+ rest = rest.replace(/^ {0,3}(?:> ?)+/, "");
53
+ rest = rest.replace(/^ {0,3}#{1,6}[ \t]+/, "").replace(/[ \t]+#+[ \t]*$/, "");
54
+ rest = rest.replace(/^(\s*)[-*+][ \t]+\[[ ]\][ \t]+/, "$1\u2610 ").replace(/^(\s*)[-*+][ \t]+\[[xX]\][ \t]+/, "$1\u2611 ").replace(/^(\s*)[-*+][ \t]+/, "$1\u2022 ").replace(/^(\s*)(\d{1,9})[.)][ \t]+/, "$1$2. ");
55
+ out.push(readableInline(rest));
56
+ }
57
+ return out.join("\n").replace(/\n{3,}/g, "\n\n").trim();
58
+ }
59
+ export {
60
+ markdownToReadableText,
61
+ readableInline
62
+ };
@@ -69,8 +69,10 @@ const BUILTIN_BLOCK_COMPONENTS = {
69
69
  const BUILTIN_LOADING_COMPONENTS = {
70
70
  DiagramLoading: () => /* @__PURE__ */ jsx(LazyBlockWrapper, { children: /* @__PURE__ */ jsx(DiagramLoadingVisualization, {}) })
71
71
  };
72
+ import { ensureHostBlockRegistrations } from "../../../host/registry.js";
72
73
  const REGISTRY_KEY = /* @__PURE__ */ Symbol.for("ai-matrx.rich-content.block-components");
73
74
  function registry() {
75
+ ensureHostBlockRegistrations();
74
76
  const g = globalThis;
75
77
  return g[REGISTRY_KEY] ??= { blocks: {}, loading: {} };
76
78
  }
@@ -472,6 +472,7 @@ const BLOCK_DISPATCH_CLASSIFICATION = {
472
472
  const DISPATCH_MAP = new Map(
473
473
  Object.entries(BLOCK_DISPATCH)
474
474
  );
475
+ import { ensureHostBlockRegistrations } from "../../../host/registry.js";
475
476
  const REGISTERED_KEY = /* @__PURE__ */ Symbol.for("ai-matrx.rich-content.block-dispatch");
476
477
  function registered() {
477
478
  const g = globalThis;
@@ -481,6 +482,7 @@ function registerBlockDispatch(entries) {
481
482
  for (const [type, fn] of Object.entries(entries)) if (fn) registered().set(type, fn);
482
483
  }
483
484
  function resolveBlockDispatch(type) {
485
+ ensureHostBlockRegistrations();
484
486
  return registered().get(type) ?? DISPATCH_MAP.get(type) ?? null;
485
487
  }
486
488
  export {
@@ -32,6 +32,21 @@ export interface RichContentAppBindings {
32
32
  useHostUser: HostFn;
33
33
  useIsAdminDebugger: HostFn;
34
34
  useIsAuthenticated: HostFn;
35
+ useHostDispatch: HostFn;
36
+ useHostGetState: HostFn;
37
+ useIsSuperAdmin: HostFn;
38
+ useActiveOrganizationId: HostFn;
39
+ holdDeliberateIntent: HostFn;
40
+ useAlchemyDisclosure: HostFn;
41
+ useRegistryMenuSource: HostFn;
42
+ sameContentSource: HostFn;
43
+ contentSourceKey: HostFn;
44
+ openContextMenuForElement: HostFn;
45
+ convertOriginForSource: HostFn;
46
+ useDocumentDialogsHost: HostFn;
47
+ RecordAnnotations: HostComponent;
48
+ annotationRecordOf: HostFn;
49
+ recordKeyOf: HostFn;
35
50
  useMermaidPreferences: HostFn;
36
51
  useSetMermaidPreferences: HostFn;
37
52
  useImageKnob: HostFn;
@@ -128,6 +143,20 @@ export declare const KindInstanceRender: HostComponent;
128
143
  export declare const KindRecordChrome: HostComponent;
129
144
  export declare const kindHasRecordChrome: HostFn;
130
145
  export declare const KindFixItBar: HostComponent;
146
+ export declare const useHostDispatch: HostFn;
147
+ export declare const useHostGetState: HostFn;
148
+ export declare const useIsSuperAdmin: HostFn;
149
+ export declare const useActiveOrganizationId: HostFn;
150
+ export declare const useAlchemyDisclosure: HostFn;
151
+ export declare const useRegistryMenuSource: HostFn;
152
+ export declare const sameContentSource: HostFn;
153
+ export declare const contentSourceKey: HostFn;
154
+ export declare const openContextMenuForElement: HostFn;
155
+ export declare const convertOriginForSource: HostFn;
156
+ export declare const useDocumentDialogsHost: HostFn;
157
+ export declare const RecordAnnotations: HostComponent;
158
+ export declare const annotationRecordOf: HostFn;
159
+ export declare const recordKeyOf: HostFn;
131
160
  export declare const MarkdownStream: HostComponent;
132
161
  export declare const CitationMarkerInline: HostComponent;
133
162
  export declare const CopyButtons: HostComponent;
@@ -142,6 +171,7 @@ export declare const IconInputWithValidation: HostComponent;
142
171
  export declare const LocatedTableViewer: HostComponent;
143
172
  export declare const OpenDestinationDialog: HostComponent;
144
173
  export declare function hostHtmlPageService(): unknown;
174
+ export declare const holdDeliberateIntent: <T>(work: () => T | Promise<T>) => Promise<T>;
145
175
  export declare const ensureOrganizationContext: HostFn;
146
176
  export declare const isOrganizationSelectionCancelled: HostFn;
147
177
  export declare const loadExportTargets: HostFn;
@@ -68,6 +68,24 @@ const KindInstanceRender = component("KindInstanceRender", ValueFloor, "kind ins
68
68
  const KindRecordChrome = component("KindRecordChrome", Passthrough, "kind records show without record chrome");
69
69
  const kindHasRecordChrome = fn("kindHasRecordChrome", () => false, "kind records show without record chrome");
70
70
  const KindFixItBar = component("KindFixItBar", null, "no fix-it bar on broken kinds");
71
+ const useHostDispatch = fn("useHostDispatch", () => (action) => action, "actions dispatch nowhere");
72
+ const useHostGetState = fn("useHostGetState", () => () => ({}), "actions read an empty host state");
73
+ const useIsSuperAdmin = fn("useIsSuperAdmin", () => false, "admin-only actions are absent");
74
+ const useActiveOrganizationId = fn("useActiveOrganizationId", () => null, "no organization is active");
75
+ const useAlchemyDisclosure = fn("useAlchemyDisclosure", noop, "no Alchemy disclosure");
76
+ const useRegistryMenuSource = fn("useRegistryMenuSource", () => null, "no menu carries a content source");
77
+ const sameContentSource = fn(
78
+ "sameContentSource",
79
+ (a, b) => Boolean(a && b && JSON.stringify(a) === JSON.stringify(b)),
80
+ "content sources compare by value"
81
+ );
82
+ const contentSourceKey = fn("contentSourceKey", (s) => JSON.stringify(s), "content sources key by value");
83
+ const openContextMenuForElement = fn("openContextMenuForElement", noop, "no context menu opens");
84
+ const convertOriginForSource = fn("convertOriginForSource", () => null, "convert is absent");
85
+ const useDocumentDialogsHost = fn("useDocumentDialogsHost", () => ({ callbacks: {} }), "document dialogs are absent");
86
+ const RecordAnnotations = component("RecordAnnotations", Passthrough, "no reading set on saved records");
87
+ const annotationRecordOf = fn("annotationRecordOf", () => null, "no saved record is known");
88
+ const recordKeyOf = fn("recordKeyOf", (r) => `${r.token}:${r.id}`, "records key as token:id");
71
89
  const MarkdownStream = component("MarkdownStream", null, "the full renderer is not registered");
72
90
  const CitationMarkerInline = component("CitationMarkerInline", TextOnly, "citation markers show as text");
73
91
  const CopyButtons = component("CopyButtons", null, "no copy menu on rendered content");
@@ -84,6 +102,11 @@ const OpenDestinationDialog = component("OpenDestinationDialog", null, "no desti
84
102
  function hostHtmlPageService() {
85
103
  return binding("HTMLPageService") ?? null;
86
104
  }
105
+ const holdDeliberateIntent = fn(
106
+ "holdDeliberateIntent",
107
+ (work) => Promise.resolve().then(work),
108
+ "actions run without an intent hold"
109
+ );
87
110
  const ensureOrganizationContext = fn("ensureOrganizationContext", async () => null, "no organization can be chosen");
88
111
  const isOrganizationSelectionCancelled = fn("isOrganizationSelectionCancelled", () => false, "no organization can be chosen");
89
112
  const loadExportTargets = fn("loadExportTargets", async () => null, "no workbook export");
@@ -121,12 +144,17 @@ export {
121
144
  NonEditableContextMenu,
122
145
  OpenDestinationDialog,
123
146
  RawJsonExplorer,
147
+ RecordAnnotations,
124
148
  StructuredValueView,
149
+ annotationRecordOf,
125
150
  announceProposedGoogleWrite,
151
+ contentSourceKey,
152
+ convertOriginForSource,
126
153
  createMermaidEditorScope,
127
154
  ensureOrganizationContext,
128
155
  getArtifactDef,
129
156
  hasArtifactRenderer,
157
+ holdDeliberateIntent,
130
158
  hostCodeEditorAgents,
131
159
  hostHtmlPageService,
132
160
  hostMermaidEditorManifest,
@@ -136,19 +164,28 @@ export {
136
164
  kindHasRecordChrome,
137
165
  loadExportTargets,
138
166
  loadSendToGoogle,
167
+ openContextMenuForElement,
168
+ recordKeyOf,
139
169
  reportCanvasOpenDrop,
140
170
  resolveArtifactDef,
171
+ sameContentSource,
141
172
  setImageKnobMapEntry,
173
+ useActiveOrganizationId,
142
174
  useAdvancedMenu,
175
+ useAlchemyDisclosure,
143
176
  useCanvas,
144
177
  useCanvasOpenGuard,
145
178
  useDiagramAgents,
179
+ useDocumentDialogsHost,
146
180
  useHideReasoning,
147
181
  useHideToolResults,
182
+ useHostDispatch,
183
+ useHostGetState,
148
184
  useHostUser,
149
185
  useImageKnob,
150
186
  useIsAdminDebugger,
151
187
  useIsAuthenticated,
188
+ useIsSuperAdmin,
152
189
  useMachineFramesVisible,
153
190
  useMermaidPreferences,
154
191
  useOpenArtifactInCanvas,
@@ -156,6 +193,7 @@ export {
156
193
  useOpenOverlay,
157
194
  useOpenSmartCodeEditorWindow,
158
195
  useOpenTableViewerWindow,
196
+ useRegistryMenuSource,
159
197
  useSaveAndOpenInCodeEditor,
160
198
  useSetMermaidPreferences,
161
199
  useThemeMode
@@ -0,0 +1,16 @@
1
+ /**
2
+ * What a feedback report points at (matrx-frontend: features/overlays/openers/feedbackDialog
3
+ * `FeedbackSubject`). The engine only builds the text-passage subject; the host owns the rest.
4
+ */
5
+ export interface TextPassageFeedbackSubject {
6
+ kind: "text_passage";
7
+ sourceToken: string;
8
+ sourceId: string;
9
+ sourceTitle: string;
10
+ quote: string;
11
+ anchor?: unknown;
12
+ [extra: string]: unknown;
13
+ }
14
+ export type FeedbackSubject = TextPassageFeedbackSubject | ({
15
+ kind: string;
16
+ } & Record<string, unknown>);
File without changes
@@ -0,0 +1,7 @@
1
+ export interface ManualCopyOptions {
2
+ /** The text the person needs on their clipboard. */
3
+ text: string;
4
+ title?: string;
5
+ description?: string;
6
+ }
7
+ export declare function showManualCopy(opts: ManualCopyOptions): void;
@@ -0,0 +1,11 @@
1
+ import { announceBareHost, hostCapability } from "./registry.js";
2
+ function showManualCopy(opts) {
3
+ if (!opts.text) return;
4
+ const show = hostCapability("showManualCopy");
5
+ if (show) return show(opts);
6
+ announceBareHost("showManualCopy", "a refused copy is written to the console");
7
+ console.warn("[rich-content] the clipboard refused this copy; the text follows:\n" + opts.text);
8
+ }
9
+ export {
10
+ showManualCopy
11
+ };
@@ -25,3 +25,5 @@ export declare function announceBareHost(capability: string, degraded: string):
25
25
  export declare const BARE_HOST_ATTR: {
26
26
  readonly "data-rich-content-host": "bare";
27
27
  };
28
+ /** Run the host's `ensureBlockRegistrations` once (see RichContentHost). */
29
+ export declare function ensureHostBlockRegistrations(): void;
@@ -44,10 +44,20 @@ function announceBareHost(capability, degraded) {
44
44
  console.warn(`[@ai-matrx/rich-content] The host registered no "${capability}", so ${degraded}.`);
45
45
  }
46
46
  const BARE_HOST_ATTR = { "data-rich-content-host": "bare" };
47
+ const ENSURED_KEY = /* @__PURE__ */ Symbol.for("ai-matrx.rich-content.block-registrations-ensured");
48
+ function ensureHostBlockRegistrations() {
49
+ const g = globalThis;
50
+ if (g[ENSURED_KEY]) return;
51
+ const ensure = hostCapability("ensureBlockRegistrations");
52
+ if (!ensure) return;
53
+ g[ENSURED_KEY] = true;
54
+ ensure();
55
+ }
47
56
  export {
48
57
  BARE_HOST_ATTR,
49
58
  announceBareHost,
50
59
  configureRichContent,
60
+ ensureHostBlockRegistrations,
51
61
  hostCapability,
52
62
  resetRichContentHost,
53
63
  richContentHostVersion,
@@ -0,0 +1,5 @@
1
+ export interface KnobRef {
2
+ feature: string;
3
+ key: string;
4
+ }
5
+ export declare function getSessionKnob(knob: KnobRef): unknown;
@@ -0,0 +1,7 @@
1
+ import { hostCapability } from "./registry.js";
2
+ function getSessionKnob(knob) {
3
+ return hostCapability("readSessionKnob")?.(knob);
4
+ }
5
+ export {
6
+ getSessionKnob
7
+ };
@@ -149,6 +149,30 @@ export interface RichContentHost {
149
149
  splitterEnvelopes: RichContentSplitterEnvelopes;
150
150
  /** A hook returning the host's "save these rows as a table" opener, or null. Default: no opener (the button is absent). */
151
151
  useOpenSaveToTable: () => ((options: Record<string, unknown>) => unknown) | null;
152
+ /**
153
+ * Loads the host's own block registrations on first use (matrx-frontend's Jest setup requires its
154
+ * registration module here, so suites that mock a block still see the mock). Called once, on the
155
+ * first block-registry or dispatch lookup. Default: none (registrations arrive by import).
156
+ */
157
+ ensureBlockRegistrations: () => void;
158
+ /** Loads the host's rich-document registrations (handlers, source adapters) on first registry read. */
159
+ ensureRichDocumentRegistrations: () => void;
160
+ /** The manual-copy dialog for a copy the clipboard refused. Default: the console. */
161
+ showManualCopy: (opts: {
162
+ text: string;
163
+ title?: string;
164
+ description?: string;
165
+ }) => void;
166
+ /** A knob's effective value for the signed-in person, synchronously. Default: undefined. */
167
+ readSessionKnob: (knob: {
168
+ feature: string;
169
+ key: string;
170
+ }) => unknown;
171
+ /**
172
+ * The editor's HTML → markdown converter (matrx-frontend: @ai-matrx/rich-editor core), loaded at
173
+ * copy time. Default: none — a copied selection keeps its shape text (tables and lists).
174
+ */
175
+ loadHtmlToMarkdown: () => Promise<(html: string) => string>;
152
176
  /** Loads mermaid (`() => import("mermaid").then((m) => m.default)`). Default: none — diagrams show their source. */
153
177
  loadMermaid: () => Promise<unknown>;
154
178
  /** Loads the ELK layout loaders (`() => import("@mermaid-js/layout-elk").then((m) => m.default)`). Default: dagre only. */
@@ -0,0 +1,29 @@
1
+ import * as React from "react";
2
+ import { NonEditableContextMenu } from "../host/app-bindings.js";
3
+ import type { ContentSource, RichDocumentAction, RichDocumentActionId, RichDocumentActionsProp } from "./types.js";
4
+ export interface RegistryContextMenuProps {
5
+ content: string;
6
+ source: ContentSource;
7
+ actions?: RichDocumentActionsProp;
8
+ /** Context-menu-only additions / removals. */
9
+ extra?: RichDocumentAction[];
10
+ exclude?: (RichDocumentActionId | string)[];
11
+ /** Yield to the native menu (e.g. while the content streams). */
12
+ suppressed?: boolean;
13
+ sourceFeature?: React.ComponentProps<typeof NonEditableContextMenu>["sourceFeature"];
14
+ surfaceName?: string;
15
+ /**
16
+ * The surface's declared values (e.g. `conversation_id` for the assistant
17
+ * message surface) — merged into the menu scope so bound agents and
18
+ * shortcuts receive them.
19
+ */
20
+ contextData?: Record<string, unknown>;
21
+ /**
22
+ * Which agent-menu placements show (e.g. `{ "content-block": "hide" }` over
23
+ * a rendered answer, where a block could only be copied, never inserted).
24
+ */
25
+ placementMode?: React.ComponentProps<typeof NonEditableContextMenu>["placementMode"];
26
+ children: React.ReactNode;
27
+ }
28
+ export declare function RegistryContextMenu(props: RegistryContextMenuProps): React.ReactElement;
29
+ export default RegistryContextMenu;
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { NonEditableContextMenu } from "../host/app-bindings.js";
4
+ import { useActionSurfaceProvider } from "./runtime/useActionSurfaceProvider.js";
5
+ function RegistryContextMenu(props) {
6
+ const { content, source, actions, extra, exclude, suppressed, children } = props;
7
+ const { ctx } = useActionSurfaceProvider({
8
+ content,
9
+ source,
10
+ actions,
11
+ actionsVariant: "none"
12
+ });
13
+ const excludes = [...actions?.exclude ?? [], ...exclude ?? []];
14
+ return /* @__PURE__ */ jsx(
15
+ NonEditableContextMenu,
16
+ {
17
+ sourceFeature: props.sourceFeature ?? "documents",
18
+ surfaceName: props.surfaceName,
19
+ suppressed,
20
+ contentSource: source,
21
+ contextData: { ...props.contextData, content: ctx.content },
22
+ placementMode: props.placementMode,
23
+ excludedRichActions: excludes,
24
+ richDocCtxExtras: {
25
+ callbacks: actions?.callbacks,
26
+ extensions: actions?.extensions,
27
+ metadata: actions?.metadata ?? null,
28
+ isCreator: actions?.isCreator ?? false,
29
+ surfaceKey: actions?.surfaceKey ?? null
30
+ },
31
+ extraRichActions: [...actions?.extra ?? [], ...extra ?? []],
32
+ children
33
+ }
34
+ );
35
+ }
36
+ var RegistryContextMenu_default = RegistryContextMenu;
37
+ export {
38
+ RegistryContextMenu,
39
+ RegistryContextMenu_default as default
40
+ };