@dxos/react-ui-editor 0.3.11-main.a6c4a82 → 0.3.11-main.a996413

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.
Files changed (111) hide show
  1. package/dist/lib/browser/index.mjs +197 -163
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +0 -3
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -2
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/index.d.ts +0 -2
  9. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
  10. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -0
  11. package/dist/types/src/extensions/basic.d.ts.map +1 -0
  12. package/dist/types/src/extensions/blast.d.ts.map +1 -0
  13. package/dist/types/src/extensions/code.d.ts.map +1 -0
  14. package/dist/types/src/{components/TextEditor/extensions → extensions}/comments.d.ts +4 -2
  15. package/dist/types/src/extensions/comments.d.ts.map +1 -0
  16. package/dist/types/src/extensions/hr.d.ts.map +1 -0
  17. package/dist/types/src/extensions/image.d.ts.map +1 -0
  18. package/dist/types/src/{components/TextEditor/extensions → extensions}/index.d.ts +0 -1
  19. package/dist/types/src/extensions/index.d.ts.map +1 -0
  20. package/dist/types/src/{components/TextEditor/extensions → extensions}/link.d.ts +1 -0
  21. package/dist/types/src/extensions/link.d.ts.map +1 -0
  22. package/dist/types/src/extensions/listener.d.ts +10 -0
  23. package/dist/types/src/extensions/listener.d.ts.map +1 -0
  24. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -0
  25. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -0
  26. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -0
  27. package/dist/types/src/extensions/mention.d.ts.map +1 -0
  28. package/dist/types/src/extensions/mermaid.d.ts.map +1 -0
  29. package/dist/types/src/extensions/table.d.ts.map +1 -0
  30. package/dist/types/src/extensions/tasklist.d.ts.map +1 -0
  31. package/dist/types/src/extensions/typewriter.d.ts.map +1 -0
  32. package/dist/types/src/extensions/util.d.ts.map +1 -0
  33. package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -1
  34. package/dist/types/src/hooks/useTextModel.d.ts +1 -1
  35. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  36. package/dist/types/src/index.d.ts +2 -0
  37. package/dist/types/src/index.d.ts.map +1 -1
  38. package/dist/types/src/{components/TextEditor/themes → themes}/default.d.ts +1 -1
  39. package/dist/types/src/themes/default.d.ts.map +1 -0
  40. package/dist/types/src/themes/index.d.ts.map +1 -0
  41. package/package.json +21 -21
  42. package/src/components/TextEditor/MarkdownEditor.stories.tsx +11 -13
  43. package/src/components/TextEditor/TextEditor.stories.tsx +1 -1
  44. package/src/components/TextEditor/TextEditor.tsx +6 -6
  45. package/src/components/TextEditor/index.ts +0 -3
  46. package/src/{components/TextEditor/extensions → extensions}/code.ts +1 -1
  47. package/src/{components/TextEditor/extensions → extensions}/comments.ts +27 -10
  48. package/src/{components/TextEditor/extensions → extensions}/hr.ts +1 -1
  49. package/src/{components/TextEditor/extensions → extensions}/index.ts +0 -1
  50. package/src/{components/TextEditor/extensions → extensions}/link.ts +66 -10
  51. package/src/extensions/listener.ts +35 -0
  52. package/src/{components/TextEditor/extensions → extensions}/markdown/highlight.ts +1 -1
  53. package/src/{components/TextEditor/extensions → extensions}/typewriter.ts +1 -1
  54. package/src/hooks/automerge/plugin.ts +3 -5
  55. package/src/hooks/useTextModel.ts +5 -4
  56. package/src/index.ts +2 -0
  57. package/src/{components/TextEditor/themes → themes}/default.ts +1 -1
  58. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +0 -1
  59. package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +0 -1
  60. package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +0 -1
  61. package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +0 -1
  62. package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +0 -1
  63. package/dist/types/src/components/TextEditor/extensions/hr.d.ts.map +0 -1
  64. package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +0 -1
  65. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +0 -1
  66. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +0 -1
  67. package/dist/types/src/components/TextEditor/extensions/listener.d.ts +0 -9
  68. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +0 -1
  69. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +0 -1
  70. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +0 -1
  71. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +0 -1
  72. package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +0 -1
  73. package/dist/types/src/components/TextEditor/extensions/mermaid.d.ts.map +0 -1
  74. package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +0 -1
  75. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +0 -1
  76. package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts +0 -12
  77. package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts.map +0 -1
  78. package/dist/types/src/components/TextEditor/extensions/typewriter.d.ts.map +0 -1
  79. package/dist/types/src/components/TextEditor/extensions/util.d.ts.map +0 -1
  80. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +0 -1
  81. package/dist/types/src/components/TextEditor/themes/index.d.ts.map +0 -1
  82. package/src/components/TextEditor/extensions/listener.ts +0 -23
  83. package/src/components/TextEditor/extensions/tooltip.ts +0 -61
  84. /package/dist/types/src/{components/TextEditor/extensions → extensions}/autocomplete.d.ts +0 -0
  85. /package/dist/types/src/{components/TextEditor/extensions → extensions}/basic.d.ts +0 -0
  86. /package/dist/types/src/{components/TextEditor/extensions → extensions}/blast.d.ts +0 -0
  87. /package/dist/types/src/{components/TextEditor/extensions → extensions}/code.d.ts +0 -0
  88. /package/dist/types/src/{components/TextEditor/extensions → extensions}/hr.d.ts +0 -0
  89. /package/dist/types/src/{components/TextEditor/extensions → extensions}/image.d.ts +0 -0
  90. /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/bundle.d.ts +0 -0
  91. /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/highlight.d.ts +0 -0
  92. /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/index.d.ts +0 -0
  93. /package/dist/types/src/{components/TextEditor/extensions → extensions}/mention.d.ts +0 -0
  94. /package/dist/types/src/{components/TextEditor/extensions → extensions}/mermaid.d.ts +0 -0
  95. /package/dist/types/src/{components/TextEditor/extensions → extensions}/table.d.ts +0 -0
  96. /package/dist/types/src/{components/TextEditor/extensions → extensions}/tasklist.d.ts +0 -0
  97. /package/dist/types/src/{components/TextEditor/extensions → extensions}/typewriter.d.ts +0 -0
  98. /package/dist/types/src/{components/TextEditor/extensions → extensions}/util.d.ts +0 -0
  99. /package/dist/types/src/{components/TextEditor/themes → themes}/index.d.ts +0 -0
  100. /package/src/{components/TextEditor/extensions → extensions}/autocomplete.ts +0 -0
  101. /package/src/{components/TextEditor/extensions → extensions}/basic.ts +0 -0
  102. /package/src/{components/TextEditor/extensions → extensions}/blast.ts +0 -0
  103. /package/src/{components/TextEditor/extensions → extensions}/image.ts +0 -0
  104. /package/src/{components/TextEditor/extensions → extensions}/markdown/bundle.ts +0 -0
  105. /package/src/{components/TextEditor/extensions → extensions}/markdown/index.ts +0 -0
  106. /package/src/{components/TextEditor/extensions → extensions}/mention.ts +0 -0
  107. /package/src/{components/TextEditor/extensions → extensions}/mermaid.ts +0 -0
  108. /package/src/{components/TextEditor/extensions → extensions}/table.ts +0 -0
  109. /package/src/{components/TextEditor/extensions → extensions}/tasklist.ts +0 -0
  110. /package/src/{components/TextEditor/extensions → extensions}/util.ts +0 -0
  111. /package/src/{components/TextEditor/themes → themes}/index.ts +0 -0
