@dxos/react-ui-editor 0.8.3 → 0.8.4-main.28f8d3d

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 (174) hide show
  1. package/dist/lib/browser/chunk-22UMM3QJ.mjs +22 -0
  2. package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +790 -700
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +1 -1
  7. package/dist/lib/browser/testing/index.mjs.map +2 -2
  8. package/dist/lib/browser/types/index.mjs +13 -0
  9. package/dist/lib/browser/types/index.mjs.map +7 -0
  10. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs +24 -0
  11. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +7 -0
  12. package/dist/lib/node-esm/index.mjs +789 -700
  13. package/dist/lib/node-esm/index.mjs.map +4 -4
  14. package/dist/lib/node-esm/meta.json +1 -1
  15. package/dist/lib/node-esm/testing/index.mjs +1 -1
  16. package/dist/lib/node-esm/testing/index.mjs.map +2 -2
  17. package/dist/lib/node-esm/types/index.mjs +14 -0
  18. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  19. package/dist/types/src/components/Editor/Editor.d.ts +19 -0
  20. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -0
  21. package/dist/types/src/components/Editor/index.d.ts +2 -0
  22. package/dist/types/src/components/Editor/index.d.ts.map +1 -0
  23. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  24. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  25. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  26. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
  27. package/dist/types/src/components/EditorToolbar/util.d.ts +4 -3
  28. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  29. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +1 -1
  30. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  31. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +1 -1
  32. package/dist/types/src/components/index.d.ts +1 -0
  33. package/dist/types/src/components/index.d.ts.map +1 -1
  34. package/dist/types/src/extensions/autocomplete.d.ts +1 -1
  35. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  36. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  37. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +28 -28
  38. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  39. package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
  40. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  41. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  42. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  43. package/dist/types/src/extensions/blast.d.ts.map +1 -1
  44. package/dist/types/src/extensions/command/action.d.ts +1 -1
  45. package/dist/types/src/extensions/command/action.d.ts.map +1 -1
  46. package/dist/types/src/extensions/command/command-menu.d.ts +1 -1
  47. package/dist/types/src/extensions/command/command-menu.d.ts.map +1 -1
  48. package/dist/types/src/extensions/command/command.d.ts.map +1 -1
  49. package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
  50. package/dist/types/src/extensions/command/index.d.ts +1 -1
  51. package/dist/types/src/extensions/command/index.d.ts.map +1 -1
  52. package/dist/types/src/extensions/command/state.d.ts +1 -1
  53. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  54. package/dist/types/src/extensions/command/typeahead.d.ts +7 -2
  55. package/dist/types/src/extensions/command/typeahead.d.ts.map +1 -1
  56. package/dist/types/src/extensions/command/useCommandMenu.d.ts +1 -1
  57. package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +1 -1
  58. package/dist/types/src/extensions/comments.d.ts +1 -1
  59. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  60. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  61. package/dist/types/src/extensions/factories.d.ts +19 -0
  62. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  63. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  64. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  65. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  66. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  67. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  68. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  69. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  70. package/dist/types/src/extensions/modes.d.ts +0 -7
  71. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  72. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  73. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -1
  74. package/dist/types/src/extensions/outliner/tree.d.ts +1 -1
  75. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -1
  76. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  77. package/dist/types/src/index.d.ts +1 -1
  78. package/dist/types/src/index.d.ts.map +1 -1
  79. package/dist/types/src/stories/Command.stories.d.ts.map +1 -1
  80. package/dist/types/src/stories/CommandMenu.stories.d.ts +1 -1
  81. package/dist/types/src/stories/CommandMenu.stories.d.ts.map +1 -1
  82. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  83. package/dist/types/src/stories/EditorToolbar.stories.d.ts +1 -1
  84. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  85. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  86. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  87. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  88. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  89. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  90. package/dist/types/src/stories/components/EditorStory.d.ts +2 -2
  91. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  92. package/dist/types/src/testing/util.d.ts +1 -0
  93. package/dist/types/src/testing/util.d.ts.map +1 -1
  94. package/dist/types/src/translations.d.ts +28 -29
  95. package/dist/types/src/translations.d.ts.map +1 -1
  96. package/dist/types/src/types/index.d.ts +2 -0
  97. package/dist/types/src/types/index.d.ts.map +1 -0
  98. package/dist/types/src/types/types.d.ts +21 -0
  99. package/dist/types/src/types/types.d.ts.map +1 -0
  100. package/dist/types/src/util/cursor.d.ts.map +1 -1
  101. package/dist/types/tsconfig.tsbuildinfo +1 -1
  102. package/package.json +47 -41
  103. package/src/components/Editor/Editor.tsx +39 -0
  104. package/src/components/Editor/index.ts +5 -0
  105. package/src/components/EditorToolbar/EditorToolbar.tsx +1 -1
  106. package/src/components/EditorToolbar/blocks.ts +4 -3
  107. package/src/components/EditorToolbar/formatting.ts +3 -2
  108. package/src/components/EditorToolbar/headings.ts +2 -1
  109. package/src/components/EditorToolbar/lists.ts +3 -2
  110. package/src/components/EditorToolbar/util.ts +6 -5
  111. package/src/components/EditorToolbar/view-mode.ts +3 -2
  112. package/src/components/Popover/RefDropdownMenu.tsx +10 -4
  113. package/src/components/Popover/RefPopover.tsx +4 -4
  114. package/src/components/index.ts +1 -0
  115. package/src/extensions/autocomplete.ts +3 -3
  116. package/src/extensions/automerge/automerge.stories.tsx +8 -6
  117. package/src/extensions/automerge/automerge.ts +4 -3
  118. package/src/extensions/automerge/defs.ts +1 -1
  119. package/src/extensions/automerge/sync.ts +1 -1
  120. package/src/extensions/automerge/update-automerge.ts +1 -1
  121. package/src/extensions/awareness/awareness.ts +2 -2
  122. package/src/extensions/blast.ts +3 -16
  123. package/src/extensions/command/action.ts +1 -1
  124. package/src/extensions/command/command-menu.ts +4 -3
  125. package/src/extensions/command/command.ts +3 -3
  126. package/src/extensions/command/hint.ts +2 -1
  127. package/src/extensions/command/index.ts +1 -1
  128. package/src/extensions/command/placeholder.ts +1 -1
  129. package/src/extensions/command/state.ts +4 -3
  130. package/src/extensions/command/typeahead.ts +28 -15
  131. package/src/extensions/command/useCommandMenu.ts +2 -1
  132. package/src/extensions/comments.ts +7 -6
  133. package/src/extensions/dnd.ts +1 -1
  134. package/src/extensions/factories.ts +28 -8
  135. package/src/extensions/markdown/action.ts +2 -1
  136. package/src/extensions/markdown/bundle.ts +1 -1
  137. package/src/extensions/markdown/changes.ts +1 -1
  138. package/src/extensions/markdown/decorate.ts +7 -6
  139. package/src/extensions/markdown/formatting.test.ts +7 -7
  140. package/src/extensions/markdown/formatting.ts +16 -14
  141. package/src/extensions/markdown/highlight.ts +1 -1
  142. package/src/extensions/mention.ts +1 -1
  143. package/src/extensions/modes.ts +0 -9
  144. package/src/extensions/outliner/outliner.test.ts +3 -2
  145. package/src/extensions/outliner/outliner.ts +4 -3
  146. package/src/extensions/outliner/selection.ts +1 -1
  147. package/src/extensions/outliner/tree.test.ts +2 -1
  148. package/src/extensions/outliner/tree.ts +1 -1
  149. package/src/hooks/useTextEditor.ts +3 -3
  150. package/src/index.ts +1 -1
  151. package/src/stories/Command.stories.tsx +6 -5
  152. package/src/stories/CommandMenu.stories.tsx +7 -6
  153. package/src/stories/Comments.stories.tsx +3 -2
  154. package/src/stories/EditorToolbar.stories.tsx +6 -7
  155. package/src/stories/Experimental.stories.tsx +4 -3
  156. package/src/stories/Markdown.stories.tsx +3 -2
  157. package/src/stories/Outliner.stories.tsx +4 -3
  158. package/src/stories/Preview.stories.tsx +25 -26
  159. package/src/stories/TextEditor.stories.tsx +16 -15
  160. package/src/stories/components/EditorStory.tsx +5 -5
  161. package/src/styles/theme.ts +8 -8
  162. package/src/testing/util.ts +2 -0
  163. package/src/translations.ts +4 -2
  164. package/src/types/index.ts +5 -0
  165. package/src/types/types.ts +32 -0
  166. package/src/util/cursor.ts +2 -1
  167. package/dist/lib/node/index.cjs +0 -7754
  168. package/dist/lib/node/index.cjs.map +0 -7
  169. package/dist/lib/node/meta.json +0 -1
  170. package/dist/lib/node/testing/index.cjs +0 -29
  171. package/dist/lib/node/testing/index.cjs.map +0 -7
  172. package/dist/types/src/types.d.ts +0 -14
  173. package/dist/types/src/types.d.ts.map +0 -1
  174. package/src/types.ts +0 -23
