@dxos/react-ui-editor 0.4.8-main.97e86fe → 0.4.8-main.a4c603b

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 (108) hide show
  1. package/dist/lib/browser/index.mjs +941 -776
  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 +103 -0
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -0
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +34 -18
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +5 -79
  9. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  10. package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
  11. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  12. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +1 -1
  13. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  14. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  15. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  16. package/dist/types/src/extensions/automerge/defs.d.ts +15 -1
  17. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  18. package/dist/types/src/extensions/automerge/index.d.ts +1 -0
  19. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/sync.d.ts +1 -2
  21. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  22. package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -2
  23. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  24. package/dist/types/src/extensions/awareness.d.ts.map +1 -0
  25. package/dist/types/src/extensions/comments.d.ts +2 -2
  26. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  27. package/dist/types/src/extensions/cursor-line-margin.d.ts +7 -6
  28. package/dist/types/src/extensions/cursor-line-margin.d.ts.map +1 -1
  29. package/dist/types/src/extensions/cursor.d.ts +1 -1
  30. package/dist/types/src/extensions/cursor.d.ts.map +1 -1
  31. package/dist/types/src/extensions/index.d.ts +1 -3
  32. package/dist/types/src/extensions/index.d.ts.map +1 -1
  33. package/dist/types/src/extensions/markdown/bundle.d.ts +4 -5
  34. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  35. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  36. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  37. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  38. package/dist/types/src/extensions/markdown/table.d.ts +2 -2
  39. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
  40. package/dist/types/src/extensions/outliner.d.ts +4 -0
  41. package/dist/types/src/extensions/outliner.d.ts.map +1 -0
  42. package/dist/types/src/{extensions/awareness → hooks}/awareness-provider.d.ts +1 -1
  43. package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -0
  44. package/dist/types/src/hooks/defs.d.ts +20 -0
  45. package/dist/types/src/hooks/defs.d.ts.map +1 -0
  46. package/dist/types/src/hooks/index.d.ts +4 -1
  47. package/dist/types/src/hooks/index.d.ts.map +1 -1
  48. package/dist/types/src/hooks/useEditorView.d.ts +20 -0
  49. package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
  50. package/dist/types/src/hooks/useTextEditor.d.ts +44 -3
  51. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  52. package/dist/types/src/hooks/useTextEditor.stories.d.ts +0 -6
  53. package/dist/types/src/hooks/useTextEditor.stories.d.ts.map +1 -1
  54. package/dist/types/src/hooks/useTextModel.d.ts +33 -0
  55. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
  56. package/dist/types/src/themes/default.d.ts +3 -0
  57. package/dist/types/src/themes/default.d.ts.map +1 -1
  58. package/package.json +24 -24
  59. package/src/components/TextEditor/MarkdownEditor.stories.tsx +524 -0
  60. package/src/components/TextEditor/TextEditor.stories.tsx +23 -508
  61. package/src/components/TextEditor/TextEditor.tsx +149 -37
  62. package/src/components/Toolbar/Toolbar.stories.tsx +42 -42
  63. package/src/extensions/automerge/automerge.stories.tsx +17 -16
  64. package/src/extensions/automerge/automerge.ts +1 -2
  65. package/src/extensions/automerge/cursor.ts +1 -1
  66. package/src/extensions/automerge/defs.ts +22 -1
  67. package/src/extensions/automerge/index.ts +1 -0
  68. package/src/extensions/automerge/sync.ts +9 -2
  69. package/src/extensions/automerge/update-automerge.ts +1 -2
  70. package/src/extensions/{awareness/awareness.ts → awareness.ts} +1 -1
  71. package/src/extensions/command/state.ts +1 -1
  72. package/src/extensions/comments.ts +5 -9
  73. package/src/extensions/cursor-line-margin.ts +18 -17
  74. package/src/extensions/cursor.ts +1 -1
  75. package/src/extensions/index.ts +1 -3
  76. package/src/extensions/markdown/bundle.ts +28 -11
  77. package/src/extensions/markdown/decorate.ts +4 -2
  78. package/src/extensions/markdown/formatting.ts +10 -15
  79. package/src/extensions/markdown/image.ts +0 -1
  80. package/src/extensions/markdown/table.ts +3 -11
  81. package/src/extensions/outliner.ts +12 -0
  82. package/src/{extensions/awareness → hooks}/awareness-provider.ts +1 -1
  83. package/src/hooks/defs.ts +30 -0
  84. package/src/hooks/index.ts +5 -1
  85. package/src/hooks/useEditorView.ts +32 -0
  86. package/src/hooks/useTextEditor.stories.tsx +34 -39
  87. package/src/hooks/useTextEditor.ts +120 -11
  88. package/src/hooks/useTextModel.ts +121 -0
  89. package/src/index.ts +1 -1
  90. package/src/themes/default.ts +28 -1
  91. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +0 -1
  92. package/dist/types/src/extensions/awareness/awareness.d.ts.map +0 -1
  93. package/dist/types/src/extensions/awareness/index.d.ts +0 -3
  94. package/dist/types/src/extensions/awareness/index.d.ts.map +0 -1
  95. package/dist/types/src/extensions/doc.d.ts +0 -3
  96. package/dist/types/src/extensions/doc.d.ts.map +0 -1
  97. package/dist/types/src/extensions/factories.d.ts +0 -49
  98. package/dist/types/src/extensions/factories.d.ts.map +0 -1
  99. package/dist/types/src/extensions/types.d.ts +0 -9
  100. package/dist/types/src/extensions/types.d.ts.map +0 -1
  101. package/dist/types/src/hooks/useDocAccessor.d.ts +0 -7
  102. package/dist/types/src/hooks/useDocAccessor.d.ts.map +0 -1
  103. package/src/extensions/awareness/index.ts +0 -6
  104. package/src/extensions/doc.ts +0 -14
  105. package/src/extensions/factories.ts +0 -167
  106. package/src/extensions/types.ts +0 -16
  107. package/src/hooks/useDocAccessor.ts +0 -21
  108. /package/dist/types/src/extensions/{awareness/awareness.d.ts → awareness.d.ts} +0 -0
