@dxos/react-ui-editor 0.8.4-main.406dc2a → 0.8.4-main.548089c

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 (108) hide show
  1. package/dist/lib/browser/index.mjs +1379 -1139
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +1379 -1139
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -3
  8. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +17 -2
  10. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  11. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  12. package/dist/types/src/components/EditorToolbar/util.d.ts +5 -19
  13. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  14. package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
  15. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  16. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  17. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  18. package/dist/types/src/extensions/automerge/sync.d.ts +1 -1
  19. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -1
  21. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  22. package/dist/types/src/extensions/autoscroll.d.ts +14 -4
  23. package/dist/types/src/extensions/autoscroll.d.ts.map +1 -1
  24. package/dist/types/src/extensions/awareness/awareness-provider.d.ts +1 -1
  25. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -1
  26. package/dist/types/src/extensions/blocks.d.ts +2 -0
  27. package/dist/types/src/extensions/blocks.d.ts.map +1 -0
  28. package/dist/types/src/extensions/bookmarks.d.ts +12 -0
  29. package/dist/types/src/extensions/bookmarks.d.ts.map +1 -0
  30. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  31. package/dist/types/src/extensions/factories.d.ts +4 -4
  32. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  33. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  34. package/dist/types/src/extensions/index.d.ts +4 -0
  35. package/dist/types/src/extensions/index.d.ts.map +1 -1
  36. package/dist/types/src/extensions/listener.d.ts +8 -6
  37. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  38. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  39. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -2
  40. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  41. package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts +1 -1
  42. package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts.map +1 -1
  43. package/dist/types/src/extensions/popover/popover.d.ts.map +1 -1
  44. package/dist/types/src/extensions/preview/preview.d.ts +6 -2
  45. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  46. package/dist/types/src/extensions/replacer.d.ts +21 -0
  47. package/dist/types/src/extensions/replacer.d.ts.map +1 -0
  48. package/dist/types/src/extensions/replacer.test.d.ts +2 -0
  49. package/dist/types/src/extensions/replacer.test.d.ts.map +1 -0
  50. package/dist/types/src/extensions/scrolling.d.ts +78 -0
  51. package/dist/types/src/extensions/scrolling.d.ts.map +1 -0
  52. package/dist/types/src/extensions/tags/xml-tags.d.ts +41 -16
  53. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
  54. package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -1
  55. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  56. package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
  57. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  58. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -1
  59. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  60. package/dist/types/src/stories/components/util.d.ts.map +1 -1
  61. package/dist/types/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +41 -38
  63. package/src/components/Editor/Editor.stories.tsx +4 -7
  64. package/src/components/EditorToolbar/EditorToolbar.tsx +90 -90
  65. package/src/components/EditorToolbar/headings.ts +6 -4
  66. package/src/components/EditorToolbar/util.ts +4 -20
  67. package/src/extensions/autocomplete/autocomplete.ts +5 -5
  68. package/src/extensions/automerge/automerge.stories.tsx +1 -1
  69. package/src/extensions/automerge/automerge.ts +1 -1
  70. package/src/extensions/automerge/cursor.ts +1 -1
  71. package/src/extensions/automerge/sync.ts +1 -1
  72. package/src/extensions/automerge/update-automerge.ts +1 -1
  73. package/src/extensions/autoscroll.ts +74 -68
  74. package/src/extensions/awareness/awareness-provider.ts +2 -2
  75. package/src/extensions/blocks.ts +131 -0
  76. package/src/extensions/bookmarks.ts +75 -0
  77. package/src/extensions/comments.ts +2 -1
  78. package/src/extensions/factories.ts +6 -4
  79. package/src/extensions/folding.tsx +1 -2
  80. package/src/extensions/index.ts +4 -0
  81. package/src/extensions/listener.ts +14 -20
  82. package/src/extensions/markdown/bundle.ts +12 -2
  83. package/src/extensions/markdown/decorate.ts +8 -8
  84. package/src/extensions/markdown/formatting.ts +8 -8
  85. package/src/extensions/markdown/highlight.ts +1 -1
  86. package/src/extensions/markdown/image.ts +2 -2
  87. package/src/extensions/markdown/table.ts +6 -6
  88. package/src/extensions/popover/PopoverMenuProvider.tsx +2 -3
  89. package/src/extensions/popover/popover.ts +0 -4
  90. package/src/extensions/preview/preview.ts +14 -9
  91. package/src/extensions/replacer.test.ts +75 -0
  92. package/src/extensions/replacer.ts +93 -0
  93. package/src/extensions/scrolling.ts +189 -0
  94. package/src/extensions/selection.ts +1 -1
  95. package/src/extensions/tags/extended-markdown.test.ts +2 -1
  96. package/src/extensions/tags/xml-tags.ts +310 -203
  97. package/src/extensions/typewriter.ts +1 -1
  98. package/src/stories/CommandDialog.stories.tsx +9 -4
  99. package/src/stories/Comments.stories.tsx +1 -1
  100. package/src/stories/EditorToolbar.stories.tsx +4 -5
  101. package/src/stories/Popover.stories.tsx +4 -6
  102. package/src/stories/Preview.stories.tsx +15 -8
  103. package/src/stories/Tags.stories.tsx +19 -5
  104. package/src/stories/TextEditor.stories.tsx +2 -2
  105. package/src/stories/components/EditorStory.tsx +3 -3
  106. package/src/stories/components/util.tsx +39 -6
  107. package/src/styles/markdown.ts +1 -1
  108. package/src/styles/theme.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-editor",
