@dxos/react-ui-editor 0.3.9-main.9ca5eac → 0.3.9-main.9da1d41

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 (149) hide show
  1. package/dist/lib/browser/index.mjs +654 -734
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts +2 -2
  5. package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +1 -1
  6. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +2 -2
  7. package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +1 -1
  8. package/dist/types/src/automerge/automerge-plugin/handle.d.ts +9 -0
  9. package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +1 -0
  10. package/dist/types/src/automerge/automerge-plugin/index.d.ts +2 -2
  11. package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -1
  12. package/dist/types/src/automerge/automerge-plugin/plugin.d.ts +6 -5
  13. package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +1 -1
  14. package/dist/types/src/automerge/automerge.stories.d.ts +1 -0
  15. package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -1
  16. package/dist/types/src/components/TextEditor/TextEditor.d.ts +24 -20
  17. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  18. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +2 -25
  19. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  20. package/dist/types/{stories/html/code-mirror.stories.d.ts → src/components/TextEditor/codemirror.stories.d.ts} +2 -2
  21. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -0
  22. package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts +8 -0
  23. package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +1 -0
  24. package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +3 -0
  25. package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +1 -0
  26. package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +10 -0
  27. package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +1 -0
  28. package/dist/types/src/components/TextEditor/extensions/change.d.ts +7 -0
  29. package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +1 -0
  30. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +11 -0
  31. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +1 -0
  32. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
  33. package/dist/types/src/components/TextEditor/extensions/{hyperlink.d.ts → hyperlink/hyperlinkWidget.d.ts} +3 -3
  34. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
  35. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
  36. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
  37. package/dist/types/src/components/TextEditor/extensions/index.d.ts +3 -1
  38. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  39. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +8 -0
  40. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -0
  41. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +3 -0
  42. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -0
  43. package/dist/types/src/components/{Markdown/markdownTags.d.ts → TextEditor/extensions/markdown/tags.d.ts} +1 -1
  44. package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
  45. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
  46. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
  47. package/dist/types/src/components/TextEditor/index.d.ts +1 -3
  48. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
  49. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +11 -0
  50. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
  51. package/dist/types/src/components/index.d.ts +0 -3
  52. package/dist/types/src/components/index.d.ts.map +1 -1
  53. package/dist/types/src/hooks/index.d.ts +4 -0
  54. package/dist/types/src/hooks/index.d.ts.map +1 -0
  55. package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
  56. package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
  57. package/dist/types/src/{model.d.ts → hooks/useTextModel.d.ts} +1 -13
  58. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
  59. package/dist/types/src/hooks/yjs/cursors.d.ts.map +1 -0
  60. package/dist/types/src/hooks/yjs/index.d.ts.map +1 -0
  61. package/dist/types/src/hooks/yjs/space-provider.d.ts.map +1 -0
  62. package/dist/types/src/index.d.ts +2 -2
  63. package/dist/types/src/index.d.ts.map +1 -1
  64. package/dist/types/src/styles/tokens.d.ts +4 -0
  65. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  66. package/dist/types/src/testing/replicator.d.ts +1 -1
  67. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  68. package/package.json +30 -27
  69. package/src/automerge/automerge-plugin/PatchSemaphore.ts +5 -5
  70. package/src/automerge/automerge-plugin/codeMirrorToAm.ts +10 -7
  71. package/src/automerge/automerge-plugin/handle.ts +14 -0
  72. package/src/automerge/automerge-plugin/index.ts +2 -2
  73. package/src/automerge/automerge-plugin/plugin.ts +39 -10
  74. package/src/automerge/automerge.stories.tsx +31 -46
  75. package/src/components/TextEditor/TextEditor.stories.tsx +43 -65
  76. package/src/components/TextEditor/TextEditor.tsx +108 -56
  77. package/src/components/TextEditor/codemirror.stories.ts +114 -0
  78. package/src/components/TextEditor/extensions/basic/bundle.ts +26 -0
  79. package/src/components/TextEditor/extensions/basic/index.ts +6 -0
  80. package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
  81. package/src/components/TextEditor/extensions/change.ts +22 -0
  82. package/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts +99 -0
  83. package/src/components/TextEditor/extensions/{hyperlinkTooltip.tsx → hyperlink/hyperlinkTooltip.tsx} +1 -0
  84. package/src/components/TextEditor/extensions/{hyperlink.tsx → hyperlink/hyperlinkWidget.tsx} +21 -10
  85. package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
  86. package/src/components/TextEditor/extensions/index.ts +3 -1
  87. package/src/components/TextEditor/extensions/markdown/bundle.ts +99 -0
  88. package/src/components/TextEditor/extensions/markdown/index.ts +6 -0
  89. package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts} +23 -12
  90. package/src/components/TextEditor/index.ts +1 -4
  91. package/src/components/TextEditor/yjs.stories.tsx +55 -0
  92. package/src/components/index.ts +0 -3
  93. package/src/hooks/index.ts +7 -0
  94. package/src/hooks/useCollaboration.ts +35 -0
  95. package/src/{model.ts → hooks/useTextModel.ts} +4 -14
  96. package/src/index.ts +3 -3
  97. package/src/styles/tokens.ts +6 -0
  98. package/src/testing/replicator.ts +1 -2
  99. package/dist/types/src/automerge/demo.d.ts +0 -25
  100. package/dist/types/src/automerge/demo.d.ts.map +0 -1
  101. package/dist/types/src/components/Editor/Editor.d.ts +0 -15
  102. package/dist/types/src/components/Editor/Editor.d.ts.map +0 -1
  103. package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -29
  104. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +0 -1
  105. package/dist/types/src/components/Editor/index.d.ts +0 -2
  106. package/dist/types/src/components/Editor/index.d.ts.map +0 -1
  107. package/dist/types/src/components/Markdown/Markdown.d.ts +0 -20
  108. package/dist/types/src/components/Markdown/Markdown.d.ts.map +0 -1
  109. package/dist/types/src/components/Markdown/Markdown.stories.d.ts +0 -20
  110. package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +0 -1
  111. package/dist/types/src/components/Markdown/index.d.ts +0 -2
  112. package/dist/types/src/components/Markdown/index.d.ts.map +0 -1
  113. package/dist/types/src/components/Markdown/markdownTags.d.ts.map +0 -1
  114. package/dist/types/src/components/Markdown/markdownTheme.d.ts +0 -93
  115. package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +0 -1
  116. package/dist/types/src/components/RichText/RichText.d.ts +0 -20
  117. package/dist/types/src/components/RichText/RichText.d.ts.map +0 -1
  118. package/dist/types/src/components/RichText/RichText.stories.d.ts +0 -27
  119. package/dist/types/src/components/RichText/RichText.stories.d.ts.map +0 -1
  120. package/dist/types/src/components/RichText/index.d.ts +0 -2
  121. package/dist/types/src/components/RichText/index.d.ts.map +0 -1
  122. package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts.map +0 -1
  123. package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts.map +0 -1
  124. package/dist/types/src/components/TextEditor/theme.d.ts +0 -8
  125. package/dist/types/src/components/TextEditor/theme.d.ts.map +0 -1
  126. package/dist/types/src/model.d.ts.map +0 -1
  127. package/dist/types/src/yjs/cursors.d.ts.map +0 -1
  128. package/dist/types/src/yjs/index.d.ts.map +0 -1
  129. package/dist/types/src/yjs/space-provider.d.ts.map +0 -1
  130. package/dist/types/stories/html/code-mirror.stories.d.ts.map +0 -1
  131. package/src/automerge/demo.ts +0 -106
  132. package/src/components/Editor/Editor.stories.tsx +0 -82
  133. package/src/components/Editor/Editor.tsx +0 -33
  134. package/src/components/Editor/index.ts +0 -5
  135. package/src/components/Markdown/Markdown.stories.tsx +0 -59
  136. package/src/components/Markdown/Markdown.tsx +0 -214
  137. package/src/components/Markdown/index.ts +0 -5
  138. package/src/components/RichText/RichText.stories.tsx +0 -70
  139. package/src/components/RichText/RichText.tsx +0 -181
  140. package/src/components/RichText/index.ts +0 -5
  141. package/src/components/TextEditor/theme.ts +0 -33
  142. /package/dist/types/src/components/TextEditor/extensions/{hyperlinkTooltip.d.ts → hyperlink/hyperlinkTooltip.d.ts} +0 -0
  143. /package/dist/types/src/{yjs → hooks/yjs}/cursors.d.ts +0 -0
  144. /package/dist/types/src/{yjs → hooks/yjs}/index.d.ts +0 -0
  145. /package/dist/types/src/{yjs → hooks/yjs}/space-provider.d.ts +0 -0
  146. /package/src/components/{Markdown/markdownTags.ts → TextEditor/extensions/markdown/tags.ts} +0 -0
  147. /package/src/{yjs → hooks/yjs}/cursors.ts +0 -0
  148. /package/src/{yjs → hooks/yjs}/index.ts +0 -0
  149. /package/src/{yjs → hooks/yjs}/space-provider.ts +0 -0
