@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.
- package/dist/copy/copy-commands.d.ts +42 -0
- package/dist/copy/copy-commands.js +119 -0
- package/dist/copy/markdown-copy-html.d.ts +3 -0
- package/dist/copy/markdown-copy-html.js +8 -0
- package/dist/copy/markdown-readable-text.d.ts +4 -0
- package/dist/copy/markdown-readable-text.js +62 -0
- package/dist/display/chat-markdown/block-registry/BlockComponentRegistry.js +2 -0
- package/dist/display/chat-markdown/block-registry/block-dispatch.js +2 -0
- package/dist/host/app-bindings.d.ts +30 -0
- package/dist/host/app-bindings.js +38 -0
- package/dist/host/feedback-subject.d.ts +16 -0
- package/dist/host/feedback-subject.js +0 -0
- package/dist/host/manual-copy.d.ts +7 -0
- package/dist/host/manual-copy.js +11 -0
- package/dist/host/registry.d.ts +2 -0
- package/dist/host/registry.js +10 -0
- package/dist/host/session-knob.d.ts +5 -0
- package/dist/host/session-knob.js +7 -0
- package/dist/host/types.d.ts +24 -0
- package/dist/rich-document/RegistryContextMenu.d.ts +29 -0
- package/dist/rich-document/RegistryContextMenu.js +40 -0
- package/dist/rich-document/RichDocument.d.ts +78 -0
- package/dist/rich-document/RichDocument.js +218 -0
- package/dist/rich-document/RichDocumentActionProvider.d.ts +18 -0
- package/dist/rich-document/RichDocumentActionProvider.js +18 -0
- package/dist/rich-document/RichDocumentActionSurface.d.ts +11 -0
- package/dist/rich-document/RichDocumentActionSurface.js +59 -0
- package/dist/rich-document/RichDocumentActions.d.ts +12 -0
- package/dist/rich-document/RichDocumentActions.js +29 -0
- package/dist/rich-document/actions/hostActions.d.ts +5 -0
- package/dist/rich-document/actions/hostActions.js +31 -0
- package/dist/rich-document/actions/labels.d.ts +9 -0
- package/dist/rich-document/actions/labels.js +8 -0
- package/dist/rich-document/actions/markdownTable.d.ts +9 -0
- package/dist/rich-document/actions/markdownTable.js +39 -0
- package/dist/rich-document/actions/provider.d.ts +58 -0
- package/dist/rich-document/actions/provider.js +245 -0
- package/dist/rich-document/actions/resumePendingAuthAction.d.ts +3 -0
- package/dist/rich-document/actions/resumePendingAuthAction.js +31 -0
- package/dist/rich-document/actions/sources/index.d.ts +9 -0
- package/dist/rich-document/actions/sources/index.js +22 -0
- package/dist/rich-document/actions/sources/raw.d.ts +4 -0
- package/dist/rich-document/actions/sources/raw.js +35 -0
- package/dist/rich-document/actions/useRichDocumentProvider.d.ts +1 -0
- package/dist/rich-document/actions/useRichDocumentProvider.js +13 -0
- package/dist/rich-document/host-types.d.ts +51 -0
- package/dist/rich-document/host-types.js +0 -0
- package/dist/rich-document/registrations.d.ts +1 -0
- package/dist/rich-document/registrations.js +13 -0
- package/dist/rich-document/review/applyTargets.d.ts +16 -0
- package/dist/rich-document/review/applyTargets.js +32 -0
- package/dist/rich-document/review/proposedEdit.d.ts +22 -0
- package/dist/rich-document/review/proposedEdit.js +48 -0
- package/dist/rich-document/review/protectedSpans.d.ts +14 -0
- package/dist/rich-document/review/protectedSpans.js +61 -0
- package/dist/rich-document/runtime/actionSurfacesStore.d.ts +30 -0
- package/dist/rich-document/runtime/actionSurfacesStore.js +79 -0
- package/dist/rich-document/runtime/contextMenuFor.d.ts +6 -0
- package/dist/rich-document/runtime/contextMenuFor.js +7 -0
- package/dist/rich-document/runtime/providerBridge.d.ts +20 -0
- package/dist/rich-document/runtime/providerBridge.js +23 -0
- package/dist/rich-document/runtime/useActionSurfaceProvider.d.ts +33 -0
- package/dist/rich-document/runtime/useActionSurfaceProvider.js +214 -0
- package/dist/rich-document/search/ContentFindControl.d.ts +8 -0
- package/dist/rich-document/search/ContentFindControl.js +46 -0
- package/dist/rich-document/search/RenderedFindBar.d.ts +8 -0
- package/dist/rich-document/search/RenderedFindBar.js +110 -0
- package/dist/rich-document/search/renderedFind.d.ts +1 -0
- package/dist/rich-document/search/renderedFind.js +1 -0
- package/dist/rich-document/types.d.ts +384 -0
- package/dist/rich-document/types.js +0 -0
- package/dist/rich-document/variants/ActionBar.d.ts +17 -0
- package/dist/rich-document/variants/ActionBar.js +48 -0
- package/dist/rich-document/variants/MenuVariant.d.ts +15 -0
- package/dist/rich-document/variants/MenuVariant.js +17 -0
- package/dist/rich-document/variants/MiniActionBar.d.ts +5 -0
- package/dist/rich-document/variants/MiniActionBar.js +11 -0
- package/dist/rich-document/variants/RegistryActionList.d.ts +17 -0
- package/dist/rich-document/variants/RegistryActionList.js +94 -0
- package/dist/rich-document/variants/RegistryActionMenu.d.ts +24 -0
- package/dist/rich-document/variants/RegistryActionMenu.js +74 -0
- package/dist/rich-document/variants/shared/AlchemyDocumentMenu.d.ts +7 -0
- package/dist/rich-document/variants/shared/AlchemyDocumentMenu.js +83 -0
- package/dist/rich-document/variants/shared/OpenOneMenuButton.d.ts +9 -0
- package/dist/rich-document/variants/shared/OpenOneMenuButton.js +70 -0
- package/dist/rich-document/variants/shared/StandaloneOneMenu.d.ts +8 -0
- package/dist/rich-document/variants/shared/StandaloneOneMenu.js +32 -0
- package/dist/rich-document/variants/shared/categories.d.ts +4 -0
- package/dist/rich-document/variants/shared/categories.js +31 -0
- package/dist/rich-document/variants/shared/iconMap.d.ts +2 -0
- package/dist/rich-document/variants/shared/iconMap.js +73 -0
- package/dist/rich-document/variants/shared/menuStructure.d.ts +81 -0
- package/dist/rich-document/variants/shared/menuStructure.js +271 -0
- package/dist/rich-document/variants/shared/runAction.d.ts +17 -0
- package/dist/rich-document/variants/shared/runAction.js +24 -0
- package/dist/selection-toolbar/SelectionToolbarFrame.d.ts +64 -0
- package/dist/selection-toolbar/SelectionToolbarFrame.js +191 -0
- package/dist/selection-toolbar/common-actions.d.ts +2 -0
- package/dist/selection-toolbar/common-actions.js +103 -0
- package/dist/selection-toolbar/selection-actions.d.ts +126 -0
- package/dist/selection-toolbar/selection-actions.js +240 -0
- package/dist/selection-toolbar/selection-copy.d.ts +19 -0
- package/dist/selection-toolbar/selection-copy.js +98 -0
- package/dist/selection-toolbar/selection-shape.d.ts +1 -0
- package/dist/selection-toolbar/selection-shape.js +15 -0
- package/dist/selection-toolbar/selection-zones.d.ts +90 -0
- package/dist/selection-toolbar/selection-zones.js +85 -0
- package/dist/selection-toolbar/textarea-caret.d.ts +8 -0
- package/dist/selection-toolbar/textarea-caret.js +69 -0
- package/dist/utils/alchemy-icon-keys.d.ts +18 -0
- package/dist/utils/alchemy-icon-keys.js +29 -0
- package/dist/utils/rendered-find.d.ts +9 -0
- package/dist/utils/rendered-find.js +68 -0
- package/package.json +23 -7
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { type SpecimenMode } from "../display/specimen/SpecimenContext.js";
|
|
3
|
+
import type { ContentSource, RichDocumentAction, RichDocumentActionId, RichDocumentActionsProp, RichDocumentActionsVariant, RichDocumentActionsPosition, RichDocumentActionsBehavior } from "./types.js";
|
|
4
|
+
import type { AnnotationRecord, ServerProcessedBlock } from "./host-types.js";
|
|
5
|
+
import type { TypedStreamEvent } from "../display/chat-markdown/types.js";
|
|
6
|
+
export interface RichDocumentProps {
|
|
7
|
+
content?: string;
|
|
8
|
+
events?: TypedStreamEvent[];
|
|
9
|
+
serverProcessedBlocks?: ServerProcessedBlock[];
|
|
10
|
+
taskId?: string;
|
|
11
|
+
requestId?: string;
|
|
12
|
+
turnId?: string;
|
|
13
|
+
conversationId?: string;
|
|
14
|
+
isStreamActive?: boolean;
|
|
15
|
+
/** Required. Use { type: "raw" } when the source is genuinely unknown. */
|
|
16
|
+
source: ContentSource;
|
|
17
|
+
renderer?: "basic" | "configurable" | "stream";
|
|
18
|
+
actions?: RichDocumentActionsProp;
|
|
19
|
+
actionsVariant?: RichDocumentActionsVariant;
|
|
20
|
+
/** Where the action surface sits. Default "below". */
|
|
21
|
+
actionsPosition?: RichDocumentActionsPosition;
|
|
22
|
+
/** Visibility. Default "always". */
|
|
23
|
+
actionsBehavior?: RichDocumentActionsBehavior;
|
|
24
|
+
/** Required when actionsVariant === "remote". */
|
|
25
|
+
actionsSurfaceId?: string;
|
|
26
|
+
/**
|
|
27
|
+
* DECLARE that this content is a specimen — generated work that is meant to
|
|
28
|
+
* look right and be wrong (the Bad Example probe, a wrong explanation, a
|
|
29
|
+
* decoy option). Suppresses every action surface, the right-click menu, and
|
|
30
|
+
* the actions inside the content itself (table export / workbook / Google
|
|
31
|
+
* Sheet / edit / open-in-window), and prints the specimen banner in their
|
|
32
|
+
* place. Pass `true` for the default wording, or override the two lines.
|
|
33
|
+
* See @ai-matrx/rich-content/display/specimen/SpecimenContext.tsx.
|
|
34
|
+
*/
|
|
35
|
+
specimen?: boolean | Partial<SpecimenMode>;
|
|
36
|
+
/**
|
|
37
|
+
* Enable a right-click context menu over the content. Lazy-loaded (the
|
|
38
|
+
* menu chunk only ships after the first right-click) and streaming-safe
|
|
39
|
+
* (yields to the native browser menu while isStreamActive). Pass an object
|
|
40
|
+
* to add context-menu-only `extra` actions or `exclude` specific ones.
|
|
41
|
+
* This is the extension point for future per-surface right-click actions.
|
|
42
|
+
*/
|
|
43
|
+
enableContextMenu?: boolean | {
|
|
44
|
+
extra?: RichDocumentAction[];
|
|
45
|
+
exclude?: (RichDocumentActionId | string)[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* The SAVED RECORD this content is, for the reading set (highlight, comment,
|
|
49
|
+
* suggest, link) and its Notes & comments dock. Derived from `source` for a
|
|
50
|
+
* note, a chat answer and a saved working document; pass it when the source
|
|
51
|
+
* does not say (the studio previewing a loaded document), or `null` to turn
|
|
52
|
+
* the reading set off. A read-only copy, a stream in flight and a specimen
|
|
53
|
+
* never get one.
|
|
54
|
+
*/
|
|
55
|
+
annotationRecord?: AnnotationRecord | null;
|
|
56
|
+
className?: string;
|
|
57
|
+
contentClassName?: string;
|
|
58
|
+
actionsClassName?: string;
|
|
59
|
+
onContentChange?: (newContent: string) => void;
|
|
60
|
+
applyLocalEdits?: boolean;
|
|
61
|
+
analysisData?: unknown;
|
|
62
|
+
messageId?: string;
|
|
63
|
+
allowFullScreenEditor?: boolean;
|
|
64
|
+
hideCopyButton?: boolean;
|
|
65
|
+
onError?: (error: string) => void;
|
|
66
|
+
onPhaseUpdate?: (phase: string) => void;
|
|
67
|
+
strictServerData?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* WHO WROTE this content — "ai" (a model), "other" (someone else) or "self"
|
|
70
|
+
* (the viewer). Decides whether remote images load by themselves
|
|
71
|
+
* (components/rich-content/prose/remote-image-policy.tsx, chair ruling
|
|
72
|
+
* 2026-09-25). Declare it at every call site — guard:
|
|
73
|
+
* components/rich-content/__tests__/image-policy-declared.test.ts.
|
|
74
|
+
*/
|
|
75
|
+
imagePolicy?: "self" | "other" | "ai" | "inherit";
|
|
76
|
+
}
|
|
77
|
+
export declare function RichDocument(props: RichDocumentProps): React.ReactElement;
|
|
78
|
+
export default RichDocument;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "@ai-matrx/design-system";
|
|
4
|
+
import { useActionSurfaceProvider } from "./runtime/useActionSurfaceProvider.js";
|
|
5
|
+
import { RegistryContextMenu } from "./RegistryContextMenu.js";
|
|
6
|
+
import { getSourceAdapter } from "./actions/sources/index.js";
|
|
7
|
+
import {
|
|
8
|
+
convertOriginForSource,
|
|
9
|
+
useDocumentDialogsHost,
|
|
10
|
+
RecordAnnotations,
|
|
11
|
+
annotationRecordOf,
|
|
12
|
+
recordKeyOf,
|
|
13
|
+
MarkdownStream
|
|
14
|
+
} from "../host/app-bindings.js";
|
|
15
|
+
import { ActionBar } from "./variants/ActionBar.js";
|
|
16
|
+
import { MiniActionBar } from "./variants/MiniActionBar.js";
|
|
17
|
+
import { MenuVariant } from "./variants/MenuVariant.js";
|
|
18
|
+
import { contextMenuFor } from "./runtime/contextMenuFor.js";
|
|
19
|
+
import {
|
|
20
|
+
SpecimenProvider,
|
|
21
|
+
SpecimenBanner,
|
|
22
|
+
resolveSpecimenMode
|
|
23
|
+
} from "../display/specimen/SpecimenContext.js";
|
|
24
|
+
function RichDocument(props) {
|
|
25
|
+
const {
|
|
26
|
+
source,
|
|
27
|
+
actions: actionsProp,
|
|
28
|
+
actionsVariant = "none",
|
|
29
|
+
actionsPosition = "below",
|
|
30
|
+
actionsBehavior = "always",
|
|
31
|
+
actionsSurfaceId,
|
|
32
|
+
specimen,
|
|
33
|
+
enableContextMenu,
|
|
34
|
+
className,
|
|
35
|
+
contentClassName,
|
|
36
|
+
actionsClassName,
|
|
37
|
+
content,
|
|
38
|
+
events,
|
|
39
|
+
serverProcessedBlocks,
|
|
40
|
+
taskId,
|
|
41
|
+
requestId,
|
|
42
|
+
turnId,
|
|
43
|
+
conversationId,
|
|
44
|
+
isStreamActive,
|
|
45
|
+
onContentChange,
|
|
46
|
+
applyLocalEdits,
|
|
47
|
+
analysisData,
|
|
48
|
+
messageId,
|
|
49
|
+
allowFullScreenEditor,
|
|
50
|
+
hideCopyButton,
|
|
51
|
+
onError,
|
|
52
|
+
onPhaseUpdate,
|
|
53
|
+
strictServerData,
|
|
54
|
+
imagePolicy,
|
|
55
|
+
annotationRecord
|
|
56
|
+
} = props;
|
|
57
|
+
const specimenMode = resolveSpecimenMode(specimen);
|
|
58
|
+
const effectiveActionsVariant = specimenMode ? "none" : actionsVariant;
|
|
59
|
+
const dialogsHost = useDocumentDialogsHost({
|
|
60
|
+
convertOrigin: convertOriginForSource(
|
|
61
|
+
source,
|
|
62
|
+
source.type === "note" ? "Note" : "Chat response"
|
|
63
|
+
),
|
|
64
|
+
text: content ?? "",
|
|
65
|
+
// Clean up / Help / Custom agent need somewhere to APPLY the result.
|
|
66
|
+
writable: !source.readOnly && Boolean(getSourceAdapter(source.type).edit) && !(actionsProp?.extensions?.type === "chat-message" && (actionsProp.extensions.contentIsStructuredRaw || actionsProp.extensions.role === "user")),
|
|
67
|
+
chatMessage: source.type === "chat-message" && !source.readOnly ? {
|
|
68
|
+
conversationId: source.conversationId,
|
|
69
|
+
messageId: source.messageId,
|
|
70
|
+
surfaceKey: actionsProp?.surfaceKey ?? null
|
|
71
|
+
} : null
|
|
72
|
+
});
|
|
73
|
+
const record = annotationRecord !== void 0 ? annotationRecord : source.readOnly ? null : annotationRecordOf(source);
|
|
74
|
+
const hostedActions = {
|
|
75
|
+
...actionsProp,
|
|
76
|
+
callbacks: {
|
|
77
|
+
...dialogsHost.callbacks,
|
|
78
|
+
// A host that names its record explicitly (the studio's loaded document
|
|
79
|
+
// rides a raw source) tells the ⋯ "Notes & comments" row which dock it is.
|
|
80
|
+
...record && annotationRecord !== void 0 ? { annotationRecordKey: () => recordKeyOf(record) } : {},
|
|
81
|
+
...actionsProp?.callbacks
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const { ctx, getCtx, resolvedActions, target } = useActionSurfaceProvider({
|
|
85
|
+
content,
|
|
86
|
+
source,
|
|
87
|
+
actions: hostedActions,
|
|
88
|
+
actionsVariant: effectiveActionsVariant,
|
|
89
|
+
actionsSurfaceId
|
|
90
|
+
});
|
|
91
|
+
let variantNode = null;
|
|
92
|
+
switch (effectiveActionsVariant) {
|
|
93
|
+
case "bar":
|
|
94
|
+
variantNode = /* @__PURE__ */ jsx(
|
|
95
|
+
ActionBar,
|
|
96
|
+
{
|
|
97
|
+
actions: resolvedActions,
|
|
98
|
+
getCtx,
|
|
99
|
+
target,
|
|
100
|
+
sourceId: ctx.instanceKey("alchemy")
|
|
101
|
+
}
|
|
102
|
+
);
|
|
103
|
+
break;
|
|
104
|
+
case "mini-bar":
|
|
105
|
+
variantNode = /* @__PURE__ */ jsx(
|
|
106
|
+
MiniActionBar,
|
|
107
|
+
{
|
|
108
|
+
actions: resolvedActions,
|
|
109
|
+
getCtx,
|
|
110
|
+
target,
|
|
111
|
+
sourceId: ctx.instanceKey("alchemy")
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
break;
|
|
115
|
+
case "menu":
|
|
116
|
+
case "icon-only":
|
|
117
|
+
variantNode = /* @__PURE__ */ jsx(MenuVariant, { getCtx, target });
|
|
118
|
+
break;
|
|
119
|
+
case "remote":
|
|
120
|
+
case "none":
|
|
121
|
+
default:
|
|
122
|
+
variantNode = null;
|
|
123
|
+
}
|
|
124
|
+
const isAbsolute = actionsPosition === "top-right" || actionsPosition === "top-left" || actionsPosition === "middle-right" || actionsPosition === "middle-left";
|
|
125
|
+
const absolutePositionClass = isAbsolute ? cn(
|
|
126
|
+
"absolute z-10",
|
|
127
|
+
actionsPosition === "top-right" && "right-1 top-1",
|
|
128
|
+
actionsPosition === "top-left" && "left-1 top-1",
|
|
129
|
+
actionsPosition === "middle-right" && "right-1 top-1/2 -translate-y-1/2",
|
|
130
|
+
actionsPosition === "middle-left" && "left-1 top-1/2 -translate-y-1/2"
|
|
131
|
+
) : null;
|
|
132
|
+
const hoverClass = actionsBehavior === "hover-only" ? "opacity-0 transition-opacity group-hover:opacity-100 focus-within:opacity-100" : null;
|
|
133
|
+
const inFlowClass = !isAbsolute ? actionsPosition === "above" ? "mb-1" : "mt-1" : null;
|
|
134
|
+
const actionsNode = variantNode ? /* @__PURE__ */ jsx(
|
|
135
|
+
"div",
|
|
136
|
+
{
|
|
137
|
+
className: cn(
|
|
138
|
+
absolutePositionClass,
|
|
139
|
+
hoverClass,
|
|
140
|
+
inFlowClass,
|
|
141
|
+
actionsClassName
|
|
142
|
+
),
|
|
143
|
+
children: variantNode
|
|
144
|
+
}
|
|
145
|
+
) : null;
|
|
146
|
+
const rootClassName = cn(
|
|
147
|
+
"rich-document",
|
|
148
|
+
(isAbsolute || actionsBehavior === "hover-only") && "relative group",
|
|
149
|
+
className
|
|
150
|
+
);
|
|
151
|
+
const annotationSource = record && !specimenMode && !isStreamActive && typeof content === "string" && content.trim() ? {
|
|
152
|
+
token: record.token,
|
|
153
|
+
id: record.id,
|
|
154
|
+
title: record.title ?? "",
|
|
155
|
+
body: content,
|
|
156
|
+
contentVersion: Math.max(1, record.contentVersion ?? 1),
|
|
157
|
+
...record.href ? { href: record.href } : {},
|
|
158
|
+
...record.conversationId ? { conversationId: record.conversationId } : {}
|
|
159
|
+
} : null;
|
|
160
|
+
const engineInner = /* @__PURE__ */ jsx(RecordAnnotations, { record: annotationSource, children: /* @__PURE__ */ jsx("div", { className: cn("rich-document__content", contentClassName), children: /* @__PURE__ */ jsx(
|
|
161
|
+
MarkdownStream,
|
|
162
|
+
{
|
|
163
|
+
imagePolicy,
|
|
164
|
+
content,
|
|
165
|
+
events,
|
|
166
|
+
serverProcessedBlocks,
|
|
167
|
+
taskId,
|
|
168
|
+
requestId,
|
|
169
|
+
turnId,
|
|
170
|
+
conversationId,
|
|
171
|
+
isStreamActive,
|
|
172
|
+
onContentChange,
|
|
173
|
+
applyLocalEdits,
|
|
174
|
+
analysisData,
|
|
175
|
+
messageId,
|
|
176
|
+
allowFullScreenEditor,
|
|
177
|
+
hideCopyButton,
|
|
178
|
+
onError,
|
|
179
|
+
onPhaseUpdate,
|
|
180
|
+
strictServerData
|
|
181
|
+
}
|
|
182
|
+
) }) });
|
|
183
|
+
let engine = engineInner;
|
|
184
|
+
const contextMenu = contextMenuFor(enableContextMenu, effectiveActionsVariant);
|
|
185
|
+
if (contextMenu && !specimenMode) {
|
|
186
|
+
const cmOptions = typeof contextMenu === "object" ? contextMenu : {};
|
|
187
|
+
engine = /* @__PURE__ */ jsx(
|
|
188
|
+
RegistryContextMenu,
|
|
189
|
+
{
|
|
190
|
+
content: content ?? "",
|
|
191
|
+
source,
|
|
192
|
+
actions: hostedActions,
|
|
193
|
+
extra: cmOptions.extra,
|
|
194
|
+
exclude: cmOptions.exclude,
|
|
195
|
+
suppressed: isStreamActive,
|
|
196
|
+
children: engineInner
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
if (specimenMode) {
|
|
201
|
+
return /* @__PURE__ */ jsxs("div", { className: rootClassName, children: [
|
|
202
|
+
/* @__PURE__ */ jsx(SpecimenBanner, { mode: specimenMode }),
|
|
203
|
+
/* @__PURE__ */ jsx(SpecimenProvider, { value: specimenMode, children: engine })
|
|
204
|
+
] });
|
|
205
|
+
}
|
|
206
|
+
return /* @__PURE__ */ jsxs("div", { className: rootClassName, children: [
|
|
207
|
+
isAbsolute ? actionsNode : null,
|
|
208
|
+
!isAbsolute && actionsPosition === "above" ? actionsNode : null,
|
|
209
|
+
engine,
|
|
210
|
+
!isAbsolute && actionsPosition !== "above" ? actionsNode : null,
|
|
211
|
+
dialogsHost.dialogs
|
|
212
|
+
] });
|
|
213
|
+
}
|
|
214
|
+
var RichDocument_default = RichDocument;
|
|
215
|
+
export {
|
|
216
|
+
RichDocument,
|
|
217
|
+
RichDocument_default as default
|
|
218
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ContentSource, RichDocumentActionsProp } from "./types.js";
|
|
3
|
+
export interface RichDocumentActionProviderProps {
|
|
4
|
+
/** Live content the actions operate on (re-read at click time via the bridge). */
|
|
5
|
+
content: string;
|
|
6
|
+
/** Source identity — drives which actions show + save-to-task parent linking. */
|
|
7
|
+
source: ContentSource;
|
|
8
|
+
/** The surface a <RichDocumentActionSurface/> consumes. Required. */
|
|
9
|
+
surfaceId: string;
|
|
10
|
+
/** Trim/extend the action set + supply host callbacks (same shape as RichDocument). */
|
|
11
|
+
actions?: RichDocumentActionsProp;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Registers a remote RichDocument action provider for `surfaceId`. Renders
|
|
15
|
+
* nothing. See the file header for when to reach for this over RichDocument.
|
|
16
|
+
*/
|
|
17
|
+
export declare function RichDocumentActionProvider(props: RichDocumentActionProviderProps): React.ReactElement | null;
|
|
18
|
+
export default RichDocumentActionProvider;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useActionSurfaceProvider } from "./runtime/useActionSurfaceProvider.js";
|
|
3
|
+
function RichDocumentActionProvider(props) {
|
|
4
|
+
const { content, source, surfaceId, actions } = props;
|
|
5
|
+
useActionSurfaceProvider({
|
|
6
|
+
content,
|
|
7
|
+
source,
|
|
8
|
+
actions,
|
|
9
|
+
actionsVariant: "remote",
|
|
10
|
+
actionsSurfaceId: surfaceId
|
|
11
|
+
});
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
var RichDocumentActionProvider_default = RichDocumentActionProvider;
|
|
15
|
+
export {
|
|
16
|
+
RichDocumentActionProvider,
|
|
17
|
+
RichDocumentActionProvider_default as default
|
|
18
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface RichDocumentActionSurfaceProps {
|
|
3
|
+
surfaceId: string;
|
|
4
|
+
/** Which inline variant to render. Defaults to "bar". */
|
|
5
|
+
variant?: "bar" | "mini-bar" | "menu";
|
|
6
|
+
className?: string;
|
|
7
|
+
/** Rendered when no provider is currently registered. */
|
|
8
|
+
fallback?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
export declare function RichDocumentActionSurface(props: RichDocumentActionSurfaceProps): React.ReactElement | null;
|
|
11
|
+
export default RichDocumentActionSurface;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "@ai-matrx/design-system";
|
|
4
|
+
import { useTopProvider } from "./runtime/actionSurfacesStore.js";
|
|
5
|
+
import { getBridge } from "./runtime/providerBridge.js";
|
|
6
|
+
import { ActionBar } from "./variants/ActionBar.js";
|
|
7
|
+
import { MiniActionBar } from "./variants/MiniActionBar.js";
|
|
8
|
+
import { MenuVariant } from "./variants/MenuVariant.js";
|
|
9
|
+
function RichDocumentActionSurface(props) {
|
|
10
|
+
const { surfaceId, variant = "bar", className, fallback = null } = props;
|
|
11
|
+
const provider = useTopProvider(surfaceId);
|
|
12
|
+
if (!provider) {
|
|
13
|
+
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
14
|
+
}
|
|
15
|
+
const bridge = getBridge(provider.providerId);
|
|
16
|
+
if (!bridge) {
|
|
17
|
+
return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
18
|
+
}
|
|
19
|
+
switch (variant) {
|
|
20
|
+
case "bar":
|
|
21
|
+
return /* @__PURE__ */ jsx(
|
|
22
|
+
ActionBar,
|
|
23
|
+
{
|
|
24
|
+
actions: bridge.resolvedActions,
|
|
25
|
+
getCtx: bridge.getCtx,
|
|
26
|
+
target: bridge.target,
|
|
27
|
+
sourceId: provider.contentSourceId,
|
|
28
|
+
className
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
case "mini-bar":
|
|
32
|
+
return /* @__PURE__ */ jsx(
|
|
33
|
+
MiniActionBar,
|
|
34
|
+
{
|
|
35
|
+
actions: bridge.resolvedActions,
|
|
36
|
+
getCtx: bridge.getCtx,
|
|
37
|
+
target: bridge.target,
|
|
38
|
+
sourceId: provider.contentSourceId,
|
|
39
|
+
className
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
case "menu":
|
|
43
|
+
return /* @__PURE__ */ jsx(
|
|
44
|
+
MenuVariant,
|
|
45
|
+
{
|
|
46
|
+
target: bridge.target,
|
|
47
|
+
getCtx: bridge.getCtx,
|
|
48
|
+
className: cn(className)
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
default:
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
var RichDocumentActionSurface_default = RichDocumentActionSurface;
|
|
56
|
+
export {
|
|
57
|
+
RichDocumentActionSurface,
|
|
58
|
+
RichDocumentActionSurface_default as default
|
|
59
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { ContentSource, RichDocumentActionsProp } from "./types.js";
|
|
3
|
+
export interface RichDocumentActionsProps {
|
|
4
|
+
content: string;
|
|
5
|
+
source: ContentSource;
|
|
6
|
+
actions?: RichDocumentActionsProp;
|
|
7
|
+
className?: string;
|
|
8
|
+
/** Hide the ⋯ overflow menu (the primary row still renders). */
|
|
9
|
+
hideOverflow?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function RichDocumentActions(props: RichDocumentActionsProps): React.ReactElement;
|
|
12
|
+
export default RichDocumentActions;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useActionSurfaceProvider } from "./runtime/useActionSurfaceProvider.js";
|
|
4
|
+
import { ActionBar } from "./variants/ActionBar.js";
|
|
5
|
+
function RichDocumentActions(props) {
|
|
6
|
+
const { content, source, actions, className, hideOverflow } = props;
|
|
7
|
+
const { ctx, getCtx, resolvedActions, target } = useActionSurfaceProvider({
|
|
8
|
+
content,
|
|
9
|
+
source,
|
|
10
|
+
actions,
|
|
11
|
+
actionsVariant: "bar"
|
|
12
|
+
});
|
|
13
|
+
return /* @__PURE__ */ jsx(
|
|
14
|
+
ActionBar,
|
|
15
|
+
{
|
|
16
|
+
actions: resolvedActions,
|
|
17
|
+
getCtx,
|
|
18
|
+
target,
|
|
19
|
+
sourceId: ctx.instanceKey("alchemy"),
|
|
20
|
+
className,
|
|
21
|
+
hideOverflow
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
var RichDocumentActions_default = RichDocumentActions;
|
|
26
|
+
export {
|
|
27
|
+
RichDocumentActions,
|
|
28
|
+
RichDocumentActions_default as default
|
|
29
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RichDocumentAction } from "../types.js";
|
|
2
|
+
/** "Clear" — the host empties its own content (a transcript pad). */
|
|
3
|
+
export declare function clearContentAction(onClear: () => void, label?: string): RichDocumentAction;
|
|
4
|
+
/** A host copy that joins more than this content (transcript + cleaned text). */
|
|
5
|
+
export declare function hostCopyAction(id: string, label: string, run: () => void | Promise<void>): RichDocumentAction;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { Files, Trash2 } from "lucide-react";
|
|
2
|
+
function clearContentAction(onClear, label = "Clear") {
|
|
3
|
+
return {
|
|
4
|
+
id: "host:clear-content",
|
|
5
|
+
label,
|
|
6
|
+
icon: Trash2,
|
|
7
|
+
iconColor: "text-muted-foreground",
|
|
8
|
+
category: "edit",
|
|
9
|
+
supportedSources: "*",
|
|
10
|
+
renderSlot: "both",
|
|
11
|
+
order: 90,
|
|
12
|
+
run: () => onClear()
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function hostCopyAction(id, label, run) {
|
|
16
|
+
return {
|
|
17
|
+
id: `host:${id}`,
|
|
18
|
+
label,
|
|
19
|
+
icon: Files,
|
|
20
|
+
iconColor: "text-muted-foreground",
|
|
21
|
+
category: "copy",
|
|
22
|
+
supportedSources: "*",
|
|
23
|
+
renderSlot: "both",
|
|
24
|
+
order: 80,
|
|
25
|
+
run: () => run()
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
clearContentAction,
|
|
30
|
+
hostCopyAction
|
|
31
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** The engine half of the rich-document action helpers (the host keeps its handler helpers). */
|
|
2
|
+
import type { RichDocumentActionContext } from "../types.js";
|
|
3
|
+
/** Storage key for "do this action after the person signs in" payloads. */
|
|
4
|
+
export declare const PENDING_ACTION_KEY = "matrx_pending_post_auth_action";
|
|
5
|
+
/**
|
|
6
|
+
* Resolve an action label to a string. Supports both static labels and `(ctx) => string`
|
|
7
|
+
* callbacks so labels like "Edit history (3)" can pull counts from the live context.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveActionLabel(label: string | ((ctx: RichDocumentActionContext) => string), ctx: RichDocumentActionContext): string;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface ParsedTable {
|
|
2
|
+
headers: string[];
|
|
3
|
+
rows: string[][];
|
|
4
|
+
}
|
|
5
|
+
export declare function cleanCell(text: string): string;
|
|
6
|
+
/** The first markdown table in `content`, or null when there is none. */
|
|
7
|
+
export declare function parseFirstMarkdownTable(content: string): ParsedTable | null;
|
|
8
|
+
/** RFC 4180 CSV (comma) or TSV (tab) text for a parsed table. */
|
|
9
|
+
export declare function tableToDelimited(table: ParsedTable, delimiter: "," | "\t"): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { tableToCsv } from "../../display/tables/table-csv.js";
|
|
2
|
+
import { unwrapCodeSpans } from "@ai-matrx/content-ir/source";
|
|
3
|
+
import {
|
|
4
|
+
findTableEnd,
|
|
5
|
+
rowCells,
|
|
6
|
+
tableStartsAt,
|
|
7
|
+
unescapeCellPipes
|
|
8
|
+
} from "../../display/markdown-classification/processors/utils/gfm-table-lines.js";
|
|
9
|
+
function splitRow(line) {
|
|
10
|
+
return rowCells(line).map((cell) => cleanCell(unescapeCellPipes(cell)));
|
|
11
|
+
}
|
|
12
|
+
function cleanCell(text) {
|
|
13
|
+
return unwrapCodeSpans(text).replace(/\*\*([^*]+)\*\*/g, "$1").replace(/__([^_]+)__/g, "$1").replace(/\*([^*]+)\*/g, "$1").replace(/~~([^~]+)~~/g, "$1").replace(/\[([^\]]+)\]\(([^)]+)\)/g, "$1").replace(/<br\s*\/?>/gi, " ").trim();
|
|
14
|
+
}
|
|
15
|
+
function parseFirstMarkdownTable(content) {
|
|
16
|
+
const lines = content.split("\n");
|
|
17
|
+
for (let i = 0; i + 1 < lines.length; i += 1) {
|
|
18
|
+
if (!tableStartsAt(lines, i)) continue;
|
|
19
|
+
const headers = splitRow(lines[i]);
|
|
20
|
+
const rows = [];
|
|
21
|
+
const end = findTableEnd(lines, i);
|
|
22
|
+
for (let j = i + 2; j < end; j += 1) {
|
|
23
|
+
const cells = splitRow(lines[j]);
|
|
24
|
+
rows.push(headers.map((_, k) => cells[k] ?? ""));
|
|
25
|
+
}
|
|
26
|
+
return { headers, rows };
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function tableToDelimited(table, delimiter) {
|
|
31
|
+
if (delimiter === ",") return tableToCsv(table.headers, table.rows);
|
|
32
|
+
const flat = (value) => value.replace(/[\t\r\n]+/g, " ");
|
|
33
|
+
return [table.headers, ...table.rows].map((row) => row.map(flat).join(" ")).join("\n");
|
|
34
|
+
}
|
|
35
|
+
export {
|
|
36
|
+
cleanCell,
|
|
37
|
+
parseFirstMarkdownTable,
|
|
38
|
+
tableToDelimited
|
|
39
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { type Action, type ActionProvider, type ClickTarget } from "@ai-matrx/alchemy/actions";
|
|
2
|
+
import type { WriteTarget } from "@ai-matrx/alchemy/declare";
|
|
3
|
+
import type { RichDocumentAction, RichDocumentActionContext, RichDocumentActionId } from "../types.js";
|
|
4
|
+
export declare const RICH_DOCUMENT_PROVIDER_ID = "rich-document";
|
|
5
|
+
/** The write target every source adapter serves (edit, delete, regenerate, fork…). */
|
|
6
|
+
export declare const RICH_DOCUMENT_SOURCE_TARGET = "rich_document_source";
|
|
7
|
+
export declare const SOURCE_WRITE_TARGET: WriteTarget;
|
|
8
|
+
/** Register an action at module load. A duplicate id is refused. */
|
|
9
|
+
export declare function registerAction(action: RichDocumentAction): void;
|
|
10
|
+
/** Get one action by ID. Returns undefined if unregistered. */
|
|
11
|
+
export declare function getAction(id: RichDocumentActionId | string): RichDocumentAction | undefined;
|
|
12
|
+
/** Get all registered actions. */
|
|
13
|
+
export declare function getAllActions(): RichDocumentAction[];
|
|
14
|
+
/** The one id for a named menu group, shared with the context-menu provider. */
|
|
15
|
+
export declare function richDocumentSectionId(label: string): string;
|
|
16
|
+
export interface RichDocumentTargetHost {
|
|
17
|
+
kind: "rich-document";
|
|
18
|
+
/** Render-time context: labels, shown/hidden, toggle state. */
|
|
19
|
+
ctx: RichDocumentActionContext;
|
|
20
|
+
/** Click-time context factory: what handlers run against (live content). */
|
|
21
|
+
getCtx: () => RichDocumentActionContext;
|
|
22
|
+
/** This host's own actions (the `actions.extra` prop). */
|
|
23
|
+
extra: readonly RichDocumentAction[];
|
|
24
|
+
}
|
|
25
|
+
/** The rich-document half of a composite host, for hosts that build one. */
|
|
26
|
+
export declare function richDocumentTargetHost(ctx: RichDocumentActionContext, options?: {
|
|
27
|
+
getCtx?: () => RichDocumentActionContext;
|
|
28
|
+
extra?: readonly RichDocumentAction[];
|
|
29
|
+
}): RichDocumentTargetHost;
|
|
30
|
+
/** THE ClickTarget for a rich-document context. */
|
|
31
|
+
export declare function richDocumentClickTarget(ctx: RichDocumentActionContext, options?: {
|
|
32
|
+
getCtx?: () => RichDocumentActionContext;
|
|
33
|
+
exclude?: readonly string[];
|
|
34
|
+
extra?: readonly RichDocumentAction[];
|
|
35
|
+
}): ClickTarget;
|
|
36
|
+
export declare function toAlchemyAction(rd: RichDocumentAction): Action;
|
|
37
|
+
/**
|
|
38
|
+
* Register this provider into the app's one registry, once per registry.
|
|
39
|
+
* Called by the rich-document layouts (the only hosts that need it), so the
|
|
40
|
+
* app's root host never imports the handler graph.
|
|
41
|
+
*/
|
|
42
|
+
export declare function ensureRichDocumentProvider(registry: {
|
|
43
|
+
register(p: ActionProvider): () => void;
|
|
44
|
+
}): void;
|
|
45
|
+
/** The provider registered into the app's Alchemy action registry. */
|
|
46
|
+
export declare const richDocumentActionProvider: ActionProvider;
|
|
47
|
+
/** Re-render hook for hosts: the list changed (a handler module loaded). */
|
|
48
|
+
export declare function subscribeRichDocumentActions(listener: () => void): () => void;
|
|
49
|
+
/**
|
|
50
|
+
* The actions eligible for a context — synchronously, through the package's
|
|
51
|
+
* ONE eligibility pass. Used where a host needs the list during render (the
|
|
52
|
+
* remote-surface spec snapshot, the code-block bridge, the parity tests).
|
|
53
|
+
* A host extra whose id collides with a built-in is refused (the built-in wins).
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveActions(ctx: RichDocumentActionContext, options?: {
|
|
56
|
+
exclude?: (RichDocumentActionId | string)[];
|
|
57
|
+
extra?: RichDocumentAction[];
|
|
58
|
+
}): RichDocumentAction[];
|