@@ -12,8 +12,8 @@ import { fixedInsetFlexLayout, groupSurface, mx } from '@dxos/react-ui-theme';
12
12
  import { withTheme } from '@dxos/storybook-utils';
13
13
 
14
14
  import { defaultSlots, TextEditor, type TextEditorProps, type TextEditorRef, type TextEditorSlots } from './TextEditor';
15
- import { textTheme } from './themes';
16
15
  import { useTextModel } from '../../hooks';
16
+ import { textTheme } from '../../themes';
17
17
 
18
18
  const initialText = [
19
19
  '# TextEditor',
@@ -21,10 +21,10 @@ import { generateName } from '@dxos/display-name';
21
21
  import { useThemeContext } from '@dxos/react-ui';
22
22
  import { getColorForValue, inputSurface, mx } from '@dxos/react-ui-theme';
23
23
 
24
- import { basicBundle, markdownBundle, setCommentRange } from './extensions';
25
- import { defaultTheme, markdownTheme, textTheme } from './themes';
24
+ import { basicBundle, markdownBundle, setCommentRange } from '../../extensions';
26
25
  import { type CommentRange, type EditorModel } from '../../hooks';
27
26
  import { type ThemeStyles } from '../../styles';
27
+ import { defaultTheme, markdownTheme, textTheme } from '../../themes';
28
28
 
29
29
  export const EditorModes = ['default', 'vim'] as const;
30
30
  export type EditorMode = (typeof EditorModes)[number];
@@ -56,10 +56,10 @@ export type TextEditorSlots = {
56
56
 
57
57
  export type TextEditorProps = {
58
58
  model: EditorModel;
59
- comments?: CommentRange[];
60
- readonly?: boolean;
61
- editorMode?: EditorMode;
59
+ readonly?: boolean; // TODO(burdon): Move into model.
60
+ comments?: CommentRange[]; // TODO(burdon): Move into extension.
62
61
  extensions?: Extension[];
62
+ editorMode?: EditorMode;
63
63
  slots?: TextEditorSlots;
64
64
  };
65
65
 
@@ -68,7 +68,7 @@ export type TextEditorProps = {
68
68
  * NOTE: Rather than adding properties, try to create extensions that can be reused.
69
69
  */
70
70
  export const BaseTextEditor = forwardRef<TextEditorRef, TextEditorProps>(
71
- ({ model, comments, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
71
+ ({ model, readonly, comments, extensions = [], editorMode, slots = defaultSlots }, forwardedRef) => {
72
72
  const { themeMode } = useThemeContext();
73
73
  const tabsterDOMAttribute = useFocusableGroup({ tabBehavior: 'limited' });
74
74
  const [root, setRoot] = useState<HTMLDivElement | null>(null);
@@ -5,7 +5,4 @@
5
5
  export { tags } from '@lezer/highlight';
6
6
  export { type Extension } from '@codemirror/state';
7
7
 
8
- export * from './extensions';
9
- export * from './themes';
10
-
11
8
  export * from './TextEditor';
@@ -15,7 +15,7 @@ import get from 'lodash.get';
15
15
 
16
16
  import { mx } from '@dxos/react-ui-theme';
17
17
 
18
- import { tokens } from '../../../styles';
18
+ import { tokens } from '../styles';
19
19
 
20
20
  const CODE_REGEX = /```[\s\S]*?```/gs;
21
21
 
@@ -16,6 +16,7 @@ import {
16
16
  WidgetType,
17
17
  type Rect,
18
18
  } from '@codemirror/view';
19
+ import get from 'lodash.get';
19
20
  import sortBy from 'lodash.sortby';
20
21
 
21
22
  import { debounce } from '@dxos/async';
@@ -24,7 +25,8 @@ import { log } from '@dxos/log';
24
25
  import { nonNullable } from '@dxos/util';
25
26
 
26
27
  import { callbackWrapper } from './util';
27
- import { type CommentRange, type EditorModel, modelState, type Range } from '../../../hooks';
28
+ import { type CommentRange, type EditorModel, modelState, type Range } from '../hooks';
29
+ import { tokens } from '../styles';
28
30
 
29
31
  // TODO(burdon): Handle delete, cut, copy, and paste (separately) text that includes comment range.
30
32
  // TODO(burdon): Consider breaking into separate plugin (since not standalone)? Like mermaid?
@@ -41,10 +43,10 @@ const styles = EditorView.baseTheme({
41
43
  backgroundColor: 'orange',
42
44
  },
43
45
  '& .cm-comment': {
44
- backgroundColor: 'yellow',
46
+ backgroundColor: get(tokens, 'extend.colors.yellow.50'),
45
47
  },
46
48
  '& .cm-comment-active': {
47
- backgroundColor: 'orange',
49
+ backgroundColor: get(tokens, 'extend.colors.yellow.100'),
48
50
  },
49
51
  });
50
52
 
@@ -70,9 +72,22 @@ export type CommentsState = CommentSelected & {
70
72
  ranges: ExtendedCommentRange[];
71
73
  };
72
74
 
75
+ export const setFocus = (view: EditorView, thread: string) => {
76
+ const range = view.state.field(commentsStateField).ranges.find((range) => range.id === thread);
77
+ if (!range) {
78
+ return;
79
+ }
80
+
81
+ view.dispatch({
82
+ effects: setSelection.of({ active: thread }),
83
+ selection: { anchor: range.from },
84
+ scrollIntoView: true,
85
+ });
86
+ };
87
+
73
88
  export const setCommentRange = StateEffect.define<{ model: EditorModel; comments: CommentRange[] }>();
74
89
 
75
- const setSelection = StateEffect.define<CommentSelected>();
90
+ export const setSelection = StateEffect.define<CommentSelected>();
76
91
 
77
92
  const setCommentState = StateEffect.define<CommentsState>();
78
93
 
@@ -93,10 +108,12 @@ const commentsStateField = StateField.define<CommentsState>({
93
108
  // Update range from store.
94
109
  if (effect.is(setCommentRange)) {
95
110
  const { model, comments } = effect.value;
96
- const ranges: ExtendedCommentRange[] = comments.map((comment) => {
97
- const range = model.getRangeFromCursor!(comment.cursor)!;
98
- return { ...comment, ...range };
99
- });
111
+ const ranges: ExtendedCommentRange[] = comments
112
+ .map((comment) => {
113
+ const range = model.getRangeFromCursor!(comment.cursor);
114
+ return range && { ...comment, ...range };
115
+ })
116
+ .filter(nonNullable);
100
117
 
101
118
  return { ...value, ranges };
102
119
  }
@@ -284,7 +301,7 @@ export const comments = (options: CommentsOptions = {}): Extension => {
284
301
  ? keymap.of([
285
302
  {
286
303
  key: options?.key ?? "meta-'",
287
- run: createCommentThread,
304
+ run: callbackWrapper(createCommentThread),
288
305
  },
289
306
  ])
290
307
  : [],
@@ -334,7 +351,7 @@ export const comments = (options: CommentsOptions = {}): Extension => {
334
351
  ranges.forEach((range) => {
335
352
  if (from2 === to2) {
336
353
  const newRange = model.getRangeFromCursor!(range.cursor);
337
- if (newRange.to - newRange.from === 0) {
354
+ if (!newRange || newRange.to - newRange.from === 0) {
338
355
  // TODO(burdon): Delete range if empty.
339
356
  log.info('deleted comment', { thread: range.id });
340
357
  }
@@ -13,7 +13,7 @@ import {
13
13
  } from '@codemirror/view';
14
14
  import get from 'lodash.get';
15
15
 
16
- import { tokens } from '../../../styles';
16
+ import { tokens } from '../styles';
17
17
 
18
18
  // TODO(burdon): Reconcile with theme.
19
19
  const styles = EditorView.baseTheme({
@@ -16,5 +16,4 @@ export * from './mention';
16
16
  export * from './mermaid';
17
17
  export * from './table';
18
18
  export * from './tasklist';
19
- export * from './tooltip';
20
19
  export * from './typewriter';
@@ -12,7 +12,11 @@ import {
12
12
  StateField,
13
13
  type Transaction,
14
14
  } from '@codemirror/state';
15
- import { Decoration, EditorView, WidgetType } from '@codemirror/view';
15
+ import { Decoration, EditorView, WidgetType, hoverTooltip } from '@codemirror/view';
16
+
17
+ import { tooltipContent } from '@dxos/react-ui-theme';
18
+
19
+ const markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
16
20
 
17
21
  // Adapted from:
18
22
  // https://codemirror.net/try/?c=aW1wb3J0IHsgYmFzaWNTZXR1cCwgRWRpdG9yVmlldyB9IGZyb20gImNvZGVtaXJyb3IiCmltcG9ydCB7IG1hcmtkb3duIH0gZnJvbSAiQGNvZGVtaXJyb3IvbGFuZy1tYXJrZG93biIKaW1wb3J0IHsgc3ludGF4VHJlZSB9IGZyb20gIkBjb2RlbWlycm9yL2xhbmd1YWdlIjsKaW1wb3J0IHsgRWRpdG9yU3RhdGUsIFJhbmdlU2V0QnVpbGRlciwgU3RhdGVGaWVsZCB9IGZyb20gIkBjb2RlbWlycm9yL3N0YXRlIjsKaW1wb3J0IHsgRGVjb3JhdGlvbiwgV2lkZ2V0VHlwZSB9IGZyb20gIkBjb2RlbWlycm9yL3ZpZXciOwoKY2xhc3MgTGluayBleHRlbmRzIFdpZGdldFR5cGUgewogIGNvbnN0cnVjdG9yKHRleHQsIHVybCkgewogICAgc3VwZXIoKQogICAgdGhpcy50ZXh0ID0gdGV4dAogICAgdGhpcy51cmwgPSB1cmwKICB9CiAgZXEob3RoZXIpIHsgcmV0dXJuIHRoaXMudGV4dCA9PSBvdGhlci50ZXh0ICYmIHRoaXMudXJsID09IG90aGVyLnVybCB9CiAgdG9ET00oKSB7CiAgICBsZXQgbGluayA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKQogICAgbGluay50ZXh0Q29udGVudCA9IHRoaXMudGV4dAogICAgbGluay5ocmVmID0gdGhpcy51cmwKICAgIHJldHVybiBsaW5rOwogIH0KfQoKbGV0IGRlY29yYXRpb25zRmllbGQgPSBTdGF0ZUZpZWxkLmRlZmluZSh7CiAgY3JlYXRlKCkgewogICAgcmV0dXJuIERlY29yYXRpb24ubm9uZTsKICB9LAogIHVwZGF0ZShfLCB0cikgewogICAgY29uc3QgYnVpbGRlciA9IG5ldyBSYW5nZVNldEJ1aWxkZXIoKTsKICAgIGxldCBjdXJzb3IgPSB0ci5zdGF0ZS5zZWxlY3Rpb24ubWFpbi5oZWFkOwogICAgc3ludGF4VHJlZSh0ci5zdGF0ZSkuaXRlcmF0ZSh7CiAgICAgIGVudGVyOiAobm9kZSkgPT4gewogICAgICAgIGlmICgoY3Vyc29yIDwgbm9kZS5mcm9tIHx8IGN1cnNvciA+IG5vZGUudG8pICYmIG5vZGUubmFtZSA9PSAiTGluayIpIHsKICAgICAgICAgIGxldCBtYXJrcyA9IG5vZGUubm9kZS5nZXRDaGlsZHJlbigiTGlua01hcmsiKTsKICAgICAgICAgIGxldCB0ZXh0ID0gbWFya3MubGVuZ3RoID49IDIgPyB0ci5zdGF0ZS5zbGljZURvYyhtYXJrc1swXS50bywgbWFya3NbMV0uZnJvbSkgOiAiIgoKICAgICAgICAgIGxldCB1cmxOb2RlID0gbm9kZS5ub2RlLmdldENoaWxkKCJVUkwiKTsKICAgICAgICAgIGxldCB1cmwgPSB1cmxOb2RlID8gdHIuc3RhdGUuc2xpY2VEb2ModXJsTm9kZS5mcm9tLCB1cmxOb2RlLnRvKSA6ICIiCiAgICAgICAgICBidWlsZGVyLmFkZChub2RlLmZyb20sIG5vZGUudG8sIERlY29yYXRpb24ucmVwbGFjZSh7CiAgICAgICAgICAgIHdpZGdldDogbmV3IExpbmsodGV4dCwgdXJsKSwKICAgICAgICAgIH0pLAogICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfSwKICAgIH0pOwogICAgcmV0dXJuIGJ1aWxkZXIuZmluaXNoKCk7CiAgfSwKICBwcm92aWRlOiAoZikgPT4gRWRpdG9yVmlldy5kZWNvcmF0aW9ucy5mcm9tKGYpLAp9KTsKCmxldCB2aWV3ID0gbmV3IEVkaXRvclZpZXcoewogIGRvYzogIiMgSGVsbG8gV29ybGRcblxuW1Rlc3RdKGh0dHBzOi8vZXhhbXBsZS5jb20pXG5cblxuIiwKICBleHRlbnNpb25zOiBbZGVjb3JhdGlvbnNGaWVsZCwgbWFya2Rvd24oKV0sCiAgcGFyZW50OiBkb2N1bWVudC5ib2R5LAp9KTsKCnZpZXcuZm9jdXMoKTs=
@@ -20,6 +24,7 @@ import { Decoration, EditorView, WidgetType } from '@codemirror/view';
20
24
 
21
25
  export type LinkOptions = {
22
26
  link?: boolean;
27
+ onHover?: (el: Element, url: string) => void;
23
28
  onRender?: (el: Element, url: string) => void;
24
29
  };
25
30
 
@@ -28,11 +33,62 @@ export type LinkOptions = {
28
33
  * https://codemirror.net/docs/ref/#state.StateField
29
34
  */
30
35
  export const link = (options: LinkOptions = {}): Extension => {
31
- return StateField.define<RangeSet<any>>({
32
- create: (state) => update(state, options),
33
- update: (_: RangeSet<any>, tr: Transaction) => update(tr.state, options),
34
- provide: (field) => EditorView.decorations.from(field),
35
- });
36
+ const extensions: Extension[] = [
37
+ StateField.define<RangeSet<any>>({
38
+ create: (state) => update(state, options),
39
+ update: (_: RangeSet<any>, tr: Transaction) => update(tr.state, options),
40
+ provide: (field) => EditorView.decorations.from(field),
41
+ }),
42
+ ];
43
+
44
+ if (options.onHover) {
45
+ extensions.push(
46
+ // https://codemirror.net/examples/tooltip
47
+ // https://codemirror.net/docs/ref/#view.hoverTooltip
48
+ // https://github.com/codemirror/view/blob/main/src/tooltip.ts
49
+ hoverTooltip((view, pos) => {
50
+ const { from, text } = view.state.doc.lineAt(pos);
51
+ const p = pos - from;
52
+
53
+ let idx = 0;
54
+ let match;
55
+ do {
56
+ match = text.substring(idx).match(markdownLinkRegexp);
57
+ if (!match) {
58
+ match = undefined;
59
+ break;
60
+ }
61
+
62
+ idx = text.indexOf(match[0]);
63
+ if (p >= idx && p < idx + match[0].length) {
64
+ break;
65
+ }
66
+
67
+ idx += match[0].length;
68
+ } while (true);
69
+
70
+ if (!match) {
71
+ return null;
72
+ }
73
+
74
+ const [, , url] = match ?? [];
75
+
76
+ return {
77
+ pos: idx + from,
78
+ end: idx + from + match[0].length,
79
+ above: true,
80
+ create: () => {
81
+ const el = document.createElement('div');
82
+ el.className = tooltipContent({}, 'pli-2 plb-1');
83
+ options.onHover!(el, url);
84
+ return { dom: el, offset: { x: 0, y: 4 } };
85
+ },
86
+ };
87
+ }),
88
+ );
89
+ }
90
+
91
+ return extensions;
36
92
  };
37
93
 
38
94
  class LinkButton extends WidgetType {
@@ -56,12 +112,12 @@ class LinkButton extends WidgetType {
56
112
  }
57
113
 
58
114
  class LinkText extends WidgetType {
59
- constructor(private readonly _pos: number, private readonly _text: string, private readonly _url?: string) {
115
+ constructor(private readonly _text: string, private readonly _url?: string) {
60
116
  super();
61
117
  }
62
118
 
63
119
  override eq(other: LinkText) {
64
- return this._pos === other._pos && this._url === other._url;
120
+ return this._url === other._url;
65
121
  }
66
122
 
67
123
  toDOM(view: EditorView) {
@@ -76,7 +132,7 @@ class LinkText extends WidgetType {
76
132
  link.onclick = () => {
77
133
  view.dispatch({
78
134
  selection: {
79
- anchor: this._pos,
135
+ anchor: view.posAtDOM(link),
80
136
  },
81
137
  });
82
138
  };
@@ -112,7 +168,7 @@ const update = (state: EditorState, options: LinkOptions) => {
112
168
  node.from,
113
169
  node.to,
114
170
  Decoration.replace({
115
- widget: new LinkText(node.from, text, options.link ? url : undefined),
171
+ widget: new LinkText(text, options.link ? url : undefined),
116
172
  }),
117
173
  );
118
174
  }
@@ -0,0 +1,35 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Extension } from '@codemirror/state';
6
+ import { EditorView } from '@codemirror/view';
7
+
8
+ export type ListenerOptions = {
9
+ onFocus?: (focused: boolean) => void;
10
+ onChange?: (text: string) => void;
11
+ };
12
+
13
+ /**
14
+ * Event listener.
15
+ */
16
+ export const listener = ({ onFocus, onChange }: ListenerOptions): Extension => {
17
+ const extensions: Extension[] = [];
18
+
19
+ onFocus &&
20
+ extensions.push(
21
+ EditorView.focusChangeEffect.of((_, focused) => {
22
+ onFocus(focused);
23
+ return null;
24
+ }),
25
+ );
26
+
27
+ onChange &&
28
+ extensions.push(
29
+ EditorView.updateListener.of((update) => {
30
+ onChange(update.state.doc.toString());
31
+ }),
32
+ );
33
+
34
+ return extensions;
35
+ };
@@ -19,7 +19,7 @@ import {
19
19
  mark,
20
20
  strikethrough,
21
21
  tokens,
22
- } from '../../../../styles';
22
+ } from '../../styles';
23
23
 
24
24
  /**
25
25
  * Custom tags defined and processed by the GFM lezer extension.
@@ -19,7 +19,7 @@ const defaultItems = ['hello world!', 'this is a test.', 'this is [DXOS](https:/
19
19
  */
20
20
  export const typewriter = ({ delay = 75, items = defaultItems }: DemoOptions = {}): Extension => {
21
21
  let t: any;
22
- let idx = 0;
22
+ let idx = 0; // TODO(burdon): Make global.
23
23
 
24
24
  return [
25
25
  keymap.of([
@@ -83,15 +83,13 @@ export const automergePlugin = (handle: IDocHandle, path: Prop[]): AutomergePlug
83
83
 
84
84
  const viewPlugin = ViewPlugin.fromClass(
85
85
  class AutomergeCodemirrorViewPlugin implements PluginValue {
86
- private _view: EditorView;
87
-
88
- constructor(view: EditorView) {
89
- this._view = view;
86
+ constructor(private readonly _view: EditorView) {
90
87
  handle.addListener('change', this._handleChange);
91
88
  }
92
89
 
93
90
  update(update: ViewUpdate) {
94
- if (update.transactions.length > 0 && update.transactions.some((t) => !isReconcileTx(t))) {
91
+ if (update.transactions.length > 0 && update.transactions.some((tr) => !isReconcileTx(tr))) {
92
+ // TODO(burdon): This is a hack to ensure that the view is updated after the transaction is applied.
95
93
  queueMicrotask(() => {
96
94
  this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
97
95
  });
@@ -55,7 +55,7 @@ export type EditorModel = {
55
55
  content: string | YText | YXmlFragment | DocAccessor;
56
56
  text: () => string;
57
57
  getCursorFromRange?: (value: Range) => string;
58
- getRangeFromCursor?: (cursor: string) => Range;
58
+ getRangeFromCursor?: (cursor: string) => Range | undefined;
59
59
  extension?: Extension;
60
60
  awareness?: Awareness;
61
61
  peer?: {
@@ -110,16 +110,17 @@ const createYjsModel = ({ identity, space, text }: UseTextModelProps): EditorMod
110
110
  return [arrayToString(from), arrayToString(to)].join(':');
111
111
  },
112
112
  getRangeFromCursor: (cursor: string) => {
113
+ invariant(text.doc);
113
114
  const parts = cursor.split(':');
114
115
  const from = Y.createAbsolutePositionFromRelativePosition(
115
116
  Y.decodeRelativePosition(stringToArray(parts[0])),
116
- text.doc!,
117
+ text.doc,
117
118
  );
118
119
  const to = Y.createAbsolutePositionFromRelativePosition(
119
120
  Y.decodeRelativePosition(stringToArray(parts[1])),
120
- text.doc!,
121
+ text.doc,
121
122
  );
122
- return { from: from!.index, to: to!.index };
123
+ return from && to ? { from: from.index, to: to.index } : undefined;
123
124
  },
124
125
  extension: [yCollab(text.content as YText, provider?.awareness), modelState.init(() => model)],
125
126
  awareness: provider?.awareness,
package/src/index.ts CHANGED
@@ -7,4 +7,6 @@ export { Doc, YText, YXmlFragment } from '@dxos/text-model';
7
7
  export { type Extension } from '@codemirror/state';
8
8
 
9
9
  export * from './components';
10
+ export * from './extensions';
10
11
  export * from './hooks';
12
+ export * from './themes';
@@ -4,7 +4,7 @@
4
4
 
5
5
  import get from 'lodash.get';
6
6
 
7
- import { type ThemeStyles, tokens } from '../../../styles';
7
+ import { type ThemeStyles, tokens } from '../styles';
8
8
 
9
9
  // TODO(burdon): Can we erase All of the default CM styles?
10
10
  // TODO(burdon): Theme styles seem to be added multiple times?
@@ -1 +0,0 @@
1
- {"version":3,"file":"autocomplete.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/autocomplete.ts"],"names":[],"mappings":"AAQA,OAAO,EAGL,KAAK,UAAU,EAGhB,MAAM,0BAA0B,CAAC;AAGlC,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC;AAE5C,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,UAAU,EAAE,CAAC;CAC1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,YAAY,iBAAkB,mBAAmB,4CAgC7D,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"basic.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/basic.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,WAAW,uDAAwD,kBAAkB,KAAG,SAAS,EAa5E,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"blast.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/blast.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAMnD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,gBAAgB,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC/C,qBAAqB,EAAE;QAAE,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,CAAC;IACpE,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,MAAM,EAAE,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,YAU5B,CAAC;AAEF,eAAO,MAAM,KAAK,aAAa,QAAQ,YAAY,CAAC,KAAoB,SAmEvE,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/code.ts"],"names":[],"mappings":"AAuDA,eAAO,MAAM,IAAI,+CA2ChB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"comments.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/comments.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAA2B,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAWL,KAAK,IAAI,EACV,MAAM,kBAAkB,CAAC;AAS1B,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,WAAW,EAAc,KAAK,KAAK,EAAE,MAAM,gBAAgB,CAAC;AA8B7F,KAAK,eAAe,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAGF,KAAK,oBAAoB,GAAG,KAAK,GAC/B,YAAY,GAAG;IAEb,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;CACxB,CAAC;AAEJ,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAC5C,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC,CAAC;AAEF,eAAO,MAAM,eAAe;WAA+B,WAAW;cAAY,YAAY,EAAE;EAAK,CAAC;AA+FtG,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;IACjD;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC1C;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,KAAK,IAAI,CAAC;CACjC,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,QAAQ,aAAa,eAAe,KAAQ,SA+LxD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hr.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/hr.ts"],"names":[],"mappings":"AAmDA,eAAO,MAAM,EAAE,+CAsBd,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/image.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,mBAAmB,CAAC;AAG3B,MAAM,MAAM,YAAY,GAAG,EAAE,CAAC;AAE9B,eAAO,MAAM,KAAK,aAAa,YAAY,KAAQ,SAMlD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,MAAM,CAAC;AACrB,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AACvB,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,cAAc,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/link.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,SAAS,EAKf,MAAM,mBAAmB,CAAC;AAO3B,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,IAAI,aAAa,WAAW,KAAQ,SAMhD,CAAC"}
@@ -1,9 +0,0 @@
1
- import { StateField } from '@codemirror/state';
2
- export type ListenerOptions = {
3
- onChange: (text: string) => void;
4
- };
5
- /**
6
- * Based on https://github.com/codemirror/dev/issues/44#issuecomment-789093799
7
- */
8
- export declare const listener: ({ onChange }: ListenerOptions) => StateField<null>;
9
- //# sourceMappingURL=listener.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"listener.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/listener.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,MAAM,eAAe,GAAG;IAAE,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAAC;AAEnE;;GAEG;AACH,eAAO,MAAM,QAAQ,iBAAkB,eAAe,qBAWrD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"bundle.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/TextEditor/extensions/markdown/bundle.ts"],"names":[],"mappings":"AAUA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAYhE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIhD,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF;;;;;;;GAOG;AAEH,eAAO,MAAM,cAAc,wDAIxB,qBAAqB,KAAG,SAAS,EA6CnC,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/TextEditor/extensions/markdown/highlight.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAmB,GAAG,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,KAAK,cAAc,EAAS,MAAM,iBAAiB,CAAC;AAgB7D;;;;GAIG;AACH,eAAO,MAAM,YAAY;;;;;;;;;;;;;CAgBxB,CAAC;AAaF,eAAO,MAAM,sBAAsB,EAAE,cAAc,EAKlD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,cAAe,OAAO,mBAgIxD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/components/TextEditor/extensions/markdown/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"mention.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/mention.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;CACtC,CAAC;AAEF,eAAO,MAAM,OAAO,iBAAkB,cAAc,KAAG,SAmBtD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/mermaid.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,eAAO,MAAM,OAAO,QAAO,SAE1B,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/table.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoB,KAAK,QAAQ,EAAmB,UAAU,EAAoB,MAAM,mBAAmB,CAAC;AASnH,MAAM,MAAM,YAAY,GAAG,EAAE,CAAC;AAE9B;;;GAGG;AACH,eAAO,MAAM,KAAK,aAAa,YAAY,8BAM1C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tasklist.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/tasklist.ts"],"names":[],"mappings":"AA+DA,MAAM,MAAM,eAAe,GAAG,EAAE,CAAC;AAEjC,eAAO,MAAM,QAAQ,aAAa,eAAe,4CAuDhD,CAAC"}
@@ -1,12 +0,0 @@
1
- import { type Extension } from '@codemirror/state';
2
- export type TooltipOptions = {
3
- onHover: (el: Element, url: string) => void;
4
- regexp?: RegExp;
5
- };
6
- /**
7
- * https://codemirror.net/examples/tooltip
8
- * https://codemirror.net/docs/ref/#view.hoverTooltip
9
- * https://github.com/codemirror/view/blob/main/src/tooltip.ts
10
- */
11
- export declare const tooltip: ({ onHover, regexp }: TooltipOptions) => Extension;
12
- //# sourceMappingURL=tooltip.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/tooltip.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAOnD,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,OAAO,wBAA8C,cAAc,KAAG,SAuC/E,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"typewriter.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/typewriter.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAKnD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,UAAU,sBAA0C,WAAW,KAAQ,SAgDnF,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/extensions/util.ts"],"names":[],"mappings":"AAMA;;GAEG;AAEH,eAAO,MAAM,eAAe,kCAOR,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/themes/default.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,WAAW,EAAU,MAAM,iBAAiB,CAAC;AAK3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,EAAE,WA8P1B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,WAOvB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,WAK3B,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,WAOvB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/components/TextEditor/themes/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC"}
@@ -1,23 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import { StateField } from '@codemirror/state';
6
-
7
- export type ListenerOptions = { onChange: (text: string) => void };
8
-
9
- /**
10
- * Based on https://github.com/codemirror/dev/issues/44#issuecomment-789093799
11
- */
12
- export const listener = ({ onChange }: ListenerOptions) => {
13
- return StateField.define({
14
- create: () => null,
15
- update: (_value, transaction) => {
16
- if (transaction.docChanged && onChange) {
17
- onChange(transaction.newDoc.toString());
18
- }
19
-
20
- return null;
21
- },
22
- });
23
- };
@@ -1,61 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import { type Extension } from '@codemirror/state';
6
- import { hoverTooltip } from '@codemirror/view';
7
-
8
- import { tooltipContent } from '@dxos/react-ui-theme';
9
-
10
- const markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
11
-
12
- export type TooltipOptions = {
13
- onHover: (el: Element, url: string) => void;
14
- regexp?: RegExp;
15
- };
16
-
17
- /**
18
- * https://codemirror.net/examples/tooltip
19
- * https://codemirror.net/docs/ref/#view.hoverTooltip
20
- * https://github.com/codemirror/view/blob/main/src/tooltip.ts
21
- */
22
- export const tooltip = ({ onHover, regexp = markdownLinkRegexp }: TooltipOptions): Extension =>
23
- hoverTooltip((view, pos) => {
24
- const { from, text } = view.state.doc.lineAt(pos);
25
- const p = pos - from;
26
-
27
- let idx = 0;
28
- let match;
29
- do {
30
- match = text.substring(idx).match(regexp);
31
- if (!match) {
32
- match = undefined;
33
- break;
34
- }
35
-
36
- idx = text.indexOf(match[0]);
37
- if (p >= idx && p < idx + match[0].length) {
38
- break;
39
- }
40
-
41
- idx += match[0].length;
42
- } while (true);
43
-
44
- if (!match) {
45
- return null;
46
- }
47
-
48
- const [, , url] = match ?? [];
49
-
50
- return {
51
- pos: idx + from,
52
- end: idx + from + match[0].length,
53
- above: true,
54
- create: () => {
55
- const el = document.createElement('div');
56
- el.className = tooltipContent({}, 'pli-2 plb-1');
57
- onHover(el, url);
58
- return { dom: el, offset: { x: 0, y: 4 } };
59
- },
60
- };
61
- });