@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.
Files changed (149) hide show
  1. package/dist/lib/browser/index.mjs +1027 -827
  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 +2 -1
  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 +7 -24
  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/{hyperlinkTooltip.d.ts → hyperlink/hyperlinkTooltip.d.ts} +0 -1
  33. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
  34. package/dist/types/src/components/TextEditor/extensions/{hyperlink.d.ts → hyperlink/hyperlinkWidget.d.ts} +3 -3
  35. package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
  36. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
  37. package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
  38. package/dist/types/src/components/TextEditor/extensions/index.d.ts +3 -1
  39. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  40. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +8 -0
  41. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -0
  42. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +3 -0
  43. package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -0
  44. package/dist/types/src/components/{Markdown/markdownTags.d.ts → TextEditor/extensions/markdown/tags.d.ts} +1 -1
  45. package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
  46. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
  47. package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
  48. package/dist/types/src/components/TextEditor/index.d.ts +1 -3
  49. package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
  50. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +11 -0
  51. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
  52. package/dist/types/src/components/index.d.ts +0 -3
  53. package/dist/types/src/components/index.d.ts.map +1 -1
  54. package/dist/types/src/hooks/index.d.ts +4 -0
  55. package/dist/types/src/hooks/index.d.ts.map +1 -0
  56. package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
  57. package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
  58. package/dist/types/src/{model.d.ts → hooks/useTextModel.d.ts} +3 -15
  59. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
  60. package/dist/types/src/hooks/yjs/cursors.d.ts.map +1 -0
  61. package/dist/types/src/hooks/yjs/index.d.ts.map +1 -0
  62. package/dist/types/src/hooks/yjs/space-provider.d.ts.map +1 -0
  63. package/dist/types/src/index.d.ts +2 -2
  64. package/dist/types/src/index.d.ts.map +1 -1
  65. package/dist/types/src/styles/tokens.d.ts +4 -0
  66. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  67. package/dist/types/src/testing/replicator.d.ts +1 -1
  68. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  69. package/package.json +31 -28
  70. package/src/automerge/automerge-plugin/PatchSemaphore.ts +5 -5
  71. package/src/automerge/automerge-plugin/codeMirrorToAm.ts +10 -7
  72. package/src/automerge/automerge-plugin/handle.ts +14 -0
  73. package/src/automerge/automerge-plugin/index.ts +2 -2
  74. package/src/automerge/automerge-plugin/plugin.ts +39 -10
  75. package/src/automerge/automerge.stories.tsx +32 -47
  76. package/src/components/TextEditor/TextEditor.stories.tsx +51 -55
  77. package/src/components/TextEditor/TextEditor.tsx +113 -55
  78. package/src/components/TextEditor/codemirror.stories.ts +114 -0
  79. package/src/components/TextEditor/extensions/basic/bundle.ts +28 -0
  80. package/src/components/TextEditor/extensions/basic/index.ts +6 -0
  81. package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
  82. package/src/components/TextEditor/extensions/change.ts +22 -0
  83. package/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts +99 -0
  84. package/src/components/TextEditor/extensions/{hyperlinkTooltip.tsx → hyperlink/hyperlinkTooltip.tsx} +2 -17
  85. package/src/components/TextEditor/extensions/{hyperlink.tsx → hyperlink/hyperlinkWidget.tsx} +21 -10
  86. package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
  87. package/src/components/TextEditor/extensions/index.ts +3 -1
  88. package/src/components/TextEditor/extensions/markdown/bundle.ts +99 -0
  89. package/src/components/TextEditor/extensions/markdown/index.ts +6 -0
  90. package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts} +23 -12
  91. package/src/components/TextEditor/index.ts +1 -4
  92. package/src/components/TextEditor/yjs.stories.tsx +55 -0
  93. package/src/components/index.ts +0 -3
  94. package/src/hooks/index.ts +7 -0
  95. package/src/hooks/useCollaboration.ts +45 -0
  96. package/src/{model.ts → hooks/useTextModel.ts} +42 -17
  97. package/src/index.ts +3 -3
  98. package/src/styles/tokens.ts +6 -0
  99. package/src/testing/replicator.ts +1 -2
  100. package/dist/types/src/automerge/demo.d.ts +0 -25
  101. package/dist/types/src/automerge/demo.d.ts.map +0 -1
  102. package/dist/types/src/components/Editor/Editor.d.ts +0 -15
  103. package/dist/types/src/components/Editor/Editor.d.ts.map +0 -1
  104. package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -29
  105. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +0 -1
  106. package/dist/types/src/components/Editor/index.d.ts +0 -2
  107. package/dist/types/src/components/Editor/index.d.ts.map +0 -1
  108. package/dist/types/src/components/Markdown/Markdown.d.ts +0 -20
  109. package/dist/types/src/components/Markdown/Markdown.d.ts.map +0 -1
  110. package/dist/types/src/components/Markdown/Markdown.stories.d.ts +0 -20
  111. package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +0 -1
  112. package/dist/types/src/components/Markdown/index.d.ts +0 -2
  113. package/dist/types/src/components/Markdown/index.d.ts.map +0 -1
  114. package/dist/types/src/components/Markdown/markdownTags.d.ts.map +0 -1
  115. package/dist/types/src/components/Markdown/markdownTheme.d.ts +0 -93
  116. package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +0 -1
  117. package/dist/types/src/components/RichText/RichText.d.ts +0 -20
  118. package/dist/types/src/components/RichText/RichText.d.ts.map +0 -1
  119. package/dist/types/src/components/RichText/RichText.stories.d.ts +0 -27
  120. package/dist/types/src/components/RichText/RichText.stories.d.ts.map +0 -1
  121. package/dist/types/src/components/RichText/index.d.ts +0 -2
  122. package/dist/types/src/components/RichText/index.d.ts.map +0 -1
  123. package/dist/types/src/components/TextEditor/extensions/hyperlink.d.ts.map +0 -1
  124. package/dist/types/src/components/TextEditor/extensions/hyperlinkTooltip.d.ts.map +0 -1
  125. package/dist/types/src/components/TextEditor/theme.d.ts +0 -8
  126. package/dist/types/src/components/TextEditor/theme.d.ts.map +0 -1
  127. package/dist/types/src/model.d.ts.map +0 -1
  128. package/dist/types/src/yjs/cursors.d.ts.map +0 -1
  129. package/dist/types/src/yjs/index.d.ts.map +0 -1
  130. package/dist/types/src/yjs/space-provider.d.ts.map +0 -1
  131. package/dist/types/stories/html/code-mirror.stories.d.ts.map +0 -1
  132. package/src/automerge/demo.ts +0 -106
  133. package/src/components/Editor/Editor.stories.tsx +0 -82
  134. package/src/components/Editor/Editor.tsx +0 -33
  135. package/src/components/Editor/index.ts +0 -5
  136. package/src/components/Markdown/Markdown.stories.tsx +0 -59
  137. package/src/components/Markdown/Markdown.tsx +0 -214
  138. package/src/components/Markdown/index.ts +0 -5
  139. package/src/components/RichText/RichText.stories.tsx +0 -70
  140. package/src/components/RichText/RichText.tsx +0 -181
  141. package/src/components/RichText/index.ts +0 -5
  142. package/src/components/TextEditor/theme.ts +0 -33
  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