@@ -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
+ };
@@ -0,0 +1,6 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './bundle';
6
+ export * from './theme';
@@ -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 './markdownTags';
11
- import { bold, heading, italic, mark, strikethrough, tokens } from '../../styles';
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
- export const markdownTheme = {
36
- // TODO(thure): consider whether these commented-out rules from one-dark-theme should be integrated.
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: cursor,
125
+ caretColor: 'white',
123
126
  },
124
127
  '& .cm-cursor': {
125
128
  borderLeftColor: 'black',
126
129
  },
127
130
  '.dark & .cm-cursor': {
128
- borderLeftColor: cursor,
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 markdownDarkHighlighting = HighlightStyle.define(
188
+ export const markdownHighlightStyle = HighlightStyle.define(
178
189
  [
179
190
  {
180
191
  tag: [
@@ -2,10 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export { type StyleSpec } from 'style-mod';
6
5
  export { tags } from '@lezer/highlight';
7
6
 
8
- export * from './TextEditor';
9
-
10
7
  export * from './extensions';
11
- export * from './theme';
8
+ export * from './TextEditor';
@@ -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 : 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
+ };
@@ -2,7 +2,4 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- export * from './Editor';
6
- export * from './Markdown';
7
- export * from './RichText';
8
5
  export * from './TextEditor';
@@ -0,0 +1,7 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './useCollaboration';
6
+ export * from './useTextModel';
7
+ export * from './yjs';
@@ -0,0 +1,35 @@
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 type { ThemeMode } from '@dxos/react-ui';
11
+ import { getColorForValue } from '@dxos/react-ui-theme';
12
+ import { YText } from '@dxos/text-model';
13
+
14
+ import type { EditorModel } from './useTextModel';
15
+
16
+ /**
17
+ * Replication and awareness (incl. remote selection).
18
+ * https://codemirror.net/docs/ref/#collab
19
+ */
20
+ export const useCollaboration = (model: EditorModel, themeMode: ThemeMode): Extension | undefined => {
21
+ const { provider, peer, content } = model;
22
+ const extension = useMemo(() => (content instanceof YText ? yCollab(content, provider?.awareness) : undefined), []);
23
+
24
+ useEffect(() => {
25
+ if (provider && peer) {
26
+ provider.awareness.setLocalStateField('user', {
27
+ name: peer.name ?? generateName(peer.id),
28
+ color: getColorForValue({ value: peer.id, type: 'color' }),
29
+ colorLight: getColorForValue({ value: peer.id, themeMode, type: 'highlight' }),
30
+ });
31
+ }
32
+ }, [provider, peer, themeMode]);
33
+
34
+ return extension;
35
+ };
@@ -2,8 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type EditorView } from '@codemirror/view';
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
8
  import { type Space, type TextObject } from '@dxos/react-client/echo';
@@ -12,17 +11,7 @@ import type { YText, YXmlFragment } from '@dxos/text-model';
12
11
 
13
12
  import { SpaceAwarenessProvider } from './yjs';
14
13
 
15
- export type EditorSlots = {
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
-
14
+ // TODO(burdon): Move.
26
15
  type Awareness = awarenessProtocol.Awareness;
27
16
  type Provider = { awareness: Awareness };
28
17
 
@@ -43,8 +32,9 @@ export type UseTextModelOptions = {
43
32
  text?: TextObject;
44
33
  };
45
34
 
46
- // TODO(wittjosiah): Factor out to common package? @dxos/react-client?
35
+ // TODO(burdon): Don't support returning undefined (and remove checks from calling code).
47
36
  // TODO(burdon): Decouple space (make Editor less dependent on entire stack)?
37
+ // TODO(wittjosiah): Factor out to common package? @dxos/react-client?
48
38
  export const useTextModel = ({ identity, space, text }: UseTextModelOptions): EditorModel | undefined => {
49
39
  const provider = useMemo(() => {
50
40
  if (!space || !text?.doc) {
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';
@@ -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;
@@ -15,8 +15,7 @@ import { Event } from '@dxos/async';
15
15
  import { log } from '@dxos/log';
16
16
  import { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
17
17
 
18
- import { type EditorModel } from '../model';
19
- import { cursorColor } from '../yjs';
18
+ import { cursorColor, type EditorModel } from '../hooks';
20
19
 
21
20
  type Awareness = awarenessProtocol.Awareness;
22
21
 
@@ -1,25 +0,0 @@
1
- import { Event } from '@dxos/async';
2
- import { type Doc, next as automerge, type ChangeOptions, type ChangeFn, type Heads } from '@dxos/automerge/automerge';
3
- export declare class Peer {
4
- changeEvent: Event<void>;
5
- storage: Map<string, Uint8Array>;
6
- stats: {
7
- messagesSent: number;
8
- messagesReceived: number;
9
- bytesSent: number;
10
- bytesReceived: number;
11
- snapshotBytes: number;
12
- incrementalBytes: number;
13
- };
14
- doc: Doc<{
15
- text: string;
16
- }>;
17
- change(options: string | ChangeOptions<any> | ChangeFn<any>, callback?: ChangeFn<any>): void;
18
- changeAt(scope: Heads, options: string | ChangeOptions<any> | ChangeFn<any>, callback?: ChangeFn<any>): automerge.Heads | null;
19
- replicate(): {
20
- readable: ReadableStream<Uint8Array>;
21
- writable: WritableStream<Uint8Array>;
22
- };
23
- private _handleChange;
24
- }
25
- //# sourceMappingURL=demo.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"demo.d.ts","sourceRoot":"","sources":["../../../../src/automerge/demo.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACpC,OAAO,EACL,KAAK,GAAG,EACR,IAAI,IAAI,SAAS,EACjB,KAAK,aAAa,EAClB,KAAK,QAAQ,EACb,KAAK,KAAK,EAEX,MAAM,2BAA2B,CAAC;AAEnC,qBAAa,IAAI;IACf,WAAW,cAAe;IAE1B,OAAO,0BAAiC;IACxC,KAAK;;;;;;;MAOH;IAEF,GAAG,EAAG,GAAG,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAE5B,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC;IAKrF,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC,GAAG,CAAC;IAOrG,SAAS,IAAI;QAAE,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;KAAE;IAgD3F,OAAO,CAAC,aAAa;CAgBtB"}
@@ -1,15 +0,0 @@
1
- import React from 'react';
2
- import { type EditorSlots, type UseTextModelOptions } from '../../model';
3
- import { type MarkdownEditorRef } from '../Markdown';
4
- export type EditorProps = UseTextModelOptions & {
5
- slots?: EditorSlots;
6
- };
7
- /**
8
- * Memoized editor which depends on DXOS platform.
9
- *
10
- * Determines which editor to render based on the kind of text.
11
- */
12
- export declare const Editor: React.MemoExoticComponent<React.ForwardRefExoticComponent<UseTextModelOptions & {
13
- slots?: EditorSlots | undefined;
14
- } & React.RefAttributes<MarkdownEditorRef | import("@tiptap/react").Editor>>>;
15
- //# sourceMappingURL=Editor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Editor.d.ts","sourceRoot":"","sources":["../../../../../src/components/Editor/Editor.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAI1D,OAAO,EAAE,KAAK,WAAW,EAAgB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAkB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrE,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG;IAC9C,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AAGH,eAAO,MAAM,MAAM;;6EASlB,CAAC"}
@@ -1,29 +0,0 @@
1
- import '@dxosTheme';
2
- import React from 'react';
3
- declare const _default: {
4
- component: React.MemoExoticComponent<React.ForwardRefExoticComponent<import("../..").UseTextModelOptions & {
5
- slots?: import("../..").EditorSlots | undefined;
6
- } & React.RefAttributes<import("..").MarkdownEditorRef | import("@tiptap/react").Editor>>>;
7
- decorators: import("@storybook/react").Decorator[];
8
- };
9
- export default _default;
10
- export declare const Markdown: {
11
- render: (args: {
12
- id: number;
13
- }) => JSX.Element;
14
- decorators: import("@storybook/csf").DecoratorFunction<import("@storybook/react/dist/types-0fc72a6d").R, any>[];
15
- };
16
- export declare const Rich: {
17
- render: (args: {
18
- id: number;
19
- }) => JSX.Element;
20
- args: {
21
- slots: {
22
- editor: {
23
- className: string;
24
- };
25
- };
26
- };
27
- decorators: import("@storybook/csf").DecoratorFunction<import("@storybook/react/dist/types-0fc72a6d").R, any>[];
28
- };
29
- //# sourceMappingURL=Editor.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Editor.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Editor/Editor.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAEpB,OAAO,KAAmB,MAAM,OAAO,CAAC;;;;;;;AAYxC,wBAGE;AAoCF,eAAO,MAAM,QAAQ;mBACJ;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE;;CAE9B,CAAC;AAWF,eAAO,MAAM,IAAI;mBACA;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE;;;;;;;;;CAS9B,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './Editor';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Editor/index.ts"],"names":[],"mappings":"AAIA,cAAc,UAAU,CAAC"}
@@ -1,20 +0,0 @@
1
- import { EditorState, type Extension, type Text } from '@codemirror/state';
2
- import { EditorView } from '@codemirror/view';
3
- import React from 'react';
4
- import { type EditorModel, type EditorSlots } from '../../model';
5
- export declare const EditorModes: readonly ["default", "vim"];
6
- export type EditorMode = (typeof EditorModes)[number];
7
- export type MarkdownEditorProps = {
8
- model?: EditorModel;
9
- slots?: EditorSlots;
10
- editorMode?: EditorMode;
11
- extensions?: Extension[];
12
- onChange?: (content: string | Text) => void;
13
- };
14
- export type MarkdownEditorRef = {
15
- editor: HTMLDivElement | null;
16
- state?: EditorState;
17
- view?: EditorView;
18
- };
19
- export declare const MarkdownEditor: React.ForwardRefExoticComponent<MarkdownEditorProps & React.RefAttributes<MarkdownEditorRef>>;
20
- //# sourceMappingURL=Markdown.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Markdown.d.ts","sourceRoot":"","sources":["../../../../../src/components/Markdown/Markdown.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAE,WAAW,EAAE,KAAK,SAAS,EAAc,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEvF,OAAO,EAUL,UAAU,EACX,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAQN,MAAM,OAAO,CAAC;AAUf,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAEjE,eAAO,MAAM,WAAW,6BAA8B,CAAC;AACvD,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAEtD,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,UAAU,CAAC,EAAE,SAAS,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;CAC7C,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,cAAc,GAAG,IAAI,CAAC;IAC9B,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB,CAAC;AAEF,eAAO,MAAM,cAAc,+FA+I1B,CAAC"}
@@ -1,20 +0,0 @@
1
- import '@dxosTheme';
2
- import React from 'react';
3
- declare const _default: {
4
- component: React.ForwardRefExoticComponent<import("./Markdown").MarkdownEditorProps & React.RefAttributes<import("./Markdown").MarkdownEditorRef>>;
5
- decorators: import("@storybook/react").Decorator[];
6
- };
7
- export default _default;
8
- export declare const Default: {
9
- args: {
10
- model: {
11
- id: string;
12
- content: string;
13
- };
14
- };
15
- };
16
- export declare const WithYjs: {
17
- render: () => JSX.Element;
18
- decorators: import("@storybook/csf").DecoratorFunction<import("@storybook/react/dist/types-0fc72a6d").R, any>[];
19
- };
20
- //# sourceMappingURL=Markdown.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Markdown.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/Markdown/Markdown.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAEpB,OAAO,KAAmB,MAAM,OAAO,CAAC;;;;;AAWxC,wBAGE;AAEF,eAAO,MAAM,OAAO;;;;;;;CAOnB,CAAC;AAIF,eAAO,MAAM,OAAO;;;CAyBnB,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './Markdown';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/Markdown/index.ts"],"names":[],"mappings":"AAIA,cAAc,YAAY,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdownTags.d.ts","sourceRoot":"","sources":["../../../../../src/components/Markdown/markdownTags.ts"],"names":[],"mappings":"AAIA,OAAO,EAAa,GAAG,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD,eAAO,MAAM,YAAY;;;;;;;;;;;;CAYxB,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,cAgBnC,CAAC"}
@@ -1,93 +0,0 @@
1
- import { HighlightStyle } from '@codemirror/language';
2
- export declare const chalky = "#e5c07b";
3
- export declare const coral = "#e06c75";
4
- export declare const cyan = "#56b6c2";
5
- export declare const invalid = "#ffffff";
6
- export declare const ivory = "#abb2bf";
7
- export declare const stone = "#7d8799";
8
- export declare const malibu = "#61afef";
9
- export declare const sage = "#98c379";
10
- export declare const whiskey = "#d19a66";
11
- export declare const violet = "#c678dd";
12
- export declare const highlightBackground = "#2c313a";
13
- export declare const tooltipBackground = "#353a42";
14
- export declare const cursor = "#ffffff";
15
- export declare const markdownTheme: {
16
- '.cm-tooltip': {
17
- backgroundColor: string;
18
- border: string;
19
- };
20
- '&.cm-focused': {
21
- outline: string;
22
- };
23
- '& .cm-line': {
24
- paddingInline: number;
25
- minBlockSize: string;
26
- };
27
- '& .cm-line *': {
28
- lineHeight: number;
29
- };
30
- '&.cm-focused .cm-selectionBackground, & .cm-selectionBackground': {
31
- background: any;
32
- };
33
- '.dark & .cm-selectionBackground, .dark &.cm-focused .cm-selectionBackground': {
34
- background: any;
35
- };
36
- '& .cm-selectionMatch': {
37
- background: string;
38
- };
39
- '.dark & .cm-selectionMatch': {
40
- background: string;
41
- };
42
- '& .cm-content': {
43
- caretColor: string;
44
- };
45
- '.dark & .cm-content': {
46
- caretColor: string;
47
- };
48
- '& .cm-cursor': {
49
- borderLeftColor: string;
50
- };
51
- '.dark & .cm-cursor': {
52
- borderLeftColor: string;
53
- };
54
- '.cm-placeholder': {
55
- fontFamily: any;
56
- };
57
- '& .cm-scroller': {
58
- fontFamily: any;
59
- overflow: string;
60
- };
61
- '& .cm-activeLine': {
62
- backgroundColor: string;
63
- };
64
- '.dark & .cm-activeLine': {
65
- backgroundColor: string;
66
- };
67
- '& .cm-ySelectionInfo': {
68
- fontFamily: any;
69
- padding: string;
70
- marginBlockStart: string;
71
- };
72
- '& .cm-ySelection, & .cm-selectionMatch': {
73
- paddingBlockStart: string;
74
- paddingBlockEnd: string;
75
- };
76
- '& .cm-ySelection, & .cm-yLineSelection': {
77
- mixBlendMode: string;
78
- };
79
- '.dark & .cm-ySelection, .dark & .cm-yLineSelection': {
80
- mixBlendMode: string;
81
- };
82
- '& .cm-ySelectionCaret': {
83
- display: string;
84
- insetBlockStart: string;
85
- blockSize: string;
86
- verticalAlign: string;
87
- };
88
- '& .cm-yLineSelection': {
89
- margin: string;
90
- };
91
- };
92
- export declare const markdownDarkHighlighting: HighlightStyle;
93
- //# sourceMappingURL=markdownTheme.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"markdownTheme.d.ts","sourceRoot":"","sources":["../../../../../src/components/Markdown/markdownTheme.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAUtD,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,KAAK,YAAY,CAAC;AAC/B,eAAO,MAAM,IAAI,YAAY,CAAC;AAC9B,eAAO,MAAM,OAAO,YAAY,CAAC;AACjC,eAAO,MAAM,KAAK,YAAY,CAAC;AAC/B,eAAO,MAAM,KAAK,YAAY,CAAC;AAC/B,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,IAAI,YAAY,CAAC;AAC9B,eAAO,MAAM,OAAO,YAAY,CAAC;AACjC,eAAO,MAAM,MAAM,YAAY,CAAC;AAEhC,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAE7C,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C,eAAO,MAAM,MAAM,YAAY,CAAC;AAIhC,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4IzB,CAAC;AAEF,eAAO,MAAM,wBAAwB,gBA6EpC,CAAC"}