@@ -2,15 +2,15 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { EditorSelection, Prec, RangeSetBuilder, type Extension } from '@codemirror/state';
5
+ import { EditorSelection, type Extension, Prec, RangeSetBuilder } from '@codemirror/state';
6
6
  import {
7
7
  type Command,
8
8
  Decoration,
9
9
  type DecorationSet,
10
10
  type EditorView,
11
- keymap,
12
11
  ViewPlugin,
13
12
  type ViewUpdate,
13
+ keymap,
14
14
  } from '@codemirror/view';
15
15
 
16
16
  import { Hint } from './hint';
@@ -87,30 +87,43 @@ export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
87
87
  ];
88
88
  };
89
89
 
90
+ type CompletionOptions = {
91
+ default?: string;
92
+ minLength?: number;
93
+ };
94
+
90
95
  /**
91
96
  * Util to match current line to a static list of completions.
92
97
  */
93
98
  export const staticCompletion =
94
- (completions: string[], defaultCompletion?: string) =>
99
+ (completions: string[], options: CompletionOptions = {}) =>
95
100
  ({ line }: TypeaheadContext) => {
96
- if (line.length === 0 && defaultCompletion) {
97
- return defaultCompletion;
101
+ if (line.length === 0 && options.default) {
102
+ return options.default;
98
103
  }
99
104
 
100
- const words = line.split(/\s+/).filter(Boolean);
101
- if (words.length) {
102
- const word = words.at(-1)!;
103
- for (const completion of completions) {
104
- const match = matchCompletion(completion, word);
105
- if (match) {
106
- return match;
105
+ const parts = line.split(/\s+/).filter(Boolean);
106
+ if (parts.length) {
107
+ const str = parts.at(-1)!;
108
+ if (str.length >= (options.minLength ?? 0)) {
109
+ for (const completion of completions) {
110
+ const match = matchCompletion(completion, str);
111
+ if (match) {
112
+ return match;
113
+ }
107
114
  }
108
115
  }
109
116
  }
110
117
  };
111
118
 
112
- export const matchCompletion = (completion: string, word: string): string | undefined => {
113
- if (completion.length > word.length && completion.startsWith(word)) {
114
- return completion.slice(word.length);
119
+ export const matchCompletion = (completion: string, str: string, minLength = 0): string | undefined => {
120
+ if (
121
+ str.length >= minLength &&
122
+ completion.length > str.length &&
123
+ completion.startsWith(str)
124
+ // TODO(burdon): If case insensitive, need to replace existing chars.
125
+ // completion.toLowerCase().startsWith(str.toLowerCase())
126
+ ) {
127
+ return completion.slice(str.length);
115
128
  }
116
129
  };
@@ -8,9 +8,10 @@ import { type RefObject, useCallback, useMemo, useRef, useState } from 'react';
8
8
  import { type DxRefTag, type DxRefTagActivate } from '@dxos/lit-ui';
9
9
  import { type MaybePromise } from '@dxos/util';
10
10
 
11
+ import { type CommandMenuGroup, type CommandMenuItem, getItem, getNextItem, getPreviousItem } from '../../components';
12
+
11
13
  import { commandMenu, commandRangeEffect } from './command-menu';
12
14
  import { type PlaceholderOptions } from './placeholder';
13
- import { getItem, getNextItem, getPreviousItem, type CommandMenuGroup, type CommandMenuItem } from '../../components';
14
15
 
15
16
  export type UseCommandMenuOptions = {
16
17
  viewRef: RefObject<EditorView | undefined>;
@@ -5,25 +5,26 @@
5
5
  import { invertedEffects } from '@codemirror/commands';
6
6
  import { type ChangeDesc, type Extension, StateEffect, StateField, type Text } from '@codemirror/state';
7
7
  import {
8
- hoverTooltip,
9
- keymap,
10
8
  type Command,
11
9
  Decoration,
12
10
  EditorView,
13
- type Rect,
14
11
  type PluginValue,
12
+ type Rect,
15
13
  ViewPlugin,
14
+ hoverTooltip,
15
+ keymap,
16
16
  } from '@codemirror/view';
17
17
  import sortBy from 'lodash.sortby';
18
18
  import { useEffect } from 'react';
19
19
 
20
- import { debounce, type CleanupFn } from '@dxos/async';
20
+ import { type CleanupFn, debounce } from '@dxos/async';
21
21
  import { log } from '@dxos/log';
22
22
  import { isNonNullable } from '@dxos/util';
23
23
 
24
+ import { type Comment, type Range, type RenderCallback } from '../types';
25
+ import { Cursor, callbackWrapper, singleValueFacet } from '../util';
26
+
24
27
  import { documentId } from './selection';
25
- import { type RenderCallback, type Comment, type Range } from '../types';
26
- import { Cursor, singleValueFacet, callbackWrapper } from '../util';
27
28
 
28
29
  //
29
30
  // State management.
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import type { Extension } from '@codemirror/state';
6
- import { dropCursor, EditorView } from '@codemirror/view';
6
+ import { EditorView, dropCursor } from '@codemirror/view';
7
7
 
8
8
  export type DNDOptions = { onDrop?: (view: EditorView, event: { files: FileList }) => void };
9
9
 
@@ -31,11 +31,12 @@ import { type ThemeMode } from '@dxos/react-ui';
31
31
  import { type HuePalette } from '@dxos/react-ui-theme';
32
32
  import { hexToHue, isNotFalsy } from '@dxos/util';
33
33
 
34
+ import { editorGutter, editorMonospace } from '../defaults';
35
+ import { type ThemeStyles, defaultTheme } from '../styles';
36
+
34
37
  import { automerge } from './automerge';
35
38
  import { SpaceAwarenessProvider, awareness } from './awareness';
36
39
  import { focus } from './focus';
37
- import { editorGutter, editorMonospace } from '../defaults';
38
- import { type ThemeStyles, defaultTheme } from '../styles';
39
40
 
40
41
  //
41
42
  // Basic
@@ -82,8 +83,8 @@ const defaultBasicOptions: BasicExtensionsOptions = {
82
83
  history: true,
83
84
  keymap: 'standard',
84
85
  lineWrapping: true,
85
- search: true,
86
- };
86
+ search: false,
87
+ } as const;
87
88
 
88
89
  const keymaps: { [key: string]: readonly KeyBinding[] } = {
89
90
  // https://codemirror.net/docs/ref/#commands.standardKeymap
@@ -93,7 +94,7 @@ const keymaps: { [key: string]: readonly KeyBinding[] } = {
93
94
  };
94
95
 
95
96
  export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extension => {
96
- const props: BasicExtensionsOptions = defaultsDeep({}, _props, defaultBasicOptions);
97
+ const props = defaultsDeep({}, _props, defaultBasicOptions);
97
98
  return [
98
99
  // NOTE: Doesn't catch errors in keymap functions.
99
100
  EditorView.exceptionSink.of((err) => {
@@ -157,17 +158,28 @@ export type ThemeExtensionsOptions = {
157
158
  scroll?: {
158
159
  className?: string;
159
160
  };
161
+ scroller?: {
162
+ className?: string;
163
+ };
160
164
  content?: {
161
165
  className?: string;
162
166
  };
163
167
  };
164
168
  };
165
169
 
166
- const defaultThemeSlots = {
170
+ export const grow: ThemeExtensionsOptions['slots'] = {
167
171
  editor: {
168
- className: 'w-full bs-full',
172
+ className: 'is-full bs-full',
169
173
  },
170
- };
174
+ } as const;
175
+
176
+ export const fullWidth: ThemeExtensionsOptions['slots'] = {
177
+ editor: {
178
+ className: 'is-full',
179
+ },
180
+ } as const;
181
+
182
+ export const defaultThemeSlots = grow;
171
183
 
172
184
  /**
173
185
  * https://codemirror.net/examples/styling
@@ -195,6 +207,14 @@ export const createThemeExtensions = ({
195
207
  }
196
208
  },
197
209
  ),
210
+ slots.scroller?.className &&
211
+ ViewPlugin.fromClass(
212
+ class {
213
+ constructor(view: EditorView) {
214
+ view.dom.querySelector('.cm-scroller')?.classList.add(...slots.scroller.className.split(' '));
215
+ }
216
+ },
217
+ ),
198
218
  ].filter(isNotFalsy);
199
219
  };
200
220
 
@@ -7,6 +7,8 @@ import { type EditorView } from '@codemirror/view';
7
7
  import { type Action } from '@dxos/app-graph';
8
8
  import { type MenuActionProperties } from '@dxos/react-ui-menu';
9
9
 
10
+ import { createComment } from '../comments';
11
+
10
12
  import {
11
13
  Inline,
12
14
  List,
@@ -25,7 +27,6 @@ import {
25
27
  toggleList,
26
28
  toggleStyle,
27
29
  } from './formatting';
28
- import { createComment } from '../comments';
29
30
 
30
31
  export type PayloadType =
31
32
  | 'view-mode'
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { completionKeymap } from '@codemirror/autocomplete';
6
6
  import { defaultKeymap, indentWithTab } from '@codemirror/commands';
7
- import { markdownLanguage, markdown } from '@codemirror/lang-markdown';
7
+ import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
8
8
  import { syntaxHighlighting } from '@codemirror/language';
9
9
  import { languages } from '@codemirror/language-data';
10
10
  import { type Extension } from '@codemirror/state';
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { syntaxTree } from '@codemirror/language';
6
6
  import { type ChangeSpec, Transaction } from '@codemirror/state';
7
- import { ViewPlugin, type ViewUpdate, type PluginValue } from '@codemirror/view';
7
+ import { type PluginValue, ViewPlugin, type ViewUpdate } from '@codemirror/view';
8
8
 
9
9
  /**
10
10
  * Monitors and augments changes.
@@ -3,20 +3,21 @@
3
3
  //
4
4
 
5
5
  import { syntaxTree } from '@codemirror/language';
6
- import { RangeSetBuilder, type EditorState, StateEffect } from '@codemirror/state';
7
- import { EditorView, Decoration, type DecorationSet, WidgetType, ViewPlugin, type ViewUpdate } from '@codemirror/view';
6
+ import { type EditorState, RangeSetBuilder, StateEffect } from '@codemirror/state';
7
+ import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';
8
8
  import { type SyntaxNodeRef } from '@lezer/common';
9
9
 
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { mx } from '@dxos/react-ui-theme';
12
12
 
13
+ import { type HeadingLevel, theme } from '../../styles';
14
+ import { type RenderCallback } from '../../types';
15
+ import { wrapWithCatch } from '../../util';
16
+
13
17
  import { adjustChanges } from './changes';
14
18
  import { image } from './image';
15
- import { formattingStyles, bulletListIndentationWidth, orderedListIndentationWidth } from './styles';
19
+ import { bulletListIndentationWidth, formattingStyles, orderedListIndentationWidth } from './styles';
16
20
  import { table } from './table';
17
- import { theme, type HeadingLevel } from '../../styles';
18
- import { type RenderCallback } from '../../types';
19
- import { wrapWithCatch } from '../../util';
20
21
 
21
22
  /**
22
23
  * Unicode characters.
@@ -7,21 +7,21 @@ import { EditorState, type StateCommand } from '@codemirror/state';
7
7
  import { describe, expect, test } from 'vitest';
8
8
 
9
9
  import {
10
+ type Formatting,
11
+ Inline,
12
+ List,
10
13
  addBlockquote,
11
14
  addCodeblock,
12
15
  addLink,
13
16
  addList,
14
17
  addStyle,
15
18
  getFormatting,
16
- removeStyle,
17
- removeLink,
18
- removeList,
19
19
  removeBlockquote,
20
20
  removeCodeblock,
21
+ removeLink,
22
+ removeList,
23
+ removeStyle,
21
24
  setHeading,
22
- Inline,
23
- List,
24
- type Formatting,
25
25
  } from './formatting';
26
26
 
27
27
  export const emptyFormatting: Formatting = {
@@ -182,7 +182,7 @@ describe('removeStyle', () => {
182
182
 
183
183
  testCommand('can remove code style', 'a `{variable}`', code, 'a {variable}');
184
184
 
185
- // TODO(dmaretskyi): Flaky on CI: https://cloud.nx.app/runs/0byxg4Uq5G/task/react-ui-editor%3Atest
185
+ // TODO(dmaretskyi): Flaky on CI.
186
186
  // testCommand(
187
187
  // 'can remove emphasis across multiple blocks',
188
188
  // '{*one*\n\n# *two*\n\n> 1. *three} four*\n',
@@ -7,16 +7,17 @@ import { syntaxTree } from '@codemirror/language';
7
7
  import {
8
8
  type ChangeSpec,
9
9
  EditorSelection,
10
- type Extension,
11
10
  type EditorState,
11
+ type Extension,
12
12
  type Line,
13
13
  type StateCommand,
14
14
  type Text,
15
15
  } from '@codemirror/state';
16
- import { EditorView, keymap } from '@codemirror/view';
17
- import { type SyntaxNodeRef, type SyntaxNode } from '@lezer/common';
18
- import { useMemo } from 'react';
16
+ import { EditorView, type ViewUpdate, keymap } from '@codemirror/view';
17
+ import { type SyntaxNode, type SyntaxNodeRef } from '@lezer/common';
18
+ import { useCallback, useMemo } from 'react';
19
19
 
20
+ import { debounceAndThrottle } from '@dxos/async';
20
21
  import { type Live } from '@dxos/live-object';
21
22
 
22
23
  import { type EditorToolbarState } from '../../components';
@@ -1251,15 +1252,16 @@ export const getFormatting = (state: EditorState): Formatting => {
1251
1252
  * Hook provides an extension to compute the current formatting state.
1252
1253
  */
1253
1254
  export const useFormattingState = (state: Live<EditorToolbarState>): Extension => {
1254
- return useMemo(
1255
- () =>
1256
- EditorView.updateListener.of((update) => {
1257
- if (update.docChanged || update.selectionSet) {
1258
- Object.entries(getFormatting(update.state)).forEach(([key, active]) => {
1259
- state[key as keyof Formatting] = active as any;
1260
- });
1261
- }
1262
- }),
1263
- [],
1255
+ const handleUpdate = useCallback(
1256
+ debounceAndThrottle((update: ViewUpdate) => {
1257
+ if (update.docChanged || update.selectionSet) {
1258
+ Object.entries(getFormatting(update.state)).forEach(([key, active]) => {
1259
+ state[key as keyof Formatting] = active as any;
1260
+ });
1261
+ }
1262
+ }, 100),
1263
+ [state],
1264
1264
  );
1265
+
1266
+ return useMemo(() => EditorView.updateListener.of(handleUpdate), [handleUpdate]);
1265
1267
  };
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { markdownLanguage } from '@codemirror/lang-markdown';
6
6
  import { HighlightStyle } from '@codemirror/language';
7
- import { tags, styleTags, Tag } from '@lezer/highlight';
7
+ import { Tag, styleTags, tags } from '@lezer/highlight';
8
8
  import { type MarkdownConfig, Table } from '@lezer/markdown';
9
9
 
10
10
  import { fontBody, theme } from '../../styles';
@@ -2,7 +2,7 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { autocompletion, type CompletionContext, type CompletionResult } from '@codemirror/autocomplete';
5
+ import { type CompletionContext, type CompletionResult, autocompletion } from '@codemirror/autocomplete';
6
6
  import type { Extension } from '@codemirror/state';
7
7
 
8
8
  import { log } from '@dxos/log';
@@ -6,18 +6,9 @@ import { type Extension } from '@codemirror/state';
6
6
  import { keymap } from '@codemirror/view';
7
7
  import { vim } from '@replit/codemirror-vim';
8
8
  import { vscodeKeymap } from '@replit/codemirror-vscode-keymap';
9
- import { Schema } from 'effect';
10
9
 
11
10
  import { singleValueFacet } from '../util';
12
11
 
13
- export const EditorViewModes = ['preview', 'readonly', 'source'] as const;
14
- export const EditorViewMode = Schema.Union(...EditorViewModes.map((mode) => Schema.Literal(mode)));
15
- export type EditorViewMode = Schema.Schema.Type<typeof EditorViewMode>;
16
-
17
- export const EditorInputModes = ['default', 'vim', 'vscode'] as const;
18
- export const EditorInputMode = Schema.Union(...EditorInputModes.map((mode) => Schema.Literal(mode)));
19
- export type EditorInputMode = Schema.Schema.Type<typeof EditorInputMode>;
20
-
21
12
  export type EditorInputConfig = {
22
13
  type?: string;
23
14
  noTabster?: boolean;
@@ -6,11 +6,12 @@ import { EditorSelection, EditorState } from '@codemirror/state';
6
6
  import { EditorView } from '@codemirror/view';
7
7
  import { describe, test } from 'vitest';
8
8
 
9
- import { indentItemLess, indentItemMore, moveItemDown, moveItemUp } from './commands';
10
- import { listItemToString, outlinerTree, treeFacet } from './tree';
11
9
  import { str } from '../../testing';
12
10
  import { createMarkdownExtensions } from '../markdown';
13
11
 
12
+ import { indentItemLess, indentItemMore, moveItemDown, moveItemUp } from './commands';
13
+ import { listItemToString, outlinerTree, treeFacet } from './tree';
14
+
14
15
  const lines = [
15
16
  '- [ ] 1',
16
17
  '- [ ] 2',
@@ -7,12 +7,13 @@ import { Decoration, type DecorationSet, EditorView, ViewPlugin, type ViewUpdate
7
7
 
8
8
  import { mx } from '@dxos/react-ui-theme';
9
9
 
10
+ import { floatingMenu } from '../command';
11
+ import { decorateMarkdown } from '../markdown';
12
+
10
13
  import { commands } from './commands';
11
14
  import { editor } from './editor';
12
- import { selectionCompartment, selectionFacet, selectionEquals } from './selection';
15
+ import { selectionCompartment, selectionEquals, selectionFacet } from './selection';
13
16
  import { outlinerTree, treeFacet } from './tree';
14
- import { floatingMenu } from '../command';
15
- import { decorateMarkdown } from '../markdown';
16
17
 
17
18
  // ISSUES:
18
19
  // TODO(burdon): Remove requirement for continuous lines to be indented (so that user's can't accidentally delete them and break the layout).
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { Compartment, type EditorState, Facet, type SelectionRange } from '@codemirror/state';
6
- import { type EditorView, type Command } from '@codemirror/view';
6
+ import { type Command, type EditorView } from '@codemirror/view';
7
7
 
8
8
  import { treeFacet } from './tree';
9
9
 
@@ -6,10 +6,11 @@ import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
6
6
  import { EditorState } from '@codemirror/state';
7
7
  import { beforeEach, describe, test } from 'vitest';
8
8
 
9
- import { outlinerTree, treeFacet, listItemToString, type Item } from './tree';
10
9
  import { str } from '../../testing';
11
10
  import { type Range } from '../../types';
12
11
 
12
+ import { type Item, listItemToString, outlinerTree, treeFacet } from './tree';
13
+
13
14
  const lines = [
14
15
  '- [ ] 1',
15
16
  '- [ ] 2',
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { syntaxTree } from '@codemirror/language';
6
- import { StateField, type Transaction, type Extension, type EditorState } from '@codemirror/state';
6
+ import { type EditorState, type Extension, StateField, type Transaction } from '@codemirror/state';
7
7
  import { Facet } from '@codemirror/state';
8
8
  import { type SyntaxNode } from '@lezer/common';
9
9
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  import { EditorState, type EditorStateConfig, type Text } from '@codemirror/state';
6
6
  import { EditorView } from '@codemirror/view';
7
- import { useFocusableGroup, type TabsterTypes } from '@fluentui/react-tabster';
7
+ import { type TabsterTypes, useFocusableGroup } from '@fluentui/react-tabster';
8
8
  import {
9
9
  type DependencyList,
10
10
  type KeyboardEventHandler,
@@ -17,9 +17,9 @@ import {
17
17
  } from 'react';
18
18
 
19
19
  import { log } from '@dxos/log';
20
- import { getProviderValue, isNotFalsy, type MaybeProvider } from '@dxos/util';
20
+ import { type MaybeProvider, getProviderValue, isNotFalsy } from '@dxos/util';
21
21
 
22
- import { type EditorSelection, documentId, createEditorStateTransaction, editorInputMode } from '../extensions';
22
+ import { type EditorSelection, createEditorStateTransaction, documentId, editorInputMode } from '../extensions';
23
23
  import { debugDispatcher } from '../util';
24
24
 
25
25
  let instanceCount = 0;
package/src/index.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // Copyright 2022 DXOS.org
3
3
  //
4
4
 
5
- import translations from './translations';
5
+ import { translations } from './translations';
6
6
 
7
7
  export { type Extension, EditorState } from '@codemirror/state';
8
8
  export { EditorView, keymap } from '@codemirror/view';
@@ -4,19 +4,20 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import React, { useState, type KeyboardEvent } from 'react';
7
+ import React, { type KeyboardEvent, useState } from 'react';
8
8
 
9
- import { Button, Icon, Input, DropdownMenu } from '@dxos/react-ui';
9
+ import { Button, DropdownMenu, Icon, Input } from '@dxos/react-ui';
10
10
  import { mx } from '@dxos/react-ui-theme';
11
- import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
11
+ import { type Meta, withLayout, withTheme } from '@dxos/storybook-utils';
12
12
 
13
- import { EditorStory } from './components';
14
13
  import { RefDropdownMenu } from '../components';
15
14
  import { editorWidth } from '../defaults';
16
- import { command, type Action, floatingMenu } from '../extensions';
15
+ import { type Action, command, floatingMenu } from '../extensions';
17
16
  import { str } from '../testing';
18
17
  import { createRenderer } from '../util';
19
18
 
19
+ import { EditorStory } from './components';
20
+
20
21
  const CommandDialog = ({ onAction }: { onAction: (action?: Action) => void }) => {
21
22
  const [text, setText] = useState('');
22
23
 
@@ -5,16 +5,15 @@
5
5
  import '@dxos-theme';
6
6
 
7
7
  import { type EditorView } from '@codemirror/view';
8
- import { type StoryObj } from '@storybook/react';
8
+ import { type StoryObj } from '@storybook/react-vite';
9
9
  import React, { useCallback, useRef } from 'react';
10
10
 
11
11
  import { Obj, Query } from '@dxos/echo';
12
12
  import { faker } from '@dxos/random';
13
13
  import { useClientProvider, withClientProvider } from '@dxos/react-client/testing';
14
- import { createObjectFactory, Testing, type ValueGenerator } from '@dxos/schema/testing';
15
- import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
14
+ import { Testing, type ValueGenerator, createObjectFactory } from '@dxos/schema/testing';
15
+ import { type Meta, withLayout, withTheme } from '@dxos/storybook-utils';
16
16
 
17
- import { EditorStory, names } from './components';
18
17
  import {
19
18
  CommandMenu,
20
19
  type CommandMenuGroup,
@@ -26,10 +25,12 @@ import {
26
25
  insertAtLineStart,
27
26
  linkSlashCommands,
28
27
  } from '../components';
29
- import { useCommandMenu, type UseCommandMenuOptions } from '../extensions';
28
+ import { type UseCommandMenuOptions, useCommandMenu } from '../extensions';
30
29
  import { str } from '../testing';
31
30
  import { createElement } from '../util';
32
31
 
32
+ import { EditorStory, names } from './components';
33
+
33
34
  const generator: ValueGenerator = faker as any;
34
35
 
35
36
  type StoryProps = Omit<UseCommandMenuOptions, 'viewRef'> & { text: string };
@@ -113,7 +114,7 @@ export const Link: Story = {
113
114
  return [];
114
115
  }
115
116
 
116
- const name = query?.startsWith('@') ? query.slice(1).toLowerCase() : query?.toLowerCase() ?? '';
117
+ const name = query?.startsWith('@') ? query.slice(1).toLowerCase() : (query?.toLowerCase() ?? '');
117
118
  const result = await space?.db.query(Query.type(Testing.Contact)).run();
118
119
  const items = result.objects
119
120
  .filter((object) => object.name.toLowerCase().includes(name))
@@ -10,14 +10,15 @@ import React, { type FC } from 'react';
10
10
  import { keySymbols, parseShortcut } from '@dxos/keyboard';
11
11
  import { PublicKey } from '@dxos/keys';
12
12
  import { log } from '@dxos/log';
13
- import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
13
+ import { type Meta, withLayout, withTheme } from '@dxos/storybook-utils';
14
14
 
15
- import { EditorStory, content, longText } from './components';
16
15
  import { annotations, comments, createExternalCommentSync } from '../extensions';
17
16
  import { str } from '../testing';
18
17
  import { type Comment } from '../types';
19
18
  import { createRenderer } from '../util';
20
19
 
20
+ import { EditorStory, content, longText } from './components';
21
+
21
22
  const meta: Meta<typeof EditorStory> = {
22
23
  title: 'ui/react-ui-editor/Comments',
23
24
  component: EditorStory,
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '@dxos-theme';
6
6
 
7
- import { type StoryObj } from '@storybook/react';
7
+ import { type StoryObj } from '@storybook/react-vite';
8
8
  import React, { useCallback, useState } from 'react';
9
9
 
10
10
  import { invariant } from '@dxos/invariant';
@@ -15,18 +15,17 @@ import { type Meta, withLayout, withTheme } from '@dxos/storybook-utils';
15
15
  import { EditorToolbar, useEditorToolbarState } from '../components';
16
16
  import { editorWidth } from '../defaults';
17
17
  import {
18
- type EditorInputMode,
19
- type EditorViewMode,
20
18
  InputModeExtensions,
21
- createMarkdownExtensions,
22
19
  createBasicExtensions,
20
+ createMarkdownExtensions,
23
21
  createThemeExtensions,
24
22
  decorateMarkdown,
25
23
  formattingKeymap,
26
24
  useFormattingState,
27
25
  } from '../extensions';
28
- import { useTextEditor, type UseTextEditorProps } from '../hooks';
29
- import translations from '../translations';
26
+ import { type UseTextEditorProps, useTextEditor } from '../hooks';
27
+ import { translations } from '../translations';
28
+ import { type EditorInputMode, type EditorViewMode } from '../types';
30
29
 
31
30
  type StoryProps = { placeholder?: string } & UseTextEditorProps;
32
31
 
@@ -44,7 +43,7 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
44
43
  moveToEndOfLine: true,
45
44
  extensions: [
46
45
  editorInputMode ? InputModeExtensions[editorInputMode] : [],
47
- createBasicExtensions({ placeholder, lineWrapping: true, readOnly: viewMode === 'readonly' }),
46
+ createBasicExtensions({ placeholder, lineWrapping: true, readOnly: viewMode === 'readonly', search: true }),
48
47
  createMarkdownExtensions({ themeMode }),
49
48
  createThemeExtensions({ themeMode, syntaxHighlighting: true }),
50
49
  viewMode === 'source' ? [] : decorateMarkdown(),
@@ -9,12 +9,13 @@ import React from 'react';
9
9
 
10
10
  import { log } from '@dxos/log';
11
11
  import { faker } from '@dxos/random';
12
- import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
12
+ import { type Meta, withLayout, withTheme } from '@dxos/storybook-utils';
13
13
 
14
- import { EditorStory, content } from './components';
15
- import { typewriter, blast, defaultOptions, dropFile } from '../extensions';
14
+ import { blast, defaultOptions, dropFile, typewriter } from '../extensions';
16
15
  import { str } from '../testing';
17
16
 
17
+ import { EditorStory, content } from './components';
18
+
18
19
  const meta: Meta<typeof EditorStory> = {
19
20
  title: 'ui/react-ui-editor/Experimental',
20
21
  component: EditorStory,