@dxos/react-ui-editor 0.3.11-main.c95bc86 → 0.3.11-main.cb8120f

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 (57) hide show
  1. package/dist/lib/browser/index.mjs +434 -210
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  5. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  6. package/dist/types/src/components/Toolbar/Toolbar.d.ts +9 -0
  7. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  8. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +14 -0
  9. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
  10. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  11. package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
  12. package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
  13. package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
  14. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
  15. package/dist/types/src/extensions/automerge/defs.d.ts +5 -5
  16. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  17. package/dist/types/src/extensions/automerge/semaphore.d.ts +2 -1
  18. package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  20. package/dist/types/src/extensions/awareness.d.ts +1 -1
  21. package/dist/types/src/extensions/comments.d.ts +5 -1
  22. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  23. package/dist/types/src/extensions/markdown/code.d.ts.map +1 -1
  24. package/dist/types/src/extensions/markdown/formatting.d.ts +11 -0
  25. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
  26. package/dist/types/src/extensions/markdown/index.d.ts +1 -0
  27. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  28. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  29. package/dist/types/src/hooks/index.d.ts +1 -0
  30. package/dist/types/src/hooks/index.d.ts.map +1 -1
  31. package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
  32. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
  33. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  34. package/package.json +36 -24
  35. package/src/components/TextEditor/MarkdownEditor.stories.tsx +8 -13
  36. package/src/components/TextEditor/TextEditor.tsx +3 -1
  37. package/src/components/Toolbar/Toolbar.stories.tsx +86 -0
  38. package/src/components/Toolbar/Toolbar.tsx +115 -0
  39. package/src/extensions/automerge/automerge.spec.tsx +76 -0
  40. package/src/extensions/automerge/automerge.test.ts +13 -0
  41. package/src/extensions/automerge/automerge.ts +26 -11
  42. package/src/extensions/automerge/cursor.ts +3 -3
  43. package/src/extensions/automerge/defs.ts +9 -9
  44. package/src/extensions/automerge/semaphore.ts +17 -19
  45. package/src/extensions/automerge/update-automerge.ts +12 -6
  46. package/src/extensions/automerge/update-codemirror.ts +5 -5
  47. package/src/extensions/awareness.ts +3 -3
  48. package/src/extensions/comments.ts +112 -64
  49. package/src/extensions/markdown/code.ts +24 -9
  50. package/src/extensions/markdown/formatting.ts +159 -0
  51. package/src/extensions/markdown/heading.ts +1 -1
  52. package/src/extensions/markdown/index.ts +1 -0
  53. package/src/extensions/markdown/link.ts +4 -0
  54. package/src/hooks/index.ts +1 -0
  55. package/src/hooks/useActionHandler.ts +45 -0
  56. package/src/hooks/useTextModel.ts +11 -8
  57. package/src/themes/default.ts +1 -1
@@ -4,6 +4,7 @@
4
4
 
5
5
  export * from './bundle';
6
6
  export * from './code';
7
+ export * from './formatting';
7
8
  export * from './heading';
8
9
  export * from './highlight';
9
10
  export * from './hr';