@@ -1,59 +0,0 @@
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 { ClientDecorator, textGenerator, useDataGenerator } from '@dxos/react-client/testing';
12
- import { useId } from '@dxos/react-ui';
13
- import { withTheme } from '@dxos/storybook-utils';
14
-
15
- import { MarkdownEditor } from './Markdown';
16
- import { Replicator, useYjsModel } from '../../testing';
17
-
18
- export default {
19
- component: MarkdownEditor,
20
- decorators: [withTheme],
21
- };
22
-
23
- export const Default = {
24
- args: {
25
- model: {
26
- id: 'editor',
27
- content: 'Hello, Storybook!',
28
- },
29
- },
30
- };
31
-
32
- const replicator = new Replicator(TextKind.PLAIN);
33
-
34
- export const WithYjs = {
35
- render: () => {
36
- const [generate, setGenerate] = useState(false);
37
- const generateId = useId('generate');
38
-
39
- const [id] = useState(PublicKey.random().toHex());
40
- const model = useYjsModel({ id, replicator });
41
-
42
- useDataGenerator({
43
- generator: generate ? textGenerator : undefined,
44
- options: { text: typeof model?.content !== 'string' ? model?.content : undefined },
45
- });
46
-
47
- return (
48
- <main className='flex-1 min-w-0 p-4'>
49
- <div id={generateId} className='flex'>
50
- <input type='checkbox' onChange={(event) => setGenerate(event.target.checked)} />
51
- Generate Data
52
- </div>
53
- <MarkdownEditor model={model} />
54
- </main>
55
- );
56
- },
57
- // TODO(wittjosiah): Decorator for doing this without clients being initialized?
58
- decorators: [ClientDecorator({ count: 2 })],
59
- };
@@ -1,214 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import { autocompletion, completionKeymap, closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
6
- import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands';
7
- import { markdown, markdownLanguage } 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 { searchKeymap, highlightSelectionMatches } from '@codemirror/search';
18
- import { EditorState, type Extension, StateField, type Text } from '@codemirror/state';
19
- import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
20
- import {
21
- keymap,
22
- crosshairCursor,
23
- drawSelection,
24
- dropCursor,
25
- highlightActiveLine,
26
- highlightActiveLineGutter,
27
- highlightSpecialChars,
28
- placeholder,
29
- rectangularSelection,
30
- EditorView,
31
- } from '@codemirror/view';
32
- import { useFocusableGroup } from '@fluentui/react-tabster';
33
- import { vim } from '@replit/codemirror-vim';
34
- import React, {
35
- type KeyboardEvent,
36
- forwardRef,
37
- useEffect,
38
- useImperativeHandle,
39
- useState,
40
- useMemo,
41
- useCallback,
42
- } from 'react';
43
- import { yCollab } from 'y-codemirror.next';
44
-
45
- import { generateName } from '@dxos/display-name';
46
- import { useThemeContext } from '@dxos/react-ui';
47
- import { getColorForValue } from '@dxos/react-ui-theme';
48
- import { YText } from '@dxos/text-model';
49
-
50
- import { markdownTagsExtension } from './markdownTags';
51
- import { markdownDarkHighlighting, markdownTheme } from './markdownTheme';
52
- import { type EditorModel, type EditorSlots } from '../../model';
53
-
54
- export const EditorModes = ['default', 'vim'] as const;
55
- export type EditorMode = (typeof EditorModes)[number];
56
-
57
- export type MarkdownEditorProps = {
58
- model?: EditorModel;
59
- slots?: EditorSlots;
60
- editorMode?: EditorMode;
61
- extensions?: Extension[];
62
- onChange?: (content: string | Text) => void;
63
- };
64
-
65
- export type MarkdownEditorRef = {
66
- editor: HTMLDivElement | null;
67
- state?: EditorState;
68
- view?: EditorView;
69
- };
70
-
71
- export const MarkdownEditor = forwardRef<MarkdownEditorRef, MarkdownEditorProps>(
72
- ({ model, slots = {}, editorMode, extensions = [], onChange }, forwardedRef) => {
73
- const { id, content, provider, peer } = model ?? {};
74
- const { themeMode } = useThemeContext();
75
- const tabsterDOMAttribute = useFocusableGroup({ tabBehavior: 'limited' });
76
-
77
- const [parent, setParent] = useState<HTMLDivElement | null>(null);
78
- const [state, setState] = useState<EditorState>();
79
- const [view, setView] = useState<EditorView>();
80
-
81
- useImperativeHandle(forwardedRef, () => ({
82
- editor: parent,
83
- state,
84
- view,
85
- }));
86
-
87
- const listenChangesExtension = useMemo(
88
- () =>
89
- StateField.define({
90
- create: () => null,
91
- update: (_value, transaction) => {
92
- if (transaction.docChanged && onChange) {
93
- onChange(transaction.newDoc);
94
- }
95
- return null;
96
- },
97
- }),
98
- [onChange],
99
- );
100
-
101
- useEffect(() => {
102
- if (provider && peer) {
103
- provider.awareness.setLocalStateField('user', {
104
- name: peer.name ?? generateName(peer.id),
105
- color: getColorForValue({ value: peer.id, type: 'color' }),
106
- colorLight: getColorForValue({ value: peer.id, themeMode, type: 'highlight' }),
107
- });
108
- }
109
- }, [provider, peer, themeMode]);
110
-
111
- useEffect(() => {
112
- if (!parent) {
113
- return;
114
- }
115
-
116
- const state = EditorState.create({
117
- doc: content?.toString(),
118
- extensions: [
119
- // Based on https://github.com/codemirror/dev/issues/44#issuecomment-789093799.
120
- listenChangesExtension,
121
-
122
- ...(editorMode === 'vim' ? [vim()] : []),
123
-
124
- // All of https://github.com/codemirror/basic-setup minus line numbers and fold gutter.
125
- highlightActiveLineGutter(),
126
- highlightSpecialChars(),
127
- history(),
128
- drawSelection(),
129
- dropCursor(),
130
- EditorState.allowMultipleSelections.of(true),
131
- indentOnInput(),
132
- syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
133
- bracketMatching(),
134
- closeBrackets(),
135
- autocompletion(),
136
- rectangularSelection(),
137
- crosshairCursor(),
138
- highlightActiveLine(),
139
- highlightSelectionMatches(),
140
- placeholder(slots.editor?.placeholder ?? ''), // TODO(burdon): Needs consistent styling.
141
- keymap.of([
142
- ...closeBracketsKeymap,
143
- ...defaultKeymap,
144
- ...searchKeymap,
145
- ...historyKeymap,
146
- ...foldKeymap,
147
- ...completionKeymap,
148
- ...lintKeymap,
149
- indentWithTab,
150
- ]),
151
- EditorView.lineWrapping,
152
-
153
- // Themes.
154
- markdown({ base: markdownLanguage, codeLanguages: languages, extensions: [markdownTagsExtension] }),
155
- EditorView.theme({ ...markdownTheme, ...slots.editor?.markdownTheme }),
156
- ...(themeMode === 'dark'
157
- ? [syntaxHighlighting(oneDarkHighlightStyle)]
158
- : [syntaxHighlighting(defaultHighlightStyle)]),
159
- // TODO(thure): All but one rule here apply to both themes; rename or refactor.
160
- syntaxHighlighting(markdownDarkHighlighting),
161
-
162
- // Replication and awareness (incl. remote selection).
163
- ...(content instanceof YText ? [yCollab(content, provider?.awareness)] : []),
164
-
165
- // Custom.
166
- ...extensions,
167
- ],
168
- });
169
-
170
- setState(state);
171
-
172
- // NOTE: This repaints the editor.
173
- // If the new state is derived from the old state, it will likely not be visible other than the cursor resetting.
174
- // Ideally this should not be hit except when changing between text objects.
175
- view?.destroy();
176
- setView(new EditorView({ state, parent }));
177
-
178
- return () => {
179
- view?.destroy();
180
- setView(undefined);
181
- setState(undefined);
182
- };
183
- }, [parent, content, provider?.awareness, themeMode, editorMode]);
184
-
185
- const handleKeyUp = useCallback(
186
- (event: KeyboardEvent) => {
187
- const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
188
- switch (key) {
189
- case 'Enter': {
190
- view?.contentDOM.focus();
191
- break;
192
- }
193
-
194
- case 'Escape': {
195
- editorMode === 'vim' && (altKey || shiftKey || metaKey || ctrlKey) && parent?.focus();
196
- break;
197
- }
198
- }
199
- },
200
- [view, editorMode],
201
- );
202
-
203
- return (
204
- <div
205
- tabIndex={0}
206
- ref={setParent}
207
- key={id}
208
- {...slots.root}
209
- {...(editorMode !== 'vim' ? tabsterDOMAttribute : {})}
210
- onKeyUp={handleKeyUp}
211
- />
212
- );
213
- },
214
- );
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- export * from './Markdown';
@@ -1,70 +0,0 @@
1
- //
2
- // Copyright 2022 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 { ClientDecorator, textGenerator, useDataGenerator } from '@dxos/react-client/testing';
12
- import { useId } from '@dxos/react-ui';
13
- import { mx } from '@dxos/react-ui-theme';
14
- import { withTheme } from '@dxos/storybook-utils';
15
-
16
- import { RichTextEditor, type RichTextEditorProps } from './RichText';
17
- import { Replicator, useYjsModel } from '../../testing';
18
-
19
- export default {
20
- component: RichTextEditor,
21
- decorators: [withTheme],
22
- };
23
-
24
- export const Default = {
25
- args: {
26
- model: {
27
- id: 'editor',
28
- content: 'Hello, Storybook!',
29
- },
30
- },
31
- };
32
-
33
- const replicator = new Replicator(TextKind.RICH);
34
- export const WithYjs = {
35
- render: (args: Omit<RichTextEditorProps, 'model'>) => {
36
- const [generate, setGenerate] = useState(false);
37
- const generateId = useId('generate');
38
-
39
- const [id] = useState(PublicKey.random().toHex());
40
- const model = useYjsModel({ id, replicator });
41
-
42
- useDataGenerator({
43
- generator: generate ? textGenerator : undefined,
44
- options: { text: typeof model?.content !== 'string' ? model?.content : undefined },
45
- });
46
-
47
- return (
48
- <main className='flex-1 min-w-0 p-4'>
49
- <div id={generateId} className='flex'>
50
- <input type='checkbox' onChange={(event) => setGenerate(event.target.checked)} />
51
- Generate Data
52
- </div>
53
- <RichTextEditor
54
- {...args}
55
- model={model}
56
- slots={{
57
- editor: {
58
- className: mx(
59
- 'z-0 rounded bg-white text-neutral-900 w-full p-4 dark:bg-neutral-850 dark:text-white min-bs-[12em]',
60
- args.slots?.editor?.className,
61
- ),
62
- },
63
- }}
64
- />
65
- </main>
66
- );
67
- },
68
- // TODO(wittjosiah): Decorator for doing this without clients being initialized?
69
- decorators: [ClientDecorator({ count: 2 })],
70
- };
@@ -1,181 +0,0 @@
1
- //
2
- // Copyright 2022 DXOS.org
3
- //
4
- import { mergeAttributes } from '@tiptap/core';
5
- import Collaboration from '@tiptap/extension-collaboration';
6
- import CollaborationCursor from '@tiptap/extension-collaboration-cursor';
7
- import Heading from '@tiptap/extension-heading';
8
- import ListItem from '@tiptap/extension-list-item';
9
- import Placeholder from '@tiptap/extension-placeholder';
10
- import { type Editor, EditorContent, useEditor as useNaturalEditor } from '@tiptap/react';
11
- import StarterKit from '@tiptap/starter-kit';
12
- import React, { forwardRef, useImperativeHandle, useMemo } from 'react';
13
-
14
- import { generateName } from '@dxos/display-name';
15
- import { mx } from '@dxos/react-ui-theme';
16
-
17
- import { type EditorModel, type EditorSlots } from '../../model';
18
- import {
19
- blockquote,
20
- bold,
21
- codeBlock,
22
- heading,
23
- type HeadingLevel,
24
- horizontalRule,
25
- italic,
26
- listItem,
27
- orderedList,
28
- paragraph,
29
- strikethrough,
30
- unorderedList,
31
- codeWithoutMarks,
32
- } from '../../styles';
33
- import { cursorColor } from '../../yjs';
34
-
35
- export type TipTapEditor = Editor;
36
-
37
- type UseEditorOptions = {
38
- model?: EditorModel;
39
- placeholder?: string;
40
- slots?: Pick<EditorSlots, 'editor'>;
41
- };
42
-
43
- const useEditor = ({ model, placeholder = 'Enter text…', slots = {} }: UseEditorOptions) => {
44
- const extensions = useMemo(
45
- () => [
46
- StarterKit.configure({
47
- // Extensions
48
- history: false,
49
- // Nodes
50
- blockquote: {
51
- HTMLAttributes: {
52
- class: blockquote,
53
- },
54
- },
55
- bulletList: {
56
- HTMLAttributes: {
57
- class: unorderedList,
58
- },
59
- },
60
- codeBlock: {
61
- HTMLAttributes: {
62
- class: codeBlock,
63
- },
64
- },
65
- heading: false, // (thure): `StarterKit` doesn’t let you configure how headings are rendered, see `Heading` below.
66
- horizontalRule: {
67
- HTMLAttributes: {
68
- class: horizontalRule,
69
- },
70
- },
71
- listItem: false, // (thure): `StarterKit` doesn’t let you configure how list items are rendered, see `ListItem` below.
72
- orderedList: {
73
- HTMLAttributes: {
74
- class: orderedList,
75
- },
76
- },
77
- paragraph: {
78
- HTMLAttributes: {
79
- class: paragraph,
80
- },
81
- },
82
- // Marks
83
- bold: {
84
- HTMLAttributes: {
85
- class: bold,
86
- },
87
- },
88
- code: {
89
- HTMLAttributes: {
90
- class: codeWithoutMarks,
91
- },
92
- },
93
- italic: {
94
- HTMLAttributes: {
95
- class: italic,
96
- },
97
- },
98
- strike: {
99
- HTMLAttributes: {
100
- class: strikethrough,
101
- },
102
- },
103
- }),
104
- Heading.extend({
105
- renderHTML({ node, HTMLAttributes }) {
106
- const hasLevel = this.options.levels.includes(node.attrs.level);
107
- const level: HeadingLevel = hasLevel ? node.attrs.level : this.options.levels[0];
108
-
109
- return [
110
- `h${level}`,
111
- mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
112
- class: heading[level],
113
- }),
114
- 0,
115
- ];
116
- },
117
- }),
118
- ListItem.extend({
119
- renderHTML: ({ HTMLAttributes }) => [
120
- 'li',
121
- mergeAttributes(HTMLAttributes, {
122
- marker: '• ',
123
- class: listItem,
124
- }),
125
- ['div', { role: 'none' }, 0],
126
- ],
127
- }),
128
- // https://github.com/ueberdosis/tiptap/tree/main/packages/extension-collaboration
129
- ...(model && typeof model.content !== 'string' ? [Collaboration.configure({ fragment: model.content })] : []),
130
- ...(model?.provider
131
- ? [
132
- CollaborationCursor.configure({
133
- provider: model.provider,
134
- user: model.peer && {
135
- name: model.peer.name ?? generateName(model.peer.id),
136
- color: cursorColor.color,
137
- },
138
- }),
139
- ]
140
- : []),
141
- Placeholder.configure({
142
- placeholder,
143
- emptyEditorClass: 'before:content-[attr(data-placeholder)] before:absolute opacity-50 cursor-text',
144
- }),
145
- ],
146
- [model?.id],
147
- );
148
-
149
- return useNaturalEditor(
150
- {
151
- extensions,
152
- editorProps: {
153
- attributes: {
154
- class: mx('focus:outline-none focus-visible:outline-none', slots.editor?.className),
155
- spellcheck: slots.editor?.spellCheck === false ? 'false' : 'true',
156
- tabindex: slots.editor?.tabIndex ? String(slots.editor?.tabIndex) : '0',
157
- },
158
- },
159
- },
160
- [extensions],
161
- );
162
- };
163
-
164
- export type RichTextEditorProps = UseEditorOptions & {
165
- slots?: EditorSlots;
166
- };
167
-
168
- /**
169
- * @deprecated
170
- */
171
- // TODO(burdon): Currently broken.
172
- export const RichTextEditor = forwardRef<Editor | null, RichTextEditorProps>((props, ref) => {
173
- const editor = useEditor(props);
174
- useImperativeHandle<Editor | null, Editor | null>(ref, () => editor, [editor]);
175
-
176
- // Reference:
177
- // https://tiptap.dev/installation/react
178
- // https://github.com/ueberdosis/tiptap
179
- // https://tiptap.dev/guide/output/#option-3-yjs
180
- return <EditorContent {...props.slots?.root} editor={editor} />;
181
- });
@@ -1,5 +0,0 @@
1
- //
2
- // Copyright 2022 DXOS.org
3
- //
4
-
5
- export * from './RichText';
@@ -1,33 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- import get from 'lodash.get';
6
- import { type StyleSpec } from 'style-mod';
7
-
8
- import { tailwindConfig, type TailwindConfig } from '@dxos/react-ui-theme';
9
-
10
- const tokens: TailwindConfig['theme'] = tailwindConfig({}).theme;
11
-
12
- /**
13
- * https://codemirror.net/examples/styling
14
- */
15
- // TODO(burdon): If given a "theme" suffix, `__docgen` properties are added to the object.
16
- export const defaultStyles: {
17
- [selector: string]: StyleSpec;
18
- } = {
19
- '&.cm-focused': {
20
- outline: 'none',
21
- },
22
- '.cm-placeholder': {
23
- fontFamily: get(tokens, 'fontFamily.body', []).join(','),
24
- },
25
- '& .cm-scroller': {
26
- fontFamily: get(tokens, 'fontFamily.body', []).join(','),
27
- overflow: 'visible',
28
- },
29
- '.cm-tooltip': {
30
- backgroundColor: 'transparent',
31
- border: 'none',
32
- },
33
- };
File without changes
File without changes
File without changes
File without changes
File without changes