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

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 (128) hide show
  1. package/dist/lib/browser/chunk-CIQSMP7K.mjs +148 -0
  2. package/dist/lib/browser/chunk-CIQSMP7K.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +248 -355
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/state/index.mjs +17 -0
  7. package/dist/lib/browser/state/index.mjs.map +7 -0
  8. package/dist/lib/node/chunk-GZWIENFM.cjs +169 -0
  9. package/dist/lib/node/chunk-GZWIENFM.cjs.map +7 -0
  10. package/dist/lib/node/index.cjs +5491 -0
  11. package/dist/lib/node/index.cjs.map +7 -0
  12. package/dist/lib/node/meta.json +1 -0
  13. package/dist/lib/node/state/index.cjs +39 -0
  14. package/dist/lib/node/state/index.cjs.map +7 -0
  15. package/dist/lib/node-esm/chunk-GP5RCZ3X.mjs +150 -0
  16. package/dist/lib/node-esm/chunk-GP5RCZ3X.mjs.map +7 -0
  17. package/dist/lib/node-esm/index.mjs +5482 -0
  18. package/dist/lib/node-esm/index.mjs.map +7 -0
  19. package/dist/lib/node-esm/meta.json +1 -0
  20. package/dist/lib/node-esm/state/index.mjs +18 -0
  21. package/dist/lib/node-esm/state/index.mjs.map +7 -0
  22. package/dist/types/src/InputMode.stories.d.ts +11 -11
  23. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  24. package/dist/types/src/TextEditor.stories.d.ts +4 -1
  25. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  26. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  27. package/dist/types/src/defaults.d.ts.map +1 -1
  28. package/dist/types/src/extensions/autocomplete.d.ts +2 -1
  29. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  30. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -1
  31. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  32. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  33. package/dist/types/src/extensions/awareness/awareness.d.ts +2 -2
  34. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  35. package/dist/types/src/extensions/command/state.d.ts +2 -2
  36. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  37. package/dist/types/src/extensions/comments.d.ts +1 -1
  38. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  39. package/dist/types/src/extensions/debug.d.ts +2 -2
  40. package/dist/types/src/extensions/debug.d.ts.map +1 -1
  41. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  42. package/dist/types/src/extensions/index.d.ts +0 -4
  43. package/dist/types/src/extensions/index.d.ts.map +1 -1
  44. package/dist/types/src/extensions/listener.d.ts +1 -0
  45. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  46. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  47. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  48. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  49. package/dist/types/src/extensions/markdown/link.d.ts +1 -1
  50. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  51. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  52. package/dist/types/src/extensions/modes.d.ts +3 -3
  53. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  54. package/dist/types/src/extensions/util/overlap.d.ts +1 -1
  55. package/dist/types/src/extensions/util/overlap.d.ts.map +1 -1
  56. package/dist/types/src/extensions/util/react.d.ts +1 -1
  57. package/dist/types/src/extensions/util/react.d.ts.map +1 -1
  58. package/dist/types/src/hooks/useTextEditor.d.ts +1 -1
  59. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  60. package/dist/types/src/index.d.ts +1 -0
  61. package/dist/types/src/index.d.ts.map +1 -1
  62. package/dist/types/src/{extensions → state}/cursor.d.ts +2 -2
  63. package/dist/types/src/state/cursor.d.ts.map +1 -0
  64. package/dist/types/src/state/doc.d.ts +5 -0
  65. package/dist/types/src/state/doc.d.ts.map +1 -0
  66. package/dist/types/src/state/index.d.ts +6 -0
  67. package/dist/types/src/state/index.d.ts.map +1 -0
  68. package/dist/types/src/{extensions → state}/state.d.ts +2 -2
  69. package/dist/types/src/state/state.d.ts.map +1 -0
  70. package/dist/types/src/state/types.d.ts.map +1 -0
  71. package/dist/types/src/state/util.d.ts +3 -0
  72. package/dist/types/src/state/util.d.ts.map +1 -0
  73. package/dist/types/src/styles/markdown.d.ts +1 -2
  74. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  75. package/dist/types/src/styles/theme.d.ts.map +1 -1
  76. package/dist/types/src/util.d.ts +6 -0
  77. package/dist/types/src/util.d.ts.map +1 -1
  78. package/package.json +60 -41
  79. package/src/InputMode.stories.tsx +8 -8
  80. package/src/TextEditor.stories.tsx +93 -70
  81. package/src/components/Toolbar/Toolbar.tsx +8 -11
  82. package/src/defaults.ts +0 -2
  83. package/src/extensions/annotations.ts +1 -1
  84. package/src/extensions/autocomplete.ts +9 -8
  85. package/src/extensions/automerge/automerge.stories.tsx +2 -2
  86. package/src/extensions/automerge/{automerge.spec.tsx → automerge.test.tsx} +1 -0
  87. package/src/extensions/automerge/automerge.ts +2 -2
  88. package/src/extensions/automerge/cursor.ts +1 -1
  89. package/src/extensions/awareness/awareness.ts +3 -5
  90. package/src/extensions/command/hint.ts +1 -1
  91. package/src/extensions/command/state.ts +3 -4
  92. package/src/extensions/comments.ts +44 -45
  93. package/src/extensions/debug.ts +2 -2
  94. package/src/extensions/folding.tsx +6 -4
  95. package/src/extensions/index.ts +0 -4
  96. package/src/extensions/listener.ts +1 -0
  97. package/src/extensions/markdown/changes.test.ts +1 -3
  98. package/src/extensions/markdown/decorate.ts +49 -6
  99. package/src/extensions/markdown/formatting.test.ts +1 -3
  100. package/src/extensions/markdown/highlight.ts +0 -5
  101. package/src/extensions/markdown/link.ts +3 -2
  102. package/src/extensions/markdown/parser.test.ts +1 -2
  103. package/src/extensions/markdown/styles.ts +10 -0
  104. package/src/extensions/markdown/table.ts +3 -3
  105. package/src/extensions/modes.ts +6 -5
  106. package/src/extensions/util/overlap.ts +1 -1
  107. package/src/extensions/util/react.tsx +6 -1
  108. package/src/hooks/useTextEditor.ts +36 -32
  109. package/src/index.ts +1 -0
  110. package/src/{extensions → state}/cursor.ts +3 -6
  111. package/src/state/doc.ts +10 -0
  112. package/src/state/index.ts +11 -0
  113. package/src/{extensions → state}/state.ts +7 -3
  114. package/src/state/util.ts +13 -0
  115. package/src/styles/markdown.ts +1 -3
  116. package/src/styles/theme.ts +3 -1
  117. package/src/util.ts +10 -0
  118. package/dist/types/src/extensions/automerge/automerge.spec.d.ts +0 -2
  119. package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +0 -1
  120. package/dist/types/src/extensions/cursor.d.ts.map +0 -1
  121. package/dist/types/src/extensions/doc.d.ts +0 -6
  122. package/dist/types/src/extensions/doc.d.ts.map +0 -1
  123. package/dist/types/src/extensions/state.d.ts.map +0 -1
  124. package/dist/types/src/extensions/types.d.ts.map +0 -1
  125. package/src/extensions/automerge/automerge.test.ts +0 -13
  126. package/src/extensions/doc.ts +0 -17
  127. /package/dist/types/src/{extensions → state}/types.d.ts +0 -0
  128. /package/src/{extensions → state}/types.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';