@@ -22,6 +22,7 @@ import { tooltipContent } from '@dxos/react-ui-theme';
22
22
  // https://codemirror.net/try/?c=aW1wb3J0IHsgYmFzaWNTZXR1cCwgRWRpdG9yVmlldyB9IGZyb20gImNvZGVtaXJyb3IiCmltcG9ydCB7IG1hcmtkb3duIH0gZnJvbSAiQGNvZGVtaXJyb3IvbGFuZy1tYXJrZG93biIKaW1wb3J0IHsgc3ludGF4VHJlZSB9IGZyb20gIkBjb2RlbWlycm9yL2xhbmd1YWdlIjsKaW1wb3J0IHsgRWRpdG9yU3RhdGUsIFJhbmdlU2V0QnVpbGRlciwgU3RhdGVGaWVsZCB9IGZyb20gIkBjb2RlbWlycm9yL3N0YXRlIjsKaW1wb3J0IHsgRGVjb3JhdGlvbiwgV2lkZ2V0VHlwZSB9IGZyb20gIkBjb2RlbWlycm9yL3ZpZXciOwoKY2xhc3MgTGluayBleHRlbmRzIFdpZGdldFR5cGUgewogIGNvbnN0cnVjdG9yKHRleHQsIHVybCkgewogICAgc3VwZXIoKQogICAgdGhpcy50ZXh0ID0gdGV4dAogICAgdGhpcy51cmwgPSB1cmwKICB9CiAgZXEob3RoZXIpIHsgcmV0dXJuIHRoaXMudGV4dCA9PSBvdGhlci50ZXh0ICYmIHRoaXMudXJsID09IG90aGVyLnVybCB9CiAgdG9ET00oKSB7CiAgICBsZXQgbGluayA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKQogICAgbGluay50ZXh0Q29udGVudCA9IHRoaXMudGV4dAogICAgbGluay5ocmVmID0gdGhpcy51cmwKICAgIHJldHVybiBsaW5rOwogIH0KfQoKbGV0IGRlY29yYXRpb25zRmllbGQgPSBTdGF0ZUZpZWxkLmRlZmluZSh7CiAgY3JlYXRlKCkgewogICAgcmV0dXJuIERlY29yYXRpb24ubm9uZTsKICB9LAogIHVwZGF0ZShfLCB0cikgewogICAgY29uc3QgYnVpbGRlciA9IG5ldyBSYW5nZVNldEJ1aWxkZXIoKTsKICAgIGxldCBjdXJzb3IgPSB0ci5zdGF0ZS5zZWxlY3Rpb24ubWFpbi5oZWFkOwogICAgc3ludGF4VHJlZSh0ci5zdGF0ZSkuaXRlcmF0ZSh7CiAgICAgIGVudGVyOiAobm9kZSkgPT4gewogICAgICAgIGlmICgoY3Vyc29yIDwgbm9kZS5mcm9tIHx8IGN1cnNvciA+IG5vZGUudG8pICYmIG5vZGUubmFtZSA9PSAiTGluayIpIHsKICAgICAgICAgIGxldCBtYXJrcyA9IG5vZGUubm9kZS5nZXRDaGlsZHJlbigiTGlua01hcmsiKTsKICAgICAgICAgIGxldCB0ZXh0ID0gbWFya3MubGVuZ3RoID49IDIgPyB0ci5zdGF0ZS5zbGljZURvYyhtYXJrc1swXS50bywgbWFya3NbMV0uZnJvbSkgOiAiIgoKICAgICAgICAgIGxldCB1cmxOb2RlID0gbm9kZS5ub2RlLmdldENoaWxkKCJVUkwiKTsKICAgICAgICAgIGxldCB1cmwgPSB1cmxOb2RlID8gdHIuc3RhdGUuc2xpY2VEb2ModXJsTm9kZS5mcm9tLCB1cmxOb2RlLnRvKSA6ICIiCiAgICAgICAgICBidWlsZGVyLmFkZChub2RlLmZyb20sIG5vZGUudG8sIERlY29yYXRpb24ucmVwbGFjZSh7CiAgICAgICAgICAgIHdpZGdldDogbmV3IExpbmsodGV4dCwgdXJsKSwKICAgICAgICAgIH0pLAogICAgICAgICAgICAgICAgICAgICApOwogICAgICAgICAgcmV0dXJuIGZhbHNlOwogICAgICAgIH0KICAgICAgICByZXR1cm4gdHJ1ZTsKICAgICAgfSwKICAgIH0pOwogICAgcmV0dXJuIGJ1aWxkZXIuZmluaXNoKCk7CiAgfSwKICBwcm92aWRlOiAoZikgPT4gRWRpdG9yVmlldy5kZWNvcmF0aW9ucy5mcm9tKGYpLAp9KTsKCmxldCB2aWV3ID0gbmV3IEVkaXRvclZpZXcoewogIGRvYzogIiMgSGVsbG8gV29ybGRcblxuW1Rlc3RdKGh0dHBzOi8vZXhhbXBsZS5jb20pXG5cblxuIiwKICBleHRlbnNpb25zOiBbZGVjb3JhdGlvbnNGaWVsZCwgbWFya2Rvd24oKV0sCiAgcGFyZW50OiBkb2N1bWVudC5ib2R5LAp9KTsKCnZpZXcuZm9jdXMoKTs=
23
23
  // https://discuss.codemirror.net/t/link-widget-is-clicked-only-if-editor-is-out-of-focus/7433
24
24
 