@@ -2,30 +2,57 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { EditorSelection, EditorState } from '@codemirror/state';
6
- import { EditorView } from '@codemirror/view';
7
- import { type DependencyList, type RefObject, useEffect, useMemo, useRef, useState } from 'react';
5
+ import { closeBrackets } from '@codemirror/autocomplete';
6
+ import { history } from '@codemirror/commands';
7
+ import { bracketMatching } from '@codemirror/language';
8
+ import {
9
+ EditorSelection,
10
+ EditorState,
11
+ type EditorStateConfig,
12
+ type Extension,
13
+ type StateEffect,
14
+ } from '@codemirror/state';
15
+ import {
16
+ crosshairCursor,
17
+ drawSelection,
18
+ dropCursor,
19
+ EditorView,
20
+ highlightActiveLine,
21
+ lineNumbers,
22
+ placeholder,
23
+ scrollPastEnd,
24
+ } from '@codemirror/view';
25
+ import defaultsDeep from 'lodash.defaultsdeep';
26
+ import { type DependencyList, type RefObject, useEffect, useRef, useState } from 'react';
8
27
 
9
28
  import { log } from '@dxos/log';
29
+ import { type ThemeMode } from '@dxos/react-ui';
10
30
  import { isNotFalsy } from '@dxos/util';
11
31
 
12
- import { type TextEditorProps } from '../components';
13
- import { documentId } from '../extensions';
32
+ import { type ThemeStyles } from '../styles';
33
+ import { defaultTheme } from '../themes';
14
34
  import { logChanges } from '../util';
15
35
 
36
+ export type UseTextEditorOptions = {
37
+ autoFocus?: boolean;
38
+ scrollTo?: StateEffect<any>;
39
+ debug?: boolean;
40
+ } & EditorStateConfig;
41
+
42
+ // TODO(burdon): Return tuple?
16
43
  export type UseTextEditor = {
17
44
  parentRef: RefObject<HTMLDivElement>;
18
45
  view?: EditorView;
19
46
  };
20
47
 
21
- export type UseTextEditorProps = Omit<TextEditorProps, 'moveToEndOfLine' | 'dataTestId'>;
22
-
23
48
  /**
24
49
  * Hook for creating editor.
25
50
  */
