@dxos/react-ui-editor 0.4.1 → 0.4.2-main.16babdb
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/lib/browser/index.mjs +207 -141
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +4 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/annotations.d.ts +6 -0
- package/dist/types/src/extensions/annotations.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +1 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/package.json +24 -24
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +17 -4
- package/src/components/TextEditor/TextEditor.stories.tsx +8 -2
- package/src/components/TextEditor/TextEditor.tsx +1 -0
- package/src/components/TextEditor/automerge.stories.tsx +4 -8
- package/src/components/Toolbar/Toolbar.stories.tsx +1 -1
- package/src/extensions/annotations.ts +78 -0
- package/src/extensions/index.ts +1 -0
- package/src/hooks/useTextModel.ts +5 -5
@@ -0,0 +1,78 @@
|
|
1
|
+
//
|
2
|
+
// Copyright 2024 DXOS.org
|
3
|
+
//
|
4
|
+
|
5
|
+
import { type EditorState, type Extension, StateField } from '@codemirror/state';
|
6
|
+
import { Decoration, EditorView } from '@codemirror/view';
|
7
|
+
|
8
|
+
import { isNotFalsy } from '@dxos/util';
|
9
|
+
|
10
|
+
import { Cursor } from './cursor';
|
11
|
+
|
12
|
+
type Annotation = {
|
13
|
+
cursor: string;
|
14
|
+
};
|
15
|
+
|
16
|
+
export type AnnotationOptions = {
|
17
|
+
match?: RegExp; // TODO(burdon): Update via hook (e.g., for search).
|
18
|
+
};
|
19
|
+
|
20
|
+
const annotationMark = Decoration.mark({ class: 'cm-annotation' });
|
21
|
+
|
22
|
+
export const annotations = (options: AnnotationOptions = {}): Extension => {
|
23
|
+
// TODO(burdon): Build index of matches and cursors (in background function).
|
24
|
+
// Define annotation action in prompt. E.g., extract company names. Find links, etc.
|
25
|
+
// Show popover card. A16Z chain demo. Identify, extract, research, link. Multi-agent.
|
26
|
+
const match = (state: EditorState) => {
|
27
|
+
const annotations: Annotation[] = [];
|
28
|
+
const text = state.doc.toString();
|
29
|
+
if (options.match) {
|
30
|
+
const matches = text.matchAll(options.match);
|
31
|
+
for (const match of matches) {
|
32
|
+
const from = match.index!;
|
33
|
+
const to = from + match[0].length;
|
34
|
+
const cursor = Cursor.getCursorFromRange(state, { from, to });
|
35
|
+
annotations.push({ cursor });
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
return annotations;
|
40
|
+
};
|
41
|
+
|
42
|
+
const annotationsState = StateField.define<Annotation[]>({
|
43
|
+
create: (state) => {
|
44
|
+
return match(state);
|
45
|
+
},
|
46
|
+
update: (value, tr) => {
|
47
|
+
if (!tr.changes.empty) {
|
48
|
+
return match(tr.state);
|
49
|
+
}
|
50
|
+
|
51
|
+
return value;
|
52
|
+
},
|
53
|
+
});
|
54
|
+
|
55
|
+
return [
|
56
|
+
annotationsState,
|
57
|
+
EditorView.decorations.compute([annotationsState], (state) => {
|
58
|
+
const annotations = state.field(annotationsState);
|
59
|
+
const decorations = annotations
|
60
|
+
.map((annotation) => {
|
61
|
+
const range = Cursor.getRangeFromCursor(state, annotation.cursor);
|
62
|
+
return range && annotationMark.range(range.from, range.to);
|
63
|
+
})
|
64
|
+
.filter(isNotFalsy);
|
65
|
+
|
66
|
+
return Decoration.set(decorations);
|
67
|
+
}),
|
68
|
+
styles,
|
69
|
+
];
|
70
|
+
};
|
71
|
+
|
72
|
+
const styles = EditorView.baseTheme({
|
73
|
+
'.cm-annotation': {
|
74
|
+
textDecoration: 'underline',
|
75
|
+
textDecorationStyle: 'wavy',
|
76
|
+
textDecorationColor: 'red',
|
77
|
+
},
|
78
|
+
});
|
package/src/extensions/index.ts
CHANGED
@@ -47,6 +47,10 @@ export const useInMemoryTextModel = ({
|
|
47
47
|
};
|
48
48
|
|
49
49
|
const createModel = ({ space, identity, text }: UseTextModelProps) => {
|
50
|
+
if (!text) {
|
51
|
+
return undefined;
|
52
|
+
}
|
53
|
+
|
50
54
|
invariant(isAutomergeObject(text));
|
51
55
|
const obj = text as any as AutomergeTextCompat;
|
52
56
|
const doc = getRawDoc(obj, [obj.field]);
|
@@ -64,11 +68,7 @@ const createModel = ({ space, identity, text }: UseTextModelProps) => {
|
|
64
68
|
peerId: identity?.identityKey.toHex() ?? 'Anonymous',
|
65
69
|
});
|
66
70
|
|
67
|
-
const extensions = [
|
68
|
-
//
|
69
|
-
modelState.init(() => model),
|
70
|
-
automerge({ handle: doc.handle, path: doc.path }),
|
71
|
-
];
|
71
|
+
const extensions = [modelState.init(() => model), automerge({ handle: doc.handle, path: doc.path })];
|
72
72
|
if (awarenessProvider) {
|
73
73
|
extensions.push(awareness(awarenessProvider));
|
74
74
|
}
|