3
- "version": "0.8.4-main.406dc2a",
3
+ "version": "0.8.4-main.548089c",
4
4
  "description": "Document editing experience within a DXOS shell.",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -40,10 +40,12 @@
40
40
  "@automerge/automerge": "3.1.2",
41
41
  "@codemirror/autocomplete": "^6.19.0",
42
42
  "@codemirror/commands": "^6.8.1",
43
+ "@codemirror/lang-html": "^6.4.11",
43
44
  "@codemirror/lang-javascript": "^6.2.4",
44
45
  "@codemirror/lang-json": "^6.0.2",
45
46
  "@codemirror/lang-markdown": "^6.3.4",
46
47
  "@codemirror/lang-xml": "^6.1.0",
48
+ "@codemirror/lang-yaml": "^6.1.2",
47
49
  "@codemirror/language": "^6.11.3",
48
50
  "@codemirror/language-data": "^6.5.1",
49
51
  "@codemirror/lint": "^6.8.5",
@@ -70,28 +72,29 @@
70
72
  "lodash.merge": "^4.6.2",
71
73
  "lodash.sortby": "^4.7.0",
72
74
  "style-mod": "^4.1.0",
73
- "@dxos/app-graph": "0.8.4-main.406dc2a",
74
- "@dxos/async": "0.8.4-main.406dc2a",
75
- "@dxos/debug": "0.8.4-main.406dc2a",
76
- "@dxos/context": "0.8.4-main.406dc2a",
77
- "@dxos/display-name": "0.8.4-main.406dc2a",
78
- "@dxos/echo": "0.8.4-main.406dc2a",
79
- "@dxos/invariant": "0.8.4-main.406dc2a",
80
- "@dxos/lit-ui": "0.8.4-main.406dc2a",
81
- "@dxos/log": "0.8.4-main.406dc2a",
82
- "@dxos/protocols": "0.8.4-main.406dc2a",
83
- "@dxos/live-object": "0.8.4-main.406dc2a",
84
- "@dxos/react-hooks": "0.8.4-main.406dc2a",
85
- "@dxos/react-ui-menu": "0.8.4-main.406dc2a",
86
- "@dxos/react-ui-stack": "0.8.4-main.406dc2a",
87
- "@dxos/react-ui-types": "0.8.4-main.406dc2a",
88
- "@dxos/util": "0.8.4-main.406dc2a"
75
+ "@dxos/app-graph": "0.8.4-main.548089c",
76
+ "@dxos/client": "0.8.4-main.548089c",
77
+ "@dxos/async": "0.8.4-main.548089c",
78
+ "@dxos/context": "0.8.4-main.548089c",
79
+ "@dxos/display-name": "0.8.4-main.548089c",
80
+ "@dxos/echo": "0.8.4-main.548089c",
81
+ "@dxos/invariant": "0.8.4-main.548089c",
82
+ "@dxos/debug": "0.8.4-main.548089c",
83
+ "@dxos/live-object": "0.8.4-main.548089c",
84
+ "@dxos/log": "0.8.4-main.548089c",
85
+ "@dxos/lit-ui": "0.8.4-main.548089c",
86
+ "@dxos/protocols": "0.8.4-main.548089c",
87
+ "@dxos/react-hooks": "0.8.4-main.548089c",
88
+ "@dxos/react-ui-menu": "0.8.4-main.548089c",
89
+ "@dxos/react-ui-stack": "0.8.4-main.548089c",
90
+ "@dxos/util": "0.8.4-main.548089c",
91
+ "@dxos/react-ui-types": "0.8.4-main.548089c"
89
92
  },
