@dxos/react-ui-editor 0.3.11-main.4eab977 → 0.3.11-main.4faaf44

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 (163) hide show
  1. package/dist/lib/browser/index.mjs +1134 -1241
  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 +16 -13
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -6
  9. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
  11. package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
  12. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  13. package/dist/types/src/extensions/automerge/automerge.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 +7 -9
  17. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  18. package/dist/types/src/extensions/automerge/index.d.ts +0 -1
  19. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/semaphore.d.ts +7 -12
  21. package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
  22. package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
  23. package/dist/types/src/extensions/awareness.d.ts +1 -1
  24. package/dist/types/src/extensions/awareness.d.ts.map +1 -1
  25. package/dist/types/src/extensions/basic.d.ts +4 -5
  26. package/dist/types/src/extensions/basic.d.ts.map +1 -1
  27. package/dist/types/src/extensions/comments.d.ts +32 -19
  28. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  29. package/dist/types/src/{util → extensions}/cursor.d.ts +10 -2
  30. package/dist/types/src/extensions/cursor.d.ts.map +1 -0
  31. package/dist/types/src/extensions/index.d.ts +2 -7
  32. package/dist/types/src/extensions/index.d.ts.map +1 -1
  33. package/dist/types/src/extensions/markdown/bundle.d.ts +3 -6
  34. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  35. package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
  36. package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
  37. package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
  38. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  39. package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
  40. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
  41. package/dist/types/src/extensions/markdown/index.d.ts +7 -0
  42. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
  44. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
  45. package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
  46. package/dist/types/src/extensions/mention.d.ts.map +1 -1
  47. package/dist/types/src/extensions/outliner.d.ts +4 -0
  48. package/dist/types/src/extensions/outliner.d.ts.map +1 -0
  49. package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
  50. package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
  51. package/dist/types/src/hooks/defs.d.ts +25 -0
  52. package/dist/types/src/hooks/defs.d.ts.map +1 -0
  53. package/dist/types/src/hooks/index.d.ts +2 -2
  54. package/dist/types/src/hooks/index.d.ts.map +1 -1
  55. package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
  56. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
  57. package/dist/types/src/hooks/useTextModel.d.ts +2 -32
  58. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  59. package/dist/types/src/index.d.ts +1 -0
  60. package/dist/types/src/index.d.ts.map +1 -1
  61. package/dist/types/src/styles/markdown.d.ts +2 -2
  62. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  63. package/dist/types/src/themes/default.d.ts.map +1 -1
  64. package/dist/types/src/util.d.ts +7 -0
  65. package/dist/types/src/util.d.ts.map +1 -0
  66. package/package.json +34 -36
  67. package/src/components/TextEditor/MarkdownEditor.stories.tsx +82 -82
  68. package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
  69. package/src/components/TextEditor/TextEditor.tsx +122 -93
  70. package/src/components/TextEditor/comments.stories.tsx +357 -0
  71. package/src/extensions/autocomplete.ts +6 -3
  72. package/src/extensions/automerge/automerge.ts +40 -46
  73. package/src/extensions/automerge/cursor.ts +2 -1
  74. package/src/extensions/automerge/defs.ts +10 -31
  75. package/src/extensions/automerge/index.ts +0 -1
  76. package/src/extensions/automerge/semaphore.ts +23 -20
  77. package/src/extensions/automerge/update-automerge.ts +2 -2
  78. package/src/extensions/awareness.ts +40 -46
  79. package/src/extensions/basic.ts +22 -17
  80. package/src/extensions/comments.ts +246 -238
  81. package/src/extensions/cursor.ts +50 -0
  82. package/src/extensions/index.ts +2 -7
  83. package/src/extensions/markdown/bundle.ts +20 -30
  84. package/src/extensions/markdown/code.ts +127 -0
  85. package/src/extensions/markdown/heading.ts +59 -0
  86. package/src/extensions/markdown/highlight.ts +9 -23
  87. package/src/extensions/markdown/hr.ts +71 -0
  88. package/src/extensions/{image.ts → markdown/image.ts} +2 -2
  89. package/src/extensions/markdown/index.ts +7 -0
  90. package/src/extensions/{link.ts → markdown/link.ts} +8 -9
  91. package/src/extensions/{table.ts → markdown/table.ts} +2 -2
  92. package/src/extensions/markdown/tasklist.ts +110 -0
  93. package/src/extensions/mention.ts +9 -2
  94. package/src/extensions/outliner.ts +12 -0
  95. package/src/hooks/awareness-provider.ts +24 -20
  96. package/src/hooks/defs.ts +42 -0
  97. package/src/hooks/index.ts +3 -2
  98. package/src/hooks/useTextEditor.ts +29 -0
  99. package/src/hooks/useTextModel.ts +48 -60
  100. package/src/index.ts +1 -0
  101. package/src/styles/markdown.ts +9 -12
  102. package/src/themes/default.ts +15 -50
  103. package/src/util.ts +41 -0
  104. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
  105. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
  106. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
  107. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  108. package/dist/types/src/extensions/code.d.ts.map +0 -1
  109. package/dist/types/src/extensions/hr.d.ts.map +0 -1
  110. package/dist/types/src/extensions/image.d.ts.map +0 -1
  111. package/dist/types/src/extensions/link.d.ts.map +0 -1
  112. package/dist/types/src/extensions/table.d.ts.map +0 -1
  113. package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
  114. package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
  115. package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
  116. package/dist/types/src/extensions/yjs/index.d.ts +0 -2
  117. package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
  118. package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
  119. package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
  120. package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
  121. package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
  122. package/dist/types/src/hooks/automerge.d.ts +0 -3
  123. package/dist/types/src/hooks/automerge.d.ts.map +0 -1
  124. package/dist/types/src/hooks/yjs.d.ts +0 -27
  125. package/dist/types/src/hooks/yjs.d.ts.map +0 -1
  126. package/dist/types/src/testing/index.d.ts +0 -3
  127. package/dist/types/src/testing/index.d.ts.map +0 -1
  128. package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
  129. package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
  130. package/dist/types/src/testing/proto/index.d.ts +0 -2
  131. package/dist/types/src/testing/proto/index.d.ts.map +0 -1
  132. package/dist/types/src/testing/replicator.d.ts +0 -45
  133. package/dist/types/src/testing/replicator.d.ts.map +0 -1
  134. package/dist/types/src/util/cursor.d.ts.map +0 -1
  135. package/dist/types/src/util/index.d.ts +0 -3
  136. package/dist/types/src/util/index.d.ts.map +0 -1
  137. package/dist/types/src/util/util.d.ts +0 -5
  138. package/dist/types/src/util/util.d.ts.map +0 -1
  139. package/src/components/TextEditor/codemirror.stories.ts +0 -115
  140. package/src/components/TextEditor/yjs.stories.tsx +0 -56
  141. package/src/extensions/code.ts +0 -98
  142. package/src/extensions/hr.ts +0 -73
  143. package/src/extensions/tasklist.ts +0 -119
  144. package/src/extensions/yjs/cursor.ts +0 -21
  145. package/src/extensions/yjs/index.ts +0 -5
  146. package/src/extensions/yjs/yjs.test.ts +0 -35
  147. package/src/extensions/yjs/yjs.ts +0 -16
  148. package/src/hooks/automerge.ts +0 -52
  149. package/src/hooks/yjs.ts +0 -178
  150. package/src/testing/index.ts +0 -6
  151. package/src/testing/proto/gen/schema.ts +0 -49
  152. package/src/testing/proto/index.ts +0 -5
  153. package/src/testing/proto/schema.proto +0 -15
  154. package/src/testing/replicator.ts +0 -184
  155. package/src/util/cursor.ts +0 -29
  156. package/src/util/index.ts +0 -6
  157. package/src/util/util.ts +0 -18
  158. /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
  159. /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
  160. /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
  161. /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
  162. /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
  163. /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
