@dxos/react-ui-editor 0.6.13 → 0.6.14-main.1366248

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 (133) hide show
  1. package/dist/lib/browser/index.mjs +772 -712
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +5667 -0
  5. package/dist/lib/node/index.cjs.map +7 -0
  6. package/dist/lib/node/meta.json +1 -0
  7. package/dist/lib/node-esm/index.mjs +5650 -0
  8. package/dist/lib/node-esm/index.mjs.map +7 -0
  9. package/dist/lib/node-esm/meta.json +1 -0
  10. package/dist/types/src/InputMode.stories.d.ts +11 -11
  11. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  12. package/dist/types/src/TextEditor.stories.d.ts +4 -1
  13. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  14. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  15. package/dist/types/src/defaults.d.ts.map +1 -1
  16. package/dist/types/src/extensions/autocomplete.d.ts +2 -1
  17. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  18. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  20. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  21. package/dist/types/src/extensions/awareness/awareness.d.ts +2 -2
  22. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  23. package/dist/types/src/extensions/command/state.d.ts +2 -2
  24. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  25. package/dist/types/src/extensions/comments.d.ts +1 -1
  26. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  27. package/dist/types/src/extensions/debug.d.ts +2 -2
  28. package/dist/types/src/extensions/debug.d.ts.map +1 -1
  29. package/dist/types/src/extensions/factories.d.ts +1 -0
  30. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  31. package/dist/types/src/extensions/focus.d.ts +7 -0
  32. package/dist/types/src/extensions/focus.d.ts.map +1 -0
  33. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  34. package/dist/types/src/extensions/index.d.ts +2 -4
  35. package/dist/types/src/extensions/index.d.ts.map +1 -1
  36. package/dist/types/src/extensions/listener.d.ts +2 -1
  37. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  38. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  39. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  40. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  41. package/dist/types/src/extensions/markdown/image.d.ts +3 -6
  42. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/link.d.ts +1 -1
  44. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  45. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  46. package/dist/types/src/extensions/modes.d.ts +3 -4
  47. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  48. package/dist/types/src/extensions/{state.d.ts → selection.d.ts} +8 -4
  49. package/dist/types/src/extensions/selection.d.ts.map +1 -0
  50. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  51. package/dist/types/src/index.d.ts +1 -0
  52. package/dist/types/src/index.d.ts.map +1 -1
  53. package/dist/types/src/styles/markdown.d.ts +1 -2
  54. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  55. package/dist/types/src/styles/theme.d.ts.map +1 -1
  56. package/dist/types/src/types.d.ts.map +1 -0
  57. package/dist/types/src/{extensions → util}/cursor.d.ts +9 -3
  58. package/dist/types/src/util/cursor.d.ts.map +1 -0
  59. package/dist/types/src/util/debug.d.ts +17 -0
  60. package/dist/types/src/util/debug.d.ts.map +1 -0
  61. package/dist/types/src/util/dom.d.ts.map +1 -0
  62. package/dist/types/src/util/facet.d.ts +3 -0
  63. package/dist/types/src/util/facet.d.ts.map +1 -0
  64. package/dist/types/src/util/index.d.ts +6 -0
  65. package/dist/types/src/util/index.d.ts.map +1 -0
  66. package/dist/types/src/{extensions/util → util}/react.d.ts +1 -1
  67. package/dist/types/src/util/react.d.ts.map +1 -0
  68. package/package.json +46 -41
  69. package/src/InputMode.stories.tsx +8 -8
  70. package/src/TextEditor.stories.tsx +100 -75
  71. package/src/components/Toolbar/Toolbar.tsx +8 -11
  72. package/src/defaults.ts +0 -2
  73. package/src/extensions/annotations.ts +1 -1
  74. package/src/extensions/autocomplete.ts +9 -8
  75. package/src/extensions/automerge/automerge.stories.tsx +2 -2
  76. package/src/extensions/automerge/{automerge.spec.tsx → automerge.test.tsx} +1 -0
  77. package/src/extensions/automerge/automerge.ts +2 -2
  78. package/src/extensions/automerge/cursor.ts +1 -1
  79. package/src/extensions/awareness/awareness.ts +3 -5
  80. package/src/extensions/command/hint.ts +1 -1
  81. package/src/extensions/command/state.ts +3 -4
  82. package/src/extensions/comments.ts +45 -47
  83. package/src/extensions/debug.ts +2 -2
  84. package/src/extensions/factories.ts +5 -1
  85. package/src/extensions/focus.ts +35 -0
  86. package/src/extensions/folding.tsx +7 -5
  87. package/src/extensions/index.ts +2 -4
  88. package/src/extensions/listener.ts +5 -2
  89. package/src/extensions/markdown/changes.test.ts +1 -3
  90. package/src/extensions/markdown/decorate.ts +50 -7
  91. package/src/extensions/markdown/formatting.test.ts +1 -3
  92. package/src/extensions/markdown/highlight.ts +0 -5
  93. package/src/extensions/markdown/image.ts +53 -42
  94. package/src/extensions/markdown/link.ts +3 -2
  95. package/src/extensions/markdown/parser.test.ts +1 -2
  96. package/src/extensions/markdown/styles.ts +10 -0
  97. package/src/extensions/markdown/table.ts +3 -3
  98. package/src/extensions/modes.ts +6 -7
  99. package/src/extensions/{state.ts → selection.ts} +20 -16
  100. package/src/hooks/useTextEditor.ts +36 -35
  101. package/src/index.ts +1 -0
  102. package/src/styles/markdown.ts +1 -3
  103. package/src/styles/theme.ts +3 -1
  104. package/src/{extensions → util}/cursor.ts +11 -8
  105. package/src/{util.ts → util/debug.ts} +25 -2
  106. package/src/util/facet.ts +13 -0
  107. package/src/{extensions/util → util}/index.ts +3 -2
  108. package/src/{extensions/util → util}/react.tsx +6 -1
  109. package/dist/types/src/extensions/automerge/automerge.spec.d.ts +0 -2
  110. package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +0 -1
  111. package/dist/types/src/extensions/cursor.d.ts.map +0 -1
  112. package/dist/types/src/extensions/doc.d.ts +0 -6
  113. package/dist/types/src/extensions/doc.d.ts.map +0 -1
  114. package/dist/types/src/extensions/state.d.ts.map +0 -1
  115. package/dist/types/src/extensions/types.d.ts.map +0 -1
  116. package/dist/types/src/extensions/util/dom.d.ts.map +0 -1
  117. package/dist/types/src/extensions/util/error.d.ts +0 -2
  118. package/dist/types/src/extensions/util/error.d.ts.map +0 -1
  119. package/dist/types/src/extensions/util/index.d.ts +0 -5
  120. package/dist/types/src/extensions/util/index.d.ts.map +0 -1
  121. package/dist/types/src/extensions/util/overlap.d.ts +0 -8
  122. package/dist/types/src/extensions/util/overlap.d.ts.map +0 -1
  123. package/dist/types/src/extensions/util/react.d.ts.map +0 -1
  124. package/dist/types/src/util.d.ts +0 -7
  125. package/dist/types/src/util.d.ts.map +0 -1
  126. package/src/extensions/automerge/automerge.test.ts +0 -13
  127. package/src/extensions/doc.ts +0 -17
  128. package/src/extensions/util/error.ts +0 -15
  129. package/src/extensions/util/overlap.ts +0 -12
  130. /package/dist/types/src/{extensions/types.d.ts → types.d.ts} +0 -0
  131. /package/dist/types/src/{extensions/util → util}/dom.d.ts +0 -0
  132. /package/src/{extensions/types.ts → types.ts} +0 -0
  133. /package/src/{extensions/util → util}/dom.ts +0 -0