90
93
  "devDependencies": {
91
94
  "@automerge/automerge": "3.1.2",
92
- "@automerge/automerge-repo": "2.3.1",
93
- "@automerge/automerge-repo-network-broadcastchannel": "2.3.1",
94
- "@effect-rx/rx-react": "0.42.4",
95
+ "@automerge/automerge-repo": "2.4.0",
96
+ "@automerge/automerge-repo-network-broadcastchannel": "2.4.0",
97
+ "@effect-atom/atom-react": "^0.3.4",
95
98
  "@effect/platform": "0.92.1",
96
99
  "@types/chai": "^4.2.15",
97
100
  "@types/chai-dom": "^1.11.0",
@@ -99,7 +102,7 @@
99
102
  "@types/lodash.merge": "^4.6.6",
100
103
  "@types/lodash.sortby": "^4.7.7",
101
104
  "@types/react": "~19.2.2",
102
- "@types/react-dom": "~19.2.1",
105
+ "@types/react-dom": "~19.2.2",
103
106
  "@types/react-test-renderer": "^17.0.2",
104
107
  "chai": "^4.4.1",
105
108
  "chai-dom": "^1.11.0",
@@ -113,29 +116,29 @@
113
116
  "vite": "7.1.9",
114
117
  "vite-plugin-top-level-await": "^1.6.0",
115
118
  "vite-plugin-wasm": "^3.5.0",
116
- "@dxos/echo": "0.8.4-main.406dc2a",
117
- "@dxos/config": "0.8.4-main.406dc2a",
118
- "@dxos/echo-signals": "0.8.4-main.406dc2a",
119
- "@dxos/keyboard": "0.8.4-main.406dc2a",
120
- "@dxos/random": "0.8.4-main.406dc2a",
121
- "@dxos/react-client": "0.8.4-main.406dc2a",
122
- "@dxos/react-ui": "0.8.4-main.406dc2a",
123
- "@dxos/react-ui-attention": "0.8.4-main.406dc2a",
124
- "@dxos/react-ui-stack": "0.8.4-main.406dc2a",
125
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.406dc2a",
126
- "@dxos/react-ui-theme": "0.8.4-main.406dc2a",
127
- "@dxos/schema": "0.8.4-main.406dc2a",
128
- "@dxos/storybook-utils": "0.8.4-main.406dc2a"
119
+ "@dxos/config": "0.8.4-main.548089c",
120
+ "@dxos/echo": "0.8.4-main.548089c",
121
+ "@dxos/echo-signals": "0.8.4-main.548089c",
122
+ "@dxos/react-client": "0.8.4-main.548089c",
123
+ "@dxos/random": "0.8.4-main.548089c",
124
+ "@dxos/keyboard": "0.8.4-main.548089c",
125
+ "@dxos/react-ui": "0.8.4-main.548089c",
126
+ "@dxos/react-ui-attention": "0.8.4-main.548089c",
127
+ "@dxos/react-ui-stack": "0.8.4-main.548089c",
128
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.548089c",
129
+ "@dxos/react-ui-theme": "0.8.4-main.548089c",
130
+ "@dxos/schema": "0.8.4-main.548089c",
131
+ "@dxos/storybook-utils": "0.8.4-main.548089c"
129
132
  },