26
- export const useTextEditor = (cb: () => UseTextEditorProps = () => ({}), deps: DependencyList = []): UseTextEditor => {
27
- let { id, doc, selection, extensions, autoFocus, scrollTo, debug } = useMemo<UseTextEditorProps>(cb, deps ?? []);
28
-
51
+ // TODO(wittjosiah): Does not work in strict mode.
52
+ export const useTextEditor = (
53
+ { autoFocus, scrollTo, debug, doc, selection, extensions }: UseTextEditorOptions = {},
54
+ deps: DependencyList = [],
55
+ ): UseTextEditor => {
29
56
  const onUpdate = useRef<() => void>();
30
57
  const [view, setView] = useState<EditorView>();
31
58
  const parentRef = useRef<HTMLDivElement>(null);
@@ -38,7 +65,6 @@ export const useTextEditor = (cb: () => UseTextEditorProps = () => ({}), deps: D
38
65
  doc,
39
66
  selection,
40
67
  extensions: [
41
- id && documentId.of(id),
42
68
  // TODO(burdon): Doesn't catch errors in keymap functions.
43
69
  EditorView.exceptionSink.of((err) => {
44
70
  log.catch(err);
@@ -81,6 +107,7 @@ export const useTextEditor = (cb: () => UseTextEditorProps = () => ({}), deps: D
81
107
  }
82
108
 
83
109
  // Set selection after first update (since content may rerender on focus).
110
+ // TODO(burdon): BUG on first render may appear in middle of formatted heading.
84
111
  // TODO(burdon): Make invisible until first render?
85
112
  if (selection || scrollTo) {
86
113
  onUpdate.current = () => {
@@ -97,3 +124,85 @@ export const useTextEditor = (cb: () => UseTextEditorProps = () => ({}), deps: D
97
124
 
98
125
  return { parentRef, view };
99
126
  };
127
+
128
+ // TODO(burdon): Factor out extension factories.
129
+
130
+ /**
131
+ * https://codemirror.net/docs/extensions
132
+ * https://github.com/codemirror/basic-setup
133
+ */
134
+ // TODO(burdon): Reconcile with createMarkdownExtensions.
135
+ export type BasicExtensionsOptions = {
136
+ allowMultipleSelections?: boolean;
137
+ bracketMatching?: boolean;
138
+ closeBrackets?: boolean;
139
+ crosshairCursor?: boolean;
140
+ dropCursor?: boolean;
141
+ drawSelection?: boolean;
142
+ editable?: boolean;
143
+ highlightActiveLine?: boolean;
144
+ history?: boolean;
145
+ lineNumbers?: boolean;
146
+ lineWrapping?: boolean;
147
+ placeholder?: string;
148
+ readonly?: boolean;
149
+ scrollPastEnd?: boolean;
150
+ tabSize?: number;
151
+ };
152
+
153
+ const defaults: BasicExtensionsOptions = {
154
+ bracketMatching: true,
155
+ closeBrackets: true,
156
+ drawSelection: true,
157
+ editable: true,
158
+ history: true,
159
+ lineWrapping: true,
160
+ };
161
+
162
+ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extension => {
163
+ const props: BasicExtensionsOptions = defaultsDeep({}, _props, defaults);
164
+ return [
165
+ // TODO(burdon): Doesn't catch errors in keymap functions.
166
+ EditorView.exceptionSink.of((err) => {
167
+ log.catch(err);
168
+ }),
169
+
170
+ props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
171
+ props.bracketMatching && bracketMatching(),
172
+ props.closeBrackets && closeBrackets(),
173
+ props.crosshairCursor && crosshairCursor(),
174
+ props.dropCursor && dropCursor(),
175
+ props.drawSelection && drawSelection(),
176
+ props.highlightActiveLine && highlightActiveLine(),
177
+ props.history && history(),
178
+ props.lineNumbers && lineNumbers(),
179
+ props.lineWrapping && EditorView.lineWrapping,
180
+ props.placeholder && placeholder(props.placeholder),
181
+ props.readonly && [EditorState.readOnly.of(true), EditorView.editable.of(false)],
182
+ props.scrollPastEnd && scrollPastEnd(),
183
+ props.tabSize && EditorState.tabSize.of(props.tabSize),
184
+ ].filter(isNotFalsy);
185
+ };
186
+
187
+ export type ThemeExtensionsOptions = {
188
+ theme?: ThemeStyles;
189
+ themeMode?: ThemeMode;
190
+ slots?: {
191
+ editor?: {
192
+ className?: string;
193
+ };
194
+ content?: {
195
+ className?: string;
196
+ };
197
+ };
198
+ };
199
+
200
+ export const createThemeExtensions = ({ theme, themeMode, slots }: ThemeExtensionsOptions = {}): Extension => {
201
+ return [
202
+ EditorView.baseTheme(defaultTheme),
203
+ EditorView.darkTheme.of(themeMode === 'dark'),
204
+ theme && EditorView.theme(theme),
205
+ slots?.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),
206
+ slots?.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),
207
+ ].filter(isNotFalsy);
208
+ };
@@ -0,0 +1,121 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import { type Extension } from '@codemirror/state';
6
+ import get from 'lodash.get';
7
+ import { type Dispatch, type SetStateAction, useState, useMemo } from 'react';
8
+
9
+ import { generateName } from '@dxos/display-name';
10
+ import { type AutomergeTextCompat, getRawDoc } from '@dxos/echo-schema';
11
+ import { invariant } from '@dxos/invariant';
12
+ import { isAutomergeObject, type Space, type TextObject } from '@dxos/react-client/echo';
13
+ import { type Identity } from '@dxos/react-client/halo';
14
+ import { type HuePalette, hueTokens } from '@dxos/react-ui-theme';
15
+ import { hexToHue } from '@dxos/util';
16
+
17
+ import { SpaceAwarenessProvider } from './awareness-provider';
18
+ import { type EditorModel } from './defs';
19
+ import { automerge, awareness } from '../extensions';
20
+ import { type DocAccessor } from '../extensions/automerge/defs';
21
+
22
+ export type useTextExtensionsProps = {
23
+ id: string;
24
+ text: DocAccessor;
25
+ space?: Space;
26
+ identity?: Identity;
27
+ };
28
+
29
+ // TODO(burdon): Factor out automerge defs and extension (not hook).
30
+ export const useTextExtensions = ({ id, text, space, identity }: useTextExtensionsProps): Extension[] => {
31
+ const extensions: Extension[] = [automerge(text)];
32
+
33
+ const peerId = identity?.identityKey.toHex();
34
+ const { cursorLightValue, cursorDarkValue } =
35
+ hueTokens[(identity?.profile?.data?.hue as HuePalette | undefined) ?? hexToHue(peerId ?? '0')];
36
+
37
+ if (space && identity) {
38
+ const awarenessProvider = new SpaceAwarenessProvider({
39
+ space,
40
+ channel: `awareness.${id}`,
41
+ peerId: identity.identityKey.toHex(),
42
+ info: {
43
+ displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
44
+ color: cursorDarkValue,
45
+ lightColor: cursorLightValue,
46
+ },
47
+ });
48
+
49
+ extensions.push(awareness(awarenessProvider));
50
+ }
51
+
52
+ return extensions;
53
+ };
54
+
55
+ export type UseTextModelProps = {
56
+ text?: TextObject;
57
+ space?: Space;
58
+ identity?: Identity | null;
59
+ };
60
+
61
+ /**
62
+ * @deprecated
63
+ */
64
+ // TODO(burdon): Remove once automerge lands.
65
+ export const useTextModel = (props: UseTextModelProps): EditorModel | undefined =>
66
+ useMemo(() => createModel(props), Object.values(props));
67
+
68
+ /**
69
+ * For use primarily in stories & tests so the dependence on TextObject can be avoided.
70
+ * @deprecated
71
+ */
72
+ // TODO(burdon): Remove.
73
+ export const useInMemoryTextModel = ({
74
+ id,
75
+ defaultContent,
76
+ }: {
77
+ id: string;
78
+ defaultContent?: string;
79
+ }): EditorModel & { setContent: Dispatch<SetStateAction<string>> } => {
80
+ const [content, setContent] = useState(defaultContent ?? '');
81
+ return { id, content, text: () => content, setContent };
82
+ };
83
+
84
+ const createModel = ({ space, identity, text }: UseTextModelProps): EditorModel | undefined => {
85
+ if (!text) {
86
+ return undefined;
87
+ }
88
+
89
+ invariant(isAutomergeObject(text));
90
+ const obj = text as any as AutomergeTextCompat;
91
+ const doc = getRawDoc(obj, [obj.field]);
92
+
93
+ const peerId = identity?.identityKey.toHex();
94
+ const { cursorLightValue, cursorDarkValue } =
95
+ hueTokens[(identity?.profile?.data?.hue as HuePalette | undefined) ?? hexToHue(peerId ?? '0')];
96
+
97
+ const awarenessProvider =
98
+ space &&
99
+ new SpaceAwarenessProvider({
100
+ space,
101
+ channel: `automerge.awareness.${obj.id}`,
102
+ info: {
103
+ displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : undefined,
104
+ color: cursorLightValue,
105
+ lightColor: cursorDarkValue,
106
+ },
107
+ peerId: identity?.identityKey.toHex() ?? 'Anonymous',
108
+ });
109
+
110
+ const extensions = [automerge({ handle: doc.handle, path: doc.path })];
111
+ if (awarenessProvider) {
112
+ extensions.push(awareness(awarenessProvider));
113
+ }
114
+
115
+ return {
116
+ id: obj.id,
117
+ content: doc,
118
+ text: () => get(doc.handle.docSync(), doc.path),
119
+ extension: extensions,
120
+ };
121
+ };
package/src/index.ts CHANGED
@@ -9,7 +9,7 @@ export { type EditorView, keymap } from '@codemirror/view';
9
9
  export { tags } from '@lezer/highlight';
10
10
 
11
11
  export { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
12
- export { Doc, YText, YXmlFragment } from '@dxos/text-model'; // TODO(burdon): Remove.
12
+ export { Doc, YText, YXmlFragment } from '@dxos/text-model';
13
13
 
14
14
  export * from './components';
15
15
  export * from './extensions';
@@ -55,7 +55,7 @@ export const defaultTheme: ThemeStyles = {
55
55
  // TODO(burdon): Reconcile with docs: https://codemirror.net/docs/guide
56
56
  // Inside of that is the scroller element. If the editor has its own scrollbar, this one should be styled with overflow: auto. But it doesn't have to—the editor also supports growing to accomodate its content, or growing up to a certain max-height and then scrolling.
57
57
  overflowY: 'auto',
58
- fontFamily: get(tokens, 'fontFamily.body', []).join(','),
58
+ fontFamily: get(tokens, 'fontFamily.mono', []).join(','),
59
59
  lineHeight: 1.5,
60
60
  },
61
61
 
@@ -261,3 +261,30 @@ export const defaultTheme: ThemeStyles = {
261
261
  marginRight: '0.4rem !important',
262
262
  },
263
263
  };
264
+
265
+ export const textTheme: ThemeStyles = {
266
+ '.cm-scroller': {
267
+ fontFamily: get(tokens, 'fontFamily.body', []).join(','),
268
+ },
269
+ '.cm-placeholder': {
270
+ fontFamily: get(tokens, 'fontFamily.body', []).join(','),
271
+ },
272
+ };
273
+
274
+ export const markdownTheme: ThemeStyles = {
275
+ '.cm-scroller': {
276
+ fontFamily: get(tokens, 'fontFamily.body', []).join(','),
277
+ },
278
+ '.cm-placeholder': {
279
+ fontFamily: get(tokens, 'fontFamily.body', []).join(','),
280
+ },
281
+ };
282
+
283
+ export const codeTheme: ThemeStyles = {
284
+ '.cm-scroller': {
285
+ fontFamily: get(tokens, 'fontFamily.mono', []).join(','),
286
+ },
287
+ '.cm-placeholder': {
288
+ fontFamily: get(tokens, 'fontFamily.mono', []).join(','),
289
+ },
290
+ };
@@ -1 +0,0 @@
1
- {"version":3,"file":"awareness-provider.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/awareness/awareness-provider.ts"],"names":[],"mappings":"AAIA,OAAO,EAAgB,KAAK,EAAS,MAAM,aAAa,CAAC;AAIzD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAGrD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,iBAAiB,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAatH,MAAM,MAAM,uBAAuB,GAAG;IACpC,KAAK,EAAE,KAAK,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,qBAAa,sBAAuB,YAAW,iBAAiB;IAC9D,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAqC;IAEnE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,OAAO,CAAC,IAAI,CAAC,CAAU;IACvB,OAAO,CAAC,SAAS,CAAC,CAAe;IACjC,OAAO,CAAC,WAAW,CAAC,CAAiB;IAErC,SAAgB,iBAAiB,cAAqB;gBAE1C,MAAM,EAAE,uBAAuB;IAO3C,IAAI;IAqCJ,KAAK;IAML,eAAe,IAAI,cAAc,EAAE;IAInC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI;IAWrD,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,kBAAkB;CAK3B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"awareness.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/awareness/awareness.ts"],"names":[],"mappings":"AAIA,OAAO,EAAc,KAAK,EAAE,KAAK,SAAS,EAAwB,MAAM,mBAAmB,CAAC;AAC5F,OAAO,EAEL,KAAK,aAAa,EAClB,UAAU,EACV,KAAK,WAAW,EAEhB,KAAK,UAAU,EAEhB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAKpC,MAAM,WAAW,iBAAiB;IAChC,iBAAiB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAE/B,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IAEd,eAAe,IAAI,cAAc,EAAE,CAAC;IACpC,MAAM,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GAAG,IAAI,CAAC;CACvD;AAYD,eAAO,MAAM,iBAAiB,6CAE5B,CAAC;AAKH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,aAAa,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS,oCAA+B,SAQpD,CAAC;AAEF;;GAEG;AACH,qBAAa,yBAA0B,YAAW,WAAW;IACpD,WAAW,EAAE,aAAa,CAAmB;IAEpD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiB;IAEtC,OAAO,CAAC,gBAAgB,CAAkB;IAC1C,OAAO,CAAC,SAAS,CAAoB;IACrC,OAAO,CAAC,WAAW,CAAC,CAAqB;IACzC,OAAO,CAAC,SAAS,CAAC,CAAqB;gBAE3B,IAAI,EAAE,UAAU;IAS5B,OAAO;IAKP,MAAM,CAAC,MAAM,EAAE,UAAU;IAKzB,OAAO,CAAC,qBAAqB;IAoB7B,OAAO,CAAC,uBAAuB;CA4EhC"}
@@ -1,3 +0,0 @@
1
- export * from './awareness';
2
- export * from './awareness-provider';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/awareness/index.ts"],"names":[],"mappings":"AAIA,cAAc,aAAa,CAAC;AAC5B,cAAc,sBAAsB,CAAC"}
@@ -1,3 +0,0 @@
1
- import { Facet } from '@codemirror/state';
2
- export declare const documentId: Facet<string, string>;
3
- //# sourceMappingURL=doc.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../../../src/extensions/doc.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAI1C,eAAO,MAAM,UAAU,uBAKrB,CAAC"}
@@ -1,49 +0,0 @@
1
- import { type Extension } from '@codemirror/state';
2
- import { type DocAccessor } from '@dxos/echo-schema';
3
- import { type Space } from '@dxos/react-client/echo';
4
- import { type Identity } from '@dxos/react-client/halo';
5
- import { type ThemeMode } from '@dxos/react-ui';
6
- import { type ThemeStyles } from '../styles';
7
- /**
8
- * https://codemirror.net/docs/extensions
9
- * https://github.com/codemirror/basic-setup
10
- */
11
- export type BasicExtensionsOptions = {
12
- allowMultipleSelections?: boolean;
13
- bracketMatching?: boolean;
14
- closeBrackets?: boolean;
15
- crosshairCursor?: boolean;
16
- dropCursor?: boolean;
17
- drawSelection?: boolean;
18
- editable?: boolean;
19
- highlightActiveLine?: boolean;
20
- history?: boolean;
21
- lineNumbers?: boolean;
22
- lineWrapping?: boolean;
23
- placeholder?: string;
24
- readonly?: boolean;
25
- scrollPastEnd?: boolean;
26
- tabSize?: number;
27
- };
28
- export declare const createBasicExtensions: (_props?: BasicExtensionsOptions) => Extension;
29
- export type ThemeExtensionsOptions = {
30
- theme?: ThemeStyles;
31
- themeMode?: ThemeMode;
32
- slots?: {
33
- editor?: {
34
- className?: string;
35
- };
36
- content?: {
37
- className?: string;
38
- };
39
- };
40
- };
41
- export declare const createThemeExtensions: ({ theme, themeMode, slots: _slots }?: ThemeExtensionsOptions) => Extension;
42
- export type DataExtensionsProps = {
43
- id: string;
44
- text: DocAccessor;
45
- space?: Space;
46
- identity?: Identity | null;
47
- };
48
- export declare const createDataExtensions: ({ id, text, space, identity }: DataExtensionsProps) => Extension[];
49
- //# sourceMappingURL=factories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"factories.d.ts","sourceRoot":"","sources":["../../../../src/extensions/factories.ts"],"names":[],"mappings":"AAOA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAchE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACrD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACxD,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMhD,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AAS7C;;;GAGG;AAEH,MAAM,MAAM,sBAAsB,GAAG;IACnC,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAWF,eAAO,MAAM,qBAAqB,YAAa,sBAAsB,KAAG,SAuBvE,CAAC;AAMF,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE;YACP,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;QACF,OAAO,CAAC,EAAE;YACR,SAAS,CAAC,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC;CACH,CAAC;AAQF,eAAO,MAAM,qBAAqB,yCAAyC,sBAAsB,KAAQ,SASxG,CAAC;AAMF,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,QAAQ,CAAC,EAAE,QAAQ,GAAG,IAAI,CAAC;CAC5B,CAAC;AAIF,eAAO,MAAM,oBAAoB,kCAAmC,mBAAmB,KAAG,SAAS,EAsBlG,CAAC"}
@@ -1,9 +0,0 @@
1
- export type Range = {
2
- from: number;
3
- to: number;
4
- };
5
- export type Comment = {
6
- id: string;
7
- cursor?: string;
8
- };
9
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/extensions/types.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;CACZ,CAAC;AAIF,MAAM,MAAM,OAAO,GAAG;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC"}
@@ -1,7 +0,0 @@
1
- import { type DocAccessor, type TextObject } from '@dxos/echo-schema';
2
- export declare const useDocAccessor: <T = any>(text: TextObject) => {
3
- id: string;
4
- doc: string | undefined;
5
- accessor: DocAccessor<T>;
6
- };
7
- //# sourceMappingURL=useDocAccessor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useDocAccessor.d.ts","sourceRoot":"","sources":["../../../../src/hooks/useDocAccessor.ts"],"names":[],"mappings":"AAMA,OAAO,EAAqB,KAAK,WAAW,EAAkB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAGzG,eAAO,MAAM,cAAc,kBACnB,UAAU;QACT,MAAM;SAAO,MAAM,GAAG,SAAS;;CASvC,CAAC"}
@@ -1,6 +0,0 @@
1
- //
2
- // Copyright 2023 DXOS.org
3
- //
4
-
5
- export * from './awareness';
6
- export * from './awareness-provider';
@@ -1,14 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { Facet } from '@codemirror/state';
6
-
7
- import { invariant } from '@dxos/invariant';
8
-
9
- export const documentId = Facet.define<string, string>({
10
- combine: (providers) => {
11
- invariant(providers.length <= 1);
12
- return providers[0];
13
- },
14
- });
@@ -1,167 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { closeBrackets } from '@codemirror/autocomplete';
6
- import { history } from '@codemirror/commands';
7
- import { bracketMatching } from '@codemirror/language';
8
- import { EditorState, type Extension } from '@codemirror/state';
9
- import {
10
- EditorView,
11
- crosshairCursor,
12
- drawSelection,
13
- dropCursor,
14
- highlightActiveLine,
15
- lineNumbers,
16
- placeholder,
17
- scrollPastEnd,
18
- } from '@codemirror/view';
19
- import defaultsDeep from 'lodash.defaultsdeep';
20
-
21
- import { generateName } from '@dxos/display-name';
22
- import { type DocAccessor } from '@dxos/echo-schema';
23
- import { log } from '@dxos/log';
24
- import { type Space } from '@dxos/react-client/echo';
25
- import { type Identity } from '@dxos/react-client/halo';
26
- import { type ThemeMode } from '@dxos/react-ui';
27
- import { type HuePalette, hueTokens } from '@dxos/react-ui-theme';
28
- import { hexToHue, isNotFalsy } from '@dxos/util';
29
-
30
- import { automerge } from './automerge';
31
- import { awareness, SpaceAwarenessProvider } from './awareness';
32
- import { type ThemeStyles } from '../styles';
33
- import { defaultTheme } from '../themes';
34
-
35
- // TODO(burdon): Move into extensions folder.
36
-
37
- //
38
- // Basic
39
- //
40
-
41
- /**
42
- * https://codemirror.net/docs/extensions
43
- * https://github.com/codemirror/basic-setup
44
- */
45
- // TODO(burdon): Reconcile with createMarkdownExtensions.
46
- export type BasicExtensionsOptions = {
47
- allowMultipleSelections?: boolean;
48
- bracketMatching?: boolean;
49
- closeBrackets?: boolean;
50
- crosshairCursor?: boolean;
51
- dropCursor?: boolean;
52
- drawSelection?: boolean;
53
- editable?: boolean;
54
- highlightActiveLine?: boolean;
55
- history?: boolean;
56
- lineNumbers?: boolean;
57
- lineWrapping?: boolean;
58
- placeholder?: string;
59
- readonly?: boolean;
60
- scrollPastEnd?: boolean;
61
- tabSize?: number;
62
- };
63
-
64
- const defaults: BasicExtensionsOptions = {
65
- bracketMatching: true,
66
- closeBrackets: true,
67
- drawSelection: true,
68
- editable: true,
69
- history: true,
70
- lineWrapping: true,
71
- };
72
-
73
- export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extension => {
74
- const props: BasicExtensionsOptions = defaultsDeep({}, _props, defaults);
75
- return [
76
- // TODO(burdon): Doesn't catch errors in keymap functions.
77
- EditorView.exceptionSink.of((err) => {
78
- log.catch(err);
79
- }),
80
-
81
- props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
82
- props.bracketMatching && bracketMatching(),
83
- props.closeBrackets && closeBrackets(),
84
- props.crosshairCursor && crosshairCursor(),
85
- props.dropCursor && dropCursor(),
86
- props.drawSelection && drawSelection(),
87
- props.highlightActiveLine && highlightActiveLine(),
88
- props.history && history(),
89
- props.lineNumbers && lineNumbers(),
90
- props.lineWrapping && EditorView.lineWrapping,
91
- props.placeholder && placeholder(props.placeholder),
92
- props.readonly && [EditorState.readOnly.of(true), EditorView.editable.of(false)],
93
- props.scrollPastEnd && scrollPastEnd(),
94
- props.tabSize && EditorState.tabSize.of(props.tabSize),
95
- ].filter(isNotFalsy);
96
- };
97
-
98
- //
99
- // Theme
100
- //
101
-
102
- export type ThemeExtensionsOptions = {
103
- theme?: ThemeStyles;
104
- themeMode?: ThemeMode;
105
- slots?: {
106
- editor?: {
107
- className?: string;
108
- };
109
- content?: {
110
- className?: string;
111
- };
112
- };
113
- };
114
-
115
- const defaultSlots = {
116
- editor: {
117
- className: 'w-full bs-full',
118
- },
119
- };
120
-
121
- export const createThemeExtensions = ({ theme, themeMode, slots: _slots }: ThemeExtensionsOptions = {}): Extension => {
122
- const slots = defaultsDeep({}, _slots, defaultSlots);
123
- return [
124
- EditorView.baseTheme(defaultTheme),
125
- EditorView.darkTheme.of(themeMode === 'dark'),
126
- theme && EditorView.theme(theme),
127
- slots.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),
128
- slots.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),
129
- ].filter(isNotFalsy);
130
- };
131
-
132
- //
133
- // Data
134
- //
135
-
136
- export type DataExtensionsProps = {
137
- id: string;
138
- text: DocAccessor; // TODO(burdon): Rename content.
139
- space?: Space;
140
- identity?: Identity | null;
141
- };
142
-
143
- // TODO(burdon): Factor out automerge defs and extension (not hook).
144
- // TODO(burdon): Move out of react-ui-editor (remove echo deps).
145
- export const createDataExtensions = ({ id, text, space, identity }: DataExtensionsProps): Extension[] => {
146
- const extensions: Extension[] = [automerge(text)];
147
-
148
- if (space && identity) {
149
- const peerId = identity?.identityKey.toHex();
150
- const { cursorLightValue, cursorDarkValue } =
151
- hueTokens[(identity?.profile?.data?.hue as HuePalette | undefined) ?? hexToHue(peerId ?? '0')];
152
- const awarenessProvider = new SpaceAwarenessProvider({
153
- space,
154
- channel: `awareness.${id}`,
155
- peerId: identity.identityKey.toHex(),
156
- info: {
157
- displayName: identity.profile?.displayName ?? generateName(identity.identityKey.toHex()),
158
- color: cursorDarkValue,
159
- lightColor: cursorLightValue,
160
- },
161
- });
162
-
163
- extensions.push(awareness(awarenessProvider));
164
- }
165
-
166
- return extensions;
167
- };
@@ -1,16 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- // Runtime data structure.
6
- export type Range = {
7
- from: number;
8
- to: number;
9
- };
10
-
11
- // Persistent data structure.
12
- // TODO(burdon): Rename annotation?
13
- export type Comment = {
14
- id: string;
15
- cursor?: string;
16
- };
@@ -1,21 +0,0 @@
1
- //
2
- // Copyright 2024 DXOS.org
3
- //
4
-
5
- import { useMemo } from 'react';
6
-
7
- import { createDocAccessor, type DocAccessor, getTextContent, type TextObject } from '@dxos/echo-schema';
8
-
9
- // TODO(burdon): Factor out.
10
- export const useDocAccessor = <T = any>(
11
- text: TextObject,
12
- ): { id: string; doc: string | undefined; accessor: DocAccessor<T> } => {
13
- return useMemo(
14
- () => ({
15
- id: text.id,
16
- doc: getTextContent(text),
17
- accessor: createDocAccessor<T>(text),
18
- }),
19
- [text],
20
- );
21
- };