25
+ // TODO(burdon): Callback to dynamically lookup title of linked pages.
25
26
  export type LinkOptions = {
26
27
  link?: boolean;
27
28
  onHover?: (el: Element, url: string) => void;
@@ -64,10 +65,12 @@ export const link = (options: LinkOptions = {}): Extension => {
64
65
  for (let i = 0, node: SyntaxNode | null = syntax; !link && node && i < 5; node = node.parent, i++) {
65
66
  link = node.name === 'Link' ? node : null;
66
67
  }
68
+
67
69
  const url = link && link.getChild('URL');
68
70
  if (!url || !link) {
69
71
  return null;
70
72
  }
73
+
71
74
  const urlText = view.state.sliceDoc(url.from, url.to);
72
75
  return {
73
76
  pos: link.from,
@@ -157,6 +160,7 @@ const buildDecorations = (view: EditorView, options: LinkOptions): DecorationSet
157
160
  return false;
158
161
  }
159
162
 
163
+ // TODO(burdon): Don't expand if moving cursor up/down.
160
164
  if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
161
165
  builder.add(
162
166
  node.from,
@@ -5,5 +5,6 @@
5
5
  export * from './awareness-provider';
6
6
  export * from './defs';
7
7
 
8
+ export * from './useActionHandler';
8
9
  export * from './useTextEditor';
9
10
  export * from './useTextModel';
@@ -0,0 +1,45 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import type { EditorView } from '@codemirror/view';
6
+
7
+ import type { ToolbarProps } from '../components/Toolbar/Toolbar';
8
+ import { createComment, setHeading, toggleBold, toggleItalic, toggleList, toggleStrikethrough } from '../extensions';
9
+
10
+ export const useActionHandler = (view: EditorView | null): ToolbarProps['onAction'] => {
11
+ return (action) => {
12
+ if (!view) {
13
+ return;
14
+ }
15
+
16
+ switch (action.type) {
17
+ case 'heading':
18
+ setHeading(parseInt(action.data))(view);
19
+ break;
20
+
21
+ case 'bold':
22
+ toggleBold(view);
23
+ break;
24
+ case 'italic':
25
+ toggleItalic(view);
26
+ break;
27
+ case 'strikethrough':
28
+ toggleStrikethrough(view);
29
+ break;
30
+
31
+ case 'list':
32
+ toggleList(view);
33
+ break;
34
+
35
+ case 'comment':
36
+ createComment(view);
37
+ break;
38
+ }
39
+
40
+ // TODO(burdon): Hack since otherwise focus doesn't leave heading selector.
41
+ setTimeout(() => {
42
+ view.focus();
43
+ });
44
+ };
45
+ };
@@ -10,11 +10,10 @@ import { type AutomergeTextCompat, getRawDoc } from '@dxos/echo-schema';
10
10
  import { invariant } from '@dxos/invariant';
11
11
  import { isAutomergeObject, type Space, type TextObject } from '@dxos/react-client/echo';
12
12
  import { type Identity } from '@dxos/react-client/halo';
13
- import { isNotNullOrUndefined } from '@dxos/util';
14
13
 
15
14
  import { SpaceAwarenessProvider } from './awareness-provider';
16
15
  import { type EditorModel, modelState } from './defs';
17
- import { automerge, awareness, AwarenessProvider } from '../extensions';
16
+ import { automerge, awareness } from '../extensions';
18
17
  import { cursorColor } from '../styles';
19
18
 
20
19
  // TODO(burdon): Remove space/identity dependency. Define interface for the framework re content and presence.
@@ -49,16 +48,20 @@ const createModel = ({ space, identity, text }: UseTextModelProps) => {
49
48
  peerId: identity?.identityKey.toHex() ?? 'Anonymous',
50
49
  });
51
50
 
51
+ const extensions = [
52
+ //
53
+ modelState.init(() => model),
54
+ automerge({ handle: doc.handle, path: doc.path }),
55
+ ];
56
+ if (awarenessProvider) {
57
+ extensions.push(awareness(awarenessProvider));
58
+ }
59
+
52
60
  const model: EditorModel = {
53
61
  id: obj.id,
54
62
  content: doc,
55
63
  text: () => get(doc.handle.docSync(), doc.path),
56
- extension: [
57
- modelState.init(() => model),
58
- automerge({ handle: doc.handle, path: doc.path }),
59
- awarenessProvider && AwarenessProvider.of(awarenessProvider),
60
- awareness(),
61
- ].filter(isNotNullOrUndefined),
64
+ extension: extensions,
62
65
  peer: identity
63
66
  ? {
64
67
  id: identity.identityKey.toHex(),
@@ -88,7 +88,7 @@ export const defaultTheme: ThemeStyles = {
88
88
  paddingInline: 0,
89
89
  },
90
90
  '.cm-activeLine': {
91
- background: 'inherit',
91
+ background: 'transparent',
92
92
  },
93
93
 
94
94
  //