@@ -3,6 +3,7 @@
3
3
  //
4
4
 
5
5
  import '@dxos-theme';
6
+
6
7
  import { javascript } from '@codemirror/lang-javascript';
7
8
  import { markdown } from '@codemirror/lang-markdown';
8
9
  import { openSearchPanel } from '@codemirror/search';
@@ -11,7 +12,7 @@ import { type EditorView } from '@codemirror/view';
11
12
  import { ArrowSquareOut, X } from '@phosphor-icons/react';
12
13
  import { effect, useSignal } from '@preact/signals-react';
13
14
  import defaultsDeep from 'lodash.defaultsdeep';
14
- import React, { type FC, type KeyboardEvent, useEffect, useState } from 'react';
15
+ import React, { useEffect, useState, type FC, type KeyboardEvent } from 'react';
15
16
  import { createRoot } from 'react-dom/client';
16
17
 
17
18
  import { create, Expando } from '@dxos/echo-schema';
@@ -19,14 +20,13 @@ import { keySymbols, parseShortcut } from '@dxos/keyboard';
19
20
  import { PublicKey } from '@dxos/keys';
20
21
  import { log } from '@dxos/log';
21
22
  import { faker } from '@dxos/random';
22
- import { createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
23
- import { Button, DensityProvider, Input, useThemeContext } from '@dxos/react-ui';
24
- import { baseSurface, mx, getSize } from '@dxos/react-ui-theme';
23
+ import { createDocAccessor, createObject } from '@dxos/react-client/echo';
24
+ import { Button, Input, useThemeContext } from '@dxos/react-ui';
25
+ import { baseSurface, getSize, mx } from '@dxos/react-ui-theme';
25
26
  import { withLayout, withTheme } from '@dxos/storybook-utils';
26
27
 
27
28
  import { editorContent, editorGutter, editorMonospace } from './defaults';
28
29
  import {
29
- InputModeExtensions,
30
30
  annotations,
31
31
  autocomplete,
32
32
  blast,
@@ -37,28 +37,29 @@ import {
37
37
  createExternalCommentSync,
38
38
  createMarkdownExtensions,
39
39
  createThemeExtensions,
40
+ debugTree,
40
41
  decorateMarkdown,
41
42
  defaultOptions,
42
43
  dropFile,
43
44
  folding,
44
45
  formattingKeymap,
45
46
  image,
47
+ InputModeExtensions,
46
48
  linkTooltip,
47
49
  listener,
48
50
  mention,
49
- state,
51
+ selectionState,
50
52
  table,
51
53
  typewriter,
52
54
  type CommandAction,
53
- type Comment,
54
55
  type CommentsOptions,
55
- type EditorSelectionState,
56
- debugTree,
57
56
  type DebugNode,
57
+ type EditorSelectionState,
58
58
  } from './extensions';
59
- import { renderRoot } from './extensions/util';
60
59
  import { useTextEditor, type UseTextEditorProps } from './hooks';
61
60
  import translations from './translations';
61
+ import { type Comment } from './types';
62
+ import { renderRoot } from './util';
62
63
 
63
64
  faker.seed(101);
64
65
 
@@ -164,8 +165,8 @@ const content = {
164
165
  '> This is a long wrapping block quote. Neque reiciendis ullam quae error labore sit, at, et, nulla, aut at nostrum omnis quas nostrum, at consectetur vitae eos asperiores non omnis ullam in beatae at vitae deserunt asperiores sapiente.',
165
166
  '',
166
167
  '> This is ...',
167
- '> ... a multi-line ...',
168
- '> block quote.',
168
+ '... a multi-line ...',
169
+ 'block quote.',
169
170
  '',
170
171
  ),
171
172
 
@@ -254,7 +255,7 @@ const renderLinkButton = (el: Element, url: string) => {
254
255
  // Story
255
256
  //
256
257
 
257
- type DebugMode = 'syntax' | 'raw';
258
+ type DebugMode = 'raw' | 'tree' | 'raw+tree';
258
259
 
259
260
  type StoryProps = {
260
261
  id?: string;
@@ -266,7 +267,7 @@ type StoryProps = {
266
267
  onReady?: (view: EditorView) => void;
267
268
  } & Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'>;
268
269
 
269
- const Story = ({
270
+ const DefaultStory = ({
270
271
  id = 'editor-' + PublicKey.random().toHex().slice(0, 8),
271
272
  debug,
272
273
  text,
@@ -278,7 +279,7 @@ const Story = ({
278
279
  lineNumbers,
279
280
  onReady,
280
281
  }: StoryProps) => {
281
- const [object] = useState(createEchoObject(create(Expando, { content: text ?? '' })));
282
+ const [object] = useState(createObject(create(Expando, { content: text ?? '' })));
282
283
  const { themeMode } = useThemeContext();
283
284
  const [tree, setTree] = useState<DebugNode>();
284
285
  const { parentRef, focusAttributes, view } = useTextEditor(
@@ -317,16 +318,16 @@ const Story = ({
317
318
  return (
318
319
  <div className='flex w-full'>
319
320
  <div role='none' className='flex w-full overflow-hidden' ref={parentRef} {...focusAttributes} />
320
- {debug === 'raw' && (
321
- <div className='w-[800px] border-l border-separator overflow-auto'>
322
- <pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>{view?.state.doc.toString()}</pre>
323
- </div>
324
- )}
325
- {debug === 'syntax' && (
326
- <div className='w-[800px] border-l border-separator overflow-auto'>
327
- <pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>
328
- {JSON.stringify(tree, null, 2)}
329
- </pre>
321
+ {debug && (
322
+ <div className='flex flex-col w-[800px] border-l border-separator divide-y divide-separator overflow-auto'>
323
+ {(debug === 'raw' || debug === 'raw+tree') && (
324
+ <pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>{view?.state.doc.toString()}</pre>
325
+ )}
326
+ {(debug === 'tree' || debug === 'raw+tree') && (
327
+ <pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>
328
+ {JSON.stringify(tree, null, 2)}
329
+ </pre>
330
+ )}
330
331
  </div>
331
332
  )}
332
333
  </div>
@@ -334,9 +335,9 @@ const Story = ({
334
335
  };
335
336
 
336
337
  export default {
337
- title: 'react-ui-editor/TextEditor',
338
+ title: 'ui/react-ui-editor/TextEditor',
338
339
  decorators: [withTheme, withLayout({ fullscreen: true })],
339
- render: Story,
340
+ render: DefaultStory,
340
341
  parameters: { translations, layout: 'fullscreen' },
341
342
  };
342
343
 
@@ -362,28 +363,28 @@ const allExtensions: Extension[] = [
362
363
  ];
363
364
 
364
365
  export const Default = {
365
- render: () => <Story text={text} extensions={defaultExtensions} />,
366
+ render: () => <DefaultStory text={text} extensions={defaultExtensions} />,
366
367
  };
367
368
 
368
369
  export const Everything = {
369
- render: () => <Story text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
370
+ render: () => <DefaultStory text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
370
371
  };
371
372
 
372
373
  export const Empty = {
373
- render: () => <Story extensions={defaultExtensions} />,
374
+ render: () => <DefaultStory extensions={defaultExtensions} />,
374
375
  };
375
376
 
376
377
  export const Readonly = {
377
- render: () => <Story text={text} extensions={defaultExtensions} readonly />,
378
+ render: () => <DefaultStory text={text} extensions={defaultExtensions} readonly />,
378
379
  };
379
380
 
380
381
  export const NoExtensions = {
381
- render: () => <Story text={text} />,
382
+ render: () => <DefaultStory text={text} />,
382
383
  };
383
384
 
384
385
  export const Vim = {
385
386
  render: () => (
386
- <Story
387
+ <DefaultStory
387
388
  text={str('# Vim Mode', '', 'The distant future. The year 2000.', '', content.paragraphs)}
388
389
  extensions={[defaultExtensions, InputModeExtensions.vim]}
389
390
  />
@@ -410,14 +411,14 @@ const headings = str(
410
411
  const global = new Map<string, EditorSelectionState>();
411
412
 
412
413
  export const Folding = {
413
- render: () => <Story text={text} extensions={[folding()]} />,
414
+ render: () => <DefaultStory text={text} extensions={[folding()]} />,
414
415
  };
415
416
 
416
417
  export const Scrolling = {
417
418
  render: () => (
418
- <Story
419
+ <DefaultStory
419
420
  text={str('# Large Document', '', longText)}
420
- extensions={state({
421
+ extensions={selectionState({
421
422
  setState: (id, state) => global.set(id, state),
422
423
  getState: (id) => global.get(id),
423
424
  })}
@@ -427,7 +428,7 @@ export const Scrolling = {
427
428
 
428
429
  export const ScrollingWithImages = {
429
430
  render: () => (
430
- <Story text={str('# Large Document', '', largeWithImages)} extensions={[decorateMarkdown(), image()]} />
431
+ <DefaultStory text={str('# Large Document', '', largeWithImages)} extensions={[decorateMarkdown(), image()]} />
431
432
  ),
432
433
  };
433
434
 
@@ -438,7 +439,7 @@ export const ScrollTo = {
438
439
  const text = str('# Scroll To', longText, '', word, '', longText);
439
440
  const idx = text.indexOf(word);
440
441
  return (
441
- <Story
442
+ <DefaultStory
442
443
  text={text}
443
444
  extensions={defaultExtensions}
444
445
  scrollTo={idx}
@@ -452,25 +453,39 @@ export const ScrollTo = {
452
453
  // Markdown
453
454
  //
454
455
 
456
+ export const Blockquote = {
457
+ render: () => (
458
+ <DefaultStory
459
+ text={str('> Blockquote', 'continuation', content.footer)}
460
+ extensions={decorateMarkdown()}
461
+ debug='raw'
462
+ />
463
+ ),
464
+ };
465
+
455
466
  export const Headings = {
456
- render: () => <Story text={headings} extensions={decorateMarkdown({ numberedHeadings: { from: 2, to: 4 } })} />,
467
+ render: () => (
468
+ <DefaultStory text={headings} extensions={decorateMarkdown({ numberedHeadings: { from: 2, to: 4 } })} />
469
+ ),
457
470
  };
458
471
 
459
472
  export const Links = {
460
- render: () => <Story text={str(content.links, content.footer)} extensions={[linkTooltip(renderLinkTooltip)]} />,
473
+ render: () => (
474
+ <DefaultStory text={str(content.links, content.footer)} extensions={[linkTooltip(renderLinkTooltip)]} />
475
+ ),
461
476
  };
462
477
 
463
478
  export const Image = {
464
- render: () => <Story text={str(content.image, content.footer)} extensions={[image()]} />,
479
+ render: () => <DefaultStory text={str(content.image, content.footer)} extensions={[image()]} />,
465
480
  };
466
481
 
467
482
  export const Code = {
468
- render: () => <Story text={str(content.codeblocks, content.footer)} extensions={[decorateMarkdown()]} />,
483
+ render: () => <DefaultStory text={str(content.codeblocks, content.footer)} extensions={[decorateMarkdown()]} />,
469
484
  };
470
485
 
471
486
  export const Lists = {
472
487
  render: () => (
473
- <Story
488
+ <DefaultStory
474
489
  text={str(content.tasks, '', content.bullets, '', content.numbered, content.footer)}
475
490
  extensions={[decorateMarkdown()]}
476
491
  />
@@ -478,24 +493,26 @@ export const Lists = {
478
493
  };
479
494
 
480
495
  export const BulletList = {
481
- render: () => <Story text={str(content.bullets, content.footer)} extensions={[decorateMarkdown()]} />,
496
+ render: () => <DefaultStory text={str(content.bullets, content.footer)} extensions={[decorateMarkdown()]} />,
482
497
  };
483
498
 
484
499
  export const OrderedList = {
485
- render: () => <Story text={str(content.numbered, content.footer)} extensions={[decorateMarkdown()]} />,
500
+ render: () => <DefaultStory text={str(content.numbered, content.footer)} extensions={[decorateMarkdown()]} />,
486
501
  };
487
502
 
488
503
  export const TaskList = {
489
- render: () => <Story text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug='raw' />,
504
+ render: () => (
505
+ <DefaultStory text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug='raw+tree' />
506
+ ),
490
507
  };
491
508
 
492
509
  export const Table = {
493
- render: () => <Story text={str(content.table, content.footer)} extensions={[decorateMarkdown(), table()]} />,
510
+ render: () => <DefaultStory text={str(content.table, content.footer)} extensions={[decorateMarkdown(), table()]} />,
494
511
  };
495
512
 
496
513
  export const CommentedOut = {
497
514
  render: () => (
498
- <Story
515
+ <DefaultStory
499
516
  text={str('# Commented out', '', content.comment, content.footer)}
500
517
  extensions={[
501
518
  decorateMarkdown(),
@@ -508,7 +525,11 @@ export const CommentedOut = {
508
525
 
509
526
  export const Typescript = {
510
527
  render: () => (
511
- <Story text={content.typescript} lineNumbers extensions={[editorMonospace, javascript({ typescript: true })]} />
528
+ <DefaultStory
529
+ text={content.typescript}
530
+ lineNumbers
531
+ extensions={[editorMonospace, javascript({ typescript: true })]}
532
+ />
512
533
  ),
513
534
  };
514
535
 
@@ -518,7 +539,7 @@ export const Typescript = {
518
539
 
519
540
  export const Autocomplete = {
520
541
  render: () => (
521
- <Story
542
+ <DefaultStory
522
543
  text={str('# Autocomplete', '', 'Press Ctrl-Space...', content.footer)}
523
544
  extensions={[
524
545
  decorateMarkdown({ renderLinkButton }),
@@ -532,7 +553,7 @@ export const Autocomplete = {
532
553
 
533
554
  export const Mention = {
534
555
  render: () => (
535
- <Story
556
+ <DefaultStory
536
557
  text={str('# Mention', '', 'Type @...', content.footer)}
537
558
  extensions={[
538
559
  mention({
@@ -545,7 +566,11 @@ export const Mention = {
545
566
 
546
567
  export const Search = {
547
568
  render: () => (
548
- <Story text={str('# Search', text)} extensions={defaultExtensions} onReady={(view) => openSearchPanel(view)} />
569
+ <DefaultStory
570
+ text={str('# Search', text)}
571
+ extensions={defaultExtensions}
572
+ onReady={(view) => openSearchPanel(view)}
573
+ />
549
574
  ),
550
575
  };
551
576
 
@@ -569,28 +594,26 @@ const CommandDialog = ({ onClose }: { onClose: (action?: CommandAction) => void
569
594
  };
570
595
 
571
596
  return (
572
- <DensityProvider density='fine'>
573
- <div className={mx('flex items-center p-2 gap-2 border rounded-md', baseSurface)}>
574
- <Input.Root>
575
- <Input.TextInput
576
- autoFocus={true}
577
- placeholder='Enter command.'
578
- value={text}
579
- onChange={({ target: { value } }) => setText(value)}
580
- onKeyDown={handleKeyDown}
581
- />
582
- </Input.Root>
583
- <Button variant='ghost' classNames='pli-0' onClick={() => onClose()}>
584
- <X className={getSize(5)} />
585
- </Button>
586
- </div>
587
- </DensityProvider>
597
+ <div className={mx('flex items-center p-2 gap-2 border rounded-md', baseSurface)}>
598
+ <Input.Root>
599
+ <Input.TextInput
600
+ autoFocus={true}
601
+ placeholder='Enter command.'
602
+ value={text}
603
+ onChange={({ target: { value } }) => setText(value)}
604
+ onKeyDown={handleKeyDown}
605
+ />
606
+ </Input.Root>
607
+ <Button variant='ghost' classNames='pli-0' onClick={() => onClose()}>
608
+ <X className={getSize(5)} />
609
+ </Button>
610
+ </div>
588
611
  );
589
612
  };
590
613
 
591
614
  export const Command = {
592
615
  render: () => (
593
- <Story
616
+ <DefaultStory
594
617
  text={str('# Command', '')}
595
618
  extensions={[
596
619
  command({
@@ -608,7 +631,7 @@ export const Comments = {
608
631
  render: () => {
609
632
  const _comments = useSignal<Comment[]>([]);
610
633
  return (
611
- <Story
634
+ <DefaultStory
612
635
  text={str('# Comments', '', content.paragraphs, content.footer)}
613
636
  extensions={[
614
637
  createExternalCommentSync(
@@ -645,12 +668,14 @@ export const Comments = {
645
668
  };
646
669
 
647
670
  export const Annotations = {
648
- render: () => <Story text={str('# Annotations', '', longText)} extensions={[annotations({ match: /volup/gi })]} />,
671
+ render: () => (
672
+ <DefaultStory text={str('# Annotations', '', longText)} extensions={[annotations({ match: /volup/gi })]} />
673
+ ),
649
674
  };
650
675
 
651
676
  export const DND = {
652
677
  render: () => (
653
- <Story
678
+ <DefaultStory
654
679
  text={str('# DND', '')}
655
680
  extensions={[
656
681
  dropFile({
@@ -665,7 +690,7 @@ export const DND = {
665
690
 
666
691
  export const Listener = {
667
692
  render: () => (
668
- <Story
693
+ <DefaultStory
669
694
  text={str('# Listener', '', content.footer)}
670
695
  extensions={[
671
696
  listener({
@@ -685,7 +710,7 @@ const typewriterItems = localStorage.getItem('dxos.org/plugin/markdown/typewrite
685
710
 
686
711
  export const Typewriter = {
687
712
  render: () => (
688
- <Story
713
+ <DefaultStory
689
714
  text={str('# Typewriter', '', content.paragraphs, content.footer)}
690
715
  extensions={[typewriter({ items: typewriterItems })]}
691
716
  />
@@ -694,7 +719,7 @@ export const Typewriter = {
694
719
 
695
720
  export const Blast = {
696
721
  render: () => (
697
- <Story
722
+ <DefaultStory
698
723
  text={str('# Blast', '', content.paragraphs, content.codeblocks, content.paragraphs)}
699
724
  extensions={[
700
725
  typewriter({ items: typewriterItems }),
@@ -37,7 +37,6 @@ import { useDropzone } from 'react-dropzone';
37
37
 
38
38
  import {
39
39
  Button,
40
- DensityProvider,
41
40
  DropdownMenu,
42
41
  ElevationProvider,
43
42
  Toolbar as NaturalToolbar,
@@ -74,16 +73,14 @@ export type ToolbarProps = ThemedClassName<
74
73
  const ToolbarRoot = ({ children, onAction, classNames, state }: ToolbarProps) => {
75
74
  return (
76
75
  <ToolbarContextProvider onAction={onAction} state={state}>
77
- <DensityProvider density='fine'>
78
- <ElevationProvider elevation='chrome'>
79
- <NaturalToolbar.Root
80
- classNames={['p-1 is-full shrink-0 overflow-x-auto overflow-y-hidden', classNames]}
81
- style={{ contain: 'layout' }}
82
- >
83
- {children}
84
- </NaturalToolbar.Root>
85
- </ElevationProvider>
86
- </DensityProvider>
76
+ <ElevationProvider elevation='chrome'>
77
+ <NaturalToolbar.Root
78
+ classNames={['p-1 is-full shrink-0 overflow-x-auto overflow-y-hidden', classNames]}
79
+ style={{ contain: 'layout' }}
80
+ >
81
+ {children}
82
+ </NaturalToolbar.Root>
83
+ </ElevationProvider>
87
84
  </ToolbarContextProvider>
88
85
  );
89
86
  };
package/src/defaults.ts CHANGED
@@ -8,8 +8,6 @@ import { mx } from '@dxos/react-ui-theme';
8
8
 
9
9
  import { fontMono } from './styles';
10
10
 
11
- // TODO(burdon): Define scrollMargins for fixed gutter?
12
- // https://codemirror.net/docs/ref/#view.EditorView^scrollMargins
13
11
  const margin = '!mt-[1rem]';
14
12
 
15
13
  /**
@@ -7,7 +7,7 @@ import { Decoration, EditorView } from '@codemirror/view';
7
7
 
8
8
  import { isNotFalsy } from '@dxos/util';
9
9
 
10
- import { Cursor } from './cursor';
10
+ import { Cursor } from '../util';
11
11
 
12
12
  type Annotation = {
13
13
  cursor: string;
@@ -2,10 +2,6 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- // https://codemirror.net/examples/autocompletion
6
- // https://codemirror.net/docs/ref/#autocomplete.autocompletion
7
- // https://codemirror.net/docs/ref/#autocomplete.Completion
8
-
9
5
  import {
10
6
  autocompletion,
11
7
  completionKeymap,
@@ -15,6 +11,7 @@ import {
15
11
  type CompletionResult,
16
12
  } from '@codemirror/autocomplete';
17
13
  import { markdownLanguage } from '@codemirror/lang-markdown';
14
+ import { type Extension } from '@codemirror/state';
18
15
  import { keymap } from '@codemirror/view';
19
16
 
20
17
  export type AutocompleteResult = Completion;
@@ -25,11 +22,15 @@ export type AutocompleteOptions = {
25
22
  onSearch?: (text: string) => Completion[];
26
23
  };
27
24
 
25
+ // https://codemirror.net/examples/autocompletion
26
+ // https://codemirror.net/docs/ref/#autocomplete.autocompletion
27
+ // https://codemirror.net/docs/ref/#autocomplete.Completion
28
+
28
29
  /**
29
30
  * Autocomplete extension.
30
31
  */
31
- export const autocomplete = ({ activateOnTyping, override, onSearch }: AutocompleteOptions = {}) => {
32
- const extentions = [
32
+ export const autocomplete = ({ activateOnTyping, override, onSearch }: AutocompleteOptions = {}): Extension => {
33
+ const extensions: Extension[] = [
33
34
  // https://codemirror.net/docs/ref/#view.keymap
34
35
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
35
36
  // TODO(burdon): Set custom keymap.
@@ -50,7 +51,7 @@ export const autocomplete = ({ activateOnTyping, override, onSearch }: Autocompl
50
51
  ];
51
52
 
52
53
  if (onSearch) {
53
- extentions.push(
54
+ extensions.push(
54
55
  // TODO(burdon): Optional decoration via addToOptions
55
56
  markdownLanguage.data.of({
56
57
  autocomplete: (context: CompletionContext): CompletionResult | null => {
@@ -68,5 +69,5 @@ export const autocomplete = ({ activateOnTyping, override, onSearch }: Autocompl
68
69
  );
69
70
  }
70
71
 
71
- return extentions;
72
+ return extensions;
72
73
  };
@@ -92,7 +92,7 @@ const Story = () => {
92
92
  };
93
93
 
94
94
  export default {
95
- title: 'react-ui-editor/Automerge',
95
+ title: 'ui/react-ui-editor/Automerge',
96
96
  component: Editor,
97
97
  decorators: [withTheme, withLayout({ fullscreen: true })],
98
98
  render: () => <Story />,
@@ -129,7 +129,7 @@ export const WithEcho = {
129
129
  count={2}
130
130
  component={EchoStory}
131
131
  createSpace
132
- onCreateSpace={async (space) => {
132
+ onSpaceCreated={async ({ space }) => {
133
133
  space.db.add(
134
134
  create({
135
135
  type: 'test',
@@ -5,6 +5,7 @@
5
5
  import { EditorState } from '@codemirror/state';
6
6
  import { EditorView } from '@codemirror/view';
7
7
  import { render, screen } from '@testing-library/react';
8
+ // TODO(wittjosiah): Move to vitest expect (and remove from package.json).
8
9
  import chai, { expect } from 'chai';
9
10
  import chaiDom from 'chai-dom';
10
11
  import get from 'lodash.get';
@@ -1,5 +1,5 @@
1
1
  //
2
- // Copyright 2023 DXOS.org
2
+ // Copyright 2024 DXOS.org
3
3
  // Copyright 2024 Automerge
4
4
  // Ref: https://github.com/automerge/automerge-codemirror
5
5
  //
@@ -13,7 +13,7 @@ import { type DocAccessor } from '@dxos/react-client/echo';
13
13
  import { cursorConverter } from './cursor';
14
14
  import { updateHeadsEffect, isReconcile, type State } from './defs';
15
15
  import { Syncer } from './sync';
16
- import { Cursor } from '../cursor';
16
+ import { Cursor } from '../../util';
17
17
 
18
18
  export const automerge = (accessor: DocAccessor): Extension => {
19
19
  const syncState = StateField.define<State>({
@@ -5,7 +5,7 @@
5
5
  import { log } from '@dxos/log';
6
6
  import { type DocAccessor, fromCursor, toCursor } from '@dxos/react-client/echo';
7
7
 
8
- import { type CursorConverter } from '../cursor';
8
+ import { type CursorConverter } from '../../util';
9
9
 
10
10
  export const cursorConverter = (accessor: DocAccessor): CursorConverter => ({
11
11
  toCursor: (pos, assoc) => {
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Annotation, Facet, type Extension, RangeSet, type Range } from '@codemirror/state';
5
+ import { Annotation, type Extension, RangeSet, type Range } from '@codemirror/state';
6
6
  import {
7
7
  Decoration,
8
8
  type DecorationSet,
@@ -16,7 +16,7 @@ import {
16
16
  import { Event } from '@dxos/async';
17
17
  import { Context } from '@dxos/context';
18
18
 
19
- import { Cursor, type CursorConverter } from '../cursor';
19
+ import { singleValueFacet, Cursor, type CursorConverter } from '../../util';
20
20
 
21
21
  export interface AwarenessProvider {
22
22
  remoteStateChange: Event<void>;
@@ -38,9 +38,7 @@ const dummyProvider: AwarenessProvider = {
38
38
  update: () => {},
39
39
  };
40
40
 
41
- export const awarenessProvider = Facet.define<AwarenessProvider, AwarenessProvider>({
42
- combine: (providers) => providers[0] ?? dummyProvider,
43
- });
41
+ export const awarenessProvider = singleValueFacet<AwarenessProvider>(dummyProvider);
44
42
 
45
43
  // TODO(dmaretskyi): Specify the users that actually changed. Currently, we recalculate positions for every user.
46
44
  const RemoteSelectionChangedAnnotation = Annotation.define();
@@ -7,7 +7,7 @@ import { Decoration, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from
7
7
 
8
8
  import { type CommandOptions } from './command';
9
9
  import { commandState } from './state';
10
- import { clientRectsFor, flattenRect } from '../util/dom';
10
+ import { clientRectsFor, flattenRect } from '../../util';
11
11
 
12
12
  class CommandHint extends WidgetType {
13
13
  constructor(readonly content: string | HTMLElement) {
@@ -2,7 +2,7 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Facet, StateEffect, StateField } from '@codemirror/state';
5
+ import { StateEffect, StateField } from '@codemirror/state';
6
6
  import {
7
7
  type Command,
8
8
  type EditorView,
@@ -13,14 +13,13 @@ import {
13
13
  } from '@codemirror/view';
14
14
 
15
15
  import { type CommandOptions } from './command';
16
+ import { singleValueFacet } from '../../util';
16
17
 
17
18
  type CommandState = {
18
19
  tooltip?: Tooltip | null;
19
20
  };
20
21
 
21
- export const commandConfig = Facet.define<CommandOptions, Required<CommandOptions>>({
22
- combine: (providers) => providers[0],
23
- });
22
+ export const commandConfig = singleValueFacet<CommandOptions>();
24
23
 
25
24
  export const commandState = StateField.define<CommandState>({
26
25
  create: () => ({}),