@dxos/react-ui-editor 0.3.9-next.4584ca9 → 0.3.9-next.8ad58eb
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 +1027 -827
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts +9 -0
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-plugin/index.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts +6 -5
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge.stories.d.ts +2 -1
- package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +24 -20
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +7 -24
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/{stories/html/code-mirror.stories.d.ts → src/components/TextEditor/codemirror.stories.d.ts} +2 -2
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +10 -0
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/change.d.ts +7 -0
- package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +11 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/{hyperlinkTooltip.d.ts → hyperlink/hyperlinkTooltip.d.ts} +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/{hyperlink.d.ts → hyperlink/hyperlinkWidget.d.ts} +3 -3
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts +3 -1
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/components/{Markdown/markdownTags.d.ts → TextEditor/extensions/markdown/tags.d.ts} +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/index.d.ts +1 -3
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +11 -0
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +4 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
- package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
- package/dist/types/src/{model.d.ts → hooks/useTextModel.d.ts} +3 -15
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/index.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +4 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts +1 -1
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/package.json +31 -28
- package/src/automerge/automerge-plugin/PatchSemaphore.ts +5 -5
- package/src/automerge/automerge-plugin/codeMirrorToAm.ts +10 -7
- package/src/automerge/automerge-plugin/handle.ts +14 -0
- package/src/automerge/automerge-plugin/index.ts +2 -2
- package/src/automerge/automerge-plugin/plugin.ts +39 -10
- package/src/automerge/automerge.stories.tsx +32 -47
- package/src/components/TextEditor/TextEditor.stories.tsx +51 -55
- package/src/components/TextEditor/TextEditor.tsx +113 -55
- package/src/components/TextEditor/codemirror.stories.ts +114 -0
- package/src/components/TextEditor/extensions/basic/bundle.ts +28 -0
- package/src/components/TextEditor/extensions/basic/index.ts +6 -0
- package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
- package/src/components/TextEditor/extensions/change.ts +22 -0
- package/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts +99 -0
- package/src/components/TextEditor/extensions/{hyperlinkTooltip.tsx → hyperlink/hyperlinkTooltip.tsx} +2 -17
- package/src/components/TextEditor/extensions/{hyperlink.tsx → hyperlink/hyperlinkWidget.tsx} +21 -10
- package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
- package/src/components/TextEditor/extensions/index.ts +3 -1
- package/src/components/TextEditor/extensions/markdown/bundle.ts +99 -0
- package/src/components/TextEditor/extensions/markdown/index.ts +6 -0
- package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts} +23 -12
- package/src/components/TextEditor/index.ts +1 -4
- package/src/components/TextEditor/yjs.stories.tsx +55 -0
- package/src/components/index.ts +0 -3
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useCollaboration.ts +45 -0
- package/src/{model.ts → hooks/useTextModel.ts} +42 -17
- package/src/index.ts +3 -3
- package/src/styles/tokens.ts +6 -0
- package/src/testing/replicator.ts +1 -2
- package/dist/types/src/automerge/demo.d.ts +0 -25
- package/dist/types/src/automerge/demo.d.ts.map +0 -1
- package/dist/types/src/components/Editor/Editor.d.ts +0 -15
- package/dist/types/src/components/Editor/Editor.d.ts.map +0 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -29
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +0 -1
- package/dist/types/src/components/Editor/index.d.ts +0 -2
- package/dist/types/src/components/Editor/index.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/Markdown.d.ts +0 -20
- package/dist/types/src/components/Markdown/Markdown.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/Markdown.stories.d.ts +0 -20
- package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/index.d.ts +0 -2
- package/dist/types/src/components/Markdown/index.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/markdownTags.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/markdownTheme.d.ts +0 -93
- package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +0 -1
- package/dist/types/src/components/RichText/RichText.d.ts +0 -20
- package/dist/types/src/components/RichText/RichText.d.ts.map +0 -1
- package/dist/types/src/components/RichText/RichText.stories.d.ts +0 -27
- package/dist/types/src/components/RichText/RichText.stories.d.ts.map +0 -1
- package/dist/types/src/components/RichText/index.d.ts +0 -2
- package/dist/types/src/components/RichText/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/theme.d.ts +0 -8
- package/dist/types/src/components/TextEditor/theme.d.ts.map +0 -1
- package/dist/types/src/model.d.ts.map +0 -1
- package/dist/types/src/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/yjs/index.d.ts.map +0 -1
- package/dist/types/src/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/stories/html/code-mirror.stories.d.ts.map +0 -1
- package/src/automerge/demo.ts +0 -106
- package/src/components/Editor/Editor.stories.tsx +0 -82
- package/src/components/Editor/Editor.tsx +0 -33
- package/src/components/Editor/index.ts +0 -5
- package/src/components/Markdown/Markdown.stories.tsx +0 -59
- package/src/components/Markdown/Markdown.tsx +0 -214
- package/src/components/Markdown/index.ts +0 -5
- package/src/components/RichText/RichText.stories.tsx +0 -70
- package/src/components/RichText/RichText.tsx +0 -181
- package/src/components/RichText/index.ts +0 -5
- package/src/components/TextEditor/theme.ts +0 -33
- /package/dist/types/src/{yjs → hooks/yjs}/cursors.d.ts +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/index.d.ts +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/space-provider.d.ts +0 -0
- /package/src/components/{Markdown/markdownTags.ts → TextEditor/extensions/markdown/tags.ts} +0 -0
- /package/src/{yjs → hooks/yjs}/cursors.ts +0 -0
- /package/src/{yjs → hooks/yjs}/index.ts +0 -0
- /package/src/{yjs → hooks/yjs}/space-provider.ts +0 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
// Copyright CodeMirror
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import { syntaxTree } from '@codemirror/language';
|
|
7
|
+
import { type EditorState, type RangeSet, RangeSetBuilder, StateField, type Transaction } from '@codemirror/state';
|
|
8
|
+
import { Decoration, EditorView, WidgetType } from '@codemirror/view';
|
|
9
|
+
|
|
10
|
+
// Adapted from:
|
|
11
|
+
// https://codemirror.net/try/?c=aW1wb3J0IHsgYmFzaWNTZXR1cCwgRWRpdG9yVmlldyB9IGZyb20gImNvZGVtaXJyb3IiCmltcG9ydCB7IG1hcmtkb3duIH0gZnJvbSAiQGNvZGVtaXJyb3IvbGFuZy1tYXJrZG93biIKaW1wb3J0IHsgc3ludGF4VHJlZSB9IGZyb20gIkBjb2RlbWlycm9yL2xhbmd1YWdlIjsKaW1wb3J0IHsgRWRpdG9yU3RhdGUsIFJhbmdlU2V0QnVpbGRlciwgU3RhdGVGaWVsZCB9IGZyb20gIkBjb2RlbWlycm9yL3N0YXRlIjsKaW1wb3J0IHsgRGVjb3JhdGlvbiwgV2lkZ2V0VHlwZSB9IGZyb20gIkBjb2RlbWlycm9yL3ZpZXciOwoKY2xhc3MgTGluayBleHRlbmRzIFdpZGdldFR5cGUgewogIGNvbnN0cnVjdG9yKHRleHQsIHVybCkgewogICAgc3VwZXIoKQogICAgdGhpcy50ZXh0ID0gdGV4dAogICAgdGhpcy51cmwgPSB1cmwKICB9CiAgZXEob3RoZXIpIHsgcmV0dXJuIHRoaXMudGV4dCA9PSBvdGhlci50ZXh0ICYmIHRoaXMudXJsID09IG90aGVyLnVybCB9CiAgdG9ET00oKSB7CiAgICBsZXQgbGluayA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKQogICAgbGluay50ZXh0Q29udGVudCA9IHRoaXMudGV4dAogICAgbGluay5ocmVmID0gdGhpcy51cmwKICAgIHJldHVybiBsaW5rOwogIH0KfQoKbGV0IGRlY29yYXRpb25zRmllbGQgPSBTdGF0ZUZpZWxkLmRlZmluZSh7CiAgY3JlYXRlKCkgewogICAgcmV0dXJuIERlY29yYXRpb24ubm9uZTsKICB9LAogIHVwZGF0ZShfLCB0cikgewogICAgY29uc3QgYnVpbGRlciA9IG5ldyBSYW5nZVNldEJ1aWxkZXIoKTsKICAgIGxldCBjdXJzb3IgPSB0ci5zdGF0ZS5zZWxlY3Rpb24ubWFpbi5oZWFkOwogICAgc3ludGF4VHJlZSh0ci5zdGF0ZSkuaXRlcmF0ZSh7CiAgICAgIGVudGVyOiAobm9kZSkgPT4gewogICAgICAgIGlmICgoY3Vyc29yIDwgbm9kZS5mcm9tIHx8IGN1cnNvciA+IG5vZGUudG8pICYmIG5vZGUubmFtZSA9PSAiTGluayIpIHsKICAgICAgICAgIGxldCBtYXJrcyA9IG5vZGUubm9kZS5nZXRDaGlsZHJlbigiTGlua01hcmsiKTsKICAgICAgICAgIGxldCB0ZXh0ID0gbWFya3MubGVuZ3RoID49IDIgPyB0ci5zdGF0ZS5zbGljZURvYyhtYXJrc1swXS50bywgbWFya3NbMV0uZnJvbSkgOiAiIgoKICAgICAgICAgIGxldCB1cmxOb2RlID0gbm9kZS5ub2RlLmdldENoaWxkKCJVUkwiKTsKICAgICAgICAgIGxldCB1cmwgPSB1cmxOb2RlID8gdHIuc3RhdGUuc2xpY2VEb2ModXJsTm9kZS5mcm9tLCB1cmxOb2RlLnRvKSA6ICIiCiAgICAgICAgICBidWlsZGVyLmFkZChub2RlLmZyb20sIG5vZGUudG8sIERlY29yYXRpb24ucmVwbGFjZSh7CiAgICAgICAgICAgIHdpZGdldDogbmV3IExpbmsodGV4dCwgdXJsKSwKICAgICAgICAgIH0pLAogICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfSwKICAgIH0pOwogICAgcmV0dXJuIGJ1aWxkZXIuZmluaXNoKCk7CiAgfSwKICBwcm92aWRlOiAoZikgPT4gRWRpdG9yVmlldy5kZWNvcmF0aW9ucy5mcm9tKGYpLAp9KTsKCmxldCB2aWV3ID0gbmV3IEVkaXRvclZpZXcoewogIGRvYzogIiMgSGVsbG8gV29ybGRcblxuW1Rlc3RdKGh0dHBzOi8vZXhhbXBsZS5jb20pXG5cblxuIiwKICBleHRlbnNpb25zOiBbZGVjb3JhdGlvbnNGaWVsZCwgbWFya2Rvd24oKV0sCiAgcGFyZW50OiBkb2N1bWVudC5ib2R5LAp9KTsKCnZpZXcuZm9jdXMoKTs=
|
|
12
|
+
// https://discuss.codemirror.net/t/link-widget-is-clicked-only-if-editor-is-out-of-focus/7433
|
|
13
|
+
|
|
14
|
+
// TODO(burdon): Adapt to make all markdown editable?
|
|
15
|
+
|
|
16
|
+
// TODO(burdon): Research overlays.
|
|
17
|
+
// https://stackoverflow.com/questions/26933344/codemirror-detect-and-create-links-inside-editor
|
|
18
|
+
// https://codemirror.net/5/doc/manual.html#addOverlay
|
|
19
|
+
// https://codemirror.net/5/demo/simplemode.html
|
|
20
|
+
// https://codemirror.net/5/demo/search.html (Search dialog).
|
|
21
|
+
|
|
22
|
+
class Link extends WidgetType {
|
|
23
|
+
constructor(private readonly _anchor: number, private readonly _text: string, private readonly _url?: string) {
|
|
24
|
+
super();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override eq(other: any) {
|
|
28
|
+
return this._text === other.text && this._url === other.url;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
toDOM(view: EditorView) {
|
|
32
|
+
const link = document.createElement('a');
|
|
33
|
+
link.setAttribute('class', 'cm-link');
|
|
34
|
+
link.textContent = this._text;
|
|
35
|
+
if (this._url) {
|
|
36
|
+
link.setAttribute('target', '_blank');
|
|
37
|
+
link.href = this._url;
|
|
38
|
+
} else {
|
|
39
|
+
link.onclick = () => {
|
|
40
|
+
view.dispatch({
|
|
41
|
+
selection: {
|
|
42
|
+
anchor: this._anchor,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return link;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type HyperlinkDecorationConfig = {
|
|
53
|
+
link?: boolean;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Creates a state field to replace AST elements with a hyperlink widget.
|
|
58
|
+
* https://codemirror.net/docs/ref/#state.StateField
|
|
59
|
+
*/
|
|
60
|
+
export const hyperlinkDecoration = ({ link }: HyperlinkDecorationConfig = {}) => {
|
|
61
|
+
return StateField.define<RangeSet<any>>({
|
|
62
|
+
create: (state) => update(state, link),
|
|
63
|
+
update: (_: RangeSet<any>, tr: Transaction) => update(tr.state, link),
|
|
64
|
+
provide: (field) => EditorView.decorations.from(field),
|
|
65
|
+
});
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const update = (state: EditorState, link?: boolean) => {
|
|
69
|
+
const builder = new RangeSetBuilder();
|
|
70
|
+
const cursor = state.selection.main.head;
|
|
71
|
+
syntaxTree(state).iterate({
|
|
72
|
+
enter: (node) => {
|
|
73
|
+
// Check if cursor is inside text.
|
|
74
|
+
if (cursor < node.from || cursor > node.to) {
|
|
75
|
+
if (node.name === 'Link') {
|
|
76
|
+
const marks = node.node.getChildren('LinkMark');
|
|
77
|
+
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : '';
|
|
78
|
+
|
|
79
|
+
const urlNode = node.node.getChild('URL');
|
|
80
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : '';
|
|
81
|
+
|
|
82
|
+
builder.add(
|
|
83
|
+
node.from,
|
|
84
|
+
node.to,
|
|
85
|
+
Decoration.replace({
|
|
86
|
+
widget: new Link(node.from, text, link ? url : undefined),
|
|
87
|
+
}),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return true;
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
return builder.finish();
|
|
99
|
+
};
|
package/src/components/TextEditor/extensions/{hyperlinkTooltip.tsx → hyperlink/hyperlinkTooltip.tsx}
RENAMED
|
@@ -3,11 +3,8 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { hoverTooltip } from '@codemirror/view';
|
|
6
|
-
import { ArrowCircleUp } from '@phosphor-icons/react';
|
|
7
|
-
import React, { StrictMode } from 'react';
|
|
8
|
-
import { createRoot } from 'react-dom/client';
|
|
9
6
|
|
|
10
|
-
import {
|
|
7
|
+
import { tooltipContent } from '@dxos/react-ui-theme';
|
|
11
8
|
|
|
12
9
|
const markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
13
10
|
|
|
@@ -18,6 +15,7 @@ export type OnHyperlinkHover = (el: Element, url: string) => void;
|
|
|
18
15
|
* https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
19
16
|
* https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
20
17
|
*/
|
|
18
|
+
// TODO(burdon): Create config object.
|
|
21
19
|
export const createHyperlinkTooltip = (onHover: OnHyperlinkHover, regexp = markdownLinkRegexp) =>
|
|
22
20
|
hoverTooltip((view, pos) => {
|
|
23
21
|
const { from, text } = view.state.doc.lineAt(pos);
|
|
@@ -61,16 +59,3 @@ export const createHyperlinkTooltip = (onHover: OnHyperlinkHover, regexp = markd
|
|
|
61
59
|
},
|
|
62
60
|
};
|
|
63
61
|
});
|
|
64
|
-
|
|
65
|
-
// TODO(burdon): Factor out (remove theme/icon deps)?
|
|
66
|
-
export const defaultHyperLinkTooltip = createHyperlinkTooltip((el, url) => {
|
|
67
|
-
const web = new URL(url);
|
|
68
|
-
createRoot(el).render(
|
|
69
|
-
<StrictMode>
|
|
70
|
-
<div className='flex gap-1 items-center'>
|
|
71
|
-
<ArrowCircleUp className={mx(getSize(6), 'text-blue-500')} />
|
|
72
|
-
<p className='pr-1'>{web.origin}</p>
|
|
73
|
-
</div>
|
|
74
|
-
</StrictMode>,
|
|
75
|
-
);
|
|
76
|
-
});
|
package/src/components/TextEditor/extensions/{hyperlink.tsx → hyperlink/hyperlinkWidget.tsx}
RENAMED
|
@@ -15,14 +15,20 @@ import {
|
|
|
15
15
|
|
|
16
16
|
// Notes: Can't edit widget content (or cursor nav through them).
|
|
17
17
|
// - https://discuss.codemirror.net/t/focusing-inputs-within-widgets/5178/7
|
|
18
|
-
// Widgets intentionally always get set to contenteditable=false,
|
|
18
|
+
// Widgets intentionally always get set to contenteditable=false,
|
|
19
|
+
// or they would become part of CodeMirror’s editable content element.
|
|
19
20
|
// You should be able to introduce new contenteditable=true child elements inside of them.
|
|
20
21
|
|
|
21
22
|
const markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)(!?)/gi;
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Custom link decorator.
|
|
26
|
+
* NOTE: The default markdown extension formats links by default.
|
|
27
|
+
* @deprecated
|
|
28
|
+
*/
|
|
23
29
|
const linkDecorator = () =>
|
|
24
30
|
new MatchDecorator({
|
|
25
|
-
regexp: markdownLinkRegexp,
|
|
31
|
+
regexp: markdownLinkRegexp,
|
|
26
32
|
decorate: (add, from, to, match, view) => {
|
|
27
33
|
const [_, label, url] = match;
|
|
28
34
|
const p0 = {
|
|
@@ -45,16 +51,21 @@ const linkDecorator = () =>
|
|
|
45
51
|
end: p1.end + 1 + url.length + 2,
|
|
46
52
|
};
|
|
47
53
|
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
add(
|
|
55
|
+
p0.start,
|
|
56
|
+
p0.end,
|
|
57
|
+
Decoration.mark({ class: 'cm-hyperlink-bracket', _attributes: { style: 'display: none' } }),
|
|
58
|
+
);
|
|
50
59
|
add(p1.start, p1.end, Decoration.mark({ class: 'cm-hyperlink-label' }));
|
|
51
|
-
add(
|
|
52
|
-
|
|
60
|
+
add(
|
|
61
|
+
p2.start,
|
|
62
|
+
p2.end,
|
|
63
|
+
Decoration.mark({ class: 'cm-hyperlink-bracket', _attributes: { style: 'display: none' } }),
|
|
64
|
+
);
|
|
65
|
+
add(p3.start, p3.end, Decoration.mark({ class: 'cm-hyperlink-url', _attributes: { style: 'display: none' } }));
|
|
53
66
|
},
|
|
54
67
|
});
|
|
55
68
|
|
|
56
|
-
// const anchor = (dom: HTMLAnchorElement) => dom;
|
|
57
|
-
|
|
58
69
|
export function hyperLinkExtension() {
|
|
59
70
|
return ViewPlugin.fromClass(
|
|
60
71
|
class HyperLinkView {
|
|
@@ -91,7 +102,7 @@ export function hyperLinkExtension() {
|
|
|
91
102
|
);
|
|
92
103
|
}
|
|
93
104
|
|
|
94
|
-
export const
|
|
105
|
+
export const hyperlinkStyle = EditorView.baseTheme({
|
|
95
106
|
'.cm-hyperlink-label': {
|
|
96
107
|
cursor: 'pointer',
|
|
97
108
|
textDecoration: 'underline',
|
|
@@ -105,4 +116,4 @@ export const hyperLinkStyle = EditorView.baseTheme({
|
|
|
105
116
|
},
|
|
106
117
|
});
|
|
107
118
|
|
|
108
|
-
export const
|
|
119
|
+
export const hyperlinkWidget: Extension = [hyperLinkExtension(), hyperlinkStyle];
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
|
|
6
|
+
import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
|
7
|
+
import { markdownLanguage, markdown } from '@codemirror/lang-markdown';
|
|
8
|
+
import {
|
|
9
|
+
bracketMatching,
|
|
10
|
+
defaultHighlightStyle,
|
|
11
|
+
foldKeymap,
|
|
12
|
+
indentOnInput,
|
|
13
|
+
syntaxHighlighting,
|
|
14
|
+
} from '@codemirror/language';
|
|
15
|
+
import { languages } from '@codemirror/language-data';
|
|
16
|
+
import { lintKeymap } from '@codemirror/lint';
|
|
17
|
+
import { highlightSelectionMatches, searchKeymap } from '@codemirror/search';
|
|
18
|
+
import { EditorState, type Extension } from '@codemirror/state';
|
|
19
|
+
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
|
|
20
|
+
import {
|
|
21
|
+
crosshairCursor,
|
|
22
|
+
drawSelection,
|
|
23
|
+
dropCursor,
|
|
24
|
+
EditorView,
|
|
25
|
+
highlightActiveLine,
|
|
26
|
+
highlightActiveLineGutter,
|
|
27
|
+
highlightSpecialChars,
|
|
28
|
+
keymap,
|
|
29
|
+
placeholder,
|
|
30
|
+
rectangularSelection,
|
|
31
|
+
} from '@codemirror/view';
|
|
32
|
+
// import { GFM } from '@lezer/markdown';
|
|
33
|
+
|
|
34
|
+
import type { ThemeMode } from '@dxos/react-ui';
|
|
35
|
+
|
|
36
|
+
import { markdownTagsExtension } from './tags';
|
|
37
|
+
import { markdownHighlightStyle } from './theme';
|
|
38
|
+
|
|
39
|
+
export type MarkdownBundleOptions = {
|
|
40
|
+
themeMode?: ThemeMode;
|
|
41
|
+
placeholder?: string;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
export const markdownBundle = ({ themeMode, placeholder: _placeholder }: MarkdownBundleOptions): Extension[] => {
|
|
45
|
+
// All of https://github.com/codemirror/basic-setup minus line numbers and fold gutter.
|
|
46
|
+
// https://codemirror.net/docs/ref/#codemirror.basicSetup
|
|
47
|
+
return [
|
|
48
|
+
bracketMatching(),
|
|
49
|
+
closeBrackets(),
|
|
50
|
+
_placeholder && placeholder(_placeholder),
|
|
51
|
+
|
|
52
|
+
EditorState.allowMultipleSelections.of(true),
|
|
53
|
+
EditorView.lineWrapping,
|
|
54
|
+
|
|
55
|
+
// autocompletion(),
|
|
56
|
+
crosshairCursor(),
|
|
57
|
+
dropCursor(),
|
|
58
|
+
drawSelection(),
|
|
59
|
+
highlightActiveLine(),
|
|
60
|
+
highlightActiveLineGutter(),
|
|
61
|
+
highlightSelectionMatches(),
|
|
62
|
+
highlightSpecialChars(),
|
|
63
|
+
history(),
|
|
64
|
+
indentOnInput(),
|
|
65
|
+
rectangularSelection(),
|
|
66
|
+
|
|
67
|
+
keymap.of([
|
|
68
|
+
...closeBracketsKeymap,
|
|
69
|
+
// ...completionKeymap,
|
|
70
|
+
...defaultKeymap,
|
|
71
|
+
...foldKeymap,
|
|
72
|
+
...historyKeymap,
|
|
73
|
+
...lintKeymap,
|
|
74
|
+
...searchKeymap,
|
|
75
|
+
indentWithTab,
|
|
76
|
+
]),
|
|
77
|
+
|
|
78
|
+
// Main extension.
|
|
79
|
+
// https://github.com/codemirror/lang-markdown
|
|
80
|
+
markdown({
|
|
81
|
+
base: markdownLanguage,
|
|
82
|
+
codeLanguages: languages,
|
|
83
|
+
extensions: [
|
|
84
|
+
// TODO(burdon): This seems to upgrade the parser.
|
|
85
|
+
// GitHub flavored markdown bundle: Table, TaskList, Strikethrough, and Autolink.
|
|
86
|
+
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
87
|
+
// https://github.github.com/gfm
|
|
88
|
+
// GFM,
|
|
89
|
+
|
|
90
|
+
// Custom styling.
|
|
91
|
+
markdownTagsExtension,
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
|
|
95
|
+
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
96
|
+
syntaxHighlighting(markdownHighlightStyle),
|
|
97
|
+
themeMode === 'dark' ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
|
98
|
+
].filter(Boolean) as Extension[];
|
|
99
|
+
};
|
package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts}
RENAMED
|
@@ -7,12 +7,10 @@ import { HighlightStyle } from '@codemirror/language';
|
|
|
7
7
|
import { tags } from '@lezer/highlight';
|
|
8
8
|
import get from 'lodash.get';
|
|
9
9
|
|
|
10
|
-
import { markdownTags } from './
|
|
11
|
-
import { bold, heading, italic, mark, strikethrough, tokens } from '
|
|
12
|
-
|
|
13
|
-
// TODO(burdon): Use theme colors.
|
|
14
|
-
// TODO(burdon): Light mode.
|
|
10
|
+
import { markdownTags } from './tags';
|
|
11
|
+
import { bold, heading, italic, mark, strikethrough, tokens, type ThemeStyles } from '../../../../styles';
|
|
15
12
|
|
|
13
|
+
// TODO(burdon): Rationalize theme/colors. Hoist onto single property object.
|
|
16
14
|
export const chalky = '#e5c07b';
|
|
17
15
|
export const coral = '#e06c75';
|
|
18
16
|
export const cyan = '#56b6c2';
|
|
@@ -28,12 +26,15 @@ export const highlightBackground = '#2c313a';
|
|
|
28
26
|
const _background = '#282c34';
|
|
29
27
|
export const tooltipBackground = '#353a42';
|
|
30
28
|
const _selection = '#3E4451';
|
|
31
|
-
export const cursor = '#ffffff';
|
|
32
29
|
|
|
33
30
|
const monospace = get(tokens, 'fontFamily.mono', ['monospace']).join(',');
|
|
34
31
|
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
/**
|
|
33
|
+
* NOTE: The '&' prefix denotes the CM editor root.
|
|
34
|
+
* https://codemirror.net/examples/styling
|
|
35
|
+
*/
|
|
36
|
+
export const markdownTheme: ThemeStyles = {
|
|
37
|
+
// TODO(thure): Consider whether these commented-out rules from one-dark-theme should be integrated.
|
|
37
38
|
// '&': {
|
|
38
39
|
// color: ivory,
|
|
39
40
|
// backgroundColor: background
|
|
@@ -71,7 +72,7 @@ export const markdownTheme = {
|
|
|
71
72
|
// color: '#ddd'
|
|
72
73
|
// },
|
|
73
74
|
|
|
74
|
-
'.cm-tooltip': {
|
|
75
|
+
'& .cm-tooltip': {
|
|
75
76
|
backgroundColor: 'transparent',
|
|
76
77
|
border: 'none',
|
|
77
78
|
},
|
|
@@ -98,6 +99,7 @@ export const markdownTheme = {
|
|
|
98
99
|
},
|
|
99
100
|
'& .cm-line': {
|
|
100
101
|
paddingInline: 0,
|
|
102
|
+
lineHeight: 1.6,
|
|
101
103
|
minBlockSize: '1.6em',
|
|
102
104
|
},
|
|
103
105
|
'& .cm-line *': {
|
|
@@ -116,16 +118,17 @@ export const markdownTheme = {
|
|
|
116
118
|
background: get(tokens, 'extend.colors.primary.600', '#00ffff') + '44',
|
|
117
119
|
},
|
|
118
120
|
'& .cm-content': {
|
|
121
|
+
padding: 0,
|
|
119
122
|
caretColor: 'black',
|
|
120
123
|
},
|
|
121
124
|
'.dark & .cm-content': {
|
|
122
|
-
caretColor:
|
|
125
|
+
caretColor: 'white',
|
|
123
126
|
},
|
|
124
127
|
'& .cm-cursor': {
|
|
125
128
|
borderLeftColor: 'black',
|
|
126
129
|
},
|
|
127
130
|
'.dark & .cm-cursor': {
|
|
128
|
-
borderLeftColor:
|
|
131
|
+
borderLeftColor: 'white',
|
|
129
132
|
},
|
|
130
133
|
'.cm-placeholder': {
|
|
131
134
|
fontFamily: get(tokens, 'fontFamily.body', []).join(','),
|
|
@@ -164,6 +167,14 @@ export const markdownTheme = {
|
|
|
164
167
|
'& .cm-yLineSelection': {
|
|
165
168
|
margin: '0',
|
|
166
169
|
},
|
|
170
|
+
'.cm-link': {
|
|
171
|
+
color: 'rgb(20 89 208)', // TODO(burdon): Rationalize.
|
|
172
|
+
textDecorationLine: 'underline',
|
|
173
|
+
textDecorationThickness: '1px',
|
|
174
|
+
textUnderlineOffset: '2px',
|
|
175
|
+
borderRadius: '.125rem',
|
|
176
|
+
},
|
|
177
|
+
// TODO(burdon): Document.
|
|
167
178
|
...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
168
179
|
const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
169
180
|
// TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
|
|
@@ -174,7 +185,7 @@ export const markdownTheme = {
|
|
|
174
185
|
}, {}),
|
|
175
186
|
};
|
|
176
187
|
|
|
177
|
-
export const
|
|
188
|
+
export const markdownHighlightStyle = HighlightStyle.define(
|
|
178
189
|
[
|
|
179
190
|
{
|
|
180
191
|
tag: [
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
|
|
7
|
+
import React, { useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { PublicKey } from '@dxos/react-client';
|
|
10
|
+
import { TextKind } from '@dxos/react-client/echo';
|
|
11
|
+
import { ClientRepeater, textGenerator, useDataGenerator } from '@dxos/react-client/testing';
|
|
12
|
+
import { useId, Input } from '@dxos/react-ui';
|
|
13
|
+
import { withTheme } from '@dxos/storybook-utils';
|
|
14
|
+
|
|
15
|
+
import { MarkdownEditor } from './TextEditor';
|
|
16
|
+
import { Replicator, useYjsModel } from '../../testing';
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
component: MarkdownEditor,
|
|
20
|
+
decorators: [withTheme],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const replicator = new Replicator(TextKind.PLAIN);
|
|
24
|
+
|
|
25
|
+
const Story = () => {
|
|
26
|
+
const [generate, setGenerate] = useState(false);
|
|
27
|
+
const generateId = useId('generate');
|
|
28
|
+
|
|
29
|
+
const [id] = useState(PublicKey.random().toHex());
|
|
30
|
+
const model = useYjsModel({ id, replicator });
|
|
31
|
+
|
|
32
|
+
useDataGenerator({
|
|
33
|
+
generator: generate ? textGenerator : undefined,
|
|
34
|
+
options: { text: typeof model?.content !== 'string' ? (model?.content as any) : undefined },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<main className='flex flex-col flex-1 p-4 gap-4'>
|
|
39
|
+
<div id={generateId} className='flex gap-2'>
|
|
40
|
+
<Input.Root>
|
|
41
|
+
<Input.Checkbox checked={generate} onCheckedChange={(checked) => setGenerate(!!checked)} />
|
|
42
|
+
<Input.Label>Start</Input.Label>
|
|
43
|
+
</Input.Root>
|
|
44
|
+
</div>
|
|
45
|
+
<div className='border'>
|
|
46
|
+
<MarkdownEditor model={model} />
|
|
47
|
+
</div>
|
|
48
|
+
</main>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const Default = {
|
|
53
|
+
// TODO(wittjosiah): Decorator for doing this without clients being initialized?
|
|
54
|
+
render: () => <ClientRepeater count={2} Component={Story} />,
|
|
55
|
+
};
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { Extension } from '@codemirror/state';
|
|
6
|
+
import { useEffect, useMemo } from 'react';
|
|
7
|
+
import { yCollab } from 'y-codemirror.next';
|
|
8
|
+
|
|
9
|
+
import { generateName } from '@dxos/display-name';
|
|
10
|
+
import { isDocAccessor } from '@dxos/echo-schema';
|
|
11
|
+
import type { ThemeMode } from '@dxos/react-ui';
|
|
12
|
+
import { getColorForValue } from '@dxos/react-ui-theme';
|
|
13
|
+
import { YText } from '@dxos/text-model';
|
|
14
|
+
|
|
15
|
+
import type { EditorModel } from './useTextModel';
|
|
16
|
+
import { automergePlugin } from '../automerge/automerge-plugin';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Replication and awareness (incl. remote selection).
|
|
20
|
+
* https://codemirror.net/docs/ref/#collab
|
|
21
|
+
*/
|
|
22
|
+
export const useCollaboration = (model: EditorModel, themeMode: ThemeMode): Extension | undefined => {
|
|
23
|
+
const { provider, peer, content } = model;
|
|
24
|
+
const extension = useMemo(() => {
|
|
25
|
+
if (content instanceof YText) {
|
|
26
|
+
return yCollab(content, provider?.awareness);
|
|
27
|
+
} else if (isDocAccessor(content)) {
|
|
28
|
+
return automergePlugin(content.handle, content.path);
|
|
29
|
+
} else {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
}, []);
|
|
33
|
+
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (provider && peer) {
|
|
36
|
+
provider.awareness.setLocalStateField('user', {
|
|
37
|
+
name: peer.name ?? generateName(peer.id),
|
|
38
|
+
color: getColorForValue({ value: peer.id, type: 'color' }),
|
|
39
|
+
colorLight: getColorForValue({ value: peer.id, themeMode, type: 'highlight' }),
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}, [provider, peer, themeMode]);
|
|
43
|
+
|
|
44
|
+
return extension;
|
|
45
|
+
};
|
|
@@ -2,34 +2,30 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { type ComponentProps, useMemo } from 'react';
|
|
5
|
+
import { useMemo } from 'react';
|
|
7
6
|
import type * as awarenessProtocol from 'y-protocols/awareness';
|
|
8
7
|
|
|
9
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
type DocAccessor,
|
|
10
|
+
type Space,
|
|
11
|
+
type TextObject,
|
|
12
|
+
type AutomergeTextCompat,
|
|
13
|
+
getRawDoc,
|
|
14
|
+
isActualAutomergeObject,
|
|
15
|
+
} from '@dxos/react-client/echo';
|
|
10
16
|
import { type Identity } from '@dxos/react-client/halo';
|
|
11
17
|
import type { YText, YXmlFragment } from '@dxos/text-model';
|
|
12
18
|
|
|
13
19
|
import { SpaceAwarenessProvider } from './yjs';
|
|
14
20
|
|
|
15
|
-
|
|
16
|
-
root?: Omit<ComponentProps<'div'>, 'ref'>;
|
|
17
|
-
editor?: {
|
|
18
|
-
className?: string;
|
|
19
|
-
placeholder?: string;
|
|
20
|
-
spellCheck?: boolean;
|
|
21
|
-
tabIndex?: number;
|
|
22
|
-
markdownTheme?: Parameters<typeof EditorView.theme>[0];
|
|
23
|
-
};
|
|
24
|
-
};
|
|
25
|
-
|
|
21
|
+
// TODO(burdon): Move.
|
|
26
22
|
type Awareness = awarenessProtocol.Awareness;
|
|
27
23
|
type Provider = { awareness: Awareness };
|
|
28
24
|
|
|
29
25
|
// TODO(wittjosiah): Factor out to common package? @dxos/react-client?
|
|
30
26
|
export type EditorModel = {
|
|
31
27
|
id: string;
|
|
32
|
-
content: string | YText | YXmlFragment;
|
|
28
|
+
content: string | YText | YXmlFragment | DocAccessor;
|
|
33
29
|
provider?: Provider;
|
|
34
30
|
peer?: {
|
|
35
31
|
id: string;
|
|
@@ -43,16 +39,45 @@ export type UseTextModelOptions = {
|
|
|
43
39
|
text?: TextObject;
|
|
44
40
|
};
|
|
45
41
|
|
|
46
|
-
// TODO(
|
|
42
|
+
// TODO(burdon): Don't support returning undefined (and remove checks from calling code).
|
|
47
43
|
// TODO(burdon): Decouple space (make Editor less dependent on entire stack)?
|
|
44
|
+
// TODO(wittjosiah): Factor out to common package? @dxos/react-client?
|
|
48
45
|
export const useTextModel = ({ identity, space, text }: UseTextModelOptions): EditorModel | undefined => {
|
|
49
46
|
const provider = useMemo(() => {
|
|
47
|
+
if (isActualAutomergeObject(text)) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
50
51
|
if (!space || !text?.doc) {
|
|
51
52
|
return undefined;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
return new SpaceAwarenessProvider({ space, doc: text.doc, channel: `yjs.awareness.${text.id}` });
|
|
55
|
-
}, [identity, space, text?.doc]);
|
|
56
|
+
}, [identity, space, text, text?.doc]);
|
|
57
|
+
|
|
58
|
+
const content = useMemo(() => {
|
|
59
|
+
if (isActualAutomergeObject(text)) {
|
|
60
|
+
const obj = text as any as AutomergeTextCompat;
|
|
61
|
+
return getRawDoc(obj, [obj.field]);
|
|
62
|
+
} else {
|
|
63
|
+
return text?.content;
|
|
64
|
+
}
|
|
65
|
+
}, [text]);
|
|
66
|
+
|
|
67
|
+
if (isActualAutomergeObject(text)) {
|
|
68
|
+
const obj = text as any as AutomergeTextCompat;
|
|
69
|
+
return {
|
|
70
|
+
id: obj.id,
|
|
71
|
+
content: content!,
|
|
72
|
+
provider: undefined,
|
|
73
|
+
peer: identity
|
|
74
|
+
? {
|
|
75
|
+
id: identity.identityKey.toHex(),
|
|
76
|
+
name: identity.profile?.displayName,
|
|
77
|
+
}
|
|
78
|
+
: undefined,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
56
81
|
|
|
57
82
|
if (!text?.doc || !text?.content) {
|
|
58
83
|
return undefined;
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// Copyright 2022 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
export * from './components';
|
|
6
|
-
export * from './model';
|
|
7
|
-
|
|
8
5
|
export { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
|
|
9
6
|
export { Doc, YText, YXmlFragment } from '@dxos/text-model';
|
|
7
|
+
|
|
8
|
+
export * from './components';
|
|
9
|
+
export * from './hooks';
|
package/src/styles/tokens.ts
CHANGED
|
@@ -2,7 +2,13 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import type { StyleSpec } from 'style-mod';
|
|
6
|
+
|
|
5
7
|
import { tailwindConfig, type TailwindConfig } from '@dxos/react-ui-theme';
|
|
6
8
|
|
|
9
|
+
export type ThemeStyles = {
|
|
10
|
+
[selector: string]: StyleSpec;
|
|
11
|
+
};
|
|
12
|
+
|
|
7
13
|
// TODO(thure): Why export the whole theme? Can this be done differently?
|
|
8
14
|
export const tokens: TailwindConfig['theme'] = tailwindConfig({}).theme;
|