@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,8 @@
|
|
|
1
|
+
export interface CaretRect {
|
|
2
|
+
left: number;
|
|
3
|
+
top: number;
|
|
4
|
+
bottom: number;
|
|
5
|
+
width: number;
|
|
6
|
+
}
|
|
7
|
+
/** The viewport box of `el`'s selection (first line of it), clamped to the field. Null when unmeasurable. */
|
|
8
|
+
export declare function textareaSelectionRect(el: HTMLTextAreaElement): CaretRect | null;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const COPIED = [
|
|
2
|
+
"boxSizing",
|
|
3
|
+
"width",
|
|
4
|
+
"height",
|
|
5
|
+
"overflowX",
|
|
6
|
+
"overflowY",
|
|
7
|
+
"borderTopWidth",
|
|
8
|
+
"borderRightWidth",
|
|
9
|
+
"borderBottomWidth",
|
|
10
|
+
"borderLeftWidth",
|
|
11
|
+
"borderStyle",
|
|
12
|
+
"paddingTop",
|
|
13
|
+
"paddingRight",
|
|
14
|
+
"paddingBottom",
|
|
15
|
+
"paddingLeft",
|
|
16
|
+
"fontStyle",
|
|
17
|
+
"fontVariant",
|
|
18
|
+
"fontWeight",
|
|
19
|
+
"fontStretch",
|
|
20
|
+
"fontSize",
|
|
21
|
+
"fontSizeAdjust",
|
|
22
|
+
"lineHeight",
|
|
23
|
+
"fontFamily",
|
|
24
|
+
"textAlign",
|
|
25
|
+
"textTransform",
|
|
26
|
+
"textIndent",
|
|
27
|
+
"textDecoration",
|
|
28
|
+
"letterSpacing",
|
|
29
|
+
"wordSpacing",
|
|
30
|
+
"tabSize"
|
|
31
|
+
];
|
|
32
|
+
function textareaSelectionRect(el) {
|
|
33
|
+
if (typeof window === "undefined" || el.selectionStart === null) return null;
|
|
34
|
+
const style = window.getComputedStyle(el);
|
|
35
|
+
const mirror = document.createElement("div");
|
|
36
|
+
const s = mirror.style;
|
|
37
|
+
for (const prop of COPIED) s[prop] = style[prop];
|
|
38
|
+
s.position = "absolute";
|
|
39
|
+
s.visibility = "hidden";
|
|
40
|
+
s.top = "0";
|
|
41
|
+
s.left = "-9999px";
|
|
42
|
+
s.whiteSpace = "pre-wrap";
|
|
43
|
+
s.overflowWrap = "break-word";
|
|
44
|
+
s.overflow = "hidden";
|
|
45
|
+
const start = el.selectionStart;
|
|
46
|
+
const end = el.selectionEnd ?? start;
|
|
47
|
+
mirror.textContent = el.value.slice(0, start);
|
|
48
|
+
const mark = document.createElement("span");
|
|
49
|
+
const selected = el.value.slice(start, end);
|
|
50
|
+
mark.textContent = selected.split("\n")[0] || ".";
|
|
51
|
+
mirror.appendChild(mark);
|
|
52
|
+
document.body.appendChild(mirror);
|
|
53
|
+
try {
|
|
54
|
+
const box = el.getBoundingClientRect();
|
|
55
|
+
const border = parseFloat(style.borderTopWidth) || 0;
|
|
56
|
+
const borderLeft = parseFloat(style.borderLeftWidth) || 0;
|
|
57
|
+
const lineHeight = mark.offsetHeight || parseFloat(style.lineHeight) || 20;
|
|
58
|
+
const left = box.left + borderLeft + mark.offsetLeft - el.scrollLeft - borderLeft;
|
|
59
|
+
const top = box.top + border + mark.offsetTop - el.scrollTop - border;
|
|
60
|
+
const width = Math.max(1, mark.offsetWidth);
|
|
61
|
+
const clampedTop = Math.min(Math.max(top, box.top), box.bottom - lineHeight);
|
|
62
|
+
return { left: Math.min(Math.max(left, box.left), box.right - 1), top: clampedTop, bottom: clampedTop + lineHeight, width };
|
|
63
|
+
} finally {
|
|
64
|
+
mirror.remove();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export {
|
|
68
|
+
textareaSelectionRect
|
|
69
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Icon KEYS for the Alchemy menu model (Matrx Alchemy ALC-15, CONTRACT §2.5).
|
|
3
|
+
*
|
|
4
|
+
* The package's model holds only string keys; this is the app half of the
|
|
5
|
+
* icon port. An app provider that owns a real icon component (rich-document's
|
|
6
|
+
* Lucide icons, a domain icon) registers it here and puts the returned key on
|
|
7
|
+
* its action; the icon port resolves that key back to the SAME component, and
|
|
8
|
+
* any other key through `@ai-matrx/icons` (Lucide names, `svg:` assets).
|
|
9
|
+
*/
|
|
10
|
+
import type { ComponentType } from "react";
|
|
11
|
+
type IconComponent = ComponentType<{
|
|
12
|
+
className?: string;
|
|
13
|
+
}>;
|
|
14
|
+
/** Register a component; returns its stable key (`app:<Name>`, suffixed when two differ). */
|
|
15
|
+
export declare function registerAlchemyIcon(component: unknown): string;
|
|
16
|
+
/** The icon port's resolve: a registered component, else an `@ai-matrx/icons` name. */
|
|
17
|
+
export declare function resolveAlchemyIcon(key: string): IconComponent | null;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { getIconComponent } from "@ai-matrx/icons";
|
|
2
|
+
const STORE_KEY = /* @__PURE__ */ Symbol.for("ai-matrx.rich-content.alchemy-icon-keys");
|
|
3
|
+
const store = globalThis[STORE_KEY] ??= {
|
|
4
|
+
byKey: /* @__PURE__ */ new Map(),
|
|
5
|
+
byComponent: /* @__PURE__ */ new WeakMap()
|
|
6
|
+
};
|
|
7
|
+
const BY_KEY = store.byKey;
|
|
8
|
+
const BY_COMPONENT = store.byComponent;
|
|
9
|
+
function registerAlchemyIcon(component) {
|
|
10
|
+
const icon = component;
|
|
11
|
+
const known = BY_COMPONENT.get(icon);
|
|
12
|
+
if (known) return known;
|
|
13
|
+
const base = `app:${icon.displayName ?? icon.name ?? "icon"}`;
|
|
14
|
+
let key = base;
|
|
15
|
+
for (let n = 2; BY_KEY.has(key) && BY_KEY.get(key) !== icon; n++) key = `${base}-${n}`;
|
|
16
|
+
BY_KEY.set(key, icon);
|
|
17
|
+
BY_COMPONENT.set(icon, key);
|
|
18
|
+
return key;
|
|
19
|
+
}
|
|
20
|
+
function resolveAlchemyIcon(key) {
|
|
21
|
+
const own = BY_KEY.get(key);
|
|
22
|
+
if (own) return own;
|
|
23
|
+
if (key.startsWith("app:")) return null;
|
|
24
|
+
return getIconComponent(key);
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
registerAlchemyIcon,
|
|
28
|
+
resolveAlchemyIcon
|
|
29
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Search the visible text of a rendered document without changing its DOM. */
|
|
2
|
+
export interface RenderedFindOptions {
|
|
3
|
+
caseSensitive?: boolean;
|
|
4
|
+
wholeWord?: boolean;
|
|
5
|
+
regex?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export declare function findRenderedTextMatches(text: string, query: string, options?: RenderedFindOptions): Array<[number, number]>;
|
|
8
|
+
/** Ranges can cross inline formatting boundaries, such as a word split by <strong>. */
|
|
9
|
+
export declare function collectRenderedFindRanges(root: HTMLElement, query: string, options?: RenderedFindOptions): Range[];
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
function findRenderedTextMatches(text, query, options = {}) {
|
|
2
|
+
if (!query.trim()) return [];
|
|
3
|
+
let expression;
|
|
4
|
+
try {
|
|
5
|
+
const pattern = options.regex ? query : query.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6
|
+
expression = new RegExp(pattern, options.caseSensitive ? "gu" : "giu");
|
|
7
|
+
} catch {
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
const matches = [];
|
|
11
|
+
for (const match of text.matchAll(expression)) {
|
|
12
|
+
if (!match[0] || match.index === void 0) continue;
|
|
13
|
+
const start = match.index;
|
|
14
|
+
const end = start + match[0].length;
|
|
15
|
+
if (options.wholeWord && (/[\p{L}\p{N}\p{M}_]/u.test(text[start - 1] ?? "") || /[\p{L}\p{N}\p{M}_]/u.test(text[end] ?? ""))) continue;
|
|
16
|
+
matches.push([start, end]);
|
|
17
|
+
}
|
|
18
|
+
return matches;
|
|
19
|
+
}
|
|
20
|
+
const IGNORE_SELECTOR = "[data-find-ignore], button, [role='button'], [role='menu'], script, style, textarea, input, [aria-hidden='true']";
|
|
21
|
+
function collectRenderedFindRanges(root, query, options = {}) {
|
|
22
|
+
if (!query.trim()) return [];
|
|
23
|
+
const doc = root.ownerDocument;
|
|
24
|
+
const walker = doc.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
|
|
25
|
+
acceptNode(node) {
|
|
26
|
+
const parent = node.parentElement;
|
|
27
|
+
return parent && node.nodeValue && !parent.closest(IGNORE_SELECTOR) ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
const nodes = [];
|
|
31
|
+
const starts = [];
|
|
32
|
+
let text = "";
|
|
33
|
+
let previousBlock = null;
|
|
34
|
+
for (let node = walker.nextNode(); node; node = walker.nextNode()) {
|
|
35
|
+
const block = node.parentElement?.closest("p,li,h1,h2,h3,h4,h5,h6,blockquote,pre,td,th,figcaption,div,section,article") ?? root;
|
|
36
|
+
if (previousBlock && block !== previousBlock) text += "\n";
|
|
37
|
+
previousBlock = block;
|
|
38
|
+
nodes.push(node);
|
|
39
|
+
starts.push(text.length);
|
|
40
|
+
text += node.nodeValue ?? "";
|
|
41
|
+
}
|
|
42
|
+
const locate = (offset, isEnd) => {
|
|
43
|
+
let lo = 0;
|
|
44
|
+
let hi = nodes.length - 1;
|
|
45
|
+
while (lo <= hi) {
|
|
46
|
+
const mid = lo + hi >> 1;
|
|
47
|
+
const start = starts[mid];
|
|
48
|
+
const length = nodes[mid].nodeValue?.length ?? 0;
|
|
49
|
+
if (isEnd ? offset > start && offset <= start + length : offset >= start && offset < start + length) return [nodes[mid], offset - start];
|
|
50
|
+
if (offset < start || isEnd && offset === start) hi = mid - 1;
|
|
51
|
+
else lo = mid + 1;
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
};
|
|
55
|
+
return findRenderedTextMatches(text, query, options).flatMap(([start, end]) => {
|
|
56
|
+
const from = locate(start, false);
|
|
57
|
+
const to = locate(end, true);
|
|
58
|
+
if (!from || !to) return [];
|
|
59
|
+
const range = doc.createRange();
|
|
60
|
+
range.setStart(from[0], from[1]);
|
|
61
|
+
range.setEnd(to[0], to[1]);
|
|
62
|
+
return [range];
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
export {
|
|
66
|
+
collectRenderedFindRanges,
|
|
67
|
+
findRenderedTextMatches
|
|
68
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-matrx/rich-content",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.16",
|
|
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",
|
|
@@ -63,6 +63,21 @@
|
|
|
63
63
|
"import": "./dist/kinds/*.js",
|
|
64
64
|
"default": "./dist/kinds/*.js"
|
|
65
65
|
},
|
|
66
|
+
"./copy/*": {
|
|
67
|
+
"types": "./dist/copy/*.d.ts",
|
|
68
|
+
"import": "./dist/copy/*.js",
|
|
69
|
+
"default": "./dist/copy/*.js"
|
|
70
|
+
},
|
|
71
|
+
"./rich-document/*": {
|
|
72
|
+
"types": "./dist/rich-document/*.d.ts",
|
|
73
|
+
"import": "./dist/rich-document/*.js",
|
|
74
|
+
"default": "./dist/rich-document/*.js"
|
|
75
|
+
},
|
|
76
|
+
"./selection-toolbar/*": {
|
|
77
|
+
"types": "./dist/selection-toolbar/*.d.ts",
|
|
78
|
+
"import": "./dist/selection-toolbar/*.js",
|
|
79
|
+
"default": "./dist/selection-toolbar/*.js"
|
|
80
|
+
},
|
|
66
81
|
"./utils/*": {
|
|
67
82
|
"types": "./dist/utils/*.d.ts",
|
|
68
83
|
"import": "./dist/utils/*.js",
|
|
@@ -116,19 +131,20 @@
|
|
|
116
131
|
"unist-util-visit-parents": "^6.0.2",
|
|
117
132
|
"yaml": "^2.9.1",
|
|
118
133
|
"@ai-matrx/alchemy": "latest",
|
|
134
|
+
"@ai-matrx/canvas": "latest",
|
|
119
135
|
"@ai-matrx/content-ir": "latest",
|
|
120
136
|
"@ai-matrx/content-ir-react": "latest",
|
|
121
137
|
"@ai-matrx/data": "latest",
|
|
122
|
-
"@ai-matrx/agents": "latest",
|
|
123
138
|
"@ai-matrx/design-system": "latest",
|
|
139
|
+
"@ai-matrx/diff": "latest",
|
|
124
140
|
"@ai-matrx/icons": "latest",
|
|
125
|
-
"@ai-matrx/canvas": "latest",
|
|
126
|
-
"@ai-matrx/kit": "latest",
|
|
127
|
-
"@ai-matrx/print": "latest",
|
|
128
|
-
"@ai-matrx/records": "latest",
|
|
129
141
|
"@ai-matrx/media": "latest",
|
|
142
|
+
"@ai-matrx/records": "latest",
|
|
143
|
+
"@ai-matrx/records-ui": "latest",
|
|
130
144
|
"@ai-matrx/tap-target": "latest",
|
|
131
|
-
"@ai-matrx/
|
|
145
|
+
"@ai-matrx/print": "latest",
|
|
146
|
+
"@ai-matrx/kit": "latest",
|
|
147
|
+
"@ai-matrx/agents": "latest"
|
|
132
148
|
},
|
|
133
149
|
"peerDependencies": {
|
|
134
150
|
"react": ">=19.0.0",
|