@@ -0,0 +1,12 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Extension } from '@codemirror/state';
6
+
7
+ export type OutlinerOptions = {};
8
+
9
+ // TODO(burdon): Experimental component: multiple hierarchical draggable editor sections.
10
+ export const outliner = (options: OutlinerOptions = {}): Extension => {
11
+ return [];
12
+ };
@@ -29,9 +29,10 @@ export type AwarenessProviderParams = {
29
29
  info: AwarenessInfo;
30
30
  };
31
31
 
32
+ /**
33
+ * Receives and broadcasts profile and cursor position.
34
+ */
32
35
  export class SpaceAwarenessProvider implements AwarenessProvider {
33
- public readonly remoteStateChange = new Event<void>();
34
-
35
36
  private readonly _remoteStates = new Map<string, AwarenessState>();
36
37
 
37
38
  private readonly _space: Space;
@@ -39,9 +40,11 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
39
40
  private readonly _peerId: string;
40
41
  private readonly _info: AwarenessInfo;
41
42
 
42
- private _localState?: AwarenessState;
43
- private _postTask?: DeferredTask;
44
43
  private _ctx?: Context;
44
+ private _postTask?: DeferredTask;
45
+ private _localState?: AwarenessState;
46
+
47
+ public readonly remoteStateChange = new Event<void>();
45
48
 
46
49
  constructor(params: AwarenessProviderParams) {
47
50
  this._space = params.space;
@@ -63,19 +66,20 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
63
66
  }
64
67
  });