@@ -19,8 +20,8 @@ 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';
23
+ import { createDocAccessor, createObject } from '@dxos/react-client/echo';
24
+ import { Button, Input, useThemeContext } from '@dxos/react-ui';
24
25
  import { baseSurface, mx, getSize } from '@dxos/react-ui-theme';
25
26
  import { withLayout, withTheme } from '@dxos/storybook-utils';
26
27
 
@@ -37,6 +38,7 @@ import {
37
38
  createExternalCommentSync,
38
39
  createMarkdownExtensions,
39
40
  createThemeExtensions,
41
+ debugTree,
40
42
  decorateMarkdown,
41
43
  defaultOptions,
42
44
  dropFile,
@@ -46,18 +48,15 @@ import {
46
48
  linkTooltip,
47
49
  listener,
48
50
  mention,
49
- state,
50
51
  table,
51
52
  typewriter,
52
53
  type CommandAction,
53
- type Comment,
54
54
  type CommentsOptions,
55
- type EditorSelectionState,
56
- debugTree,
57
55
  type DebugNode,
58
56
  } from './extensions';
59
57
  import { renderRoot } from './extensions/util';
60
58
  import { useTextEditor, type UseTextEditorProps } from './hooks';
59
+ import { type Comment, type EditorSelectionState, state } from './state';
61
60
  import translations from './translations';
62
61
 
63
62
  faker.seed(101);
@@ -164,8 +163,8 @@ const content = {
164
163
  '> 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
164
  '',
166
165
  '> This is ...',
167
- '> ... a multi-line ...',
168
- '> block quote.',
166
+ '... a multi-line ...',
167
+ 'block quote.',
169
168
  '',
170
169
  ),
171
170
 
@@ -254,7 +253,7 @@ const renderLinkButton = (el: Element, url: string) => {
254
253
  // Story
255
254
  //
256
255
 
257
- type DebugMode = 'syntax' | 'raw';
256
+ type DebugMode = 'raw' | 'tree' | 'raw+tree';
258
257
 
259
258
  type StoryProps = {
260
259
  id?: string;
@@ -266,7 +265,7 @@ type StoryProps = {
266
265
  onReady?: (view: EditorView) => void;
267
266
  } & Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'>;
268
267
 
269
- const Story = ({
268
+ const DefaultStory = ({
270
269
  id = 'editor-' + PublicKey.random().toHex().slice(0, 8),
271
270
  debug,
272
271
  text,
@@ -278,7 +277,7 @@ const Story = ({
278
277
  lineNumbers,
279
278
  onReady,
280
279
  }: StoryProps) => {
281
- const [object] = useState(createEchoObject(create(Expando, { content: text ?? '' })));
280
+ const [object] = useState(createObject(create(Expando, { content: text ?? '' })));
282
281
  const { themeMode } = useThemeContext();
283
282
  const [tree, setTree] = useState<DebugNode>();
284
283
  const { parentRef, focusAttributes, view } = useTextEditor(
@@ -317,16 +316,16 @@ const Story = ({
317
316
  return (
318
317
  <div className='flex w-full'>
319
318
  <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>
319
+ {debug && (
320
+ <div className='flex flex-col w-[800px] border-l border-separator divide-y divide-separator overflow-auto'>
321
+ {(debug === 'raw' || debug === 'raw+tree') && (
322
+ <pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>{view?.state.doc.toString()}</pre>
323
+ )}
324
+ {(debug === 'tree' || debug === 'raw+tree') && (
325
+ <pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>
326
+ {JSON.stringify(tree, null, 2)}
327
+ </pre>
328
+ )}
330
329
  </div>
331
330
  )}
332
331
  </div>
@@ -334,9 +333,9 @@ const Story = ({
334
333
  };
335
334
 
336
335
  export default {
337
- title: 'react-ui-editor/TextEditor',
336
+ title: 'ui/react-ui-editor/TextEditor',
338
337
  decorators: [withTheme, withLayout({ fullscreen: true })],
339
- render: Story,
338
+ render: DefaultStory,
340
339
  parameters: { translations, layout: 'fullscreen' },
341
340
  };
342
341
 
@@ -362,28 +361,28 @@ const allExtensions: Extension[] = [
362
361
  ];
363
362
 
364
363
  export const Default = {
365
- render: () => <Story text={text} extensions={defaultExtensions} />,
364
+ render: () => <DefaultStory text={text} extensions={defaultExtensions} />,
366
365
  };
367
366
 
368
367
  export const Everything = {
369
- render: () => <Story text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
368
+ render: () => <DefaultStory text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
370
369
  };
371
370
 
372
371
  export const Empty = {
373
- render: () => <Story extensions={defaultExtensions} />,
372
+ render: () => <DefaultStory extensions={defaultExtensions} />,
374
373
  };
375
374
 
376
375
  export const Readonly = {
377
- render: () => <Story text={text} extensions={defaultExtensions} readonly />,
376
+ render: () => <DefaultStory text={text} extensions={defaultExtensions} readonly />,
378
377
  };
379
378
 
380
379
  export const NoExtensions = {
381
- render: () => <Story text={text} />,
380
+ render: () => <DefaultStory text={text} />,
382
381
  };
383
382
 
384
383
  export const Vim = {
385
384
  render: () => (
386
- <Story
385
+ <DefaultStory
387
386
  text={str('# Vim Mode', '', 'The distant future. The year 2000.', '', content.paragraphs)}
388
387
  extensions={[defaultExtensions, InputModeExtensions.vim]}
389
388
  />
@@ -410,12 +409,12 @@ const headings = str(
410
409
  const global = new Map<string, EditorSelectionState>();
411
410
 
412
411
  export const Folding = {
413
- render: () => <Story text={text} extensions={[folding()]} />,
412
+ render: () => <DefaultStory text={text} extensions={[folding()]} />,
414
413
  };
415
414
 
416
415
  export const Scrolling = {
417
416
  render: () => (
418
- <Story
417
+ <DefaultStory
419
418
  text={str('# Large Document', '', longText)}
420
419
  extensions={state({
421
420
  setState: (id, state) => global.set(id, state),
@@ -427,7 +426,7 @@ export const Scrolling = {
427
426
 
428
427
  export const ScrollingWithImages = {
429
428
  render: () => (
430
- <Story text={str('# Large Document', '', largeWithImages)} extensions={[decorateMarkdown(), image()]} />
429
+ <DefaultStory text={str('# Large Document', '', largeWithImages)} extensions={[decorateMarkdown(), image()]} />
431
430
  ),
432
431
  };
433
432
 
@@ -438,7 +437,7 @@ export const ScrollTo = {
438
437
  const text = str('# Scroll To', longText, '', word, '', longText);
439
438
  const idx = text.indexOf(word);
440
439
  return (
441
- <Story
440
+ <DefaultStory
442
441
  text={text}
443
442
  extensions={defaultExtensions}
444
443
  scrollTo={idx}
@@ -452,25 +451,39 @@ export const ScrollTo = {
452
451
  // Markdown
453
452
  //
454
453
 
454
+ export const Blockquote = {
455
+ render: () => (
456
+ <DefaultStory
457
+ text={str('> Blockquote', 'continuation', content.footer)}
458
+ extensions={decorateMarkdown()}
459
+ debug='raw'
460
+ />
461
+ ),
462
+ };
463
+
455
464
  export const Headings = {
456
- render: () => <Story text={headings} extensions={decorateMarkdown({ numberedHeadings: { from: 2, to: 4 } })} />,
465
+ render: () => (
466
+ <DefaultStory text={headings} extensions={decorateMarkdown({ numberedHeadings: { from: 2, to: 4 } })} />
467
+ ),
457
468
  };
458
469
 
459
470
  export const Links = {
460
- render: () => <Story text={str(content.links, content.footer)} extensions={[linkTooltip(renderLinkTooltip)]} />,
471
+ render: () => (
472
+ <DefaultStory text={str(content.links, content.footer)} extensions={[linkTooltip(renderLinkTooltip)]} />
473
+ ),
461
474
  };
462
475
 
463
476
  export const Image = {
464
- render: () => <Story text={str(content.image, content.footer)} extensions={[image()]} />,
477
+ render: () => <DefaultStory text={str(content.image, content.footer)} extensions={[image()]} />,
465
478
  };
466
479
 
467
480
  export const Code = {
468
- render: () => <Story text={str(content.codeblocks, content.footer)} extensions={[decorateMarkdown()]} />,
481
+ render: () => <DefaultStory text={str(content.codeblocks, content.footer)} extensions={[decorateMarkdown()]} />,
469
482
  };
470
483
 
471
484
  export const Lists = {
472
485
  render: () => (
473
- <Story
486
+ <DefaultStory
474
487
  text={str(content.tasks, '', content.bullets, '', content.numbered, content.footer)}
475
488
  extensions={[decorateMarkdown()]}
476
489
  />
@@ -478,24 +491,26 @@ export const Lists = {
478
491
  };
479
492
 
480
493
  export const BulletList = {
481
- render: () => <Story text={str(content.bullets, content.footer)} extensions={[decorateMarkdown()]} />,
494
+ render: () => <DefaultStory text={str(content.bullets, content.footer)} extensions={[decorateMarkdown()]} />,
482
495
  };
483
496
 
484
497
  export const OrderedList = {
485
- render: () => <Story text={str(content.numbered, content.footer)} extensions={[decorateMarkdown()]} />,
498
+ render: () => <DefaultStory text={str(content.numbered, content.footer)} extensions={[decorateMarkdown()]} />,
486
499
  };
487
500
 
488
501
  export const TaskList = {
489
- render: () => <Story text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug='raw' />,
502
+ render: () => (
503
+ <DefaultStory text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug='raw+tree' />
504
+ ),
490
505
  };
491
506
 
492
507
  export const Table = {
493
- render: () => <Story text={str(content.table, content.footer)} extensions={[decorateMarkdown(), table()]} />,
508
+ render: () => <DefaultStory text={str(content.table, content.footer)} extensions={[decorateMarkdown(), table()]} />,
494
509
  };
495
510
 
496
511
  export const CommentedOut = {
497
512
  render: () => (
498
- <Story
513
+ <DefaultStory
499
514
  text={str('# Commented out', '', content.comment, content.footer)}
500
515
  extensions={[
501
516
  decorateMarkdown(),
@@ -508,7 +523,11 @@ export const CommentedOut = {
508
523
 
509
524
  export const Typescript = {
510
525
  render: () => (
511
- <Story text={content.typescript} lineNumbers extensions={[editorMonospace, javascript({ typescript: true })]} />
526
+ <DefaultStory
527
+ text={content.typescript}
528
+ lineNumbers
529
+ extensions={[editorMonospace, javascript({ typescript: true })]}
530
+ />
512
531
  ),
513
532
  };
514
533
 
@@ -518,7 +537,7 @@ export const Typescript = {
518
537
 
519
538
  export const Autocomplete = {
520
539
  render: () => (
521
- <Story
540
+ <DefaultStory
522
541
  text={str('# Autocomplete', '', 'Press Ctrl-Space...', content.footer)}
523
542
  extensions={[
524
543
  decorateMarkdown({ renderLinkButton }),
@@ -532,7 +551,7 @@ export const Autocomplete = {
532
551
 
533
552
  export const Mention = {
534
553
  render: () => (
535
- <Story
554
+ <DefaultStory
536
555
  text={str('# Mention', '', 'Type @...', content.footer)}
537
556
  extensions={[
538
557
  mention({
@@ -545,7 +564,11 @@ export const Mention = {
545
564
 
546
565
  export const Search = {
547
566
  render: () => (
548
- <Story text={str('# Search', text)} extensions={defaultExtensions} onReady={(view) => openSearchPanel(view)} />
567
+ <DefaultStory
568
+ text={str('# Search', text)}
569
+ extensions={defaultExtensions}
570
+ onReady={(view) => openSearchPanel(view)}
571
+ />
549
572
  ),
550
573
  };
551
574
 
@@ -569,28 +592,26 @@ const CommandDialog = ({ onClose }: { onClose: (action?: CommandAction) => void
569
592
  };
570
593
 
571
594
  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>
595
+ <div className={mx('flex items-center p-2 gap-2 border rounded-md', baseSurface)}>
596
+ <Input.Root>
597
+ <Input.TextInput
598
+ autoFocus={true}
599
+ placeholder='Enter command.'
600
+ value={text}
601
+ onChange={({ target: { value } }) => setText(value)}
602
+ onKeyDown={handleKeyDown}
603
+ />
604
+ </Input.Root>
605
+ <Button variant='ghost' classNames='pli-0' onClick={() => onClose()}>
606
+ <X className={getSize(5)} />
607
+ </Button>
608
+ </div>
588
609
  );
589
610
  };
590
611
 
591
612
  export const Command = {
592
613
  render: () => (
593
- <Story
614
+ <DefaultStory
594
615
  text={str('# Command', '')}
595
616
  extensions={[
596
617
  command({
@@ -608,7 +629,7 @@ export const Comments = {
608
629
  render: () => {
609
630
  const _comments = useSignal<Comment[]>([]);
610
631
  return (
611
- <Story
632
+ <DefaultStory
612
633
  text={str('# Comments', '', content.paragraphs, content.footer)}
613
634
  extensions={[
614
635
  createExternalCommentSync(
@@ -645,12 +666,14 @@ export const Comments = {
645
666
  };
646
667
 
647
668
  export const Annotations = {
648
- render: () => <Story text={str('# Annotations', '', longText)} extensions={[annotations({ match: /volup/gi })]} />,
669
+ render: () => (
670
+ <DefaultStory text={str('# Annotations', '', longText)} extensions={[annotations({ match: /volup/gi })]} />
671
+ ),
649
672
  };
650
673
 
651
674
  export const DND = {
652
675
  render: () => (
653
- <Story
676
+ <DefaultStory
654
677
  text={str('# DND', '')}
655
678
  extensions={[
656
679
  dropFile({
@@ -665,7 +688,7 @@ export const DND = {
665
688
 
666
689
  export const Listener = {
667
690
  render: () => (
668
- <Story
691
+ <DefaultStory
669
692
  text={str('# Listener', '', content.footer)}
670
693
  extensions={[
671
694
  listener({
@@ -685,7 +708,7 @@ const typewriterItems = localStorage.getItem('dxos.org/plugin/markdown/typewrite
685
708
 
686
709
  export const Typewriter = {
687
710
  render: () => (
688
- <Story
711
+ <DefaultStory
689
712
  text={str('# Typewriter', '', content.paragraphs, content.footer)}
690
713
  extensions={[typewriter({ items: typewriterItems })]}
691
714
  />
@@ -694,7 +717,7 @@ export const Typewriter = {
694
717
 
695
718
  export const Blast = {
696
719
  render: () => (
697
- <Story
720
+ <DefaultStory
698
721
  text={str('# Blast', '', content.paragraphs, content.codeblocks, content.paragraphs)}
699
722
  extensions={[
700
723
  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 '../state';
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 '../../state';
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 '../../state';
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 '../../state';
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 '../../state';
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: () => ({}),