130
133
  "peerDependencies": {
131
- "@effect-rx/rx-react": "^0.34.1",
134
+ "@effect-atom/atom-react": "^0.3.4",
132
135
  "@effect/platform": "^0.80.12",
133
136
  "effect": "^3.13.3",
134
137
  "react": "^19.0.0",
135
138
  "react-dom": "^19.0.0",
136
- "@dxos/react-client": "0.8.4-main.406dc2a",
137
- "@dxos/react-ui-theme": "0.8.4-main.406dc2a",
138
- "@dxos/react-ui": "0.8.4-main.406dc2a"
139
+ "@dxos/react-client": "0.8.4-main.548089c",
140
+ "@dxos/react-ui-theme": "0.8.4-main.548089c",
141
+ "@dxos/react-ui": "0.8.4-main.548089c"
139
142
  },
140
143
  "publishConfig": {
141
144
  "access": "public"
@@ -8,8 +8,8 @@ import { useMemo } from 'react';
8
8
 
9
9
  import { createDocAccessor, createObject } from '@dxos/client/echo';
10
10
  import { useThemeContext } from '@dxos/react-ui';
11
- import { withTheme } from '@dxos/react-ui/testing';
12
- import { DataType } from '@dxos/schema';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
+ import { Text } from '@dxos/schema';
13
13
 
14
14
  import { automerge, createBasicExtensions, createThemeExtensions } from '../../extensions';
15
15
  import { Editor } from '../Editor';
@@ -17,10 +17,7 @@ import { Editor } from '../Editor';
17
17
  const meta = {
18
18
  title: 'ui/react-ui-editor/Editor',
19
19
  component: Editor,
20
- decorators: [withTheme],
21
- parameters: {
22
- layout: 'column',
23
- },
20
+ decorators: [withTheme, withLayout({ container: 'column' })],
24
21
  } satisfies Meta<typeof Editor>;
25
22
 
26
23
  export default meta;
@@ -56,7 +53,7 @@ export const Automerge: Story = {
56
53
  // Basic extensions.
57
54
  createBasicExtensions(),
58
55
  createThemeExtensions({ themeMode }),
59
- automerge(createDocAccessor(createObject(DataType.makeText(value)), ['content'])),
56
+ automerge(createDocAccessor(createObject(Text.make(value)), ['content'])),
60
57
  ],
61
58
  [],
62
59
  );
@@ -2,11 +2,11 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { Rx } from '@effect-rx/rx-react';
5
+ import { Atom } from '@effect-atom/atom-react';
6
6
  import React, { memo, useMemo } from 'react';
7
7
 
8
8
  import { rxFromSignal } from '@dxos/app-graph';