65
68
 
66
- const unsubscribe = this._space.listen(this._channel, (message: GossipMessage) => {
67
- switch (message.payload.kind) {
68
- case 'query': {
69
- this._handleQueryMessage();
70
- break;
69
+ this._ctx.onDispose(
70
+ this._space.listen(this._channel, (message: GossipMessage) => {
71
+ switch (message.payload.kind) {
72
+ case 'query': {
73
+ this._handleQueryMessage();
74
+ break;
75
+ }
76
+ case 'post': {
77
+ this._handlePostMessage(message.payload);
78
+ break;
79
+ }
71
80
  }
72
- case 'post': {
73
- this._handlePostMessage(message.payload);
74
- break;
75
- }
76
- }
77
- });
78
- this._ctx.onDispose(unsubscribe);
81
+ }),
82
+ );
79
83
 
80
84
  void this._space
81
85
  .postMessage(this._channel, {
@@ -92,6 +96,10 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
92
96
  this._postTask = undefined;
93
97
  }
94
98
 
99
+ getRemoteStates(): AwarenessState[] {
100
+ return Array.from(this._remoteStates.values());
101
+ }
102
+
95
103
  update(position: AwarenessPosition | undefined): void {
96
104
  invariant(this._postTask);
97
105
  this._localState = {
@@ -103,10 +111,6 @@ export class SpaceAwarenessProvider implements AwarenessProvider {
103
111
  this._postTask.schedule();
104
112
  }
105
113
 
106
- getRemoteStates(): AwarenessState[] {
107
- return Array.from(this._remoteStates.values());
108
- }
109
-
110
114
  private _handleQueryMessage() {
111
115
  invariant(this._postTask);
112
116
  this._postTask.schedule();
@@ -0,0 +1,42 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Extension, StateField } from '@codemirror/state';
6
+
7
+ import { type DocAccessor } from '@dxos/echo-schema';
8
+
9
+ // Runtime data structure.
10
+ export type Range = {
11
+ from: number;
12
+ to: number;
13
+ };
14
+
15
+ // Persistent data structure.
16
+ export type Comment = {
17
+ id: string;
18
+ cursor?: string;
19
+ };
20
+
21
+ export type EditorModel = {
22
+ id: string;
23
+ text: () => string;
24
+ extension?: Extension;
25
+
26
+ // TODO(burdon): Remove.
27
+ content: string | DocAccessor;
28
+
29
+ // TODO(burdon): Remove.
30
+ peer?: {
31
+ id: string;
32
+ name?: string;
33
+ };
34
+ };
35
+
36
+ /**
37
+ * State field makes the model available to other extensions.
38
+ */
39
+ export const modelState = StateField.define<EditorModel | undefined>({
40
+ create: () => undefined,
41
+ update: (model) => model,
42
+ });
@@ -2,7 +2,8 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- export * from './automerge';
6
5
  export * from './awareness-provider';
6
+ export * from './defs';
7
+
8
+ export * from './useTextEditor';
7
9
  export * from './useTextModel';
8
- export * from './yjs';
@@ -0,0 +1,29 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type EditorView } from '@codemirror/view';
6
+ import { type RefCallback, useState } from 'react';
7
+
8
+ /**
9
+ * Hook for accessing the editor view.
10
+ *
11
+ * ```tsx
12
+ * const Test = () => {
13
+ * const [editorRef, editorView] = useTextEditor();
14
+ * useEffect(() => {
15
+ * editorView?.focus();
16
+ * }, [editorView]);
17
+ * return <TextEditor ref={editorRef} />;
18
+ * };
19
+ * ```
20
+ */
21
+ export const useTextEditor = (): [RefCallback<EditorView | null>, EditorView | null] => {
22
+ const [view, setView] = useState<EditorView | null>(null);
23
+ return [
24
+ (ref: EditorView | null) => {
25
+ setView(ref);
26
+ },
27
+ view,
28
+ ];
29
+ };
@@ -2,58 +2,20 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { StateField, type Extension } from '@codemirror/state';
5
+ import get from 'lodash.get';
6
6
  import { useEffect, useState } from 'react';
7
- import type * as YP from 'y-protocols/awareness';
8
7
 
9
- import { isAutomergeObject, type DocAccessor, type Space, type TextObject } from '@dxos/react-client/echo';
8
+ import { generateName } from '@dxos/display-name';
9
+ import { type AutomergeTextCompat, getRawDoc } from '@dxos/echo-schema';
10
+ import { invariant } from '@dxos/invariant';
11
+ import { isAutomergeObject, type Space, type TextObject } from '@dxos/react-client/echo';
10
12
  import { type Identity } from '@dxos/react-client/halo';
11
- import type { YText, YXmlFragment } from '@dxos/text-model';
13
+ import { isNotNullOrUndefined } from '@dxos/util';
12
14
 
13
- import { createAutomergeModel } from './automerge';
14
- import { createYjsModel } from './yjs';
15
-
16
- // TODO(burdon): Factor out defs.
17
-
18
- /**
19
- * State field makes the model available to other extensions.
20
- */
21
- export const modelState = StateField.define<EditorModel | undefined>({
22
- create: () => undefined,
23
- update: (model) => model,
24
- });
25
-
26
- export type Range = {
27
- from: number;
28
- to: number;
29
- };
30
-
31
- export type CommentRange = {
32
- id: string;
33
- cursor: string;
34
- };
35
-
36
- // TODO(wittjosiah): Factor out to common package? @dxos/react-client?
37
- export type EditorModel = {
38
- id: string;
39
- text: () => string;
40
- extension?: Extension;
41
-
42
- // TODO(burdon): Remove.
43
- content: string | YText | YXmlFragment | DocAccessor;
44
- /**
45
- * @deprecated Use CursorConverter.
46
- */
47
- getCursorFromRange?: (value: Range) => string;
48
- getRangeFromCursor?: (cursor: string) => Range | undefined;
49
- // TODO(burdon): Move into extension.
50
- awareness?: YP.Awareness;
51
- // TODO(burdon): Remove.
52
- peer?: {
53
- id: string;
54
- name?: string;
55
- };
56
- };
15
+ import { SpaceAwarenessProvider } from './awareness-provider';
16
+ import { type EditorModel, modelState } from './defs';
17
+ import { automerge, awareness, AwarenessProvider } from '../extensions';
18
+ import { cursorColor } from '../styles';
57
19
 
58
20
  // TODO(burdon): Remove space/identity dependency. Define interface for the framework re content and presence.
59
21
  export type UseTextModelProps = {
@@ -62,22 +24,48 @@ export type UseTextModelProps = {
62
24
  text?: TextObject;
63
25
  };
64
26
 
65
- // TODO(burdon): Remove YJS/Automerge deps (from UI component -- create abstraction; incl. all ECHO/Space deps).
66
- // TODO(wittjosiah): Factor out to common package? @dxos/react-client?
67
27
  export const useTextModel = (props: UseTextModelProps): EditorModel | undefined => {
68
28
  const { identity, space, text } = props;
69
- const [model, setModel] = useState<EditorModel | undefined>(() => createModel(props));
29
+ const [model, setModel] = useState<EditorModel | undefined>();
70
30
  useEffect(() => setModel(createModel(props)), [identity, space, text]);
71
31
  return model;
72
32
  };
73
33
 
74
- const createModel = (props: UseTextModelProps) => {
75
- const { text } = props;
76
- if (isAutomergeObject(text)) {
77
- return createAutomergeModel(props);
78
- } else if (text?.doc) {
79
- return createYjsModel(props);
80
- } else {
81
- return undefined;
82
- }
34
+ const createModel = ({ space, identity, text }: UseTextModelProps) => {
35
+ invariant(isAutomergeObject(text));
36
+ const obj = text as any as AutomergeTextCompat;
37
+ const doc = getRawDoc(obj, [obj.field]);
38
+
39
+ const awarenessProvider =
40
+ space &&
41
+ new SpaceAwarenessProvider({
42
+ space,
43
+ channel: `automerge.awareness.${obj.id}`,
44
+ info: {
45
+ displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : undefined,
46
+ color: cursorColor.color,
47
+ lightColor: cursorColor.light,
48
+ },
49
+ peerId: identity?.identityKey.toHex() ?? 'Anonymous',
50
+ });
51
+
52
+ const model: EditorModel = {
53
+ id: obj.id,
54
+ content: doc,
55
+ text: () => get(doc.handle.docSync(), doc.path),
56
+ extension: [
57
+ modelState.init(() => model),
58
+ automerge({ handle: doc.handle, path: doc.path }),
59
+ awarenessProvider && AwarenessProvider.of(awarenessProvider),
60
+ awareness(),
61
+ ].filter(isNotNullOrUndefined),
62
+ peer: identity
63
+ ? {
64
+ id: identity.identityKey.toHex(),
65
+ name: identity.profile?.displayName,
66
+ }
67
+ : undefined,
68
+ };
69
+
70
+ return model;
83
71
  };
package/src/index.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  export { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
6
6
  export { Doc, YText, YXmlFragment } from '@dxos/text-model';
7
7
  export { type Extension } from '@codemirror/state';
8
+ export { type EditorView } from '@codemirror/view';
8
9
 
9
10
  export * from './components';
10
11
  export * from './extensions';
@@ -8,18 +8,17 @@ export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
8
8
 
9
9
  // TODO(burdon): Better way to align vertically than negative margin? Font-specific?
10
10
  // https://tailwindcss.com/docs/font-weight
11
- export const headings: Record<HeadingLevel, string[]> = {
12
- 1: ['mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl', '-ml-[10px]'],
13
- 2: ['mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl', '-ml-[8px]'],
14
- 3: ['mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl', '-ml-[7px]'],
15
- 4: ['mbs-4 mbe-2 font-medium text-inherit no-underline text-xl', '-ml-[6px]'],
16
- 5: ['mbs-4 mbe-2 font-medium text-inherit no-underline text-lg', '-ml-[5px]'],
17
- 6: ['mbs-4 mbe-2 font-medium text-inherit no-underline', '-ml-[4px]'],
11
+ export const headings: Record<HeadingLevel, string> = {
12
+ 1: 'mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl',
13
+ 2: 'mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl',
14
+ 3: 'mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl',
15
+ 4: 'mbs-4 mbe-2 font-medium text-inherit no-underline text-xl',
16
+ 5: 'mbs-4 mbe-2 font-medium text-inherit no-underline text-lg',
17
+ 6: 'mbs-4 mbe-2 font-medium text-inherit no-underline',
18
18
  };
19
19
 
20
- export const heading = (level: HeadingLevel, readonly?: boolean) => {
21
- const [style, offset] = headings[level];
22
- return mx(style, readonly && offset);
20
+ export const heading = (level: HeadingLevel) => {
21
+ return headings[level];
23
22
  };
24
23
 
25
24
  export const text = 'text-neutral-800 dark:text-neutral-200';
@@ -39,10 +38,8 @@ export const codeBlock = 'mlb-2 font-mono bg-neutral-500/10 p-3 rounded';
39
38
 
40
39
  export const inlineUrl = mx(code, 'px-1');
41
40
 
42
- // TODO(burdon): Replace with widget.
43
41
  export const blockquote = mx('pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30', light);
44
42
 
45
- // TODO(burdon): Replace with widget.
46
43
  export const horizontalRule =
47
44
  'flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800';
48
45
 
@@ -6,8 +6,8 @@ import get from 'lodash.get';
6
6
 
7
7
  import { type ThemeStyles, tokens } from '../styles';
8
8
 
9
- // TODO(burdon): Can we erase All of the default CM styles?
10
- // TODO(burdon): Theme styles seem to be added multiple times?
9
+ // TODO(burdon): Can we use @apply and import css file?
10
+ // https://tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply?
11
11
 
12
12
  /**
13
13
  * Minimal styles.
@@ -119,36 +119,6 @@ export const defaultTheme: ThemeStyles = {
119
119
  backgroundColor: get(tokens, 'extend.colors.yellow.700'),
120
120
  },
121
121
 
122
- //
123
- // collaboration
124
- // TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
125
- //
126
-
127
- '&light .cm-ySelection, &light .cm-yLineSelection': {
128
- mixBlendMode: 'multiply',
129
- },
130
- '&dark .cm-ySelection, &dark .cm-yLineSelection': {
131
- mixBlendMode: 'screen',
132
- },
133
-
134
- '.cm-ySelectionInfo': {
135
- padding: '2px 4px',
136
- marginBlockStart: '-4px',
137
- },
138
- '.cm-ySelection, & .cm-selectionMatch': {
139
- paddingBlockStart: '.15em',
140
- paddingBlockEnd: '.15em',
141
- },
142
- '.cm-ySelectionCaret': {
143
- display: 'inline-block',
144
- insetBlockStart: '.1em',
145
- blockSize: '1.4em',
146
- verticalAlign: 'top',
147
- },
148
- '.cm-yLineSelection': {
149
- margin: 0,
150
- },
151
-
152
122
  //
153
123
  // link
154
124
  //
@@ -188,14 +158,6 @@ export const defaultTheme: ThemeStyles = {
188
158
  textDecoration: 'none',
189
159
  },
190
160
 
191
- //
192
- // widgets
193
- //
194
- '.cm-widgetBuffer': {
195
- display: 'none',
196
- height: 0,
197
- },
198
-
199
161
  //
200
162
  // table
201
163
  //
@@ -229,16 +191,17 @@ export const defaultTheme: ThemeStyles = {
229
191
 
230
192
  //
231
193
  // font size
232
- // 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.
194
+ // TODO(thure): This appears to be the best or only way to set selection caret heights,
195
+ // but it's far more verbose than it needs to be.
233
196
  //
234
- ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
235
- const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
236
-
237
- acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
238
- acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
239
- acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
240
- return acc;
241
- }, {}),
197
+ // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
198
+ // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
199
+ //
200
+ // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
201
+ // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
202
+ // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
203
+ // return acc;
204
+ // }, {}),
242
205
 
243
206
  /**
244
207
  * Panels
@@ -292,7 +255,9 @@ export const textTheme: ThemeStyles = {
292
255
  };
293
256
 
294
257
  export const markdownTheme: ThemeStyles = {
295
- // NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
258
+ '.cm-scroller': {
259
+ fontFamily: get(tokens, 'fontFamily.body', []).join(','),
260
+ },
296
261
  '.cm-placeholder': {
297
262
  fontFamily: get(tokens, 'fontFamily.body', []).join(','),
298
263
  },
package/src/util.ts ADDED
@@ -0,0 +1,41 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import type { Transaction } from '@codemirror/state';
6
+
7
+ import { log } from '@dxos/log';
8
+
9
+ /**
10
+ * CodeMirror callbacks swallow errors so wrap handlers.
11
+ */
12
+ // TODO(burdon): EditorView.exceptionSink should catch errors.
13
+ export const callbackWrapper = <T extends Function>(fn: T): T =>
14
+ ((...args: any[]) => {
15
+ try {
16
+ return fn(...args);
17
+ } catch (err) {
18
+ log.catch(err);
19
+ }
20
+ }) as unknown as T;
21
+
22
+ export const logChanges = (trs: readonly Transaction[]) => {
23
+ const changes = trs
24
+ .flatMap((tr) => {
25
+ if (tr.changes.empty) {
26
+ return undefined;
27
+ }
28
+
29
+ const changes: any[] = [];
30
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) =>
31
+ changes.push(JSON.stringify({ fromA, toA, fromB, toB, inserted: inserted.toString() })),
32
+ );
33
+
34
+ return changes;
35
+ })
36
+ .filter(Boolean);
37
+
38
+ if (changes.length) {
39
+ console.log('changes', changes);
40
+ }
41
+ };
@@ -1,12 +0,0 @@
1
- import { type StoryObj } from '@storybook/html';
2
- import { Client, type PublicKey } from '@dxos/react-client';
3
- declare const _default: {
4
- title: string;
5
- };
6
- export default _default;
7
- export declare const Default: StoryObj<{
8
- id: number;
9
- client: Client;
10
- spaceKey: PublicKey;
11
- }>;
12
- //# sourceMappingURL=codemirror.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"codemirror.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/TextEditor/codemirror.stories.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAMhD,OAAO,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;;;;AAU5D,wBAEE;AAqEF,eAAO,MAAM,OAAO,EAAE,QAAQ,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,CAAA;CAAE,CAoBjF,CAAC"}
@@ -1,12 +0,0 @@
1
- import '@dxosTheme';
2
- import React from 'react';
3
- declare const _default: {
4
- title: string;
5
- component: React.ForwardRefExoticComponent<import("./TextEditor").TextEditorProps & React.RefAttributes<import("./TextEditor").TextEditorRef>>;
6
- decorators: import("@storybook/react").Decorator[];
7
- };
8
- export default _default;
9
- export declare const Default: {
10
- render: () => JSX.Element;
11
- };
12
- //# sourceMappingURL=yjs.stories.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"yjs.stories.d.ts","sourceRoot":"","sources":["../../../../../src/components/TextEditor/yjs.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,YAAY,CAAC;AAEpB,OAAO,KAAmB,MAAM,OAAO,CAAC;;;;;;AAWxC,wBAIE;AA+BF,eAAO,MAAM,OAAO;;CAGnB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../src/extensions/code.ts"],"names":[],"mappings":"AAsDA,eAAO,MAAM,IAAI,+CA2ChB,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hr.d.ts","sourceRoot":"","sources":["../../../../src/extensions/hr.ts"],"names":[],"mappings":"AAkDA,eAAO,MAAM,EAAE,+CAsBd,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../../../src/extensions/image.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoB,KAAK,SAAS,EAA4C,MAAM,mBAAmB,CAAC;AAG/G,MAAM,MAAM,YAAY,GAAG,EAAE,CAAC;AAE9B,eAAO,MAAM,KAAK,aAAa,YAAY,KAAQ,SA8BlD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"link.d.ts","sourceRoot":"","sources":["../../../../src/extensions/link.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,SAAS,EAAmB,MAAM,mBAAmB,CAAC;AAkBpE,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,IAAI,aAAa,WAAW,KAAQ,SAsDhD,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"table.d.ts","sourceRoot":"","sources":["../../../../src/extensions/table.ts"],"names":[],"mappings":"AAKA,OAAO,EAAoB,KAAK,QAAQ,EAAmB,UAAU,EAAoB,MAAM,mBAAmB,CAAC;AASnH,MAAM,MAAM,YAAY,GAAG,EAAE,CAAC;AAE9B;;;GAGG;AACH,eAAO,MAAM,KAAK,aAAa,YAAY,8BAM1C,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"tasklist.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasklist.ts"],"names":[],"mappings":"AA8DA,MAAM,MAAM,eAAe,GAAG,EAAE,CAAC;AAEjC,eAAO,MAAM,QAAQ,aAAa,eAAe,4CAsDhD,CAAC"}
@@ -1,4 +0,0 @@
1
- import * as Y from 'yjs';
2
- import { type CursorConverter } from '../../util';
3
- export declare const cursorConverter: (text: Y.Text) => CursorConverter;
4
- //# sourceMappingURL=cursor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cursor.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/yjs/cursor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAIzB,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,eAAO,MAAM,eAAe,SAAU,MAAM,KAAG,eAU7C,CAAC"}
@@ -1,2 +0,0 @@
1
- export * from './yjs';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/yjs/index.ts"],"names":[],"mappings":"AAIA,cAAc,OAAO,CAAC"}
@@ -1,4 +0,0 @@
1
- import type * as YP from 'y-protocols/awareness';
2
- import type { YText } from '@dxos/text-model';
3
- export declare const yjs: (content: YText, awareness?: YP.Awareness) => import("@codemirror/state").Extension[];
4
- //# sourceMappingURL=yjs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"yjs.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/yjs/yjs.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAEjD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAK9C,eAAO,MAAM,GAAG,YAAa,KAAK,cAAc,GAAG,SAAS,4CAG3D,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=yjs.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"yjs.test.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/yjs/yjs.test.ts"],"names":[],"mappings":""}
@@ -1,3 +0,0 @@
1
- import { type EditorModel, type UseTextModelProps } from './useTextModel';
2
- export declare const createAutomergeModel: ({ space, identity, text }: UseTextModelProps) => EditorModel;
3
- //# sourceMappingURL=automerge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"automerge.d.ts","sourceRoot":"","sources":["../../../../src/hooks/automerge.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,WAAW,EAAc,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAItF,eAAO,MAAM,oBAAoB,8BAA+B,iBAAiB,KAAG,WAqCnF,CAAC"}
@@ -1,27 +0,0 @@
1
- import { Observable } from 'lib0/observable';
2
- import * as YP from 'y-protocols/awareness';
3
- import { type Doc } from 'yjs';
4
- import { type Space } from '@dxos/react-client/echo';
5
- import { type EditorModel, type UseTextModelProps } from './useTextModel';
6
- export declare const createYjsModel: ({ identity, space, text }: UseTextModelProps) => EditorModel;
7
- /**
8
- * Yjs awareness provider on top of a DXOS space.
9
- */
10
- export declare class YAwarenessProvider extends Observable<any> {
11
- private readonly _space;
12
- private readonly _awareness;
13
- private readonly _clientId;
14
- private readonly _channel;
15
- constructor({ space, doc, channel, awareness, }: {
16
- space: Space;
17
- doc: Doc;
18
- channel: string;
19
- awareness?: YP.Awareness;
20
- });
21
- get awareness(): YP.Awareness;
22
- private _handleAwarenessUpdate;
23
- private _handleSpaceMessage;
24
- private _readMessage;
25
- private _handleBeforeUnload;
26
- }
27
- //# sourceMappingURL=yjs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"yjs.d.ts","sourceRoot":"","sources":["../../../../src/hooks/yjs.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAE5C,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAI/B,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAKrD,OAAO,EAAE,KAAK,WAAW,EAA0B,KAAK,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGlG,eAAO,MAAM,cAAc,8BAA+B,iBAAiB,KAAG,WAyC7E,CAAC;AAOF;;GAEG;AACH,qBAAa,kBAAmB,SAAQ,UAAU,CAAC,GAAG,CAAC;IACrD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;IAC1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,EACV,KAAK,EACL,GAAG,EACH,OAAO,EACP,SAAS,GACV,EAAE;QACD,KAAK,EAAE,KAAK,CAAC;QACb,GAAG,EAAE,GAAG,CAAC;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC;KAC1B;IA4BD,IAAI,SAAS,IAAI,EAAE,CAAC,SAAS,CAE5B;IAED,OAAO,CAAC,sBAAsB;IAS9B,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,YAAY;IAoCpB,OAAO,CAAC,mBAAmB;CAG5B"}
@@ -1,3 +0,0 @@
1
- export * from './proto';
2
- export * from './replicator';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/testing/index.ts"],"names":[],"mappings":"AAIA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC"}