@dxos/react-ui-editor 0.3.11-main.dafb7f2 → 0.3.11-main.e0dc42b
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 +137 -137
- 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 +9 -5
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +10 -10
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +2 -2
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/index.d.ts +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
- package/dist/types/src/extensions/code.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +1 -1
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +0 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +3 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/package.json +23 -22
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +18 -15
- package/src/components/TextEditor/TextEditor.stories.tsx +3 -4
- package/src/components/TextEditor/TextEditor.tsx +59 -45
- package/src/extensions/autocomplete.ts +18 -17
- package/src/extensions/automerge/index.ts +1 -0
- package/src/extensions/awareness.ts +14 -15
- package/src/extensions/code.ts +14 -7
- package/src/extensions/comments.ts +45 -47
- package/src/extensions/hr.ts +4 -5
- package/src/extensions/image.ts +2 -2
- package/src/extensions/index.ts +0 -1
- package/src/extensions/link.ts +5 -5
- package/src/extensions/markdown/highlight.ts +3 -4
- package/src/extensions/table.ts +6 -3
- package/src/extensions/tasklist.ts +2 -2
- package/src/hooks/useTextModel.ts +1 -1
- package/src/index.ts +3 -0
- package/src/styles/tokens.ts +3 -0
- package/dist/types/src/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
- package/src/extensions/mermaid.ts +0 -11
|
@@ -7,16 +7,15 @@ import {
|
|
|
7
7
|
hoverTooltip,
|
|
8
8
|
keymap,
|
|
9
9
|
type Command,
|
|
10
|
-
type DecorationSet,
|
|
11
|
-
type ViewUpdate,
|
|
12
10
|
Decoration,
|
|
11
|
+
type DecorationSet,
|
|
13
12
|
EditorView,
|
|
14
13
|
MatchDecorator,
|
|
14
|
+
type Rect,
|
|
15
|
+
type ViewUpdate,
|
|
15
16
|
ViewPlugin,
|
|
16
17
|
WidgetType,
|
|
17
|
-
type Rect,
|
|
18
18
|
} from '@codemirror/view';
|
|
19
|
-
import get from 'lodash.get';
|
|
20
19
|
import sortBy from 'lodash.sortby';
|
|
21
20
|
|
|
22
21
|
import { debounce } from '@dxos/async';
|
|
@@ -25,7 +24,7 @@ import { log } from '@dxos/log';
|
|
|
25
24
|
import { nonNullable } from '@dxos/util';
|
|
26
25
|
|
|
27
26
|
import { type CommentRange, type EditorModel, type Range } from '../hooks';
|
|
28
|
-
import {
|
|
27
|
+
import { getToken } from '../styles';
|
|
29
28
|
import { callbackWrapper, CursorConverter } from '../util';
|
|
30
29
|
|
|
31
30
|
// TODO(burdon): Handle delete, cut, copy, and paste (separately) text that includes comment range.
|
|
@@ -43,10 +42,10 @@ const styles = EditorView.baseTheme({
|
|
|
43
42
|
backgroundColor: 'orange',
|
|
44
43
|
},
|
|
45
44
|
'& .cm-comment': {
|
|
46
|
-
backgroundColor:
|
|
45
|
+
backgroundColor: getToken('extend.colors.yellow.50'),
|
|
47
46
|
},
|
|
48
47
|
'& .cm-comment-active': {
|
|
49
|
-
backgroundColor:
|
|
48
|
+
backgroundColor: getToken('extend.colors.yellow.100'),
|
|
50
49
|
},
|
|
51
50
|
});
|
|
52
51
|
|
|
@@ -160,17 +159,13 @@ const highlightDecorations = EditorView.decorations.compute([commentsStateField]
|
|
|
160
159
|
* May correspond to a markdown bookmark.
|
|
161
160
|
*/
|
|
162
161
|
class BookmarkWidget extends WidgetType {
|
|
163
|
-
constructor(
|
|
164
|
-
private readonly _anchor: number,
|
|
165
|
-
private readonly _id: string,
|
|
166
|
-
private readonly _handleClick?: () => void,
|
|
167
|
-
) {
|
|
162
|
+
constructor(private readonly _id: string, private readonly _handleClick?: () => void) {
|
|
168
163
|
super();
|
|
169
164
|
invariant(this._id);
|
|
170
165
|
}
|
|
171
166
|
|
|
172
|
-
override eq(other:
|
|
173
|
-
return this.
|
|
167
|
+
override eq(other: this) {
|
|
168
|
+
return this._id === other._id;
|
|
174
169
|
}
|
|
175
170
|
|
|
176
171
|
override toDOM() {
|
|
@@ -198,7 +193,7 @@ export type CommentsOptions = {
|
|
|
198
193
|
/**
|
|
199
194
|
* Called to render tooltip.
|
|
200
195
|
*/
|
|
201
|
-
onHover?: (el: Element) => void;
|
|
196
|
+
onHover?: (el: Element, shortcut: string) => void;
|
|
202
197
|
};
|
|
203
198
|
|
|
204
199
|
/**
|
|
@@ -214,6 +209,8 @@ export type CommentsOptions = {
|
|
|
214
209
|
* 6). Optionally, implements a hoverTooltip to show hints when creating a selection range.
|
|
215
210
|
*/
|
|
216
211
|
export const comments = (options: CommentsOptions = {}): Extension => {
|
|
212
|
+
const { key: shortcut = "meta-'" } = options;
|
|
213
|
+
|
|
217
214
|
const handleSelect = debounce((state: CommentsState) => options.onSelect?.(state), 200);
|
|
218
215
|
|
|
219
216
|
/**
|
|
@@ -258,38 +255,37 @@ export const comments = (options: CommentsOptions = {}): Extension => {
|
|
|
258
255
|
/**
|
|
259
256
|
* Bookmark widget decoration.
|
|
260
257
|
*/
|
|
261
|
-
const bookmarksViewPlugin =
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
258
|
+
const bookmarksViewPlugin = options.footnote
|
|
259
|
+
? ViewPlugin.fromClass(
|
|
260
|
+
class BookmarkViewPlugin {
|
|
261
|
+
// Match markdown footnotes (option).
|
|
262
|
+
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
263
|
+
static bookmarkMatcher = new MatchDecorator({
|
|
264
|
+
regexp: /\[\^(\w+)\]/g,
|
|
265
|
+
decoration: (match) => {
|
|
266
|
+
const id = match[1];
|
|
267
|
+
return Decoration.replace({ id, widget: new BookmarkWidget(id) });
|
|
268
|
+
},
|
|
272
269
|
});
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
270
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
271
|
+
bookmarks: DecorationSet;
|
|
272
|
+
constructor(view: EditorView) {
|
|
273
|
+
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
274
|
+
}
|
|
280
275
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
276
|
+
update(update: ViewUpdate) {
|
|
277
|
+
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update, this.bookmarks);
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
decorations: (instance) => instance.bookmarks,
|
|
282
|
+
provide: (plugin) =>
|
|
283
|
+
EditorView.atomicRanges.of((view) => {
|
|
284
|
+
return view.plugin(plugin)?.bookmarks || Decoration.none;
|
|
285
|
+
}),
|
|
286
|
+
},
|
|
287
|
+
)
|
|
288
|
+
: [];
|
|
293
289
|
|
|
294
290
|
return [
|
|
295
291
|
bookmarksViewPlugin,
|
|
@@ -303,7 +299,7 @@ export const comments = (options: CommentsOptions = {}): Extension => {
|
|
|
303
299
|
options.onCreate
|
|
304
300
|
? keymap.of([
|
|
305
301
|
{
|
|
306
|
-
key:
|
|
302
|
+
key: shortcut,
|
|
307
303
|
run: callbackWrapper(createCommentThread),
|
|
308
304
|
},
|
|
309
305
|
])
|
|
@@ -325,7 +321,7 @@ export const comments = (options: CommentsOptions = {}): Extension => {
|
|
|
325
321
|
create: () => {
|
|
326
322
|
// TODO(burdon): Dispatch to react callback to render (or use SSR)?
|
|
327
323
|
const el = document.createElement('div');
|
|
328
|
-
options.onHover?.(el);
|
|
324
|
+
options.onHover?.(el, shortcut);
|
|
329
325
|
return { dom: el, offset: { x: 0, y: 8 } };
|
|
330
326
|
},
|
|
331
327
|
};
|
|
@@ -393,6 +389,8 @@ export const comments = (options: CommentsOptions = {}): Extension => {
|
|
|
393
389
|
}
|
|
394
390
|
});
|
|
395
391
|
|
|
392
|
+
// TODO(burdon): Fire debounced callback if range selected (to show hint).
|
|
393
|
+
|
|
396
394
|
if (selected.active !== active || selected.closest !== closest) {
|
|
397
395
|
view.dispatch({ effects: setSelection.of(selected) });
|
|
398
396
|
|
|
@@ -417,5 +415,5 @@ const getRangeFromCursor = (cursorConverter: CursorConverter, cursor: string) =>
|
|
|
417
415
|
const parts = cursor.split(':');
|
|
418
416
|
const from = cursorConverter.fromCursor(parts[0]);
|
|
419
417
|
const to = cursorConverter.fromCursor(parts[1]);
|
|
420
|
-
return from && to ? { from, to } : undefined;
|
|
418
|
+
return from !== undefined && to !== undefined ? { from, to } : undefined;
|
|
421
419
|
};
|
package/src/extensions/hr.ts
CHANGED
|
@@ -11,16 +11,15 @@ import {
|
|
|
11
11
|
type ViewUpdate,
|
|
12
12
|
WidgetType,
|
|
13
13
|
} from '@codemirror/view';
|
|
14
|
-
import get from 'lodash.get';
|
|
15
14
|
|
|
16
|
-
import {
|
|
15
|
+
import { getToken } from '../styles';
|
|
17
16
|
|
|
18
17
|
// TODO(burdon): Reconcile with theme.
|
|
19
18
|
const styles = EditorView.baseTheme({
|
|
20
19
|
'& .cm-hr': {
|
|
21
20
|
// TODO(burdon): ???
|
|
22
21
|
// Note that block-level decorations should not have vertical margins,
|
|
23
|
-
borderBottom: `1px solid ${
|
|
22
|
+
borderBottom: `1px solid ${getToken('extend.colors.neutral.200')}`,
|
|
24
23
|
},
|
|
25
24
|
});
|
|
26
25
|
|
|
@@ -29,11 +28,11 @@ class HorizontalRuleWidget extends WidgetType {
|
|
|
29
28
|
super();
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
override eq(other:
|
|
31
|
+
override eq(other: this) {
|
|
33
32
|
return this._pos === (other as any as HorizontalRuleWidget)._pos;
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
toDOM(view: EditorView) {
|
|
35
|
+
override toDOM(view: EditorView) {
|
|
37
36
|
// TODO(burdon): Create <hr> element? Does this clash with markdown parser?
|
|
38
37
|
const el = document.createElement('div');
|
|
39
38
|
el.className = 'cm-hr';
|
package/src/extensions/image.ts
CHANGED
|
@@ -72,11 +72,11 @@ class ImageWidget extends WidgetType {
|
|
|
72
72
|
super();
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
override eq(other:
|
|
75
|
+
override eq(other: this) {
|
|
76
76
|
return this._url === (other as any as ImageWidget)._url;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
toDOM(view: EditorView) {
|
|
79
|
+
override toDOM(view: EditorView) {
|
|
80
80
|
const img = document.createElement('img');
|
|
81
81
|
img.setAttribute('src', this._url);
|
|
82
82
|
img.setAttribute('class', 'cm-image');
|
package/src/extensions/index.ts
CHANGED
package/src/extensions/link.ts
CHANGED
|
@@ -93,11 +93,11 @@ class LinkButton extends WidgetType {
|
|
|
93
93
|
super();
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
override eq(other:
|
|
96
|
+
override eq(other: this) {
|
|
97
97
|
return this._url === other._url;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
toDOM(view: EditorView) {
|
|
100
|
+
override toDOM(view: EditorView) {
|
|
101
101
|
const el = document.createElement('span');
|
|
102
102
|
this._onAttach!(el, this._url);
|
|
103
103
|
return el;
|
|
@@ -109,11 +109,11 @@ class LinkText extends WidgetType {
|
|
|
109
109
|
super();
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
override eq(other:
|
|
112
|
+
override eq(other: this) {
|
|
113
113
|
return this._url === other._url;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
toDOM(view: EditorView) {
|
|
116
|
+
override toDOM(view: EditorView) {
|
|
117
117
|
const link = document.createElement('a');
|
|
118
118
|
link.setAttribute('class', 'cm-link');
|
|
119
119
|
link.textContent = this._text;
|
|
@@ -158,7 +158,7 @@ const buildDecorations = (view: EditorView, options: LinkOptions): DecorationSet
|
|
|
158
158
|
return false;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
-
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
161
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
162
162
|
builder.add(
|
|
163
163
|
node.from,
|
|
164
164
|
node.to,
|
|
@@ -6,19 +6,18 @@ import { markdownLanguage } from '@codemirror/lang-markdown';
|
|
|
6
6
|
import { HighlightStyle } from '@codemirror/language';
|
|
7
7
|
import { tags, styleTags, Tag } from '@lezer/highlight';
|
|
8
8
|
import { type MarkdownConfig, Table } from '@lezer/markdown';
|
|
9
|
-
import get from 'lodash.get';
|
|
10
9
|
|
|
11
10
|
import {
|
|
12
11
|
blockquote,
|
|
13
12
|
bold,
|
|
14
13
|
code,
|
|
15
14
|
codeMark,
|
|
15
|
+
getToken,
|
|
16
16
|
heading,
|
|
17
17
|
inlineUrl,
|
|
18
18
|
italic,
|
|
19
19
|
mark,
|
|
20
20
|
strikethrough,
|
|
21
|
-
tokens,
|
|
22
21
|
} from '../../styles';
|
|
23
22
|
|
|
24
23
|
/**
|
|
@@ -193,12 +192,12 @@ export const markdownHighlightStyle = (readonly?: boolean) => {
|
|
|
193
192
|
// Main content, paragraphs, etc.
|
|
194
193
|
// {
|
|
195
194
|
// tag: [tags.content],
|
|
196
|
-
// fontFamily:
|
|
195
|
+
// fontFamily: getToken('fontFamily.body', []).join(','),
|
|
197
196
|
// },
|
|
198
197
|
],
|
|
199
198
|
{
|
|
200
199
|
scope: markdownLanguage,
|
|
201
|
-
all: { fontFamily:
|
|
200
|
+
all: { fontFamily: getToken('fontFamily.body', []).join(',') },
|
|
202
201
|
},
|
|
203
202
|
);
|
|
204
203
|
};
|
package/src/extensions/table.ts
CHANGED
|
@@ -81,7 +81,6 @@ const update = (state: EditorState, options: TableOptions) => {
|
|
|
81
81
|
table.from,
|
|
82
82
|
table.to,
|
|
83
83
|
Decoration.replace({
|
|
84
|
-
block: true,
|
|
85
84
|
widget: new TableWidget(table),
|
|
86
85
|
}),
|
|
87
86
|
);
|
|
@@ -98,14 +97,14 @@ class TableWidget extends WidgetType {
|
|
|
98
97
|
super();
|
|
99
98
|
}
|
|
100
99
|
|
|
101
|
-
override eq(other:
|
|
100
|
+
override eq(other: this) {
|
|
102
101
|
return (
|
|
103
102
|
this._table.header?.join() === other._table.header?.join() &&
|
|
104
103
|
this._table.rows?.join() === other._table.rows?.join()
|
|
105
104
|
);
|
|
106
105
|
}
|
|
107
106
|
|
|
108
|
-
toDOM(view: EditorView) {
|
|
107
|
+
override toDOM(view: EditorView) {
|
|
109
108
|
const table = document.createElement('table');
|
|
110
109
|
|
|
111
110
|
{
|
|
@@ -132,4 +131,8 @@ class TableWidget extends WidgetType {
|
|
|
132
131
|
|
|
133
132
|
return table;
|
|
134
133
|
}
|
|
134
|
+
|
|
135
|
+
override ignoreEvent(e: Event) {
|
|
136
|
+
return !/^mouse/.test(e.type);
|
|
137
|
+
}
|
|
135
138
|
}
|
|
@@ -29,11 +29,11 @@ class CheckboxWidget extends WidgetType {
|
|
|
29
29
|
super();
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
override eq(other:
|
|
32
|
+
override eq(other: this) {
|
|
33
33
|
return this._checked === other._checked && this._indent === other._indent;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
toDOM(view: EditorView) {
|
|
36
|
+
override toDOM(view: EditorView) {
|
|
37
37
|
const wrap = document.createElement('span');
|
|
38
38
|
wrap.className = 'cm-task-item';
|
|
39
39
|
wrap.setAttribute('aria-hidden', 'true');
|
|
@@ -66,7 +66,7 @@ export type UseTextModelProps = {
|
|
|
66
66
|
// TODO(wittjosiah): Factor out to common package? @dxos/react-client?
|
|
67
67
|
export const useTextModel = (props: UseTextModelProps): EditorModel | undefined => {
|
|
68
68
|
const { identity, space, text } = props;
|
|
69
|
-
const [model, setModel] = useState<EditorModel | undefined>(
|
|
69
|
+
const [model, setModel] = useState<EditorModel | undefined>();
|
|
70
70
|
useEffect(() => setModel(createModel(props)), [identity, space, text]);
|
|
71
71
|
return model;
|
|
72
72
|
};
|
package/src/index.ts
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
export { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
|
|
6
6
|
export { Doc, YText, YXmlFragment } from '@dxos/text-model';
|
|
7
7
|
export { type Extension } from '@codemirror/state';
|
|
8
|
+
export { type EditorView } from '@codemirror/view';
|
|
8
9
|
|
|
9
10
|
export * from './components';
|
|
10
11
|
export * from './extensions';
|
|
11
12
|
export * from './hooks';
|
|
13
|
+
export { getToken } from './styles';
|
|
12
14
|
export * from './themes';
|
|
15
|
+
export * from './util';
|
package/src/styles/tokens.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import get from 'lodash.get';
|
|
5
6
|
import type { StyleSpec } from 'style-mod';
|
|
6
7
|
|
|
7
8
|
import { tailwindConfig, type TailwindConfig } from '@dxos/react-ui-theme';
|
|
@@ -12,3 +13,5 @@ export type ThemeStyles = {
|
|
|
12
13
|
|
|
13
14
|
// TODO(thure): Why export the whole theme? Can this be done differently?
|
|
14
15
|
export const tokens: TailwindConfig['theme'] = tailwindConfig({}).theme;
|
|
16
|
+
|
|
17
|
+
export const getToken = (path: string, defaultValue: any = undefined) => get(tokens, path, defaultValue);
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../../../src/extensions/mermaid.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,eAAO,MAAM,OAAO,QAAO,SAE1B,CAAC"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2024 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { type Extension } from '@codemirror/state';
|
|
6
|
-
|
|
7
|
-
// TODO(burdon): How will this interact with the code extension?
|
|
8
|
-
// TODO(burdon): Move to mermaid-plugin (which should contribute this extension).
|
|
9
|
-
export const mermaid = (): Extension => {
|
|
10
|
-
return [];
|
|
11
|
-
};
|