9
- import { ElevationProvider } from '@dxos/react-ui';
9
+ import { ElevationProvider, type ThemedClassName } from '@dxos/react-ui';
10
10
  import {
11
11
  type ActionGraphProps,
12
12
  MenuProvider,
@@ -15,121 +15,121 @@ import {
15
15
  useMenuActions,
16
16
  } from '@dxos/react-ui-menu';
17
17
 
18
+ import { type EditorViewMode } from '../../types';
19
+
18
20
  import { createBlocks } from './blocks';
19
21
  import { createFormatting } from './formatting';
20
22
  import { createHeadings } from './headings';
21
23
  import { createImageUpload } from './image';
22
24
  import { createLists } from './lists';
23
25
  import { createSearch } from './search';
24
- import { type EditorToolbarActionGraphProps, type EditorToolbarFeatureFlags, type EditorToolbarProps } from './util';
26
+ import { type EditorToolbarActionGraphProps } from './util';
25
27
  import { createViewMode } from './view-mode';
26
28
 
29
+ export type EditorToolbarFeatureFlags = Partial<{
30
+ showHeadings: boolean;
31
+ showFormatting: boolean;
32
+ showLists: boolean;
33
+ showBlocks: boolean;
34
+ showSearch: boolean;
35
+
36
+ // TODO(wittjosiah): Factor out (depends on plugin-level capabilities.)
37
+ onImageUpload: () => void;
38
+ onViewModeChange: (mode: EditorViewMode) => void;
39
+ }>;
40
+
41
+ export type EditorToolbarProps = ThemedClassName<
42
+ {
43
+ role?: string;
44
+ attendableId?: string;
45
+ } & (EditorToolbarActionGraphProps & EditorToolbarFeatureFlags)
46
+ >;
47
+
48
+ // TODO(burdon): Remove role dependency.
49
+ export const EditorToolbar = memo(({ classNames, role, attendableId, ...props }: EditorToolbarProps) => {
50
+ const menuProps = useEditorToolbarActionGraph(props);
51
+
52
+ return (
53
+ <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
54
+ <MenuProvider {...menuProps} attendableId={attendableId}>
55
+ <ToolbarMenu classNames={classNames} textBlockWidth />
56
+ </MenuProvider>
57
+ </ElevationProvider>
58
+ );
59
+ });
60
+
61
+ type ToolbarActionsProps = Pick<EditorToolbarActionGraphProps, 'state' | 'getView' | 'customActions'> &
62
+ EditorToolbarFeatureFlags;
63
+
64
+ // TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
65
+ // E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
66
+ // This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
67
+ const useEditorToolbarActionGraph = ({ state, getView, customActions, ...features }: ToolbarActionsProps) => {
68
+ const menuCreator = useMemo(
69
+ () => createToolbarActions({ state, getView, customActions, ...features }),
70
+ [
71
+ state,
72
+ getView,
73
+ customActions,
74
+ features?.showHeadings,
75
+ features?.showFormatting,
76
+ features?.showLists,
77
+ features?.showBlocks,
78
+ features?.showSearch,
79
+ features?.onImageUpload,
80
+ features?.onViewModeChange,
81
+ ],
82
+ );
83
+
84
+ return useMenuActions(menuCreator);
85
+ };
86
+
27
87
  const createToolbarActions = ({
28
- getView,
29
88
  state,
89
+ getView,
30
90
  customActions,
31
91
  ...features
32
- }: EditorToolbarFeatureFlags &
33
- Pick<EditorToolbarActionGraphProps, 'getView' | 'state' | 'customActions'>): Rx.Rx<ActionGraphProps> => {
34
- return Rx.make((get) => {
92
+ }: ToolbarActionsProps): Atom.Atom<ActionGraphProps> => {
93
+ return Atom.make((get) => {
35
94
  const graph: ActionGraphProps = {
36
95
  nodes: [],
37
96
  edges: [],
38
97
  };
39
98
 
40
- if (features.headings ?? true) {
41
- const headings = get(rxFromSignal(() => createHeadings(state, getView)));
42
- graph.nodes.push(...headings.nodes);
43
- graph.edges.push(...headings.edges);
44
- }
45
- if (features.formatting ?? true) {
46
- const formatting = get(rxFromSignal(() => createFormatting(state, getView)));
47
- graph.nodes.push(...formatting.nodes);
48
- graph.edges.push(...formatting.edges);
99
+ // TODO(burdon): Builder pattern?
100
+ const addSubGraph = (graph: ActionGraphProps, subGraph: ActionGraphProps) => {
101
+ graph.nodes.push(...subGraph.nodes);
102
+ graph.edges.push(...subGraph.edges);
103
+ };
104
+
105
+ if (features?.showHeadings ?? true) {
106
+ addSubGraph(graph, get(rxFromSignal(() => createHeadings(state, getView))));
49
107
  }
50
- if (features.lists ?? true) {
51
- const lists = get(rxFromSignal(() => createLists(state, getView)));
52
- graph.nodes.push(...lists.nodes);
53
- graph.edges.push(...lists.edges);
108
+ if (features?.showFormatting ?? true) {
109
+ addSubGraph(graph, get(rxFromSignal(() => createFormatting(state, getView))));
54
110
  }
55
- if (features.blocks ?? true) {
56
- const blocks = get(rxFromSignal(() => createBlocks(state, getView)));
57
- graph.nodes.push(...blocks.nodes);
58
- graph.edges.push(...blocks.edges);
111
+ if (features?.showLists ?? true) {
112
+ addSubGraph(graph, get(rxFromSignal(() => createLists(state, getView))));
59
113
  }
60
- if (features.image) {
61
- const image = get(rxFromSignal(() => createImageUpload(features.image!)));
62
- graph.nodes.push(...image.nodes);
63
- graph.edges.push(...image.edges);
114
+ if (features?.showBlocks ?? true) {
115
+ addSubGraph(graph, get(rxFromSignal(() => createBlocks(state, getView))));
64
116
  }
65
- {
66
- const gap = createGapSeparator();
67
- graph.nodes.push(...gap.nodes);
68
- graph.edges.push(...gap.edges);
117
+ if (features?.onImageUpload) {
118
+ addSubGraph(graph, get(rxFromSignal(() => createImageUpload(features.onImageUpload!))));
69
119
  }
120
+
121
+ addSubGraph(graph, createGapSeparator());
122
+
70
123
  if (customActions) {
71
- const custom = get(customActions);
72
- graph.nodes.push(...custom.nodes);
73
- graph.edges.push(...custom.edges);
124
+ addSubGraph(graph, get(customActions));
74
125
  }
75
- if (features.search ?? true) {
76
- const search = get(rxFromSignal(() => createSearch(getView)));
77
- graph.nodes.push(...search.nodes);
78
- graph.edges.push(...search.edges);
126
+ if (features?.showSearch ?? true) {
127
+ addSubGraph(graph, get(rxFromSignal(() => createSearch(getView))));
79
128
  }
80
- if (features.viewMode) {
81
- const viewMode = get(rxFromSignal(() => createViewMode(state, features.viewMode!)));
82
- graph.nodes.push(...viewMode.nodes);
83
- graph.edges.push(...viewMode.edges);
129
+ if (features?.onViewModeChange) {
130
+ addSubGraph(graph, get(rxFromSignal(() => createViewMode(state, features.onViewModeChange!))));
84
131
  }
85
132
 
86
133
  return graph;
87
134
  });
88
135
  };
89
-
90
- // TODO(wittjosiah): Toolbar re-rendering is causing this graph to be recreated and breaking reactivity in some cases.
91
- // E.g. for toolbar dropdowns which use active icon, the icon is not updated when the active item changes.
92
- // This is currently only happening in the markdown plugin usage and should be reproduced in an editor story.
93
- const useEditorToolbarActionGraph = (props: EditorToolbarProps) => {
94
- const menuCreator = useMemo(
95
- () =>
96
- createToolbarActions({
97
- getView: props.getView,
98
- state: props.state,
99
- customActions: props.customActions,
100
- headings: props.headings,
101
- formatting: props.formatting,
102
- lists: props.lists,
103
- blocks: props.blocks,
104
- image: props.image,
105
- search: props.search,
106
- viewMode: props.viewMode,
107
- }),
108
- [
109
- props.getView,
110
- props.state,
111
- props.customActions,
112
- props.headings,
113
- props.formatting,
114
- props.lists,
115
- props.blocks,
116
- props.image,
117
- props.search,
118
- props.viewMode,
119
- ],
120
- );
121
-
122
- return useMenuActions(menuCreator);
123
- };
124
-
125
- export const EditorToolbar = memo(({ classNames, attendableId, role, ...props }: EditorToolbarProps) => {
126
- const menuProps = useEditorToolbarActionGraph(props);
127
-
128
- return (
129
- <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
130
- <MenuProvider {...menuProps} attendableId={attendableId}>
131
- <ToolbarMenu classNames={classNames} textBlockWidth />
132
- </MenuProvider>
133
- </ElevationProvider>
134
- );
135
- });
@@ -19,12 +19,13 @@ const createHeadingGroupAction = (value: string) =>
19
19
  variant: 'dropdownMenu',
20
20
  applyActive: true,
21
21
  selectCardinality: 'single',
22
+ // TODO(wittjosiah): Remove? Not sure this does anything.
22
23
  value,
23
24
  } as ToolbarMenuActionGroupProperties,
24
25
  'ph--text-h--regular',
25
26
  );
26
27
 
27
- const createHeadingActions = (getView: () => EditorView) =>
28
+ const createHeadingActions = (currentLevel: string, getView: () => EditorView) =>
28
29
  Object.entries({
29
30
  '0': 'ph--paragraph--regular',
30
31
  '1': 'ph--text-h-one--regular',
@@ -40,6 +41,7 @@ const createHeadingActions = (getView: () => EditorView) =>
40
41
  {
41
42
  label: ['heading level label', { count: level, ns: translationKey }],
42
43
  icon,
44
+ checked: levelStr === currentLevel,
43
45
  },
44
46
  () => setHeading(level)(getView()),
45
47
  );
@@ -47,14 +49,14 @@ const createHeadingActions = (getView: () => EditorView) =>
47
49
 
48
50
  const computeHeadingValue = (state: EditorToolbarState) => {
49
51
  const blockType = state ? state.blockType : 'paragraph';
50
- const header = blockType && /heading(\d)/.exec(blockType);
51
- return header ? header[1] : blockType === 'paragraph' || !blockType ? '0' : '';
52
+ const heading = blockType && /heading(\d)/.exec(blockType);
53
+ return heading ? heading[1] : blockType === 'paragraph' || !blockType ? '0' : '';
52
54
  };
53
55
 
54
56
  export const createHeadings = (state: EditorToolbarState, getView: () => EditorView) => {
55
57
  const headingValue = computeHeadingValue(state);
56
58
  const headingGroupAction = createHeadingGroupAction(headingValue);
57
- const headingActions = createHeadingActions(getView);
59
+ const headingActions = createHeadingActions(headingValue, getView);
58
60
  return {
59
61
  nodes: [headingGroupAction as NodeArg<any>, ...headingActions],
60
62
  edges: [
@@ -3,12 +3,11 @@
3
3
  //
4
4
 
5
5
  import { type EditorView } from '@codemirror/view';
6
- import { type Rx } from '@effect-rx/rx-react';
6
+ import { type Atom } from '@effect-atom/atom-react';
7
7
  import { useMemo } from 'react';
8
8
 
9
9
  import { type Action } from '@dxos/app-graph';
10
10
  import { type Live, live } from '@dxos/live-object';
11
- import { type ThemedClassName } from '@dxos/react-ui';
12
11
  import {
13
12
  type ActionGraphProps,
14
13
  type MenuActionProperties,
@@ -23,34 +22,19 @@ import type { EditorAction, Formatting } from '../../extensions';
23
22
  import { translationKey } from '../../translations';
24
23
  import { type EditorViewMode } from '../../types';
25
24
 
26
- export type EditorToolbarState = Formatting & Partial<{ viewMode: EditorViewMode }>;
25
+ export type EditorToolbarState = { viewMode?: EditorViewMode } & Formatting;
27
26
 
28
- export const useEditorToolbarState = (initialState: Partial<EditorToolbarState> = {}) => {
27
+ export const useEditorToolbarState = (initialState: Partial<EditorToolbarState> = {}): Live<EditorToolbarState> => {
29
28
  return useMemo(() => live<EditorToolbarState>(initialState), []);
30
29
  };
31
30
 
32
- export type EditorToolbarFeatureFlags = Partial<{
33
- headings: boolean;
34
- formatting: boolean;
35
- lists: boolean;
36
- blocks: boolean;
37
- search: boolean;
38
- // TODO(wittjosiah): Factor out. Depend on plugin-level capabilities.
39
- image: () => void;
40
- viewMode: (mode: EditorViewMode) => void;
41
- }>;
42
-
43
31
  export type EditorToolbarActionGraphProps = {
44
32
  state: Live<EditorToolbarState>;
45
33
  getView: () => EditorView;
46
34
  // TODO(wittjosiah): Control positioning.
47
- customActions?: Rx.Rx<ActionGraphProps>;
35
+ customActions?: Atom.Atom<ActionGraphProps>;
48
36
  };
49
37
 
50
- export type EditorToolbarProps = ThemedClassName<
51
- EditorToolbarActionGraphProps & EditorToolbarFeatureFlags & { attendableId?: string; role?: string }
52
- >;
53
-
54
38
  export type EditorToolbarItem = EditorAction | MenuItemGroup | MenuSeparator;
55
39
 
56
40
  export const createEditorAction = (id: string, props: Partial<MenuActionProperties>, invoke: () => void) => {
@@ -207,14 +207,14 @@ class InlineSuggestionWidget extends WidgetType {
207
207
  super();
208
208
  }
209
209
 
210
- override toDOM(): HTMLSpanElement {
210
+ override eq(other: this) {
211
+ return this.suffix === other.suffix;
212
+ }
213
+
214
+ override toDOM() {
211
215
  const span = document.createElement('span');
212
216
  span.textContent = this.suffix;
213
217
  span.className = 'cm-inline-suggestion';
214
218
  return span;
215
219
  }
216
-
217
- override eq(other: InlineSuggestionWidget): boolean {
218
- return other.suffix === this.suffix;
219
- }
220
220
  }
@@ -50,7 +50,7 @@ const Editor = ({ source, autoFocus, space, identity }: EditorProps) => {
50
50
  [source, themeMode],
51
51
  );
52
52
 
53
- return <div ref={parentRef} className='flex w-full' />;
53
+ return <div ref={parentRef} className='flex is-full' />;
54
54
  };
55
55
 
56
56
  const DefaultStory = () => {
@@ -8,7 +8,7 @@ import { next as A } from '@automerge/automerge';
8
8
  import { type Extension, StateField, Transaction } from '@codemirror/state';
9
9
  import { EditorView, ViewPlugin } from '@codemirror/view';
10
10
 
11
- import { DocAccessor } from '@dxos/react-client/echo';
11
+ import { DocAccessor } from '@dxos/client/echo';
12
12
 
13
13
  import { Cursor } from '../../util';
14
14
  import { initialSync } from '../state';
@@ -2,8 +2,8 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
+ import { type DocAccessor, fromCursor, toCursor } from '@dxos/client/echo';
5
6
  import { log } from '@dxos/log';
6
- import { type DocAccessor, fromCursor, toCursor } from '@dxos/react-client/echo';
7
7
 
8
8
  import { type CursorConverter } from '../../util';
9
9
 
@@ -8,8 +8,8 @@ import { next as A } from '@automerge/automerge';
8
8
  import { type StateField } from '@codemirror/state';
9
9
  import { type EditorView } from '@codemirror/view';
10
10
 
11
+ import { type IDocHandle } from '@dxos/client/echo';
11
12
  import { log } from '@dxos/log';
12
- import { type IDocHandle } from '@dxos/react-client/echo';
13
13
 
14
14
  import { type State, getLastHeads, getPath, isReconcile, reconcileAnnotation, updateHeads } from './defs';
15
15
  import { updateAutomerge } from './update-automerge';
@@ -7,7 +7,7 @@
7
7
  import { next as A, type Heads } from '@automerge/automerge';
8
8
  import { type EditorState, type StateField, type Text, type Transaction } from '@codemirror/state';
9
9
 
10
- import { type IDocHandle } from '@dxos/react-client/echo';
10
+ import { type IDocHandle } from '@dxos/client/echo';
11
11
 
12
12
  import { type State } from './defs';
13
13