@dxos/react-ui-editor 0.8.4-main.dedc0f3 → 0.8.4-main.ead640a

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 (218) hide show
  1. package/dist/lib/browser/{chunk-22UMM3QJ.mjs → chunk-HL3YF6WC.mjs} +2 -2
  2. package/dist/lib/browser/chunk-HL3YF6WC.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +5482 -5519
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +71 -1
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/browser/types/index.mjs +1 -1
  9. package/dist/lib/node-esm/{chunk-YXYQPV6R.mjs → chunk-YJZGD3LY.mjs} +2 -2
  10. package/dist/lib/node-esm/chunk-YJZGD3LY.mjs.map +7 -0
  11. package/dist/lib/node-esm/index.mjs +5482 -5519
  12. package/dist/lib/node-esm/index.mjs.map +4 -4
  13. package/dist/lib/node-esm/meta.json +1 -1
  14. package/dist/lib/node-esm/testing/index.mjs +71 -1
  15. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  16. package/dist/lib/node-esm/types/index.mjs +1 -1
  17. package/dist/types/src/components/Editor/Editor.d.ts +24 -9
  18. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
  19. package/dist/types/src/components/Editor/Editor.stories.d.ts +27 -0
  20. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -0
  21. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  22. package/dist/types/src/components/EditorToolbar/util.d.ts +1 -1
  23. package/dist/types/src/components/index.d.ts +0 -1
  24. package/dist/types/src/components/index.d.ts.map +1 -1
  25. package/dist/types/src/extensions/{autocomplete.d.ts → autocomplete/autocomplete.d.ts} +1 -1
  26. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -0
  27. package/dist/types/src/extensions/autocomplete/index.d.ts +5 -0
  28. package/dist/types/src/extensions/autocomplete/index.d.ts.map +1 -0
  29. package/dist/types/src/extensions/autocomplete/match.d.ts +13 -0
  30. package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -0
  31. package/dist/types/src/extensions/autocomplete/placeholder.d.ts +20 -0
  32. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -0
  33. package/dist/types/src/extensions/autocomplete/typeahead.d.ts +10 -0
  34. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -0
  35. package/dist/types/src/extensions/automerge/automerge.d.ts +1 -1
  36. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  37. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +1 -1
  38. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  39. package/dist/types/src/extensions/automerge/sync.d.ts +2 -2
  40. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  41. package/dist/types/src/extensions/autoscroll.d.ts +2 -2
  42. package/dist/types/src/extensions/autoscroll.d.ts.map +1 -1
  43. package/dist/types/src/extensions/factories.d.ts +7 -2
  44. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  45. package/dist/types/src/extensions/focus.d.ts.map +1 -1
  46. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  47. package/dist/types/src/extensions/index.d.ts +2 -1
  48. package/dist/types/src/extensions/index.d.ts.map +1 -1
  49. package/dist/types/src/extensions/json.d.ts +1 -1
  50. package/dist/types/src/extensions/json.d.ts.map +1 -1
  51. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  52. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  53. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  54. package/dist/types/src/extensions/modes.d.ts +1 -1
  55. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  56. package/dist/types/src/extensions/outliner/menu.d.ts +8 -0
  57. package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -0
  58. package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts +36 -0
  59. package/dist/types/src/extensions/popover/PopoverMenuProvider.d.ts.map +1 -0
  60. package/dist/types/src/extensions/popover/index.d.ts +8 -0
  61. package/dist/types/src/extensions/popover/index.d.ts.map +1 -0
  62. package/dist/types/src/extensions/popover/menu-presets.d.ts +4 -0
  63. package/dist/types/src/extensions/popover/menu-presets.d.ts.map +1 -0
  64. package/dist/types/src/extensions/popover/menu.d.ts +24 -0
  65. package/dist/types/src/extensions/popover/menu.d.ts.map +1 -0
  66. package/dist/types/src/extensions/popover/modal.d.ts +7 -0
  67. package/dist/types/src/extensions/popover/modal.d.ts.map +1 -0
  68. package/dist/types/src/extensions/popover/popover.d.ts +47 -0
  69. package/dist/types/src/extensions/popover/popover.d.ts.map +1 -0
  70. package/dist/types/src/extensions/popover/usePopoverMenu.d.ts +34 -0
  71. package/dist/types/src/extensions/popover/usePopoverMenu.d.ts.map +1 -0
  72. package/dist/types/src/extensions/popover/util.d.ts +8 -0
  73. package/dist/types/src/extensions/popover/util.d.ts.map +1 -0
  74. package/dist/types/src/extensions/preview/preview.d.ts +0 -2
  75. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  76. package/dist/types/src/extensions/state.d.ts +2 -0
  77. package/dist/types/src/extensions/state.d.ts.map +1 -0
  78. package/dist/types/src/extensions/tags/streamer.d.ts.map +1 -1
  79. package/dist/types/src/extensions/tags/xml-tags.d.ts +1 -0
  80. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
  81. package/dist/types/src/hooks/useTextEditor.d.ts +4 -8
  82. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  83. package/dist/types/src/stories/{Command.stories.d.ts → CommandDialog.stories.d.ts} +2 -3
  84. package/dist/types/src/stories/CommandDialog.stories.d.ts.map +1 -0
  85. package/dist/types/src/stories/Comments.stories.d.ts +3 -4
  86. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  87. package/dist/types/src/stories/EditorToolbar.stories.d.ts +1 -2
  88. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  89. package/dist/types/src/stories/Experimental.stories.d.ts +3 -4
  90. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  91. package/dist/types/src/stories/Markdown.stories.d.ts +3 -4
  92. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  93. package/dist/types/src/stories/Outliner.stories.d.ts +0 -1
  94. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  95. package/dist/types/src/stories/{CommandMenu.stories.d.ts → Popover.stories.d.ts} +6 -6
  96. package/dist/types/src/stories/Popover.stories.d.ts.map +1 -0
  97. package/dist/types/src/stories/Preview.stories.d.ts +3 -4
  98. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  99. package/dist/types/src/stories/Tags.stories.d.ts +0 -1
  100. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -1
  101. package/dist/types/src/stories/TextEditor.stories.d.ts +3 -5
  102. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  103. package/dist/types/src/stories/components/EditorStory.d.ts +5 -5
  104. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  105. package/dist/types/src/styles/theme.d.ts.map +1 -1
  106. package/dist/types/src/testing/PreviewPopover.d.ts +20 -0
  107. package/dist/types/src/testing/PreviewPopover.d.ts.map +1 -0
  108. package/dist/types/src/testing/index.d.ts +1 -0
  109. package/dist/types/src/testing/index.d.ts.map +1 -1
  110. package/dist/types/src/types/types.d.ts +1 -1
  111. package/dist/types/src/types/types.d.ts.map +1 -1
  112. package/dist/types/src/util/index.d.ts +0 -1
  113. package/dist/types/src/util/index.d.ts.map +1 -1
  114. package/dist/types/tsconfig.tsbuildinfo +1 -1
  115. package/package.json +55 -52
  116. package/src/components/Editor/Editor.stories.tsx +69 -0
  117. package/src/components/Editor/Editor.tsx +57 -14
  118. package/src/components/EditorToolbar/EditorToolbar.tsx +1 -0
  119. package/src/components/index.ts +0 -1
  120. package/src/extensions/{autocomplete.ts → autocomplete/autocomplete.ts} +2 -1
  121. package/src/extensions/autocomplete/index.ts +8 -0
  122. package/src/extensions/autocomplete/match.ts +46 -0
  123. package/src/extensions/{command → autocomplete}/placeholder.ts +21 -17
  124. package/src/extensions/{command → autocomplete}/typeahead.ts +6 -48
  125. package/src/extensions/automerge/automerge.stories.tsx +8 -8
  126. package/src/extensions/automerge/automerge.ts +28 -9
  127. package/src/extensions/automerge/sync.ts +7 -3
  128. package/src/extensions/autoscroll.ts +43 -37
  129. package/src/extensions/factories.ts +41 -12
  130. package/src/extensions/focus.ts +5 -4
  131. package/src/extensions/folding.tsx +4 -6
  132. package/src/extensions/hashtag.tsx +2 -2
  133. package/src/extensions/index.ts +2 -1
  134. package/src/extensions/json.ts +1 -1
  135. package/src/extensions/markdown/bundle.ts +16 -4
  136. package/src/extensions/markdown/decorate.ts +1 -0
  137. package/src/extensions/markdown/link.ts +3 -0
  138. package/src/extensions/modes.ts +2 -2
  139. package/src/extensions/{command/floating-menu.ts → outliner/menu.ts} +15 -20
  140. package/src/extensions/outliner/outliner.ts +3 -3
  141. package/src/extensions/popover/PopoverMenuProvider.tsx +221 -0
  142. package/src/extensions/popover/index.ts +12 -0
  143. package/src/extensions/popover/menu-presets.ts +124 -0
  144. package/src/extensions/popover/menu.ts +67 -0
  145. package/src/extensions/popover/modal.ts +24 -0
  146. package/src/extensions/popover/popover.ts +291 -0
  147. package/src/extensions/popover/usePopoverMenu.ts +173 -0
  148. package/src/extensions/popover/util.ts +29 -0
  149. package/src/extensions/preview/index.ts +1 -1
  150. package/src/extensions/preview/preview.ts +0 -5
  151. package/src/extensions/selection.ts +2 -2
  152. package/src/extensions/state.ts +7 -0
  153. package/src/extensions/tags/streamer.ts +4 -5
  154. package/src/extensions/tags/xml-tags.ts +59 -1
  155. package/src/hooks/useTextEditor.ts +27 -39
  156. package/src/stories/{Command.stories.tsx → CommandDialog.stories.tsx} +10 -22
  157. package/src/stories/Comments.stories.tsx +5 -5
  158. package/src/stories/EditorToolbar.stories.tsx +6 -5
  159. package/src/stories/Experimental.stories.tsx +6 -6
  160. package/src/stories/Markdown.stories.tsx +5 -5
  161. package/src/stories/Outliner.stories.tsx +42 -26
  162. package/src/stories/Popover.stories.tsx +163 -0
  163. package/src/stories/Preview.stories.tsx +9 -9
  164. package/src/stories/Tags.stories.tsx +5 -5
  165. package/src/stories/TextEditor.stories.tsx +7 -32
  166. package/src/stories/components/EditorStory.tsx +7 -5
  167. package/src/styles/theme.ts +12 -10
  168. package/src/{components/Popover/RefDropdownMenu.tsx → testing/PreviewPopover.tsx} +20 -29
  169. package/src/testing/index.ts +1 -0
  170. package/src/types/types.ts +1 -1
  171. package/src/util/index.ts +0 -1
  172. package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +0 -7
  173. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +0 -7
  174. package/dist/types/src/components/Popover/CommandMenu.d.ts +0 -34
  175. package/dist/types/src/components/Popover/CommandMenu.d.ts.map +0 -1
  176. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +0 -14
  177. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +0 -1
  178. package/dist/types/src/components/Popover/RefPopover.d.ts +0 -37
  179. package/dist/types/src/components/Popover/RefPopover.d.ts.map +0 -1
  180. package/dist/types/src/components/Popover/index.d.ts +0 -4
  181. package/dist/types/src/components/Popover/index.d.ts.map +0 -1
  182. package/dist/types/src/extensions/autocomplete.d.ts.map +0 -1
  183. package/dist/types/src/extensions/command/action.d.ts +0 -17
  184. package/dist/types/src/extensions/command/action.d.ts.map +0 -1
  185. package/dist/types/src/extensions/command/command-menu.d.ts +0 -20
  186. package/dist/types/src/extensions/command/command-menu.d.ts.map +0 -1
  187. package/dist/types/src/extensions/command/command.d.ts +0 -6
  188. package/dist/types/src/extensions/command/command.d.ts.map +0 -1
  189. package/dist/types/src/extensions/command/floating-menu.d.ts +0 -7
  190. package/dist/types/src/extensions/command/floating-menu.d.ts.map +0 -1
  191. package/dist/types/src/extensions/command/hint.d.ts +0 -19
  192. package/dist/types/src/extensions/command/hint.d.ts.map +0 -1
  193. package/dist/types/src/extensions/command/index.d.ts +0 -7
  194. package/dist/types/src/extensions/command/index.d.ts.map +0 -1
  195. package/dist/types/src/extensions/command/placeholder.d.ts +0 -10
  196. package/dist/types/src/extensions/command/placeholder.d.ts.map +0 -1
  197. package/dist/types/src/extensions/command/state.d.ts +0 -16
  198. package/dist/types/src/extensions/command/state.d.ts.map +0 -1
  199. package/dist/types/src/extensions/command/typeahead.d.ts +0 -22
  200. package/dist/types/src/extensions/command/typeahead.d.ts.map +0 -1
  201. package/dist/types/src/extensions/command/useCommandMenu.d.ts +0 -26
  202. package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +0 -1
  203. package/dist/types/src/stories/Command.stories.d.ts.map +0 -1
  204. package/dist/types/src/stories/CommandMenu.stories.d.ts.map +0 -1
  205. package/dist/types/src/util/domino.d.ts +0 -18
  206. package/dist/types/src/util/domino.d.ts.map +0 -1
  207. package/src/components/Popover/CommandMenu.tsx +0 -279
  208. package/src/components/Popover/RefPopover.tsx +0 -117
  209. package/src/components/Popover/index.ts +0 -7
  210. package/src/extensions/command/action.ts +0 -56
  211. package/src/extensions/command/command-menu.ts +0 -211
  212. package/src/extensions/command/command.ts +0 -34
  213. package/src/extensions/command/hint.ts +0 -103
  214. package/src/extensions/command/index.ts +0 -10
  215. package/src/extensions/command/state.ts +0 -90
  216. package/src/extensions/command/useCommandMenu.ts +0 -119
  217. package/src/stories/CommandMenu.stories.tsx +0 -160
  218. package/src/util/domino.ts +0 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/react-ui-editor",
3
- "version": "0.8.4-main.dedc0f3",
3
+ "version": "0.8.4-main.ead640a",
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",
@@ -37,9 +37,10 @@
37
37
  "src"
38
38
  ],
39
39
  "dependencies": {
40
- "@automerge/automerge": "3.1.1",
41
- "@codemirror/autocomplete": "^6.18.7",
40
+ "@automerge/automerge": "3.1.2",
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",
@@ -50,17 +51,19 @@
50
51
  "@codemirror/search": "^6.5.11",
51
52
  "@codemirror/state": "^6.5.2",
52
53
  "@codemirror/theme-one-dark": "^6.1.3",
53
- "@codemirror/view": "^6.38.2",
54
+ "@codemirror/view": "^6.38.4",
54
55
  "@fluentui/react-tabster": "^9.24.2",
55
56
  "@lezer/common": "^1.2.2",
56
57
  "@lezer/generator": "^1.7.1",
57
58
  "@lezer/highlight": "^1.2.1",
58
59
  "@lezer/markdown": "^1.3.1",
59
60
  "@preact-signals/safe-react": "^0.9.0",
60
- "@preact/signals-react": "^3.2.0",
61
+ "@preact/signals-react": "^3.3.0",
61
62
  "@radix-ui/react-context": "1.1.1",
63
+ "@radix-ui/react-use-controllable-state": "1.1.0",
62
64
  "@replit/codemirror-vim": "^6.2.1",
63
65
  "@replit/codemirror-vscode-keymap": "^6.0.2",
66
+ "@uiw/codemirror-theme-vscode": "^4.25.2",
64
67
  "ajv": "^8.17.1",
65
68
  "codemirror": "^6.0.1",
66
69
  "lib0": "^0.2.65",
@@ -68,72 +71,72 @@
68
71
  "lodash.merge": "^4.6.2",
69
72
  "lodash.sortby": "^4.7.0",
70
73
  "style-mod": "^4.1.0",
71
- "@dxos/app-graph": "0.8.4-main.dedc0f3",
72
- "@dxos/async": "0.8.4-main.dedc0f3",
73
- "@dxos/context": "0.8.4-main.dedc0f3",
74
- "@dxos/display-name": "0.8.4-main.dedc0f3",
75
- "@dxos/echo-schema": "0.8.4-main.dedc0f3",
76
- "@dxos/invariant": "0.8.4-main.dedc0f3",
77
- "@dxos/debug": "0.8.4-main.dedc0f3",
78
- "@dxos/lit-ui": "0.8.4-main.dedc0f3",
79
- "@dxos/live-object": "0.8.4-main.dedc0f3",
80
- "@dxos/log": "0.8.4-main.dedc0f3",
81
- "@dxos/protocols": "0.8.4-main.dedc0f3",
82
- "@dxos/react-hooks": "0.8.4-main.dedc0f3",
83
- "@dxos/react-ui-stack": "0.8.4-main.dedc0f3",
84
- "@dxos/react-ui-menu": "0.8.4-main.dedc0f3",
85
- "@dxos/react-ui-types": "0.8.4-main.dedc0f3",
86
- "@dxos/util": "0.8.4-main.dedc0f3"
74
+ "@dxos/app-graph": "0.8.4-main.ead640a",
75
+ "@dxos/async": "0.8.4-main.ead640a",
76
+ "@dxos/debug": "0.8.4-main.ead640a",
77
+ "@dxos/display-name": "0.8.4-main.ead640a",
78
+ "@dxos/echo": "0.8.4-main.ead640a",
79
+ "@dxos/invariant": "0.8.4-main.ead640a",
80
+ "@dxos/lit-ui": "0.8.4-main.ead640a",
81
+ "@dxos/log": "0.8.4-main.ead640a",
82
+ "@dxos/protocols": "0.8.4-main.ead640a",
83
+ "@dxos/react-hooks": "0.8.4-main.ead640a",
84
+ "@dxos/react-ui-menu": "0.8.4-main.ead640a",
85
+ "@dxos/live-object": "0.8.4-main.ead640a",
86
+ "@dxos/react-ui-types": "0.8.4-main.ead640a",
87
+ "@dxos/util": "0.8.4-main.ead640a",
88
+ "@dxos/context": "0.8.4-main.ead640a",
89
+ "@dxos/react-ui-stack": "0.8.4-main.ead640a"
87
90
  },
88
91
  "devDependencies": {
89
- "@automerge/automerge": "3.1.1",
90
- "@automerge/automerge-repo": "2.3.0-alpha.0",
91
- "@automerge/automerge-repo-network-broadcastchannel": "2.3.0-alpha.0",
92
- "@effect-rx/rx-react": "0.38.0",
93
- "@effect/platform": "0.90.2",
92
+ "@automerge/automerge": "3.1.2",
93
+ "@automerge/automerge-repo": "2.3.1",
94
+ "@automerge/automerge-repo-network-broadcastchannel": "2.3.1",
95
+ "@effect-rx/rx-react": "0.42.4",
96
+ "@effect/platform": "0.92.1",
94
97
  "@types/chai": "^4.2.15",
95
98
  "@types/chai-dom": "^1.11.0",
96
99
  "@types/lodash.defaultsdeep": "^4.6.6",
97
100
  "@types/lodash.merge": "^4.6.6",
98
101
  "@types/lodash.sortby": "^4.7.7",
99
- "@types/react": "~18.2.0",
100
- "@types/react-dom": "~18.2.0",
102
+ "@types/react": "~19.2.2",
103
+ "@types/react-dom": "~19.2.1",
101
104
  "@types/react-test-renderer": "^17.0.2",
102
105
  "chai": "^4.4.1",
103
106
  "chai-dom": "^1.11.0",
104
- "effect": "3.17.7",
107
+ "effect": "3.18.3",
105
108
  "happy-dom": "^13.3.1",
106
- "jsdom": "^24.0.0",
109
+ "jsdom": "^27.0.0",
107
110
  "mocha": "^10.6.0",
108
- "react": "~18.2.0",
109
- "react-dom": "~18.2.0",
110
- "react-test-renderer": "~18.2.0",
111
- "vite": "7.1.1",
111
+ "react": "~19.2.0",
112
+ "react-dom": "~19.2.0",
113
+ "react-test-renderer": "~19.2.0",
114
+ "vite": "7.1.9",
112
115
  "vite-plugin-top-level-await": "^1.6.0",
113
116
  "vite-plugin-wasm": "^3.5.0",
114
- "@dxos/config": "0.8.4-main.dedc0f3",
115
- "@dxos/echo": "0.8.4-main.dedc0f3",
116
- "@dxos/echo-signals": "0.8.4-main.dedc0f3",
117
- "@dxos/keyboard": "0.8.4-main.dedc0f3",
118
- "@dxos/random": "0.8.4-main.dedc0f3",
119
- "@dxos/react-client": "0.8.4-main.dedc0f3",
120
- "@dxos/react-ui": "0.8.4-main.dedc0f3",
121
- "@dxos/react-ui-stack": "0.8.4-main.dedc0f3",
122
- "@dxos/react-ui-theme": "0.8.4-main.dedc0f3",
123
- "@dxos/react-ui-attention": "0.8.4-main.dedc0f3",
124
- "@dxos/schema": "0.8.4-main.dedc0f3",
125
- "@dxos/storybook-utils": "0.8.4-main.dedc0f3",
126
- "@dxos/react-ui-syntax-highlighter": "0.8.4-main.dedc0f3"
117
+ "@dxos/config": "0.8.4-main.ead640a",
118
+ "@dxos/echo": "0.8.4-main.ead640a",
119
+ "@dxos/echo-signals": "0.8.4-main.ead640a",
120
+ "@dxos/keyboard": "0.8.4-main.ead640a",
121
+ "@dxos/random": "0.8.4-main.ead640a",
122
+ "@dxos/react-client": "0.8.4-main.ead640a",
123
+ "@dxos/react-ui": "0.8.4-main.ead640a",
124
+ "@dxos/react-ui-attention": "0.8.4-main.ead640a",
125
+ "@dxos/react-ui-stack": "0.8.4-main.ead640a",
126
+ "@dxos/react-ui-syntax-highlighter": "0.8.4-main.ead640a",
127
+ "@dxos/react-ui-theme": "0.8.4-main.ead640a",
128
+ "@dxos/schema": "0.8.4-main.ead640a",
129
+ "@dxos/storybook-utils": "0.8.4-main.ead640a"
127
130
  },
128
131
  "peerDependencies": {
129
132
  "@effect-rx/rx-react": "^0.34.1",
130
133
  "@effect/platform": "^0.80.12",
131
134
  "effect": "^3.13.3",
132
- "react": "~18.2.0",
133
- "react-dom": "~18.2.0",
134
- "@dxos/react-client": "0.8.4-main.dedc0f3",
135
- "@dxos/react-ui": "0.8.4-main.dedc0f3",
136
- "@dxos/react-ui-theme": "0.8.4-main.dedc0f3"
135
+ "react": "^19.0.0",
136
+ "react-dom": "^19.0.0",
137
+ "@dxos/react-client": "0.8.4-main.ead640a",
138
+ "@dxos/react-ui-theme": "0.8.4-main.ead640a",
139
+ "@dxos/react-ui": "0.8.4-main.ead640a"
137
140
  },
138
141
  "publishConfig": {
139
142
  "access": "public"
@@ -0,0 +1,69 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React from 'react';
7
+ import { useMemo } from 'react';
8
+
9
+ import { createDocAccessor, createObject } from '@dxos/client/echo';
10
+ import { useThemeContext } from '@dxos/react-ui';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
+ import { DataType } from '@dxos/schema';
13
+
14
+ import { automerge, createBasicExtensions, createThemeExtensions } from '../../extensions';
15
+ import { Editor } from '../Editor';
16
+
17
+ const meta = {
18
+ title: 'ui/react-ui-editor/Editor',
19
+ component: Editor,
20
+ decorators: [withTheme, withLayout({ container: 'column' })],
21
+ } satisfies Meta<typeof Editor>;
22
+
23
+ export default meta;
24
+
25
+ type Story = StoryObj<typeof meta>;
26
+
27
+ export const Default: Story = {
28
+ render: (args) => {
29
+ const { themeMode } = useThemeContext();
30
+ const extensions = useMemo(
31
+ () => [
32
+ // Basic extensions.
33
+ createBasicExtensions(),
34
+ createThemeExtensions({ themeMode }),
35
+ ],
36
+ [],
37
+ );
38
+
39
+ return <Editor classNames='p-2' {...args} extensions={extensions} />;
40
+ },
41
+ args: {
42
+ moveToEnd: true,
43
+ value: 'Hello world!',
44
+ onChange: (value) => console.log(value),
45
+ },
46
+ };
47
+
48
+ export const Automerge: Story = {
49
+ render: ({ value, ...props }) => {
50
+ const { themeMode } = useThemeContext();
51
+ const extensions = useMemo(
52
+ () => [
53
+ // Basic extensions.
54
+ createBasicExtensions(),
55
+ createThemeExtensions({ themeMode }),
56
+ automerge(createDocAccessor(createObject(DataType.makeText(value)), ['content'])),
57
+ ],
58
+ [],
59
+ );
60
+
61
+ // TODO(burdon): Remove the need for initialValue.
62
+ return <Editor classNames='p-2' {...props} initialValue={value} extensions={extensions} />;
63
+ },
64
+ args: {
65
+ moveToEnd: true,
66
+ value: 'Hello world!',
67
+ onChange: (value) => console.log(value),
68
+ },
69
+ };
@@ -2,38 +2,81 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type EditorView } from '@codemirror/view';
6
- import React, { forwardRef, useImperativeHandle } from 'react';
5
+ import { Transaction } from '@codemirror/state';
6
+ import { EditorView } from '@codemirror/view';
7
+ import React, { forwardRef, useEffect, useImperativeHandle } from 'react';
7
8
 
8
- import { type ThemedClassName, useThemeContext } from '@dxos/react-ui';
9
+ import { type ThemedClassName } from '@dxos/react-ui';
9
10
  import { mx } from '@dxos/react-ui-theme';
10
- import { type DataType } from '@dxos/schema';
11
11
 
12
+ import { initialSync } from '../../extensions';
12
13
  import { type UseTextEditorProps, useTextEditor } from '../../hooks';
13
14
 
15
+ // TODO(burdon): Convert to radix-style (support hooks inside).
16
+ // <Editor.Root>
17
+ // <Editor.Toolbar />
18
+ // <Editor.TextEditor />
19
+ // </Editor.Root>
20
+
21
+ export type EditorController = {
22
+ view: EditorView | null;
23
+ focus: () => void;
24
+ };
25
+
14
26
  export type EditorProps = ThemedClassName<
15
27
  {
16
- id: string;
17
- text: DataType.Text;
18
- } & Omit<UseTextEditorProps, 'id'>
28
+ moveToEnd?: boolean;
29
+ value?: string;
30
+ onChange?: (value: string) => void;
31
+ } & UseTextEditorProps
19
32
  >;
20
33
 
21
34
  /**
22
35
  * Minimal text editor.
36
+ * NOTE: This shouold not be used with the automerge extension.
23
37
  */
24
- export const Editor = forwardRef<EditorView | undefined, EditorProps>(
25
- ({ classNames, id, text, ...props }, forwardedRef) => {
26
- const { themeMode } = useThemeContext();
38
+ export const Editor = forwardRef<EditorController, EditorProps>(
39
+ ({ classNames, id, extensions, moveToEnd, value, onChange, ...props }, forwardedRef) => {
27
40
  const { parentRef, focusAttributes, view } = useTextEditor(
28
41
  () => ({
29
42
  id,
30
- initialValue: text.content,
43
+ initialValue: value,
44
+ extensions: [
45
+ extensions ?? [],
46
+ EditorView.updateListener.of(({ view, docChanged, transactions }) => {
47
+ const isInitialSync = transactions.some((tr) => tr.annotation(Transaction.userEvent) === initialSync.value);
48
+ if (!isInitialSync && docChanged) {
49
+ onChange?.(view.state.doc.toString());
50
+ }
51
+ }),
52
+ ],
31
53
  ...props,
32
54
  }),
33
- [id, text, themeMode],
55
+ [id, extensions, onChange],
34
56
  );
35
57
 
36
- useImperativeHandle(forwardedRef, () => view, [view]);
37
- return <div ref={parentRef} className={mx(classNames)} {...focusAttributes} />;
58
+ // External controller.
59
+ useImperativeHandle(
60
+ forwardedRef,
61
+ () => ({
62
+ view,
63
+ focus: () => view?.focus(),
64
+ }),
65
+ [view],
66
+ );
67
+
68
+ // Set initial value and cursor position.
69
+ useEffect(() => {
70
+ requestAnimationFrame(() => {
71
+ view?.dispatch({
72
+ annotations: initialSync,
73
+ changes: value ? [{ from: 0, to: view?.state.doc.length ?? 0, insert: value ?? '' }] : [],
74
+ selection: moveToEnd ? { anchor: view?.state.doc.length ?? 0 } : undefined,
75
+ });
76
+ view?.focus();
77
+ });
78
+ }, [view, value, moveToEnd]);
79
+
80
+ return <div role='none' className={mx('is-full', classNames)} {...focusAttributes} ref={parentRef} />;
38
81
  },
39
82
  );
@@ -124,6 +124,7 @@ const useEditorToolbarActionGraph = (props: EditorToolbarProps) => {
124
124
 
125
125
  export const EditorToolbar = memo(({ classNames, attendableId, role, ...props }: EditorToolbarProps) => {
126
126
  const menuProps = useEditorToolbarActionGraph(props);
127
+
127
128
  return (
128
129
  <ElevationProvider elevation={role === 'section' ? 'positioned' : 'base'}>
129
130
  <MenuProvider {...menuProps} attendableId={attendableId}>
@@ -4,4 +4,3 @@
4
4
 
5
5
  export * from './Editor';
6
6
  export * from './EditorToolbar';
7
- export * from './Popover';
@@ -40,7 +40,8 @@ export type AutocompleteOptions = {
40
40
  * Creates an autocomplete extension that shows inline suggestions.
41
41
  * Pressing Tab will complete the suggestion.
42
42
  */
43
- export const autocomplete = ({ fireIfEmpty, onSubmit, onSuggest, onCancel }: AutocompleteOptions): Extension => {
43
+ // TODO(burdon): Reconcile with typeahead.
44
+ export const autocomplete = ({ fireIfEmpty, onSubmit, onSuggest, onCancel }: AutocompleteOptions = {}): Extension => {
44
45
  const suggest = ViewPlugin.fromClass(
45
46
  class {
46
47
  _decorations: DecorationSet;
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './autocomplete';
6
+ export * from './match';
7
+ export * from './placeholder';
8
+ export * from './typeahead';
@@ -0,0 +1,46 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export type CompoetionContext = { line: string };
6
+
7
+ export type CompletionOptions = {
8
+ default?: string;
9
+ minLength?: number;
10
+ };
11
+
12
+ /**
13
+ * Util to match current line to a static list of completions.
14
+ */
15
+ export const staticCompletion =
16
+ (completions: string[], options: CompletionOptions = {}) =>
17
+ ({ line }: CompoetionContext) => {
18
+ if (line.length === 0 && options.default) {
19
+ return options.default;
20
+ }
21
+
22
+ const parts = line.split(/\s+/).filter(Boolean);
23
+ if (parts.length) {
24
+ const str = parts.at(-1)!;
25
+ if (str.length >= (options.minLength ?? 0)) {
26
+ for (const completion of completions) {
27
+ const match = matchCompletion(completion, str);
28
+ if (match) {
29
+ return match;
30
+ }
31
+ }
32
+ }
33
+ }
34
+ };
35
+
36
+ export const matchCompletion = (completion: string, str: string, minLength = 0): string | undefined => {
37
+ if (
38
+ str.length >= minLength &&
39
+ completion.length > str.length &&
40
+ completion.startsWith(str)
41
+ // TODO(burdon): If case insensitive, need to replace existing chars.
42
+ // completion.toLowerCase().startsWith(str.toLowerCase())
43
+ ) {
44
+ return completion.slice(str.length);
45
+ }
46
+ };
@@ -11,20 +11,23 @@ import { clientRectsFor, flattenRect } from '../../util';
11
11
  type Content = string | HTMLElement | ((view: EditorView) => HTMLElement);
12
12
 
13
13
  export type PlaceholderOptions = {
14
- delay?: number;
15
14
  content: Content;
15
+ delay?: number;
16
16
  };
17
17
 
18
- export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Extension => {
18
+ /**
19
+ * Shows a transient placeholder at the current cursor position.
20
+ */
21
+ export const placeholder = ({ content, delay = 3_000 }: PlaceholderOptions): Extension => {
19
22
  const plugin = ViewPlugin.fromClass(
20
23
  class {
21
- decorations = Decoration.none;
22
- timeout: ReturnType<typeof setTimeout> | undefined;
24
+ _timeout: ReturnType<typeof setTimeout> | undefined;
25
+ _decorations = Decoration.none;
23
26
 
24
27
  update(update: ViewUpdate) {
25
- if (this.timeout) {
26
- window.clearTimeout(this.timeout);
27
- this.timeout = undefined;
28
+ if (this._timeout) {
29
+ window.clearTimeout(this._timeout);
30
+ this._timeout = undefined;
28
31
  }
29
32
 
30
33
  // Check if the active line (where cursor is) is empty.
@@ -33,10 +36,10 @@ export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Ext
33
36
  if (isEmpty) {
34
37
  // Create widget decoration at the start of the current line.
35
38
  const lineStart = activeLine.from;
36
- this.timeout = setTimeout(() => {
37
- this.decorations = Decoration.set([
39
+ this._timeout = setTimeout(() => {
40
+ this._decorations = Decoration.set([
38
41
  Decoration.widget({
39
- widget: new Placeholder(content),
42
+ widget: new PlaceholderWidget(content),
40
43
  side: 1,
41
44
  }).range(lineStart),
42
45
  ]);
@@ -45,18 +48,18 @@ export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Ext
45
48
  }, delay);
46
49
  }
47
50
 
48
- this.decorations = Decoration.none;
51
+ this._decorations = Decoration.none;
49
52
  }
50
53
 
51
54
  destroy() {
52
- if (this.timeout) {
53
- clearTimeout(this.timeout);
55
+ if (this._timeout) {
56
+ clearTimeout(this._timeout);
54
57
  }
55
58
  }
56
59
  },
57
60
  {
58
61
  provide: (plugin) => {
59
- return [EditorView.decorations.of((view) => view.plugin(plugin)?.decorations ?? Decoration.none)];
62
+ return [EditorView.decorations.of((view) => view.plugin(plugin)?._decorations ?? Decoration.none)];
60
63
  },
61
64
  },
62
65
  );
@@ -66,7 +69,7 @@ export const placeholder = ({ delay = 3_000, content }: PlaceholderOptions): Ext
66
69
  : plugin;
67
70
  };
68
71
 
69
- class Placeholder extends WidgetType {
72
+ export class PlaceholderWidget extends WidgetType {
70
73
  constructor(readonly content: Content) {
71
74
  super();
72
75
  }
@@ -75,6 +78,7 @@ class Placeholder extends WidgetType {
75
78
  const wrap = document.createElement('span');
76
79
  wrap.className = 'cm-placeholder';
77
80
  wrap.style.pointerEvents = 'none';
81
+ wrap.setAttribute('aria-hidden', 'true');
78
82
  wrap.appendChild(
79
83
  typeof this.content === 'string'
80
84
  ? document.createTextNode(this.content)
@@ -82,7 +86,7 @@ class Placeholder extends WidgetType {
82
86
  ? this.content(view)
83
87
  : this.content.cloneNode(true),
84
88
  );
85
- wrap.setAttribute('aria-hidden', 'true');
89
+
86
90
  return wrap;
87
91
  }
88
92
 
@@ -92,7 +96,7 @@ class Placeholder extends WidgetType {
92
96
  return null;
93
97
  }
94
98
 
95
- const style = window.getComputedStyle(dom.parentNode as HTMLElement);
99
+ const style = getComputedStyle(dom.parentNode as HTMLElement);
96
100
  const rect = flattenRect(rects[0], style.direction !== 'rtl');
97
101
  const lineHeight = parseInt(style.lineHeight);
98
102
  if (rect.bottom - rect.top > lineHeight * 1.5) {
@@ -13,17 +13,16 @@ import {
13
13
  keymap,
14
14
  } from '@codemirror/view';
15
15
 
16
- import { Hint } from './hint';
16
+ import { type CompoetionContext } from './match';
17
+ import { PlaceholderWidget } from './placeholder';
17
18
 
18
- export type TypeaheadContext = { line: string };
19
-
20
- // TODO(burdon): Option to complete only at end of line?
19
+ // TODO(burdon): Option to complete only at end of line.
21
20
  export type TypeaheadOptions = {
22
- onComplete?: (context: TypeaheadContext) => string | undefined;
21
+ onComplete?: (context: CompoetionContext) => string | undefined;
23
22
  };
24
23
 
25
24
  /**
26
- * CodeMirror extension for typeahead completion.
25
+ * Shows a completion placeholder.
27
26
  */
28
27
  export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
29
28
  let hint: string | undefined;
@@ -57,7 +56,7 @@ export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
57
56
  const str = update.state.sliceDoc(line.from, selection.from);
58
57
  hint = onComplete?.({ line: str });
59
58
  if (hint) {
60
- builder.add(selection.from, selection.to, Decoration.widget({ widget: new Hint(hint) }));
59
+ builder.add(selection.from, selection.to, Decoration.widget({ widget: new PlaceholderWidget(hint) }));
61
60
  }
62
61
  }
63
62
 
@@ -86,44 +85,3 @@ export const typeahead = ({ onComplete }: TypeaheadOptions = {}): Extension => {
86
85
  ),
87
86
  ];
88
87
  };
89
-
90
- type CompletionOptions = {
91
- default?: string;
92
- minLength?: number;
93
- };
94
-
95
- /**
96
- * Util to match current line to a static list of completions.
97
- */
98
- export const staticCompletion =
99
- (completions: string[], options: CompletionOptions = {}) =>
100
- ({ line }: TypeaheadContext) => {
101
- if (line.length === 0 && options.default) {
102
- return options.default;
103
- }
104
-
105
- const parts = line.split(/\s+/).filter(Boolean);
106
- if (parts.length) {
107
- const str = parts.at(-1)!;
108
- if (str.length >= (options.minLength ?? 0)) {
109
- for (const completion of completions) {
110
- const match = matchCompletion(completion, str);
111
- if (match) {
112
- return match;
113
- }
114
- }
115
- }
116
- }
117
- };
118
-
119
- export const matchCompletion = (completion: string, str: string, minLength = 0): string | undefined => {
120
- if (
121
- str.length >= minLength &&
122
- completion.length > str.length &&
123
- completion.startsWith(str)
124
- // TODO(burdon): If case insensitive, need to replace existing chars.
125
- // completion.toLowerCase().startsWith(str.toLowerCase())
126
- ) {
127
- return completion.slice(str.length);
128
- }
129
- };
@@ -2,8 +2,6 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import '@dxos-theme';
6
-
7
5
  import '@preact/signals-react';
8
6
 
9
7
  import { Repo } from '@automerge/automerge-repo';
@@ -16,7 +14,8 @@ import { DocAccessor, Query, type Space, createDocAccessor, useQuery, useSpace }
16
14
  import { type Identity, useIdentity } from '@dxos/react-client/halo';
17
15
  import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
18
16
  import { useThemeContext } from '@dxos/react-ui';
19
- import { render, withLayout, withTheme } from '@dxos/storybook-utils';
17
+ import { withTheme } from '@dxos/react-ui/testing';
18
+ import { render } from '@dxos/storybook-utils';
20
19
 
21
20
  import { editorSlots } from '../../defaults';
22
21
  import { useTextEditor } from '../../hooks';
@@ -96,8 +95,9 @@ const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
96
95
  const objects = useQuery(space, Query.type(Type.Expando, { type: 'test' }));
97
96
 
98
97
  useEffect(() => {
99
- if (!source && objects.length) {
100
- const source = createDocAccessor(objects[0].content, ['content']);
98
+ const content = objects[0]?.content.target;
99
+ if (!source && content) {
100
+ const source = createDocAccessor(content, ['content']);
101
101
  setSource(source);
102
102
  }
103
103
  }, [objects, source]);
@@ -113,8 +113,9 @@ const meta = {
113
113
  title: 'ui/react-ui-editor/Automerge',
114
114
  component: Editor as any,
115
115
  render: render(DefaultStory),
116
- decorators: [withTheme, withLayout({ fullscreen: true })],
116
+ decorators: [withTheme],
117
117
  parameters: {
118
+ layout: 'fullscreen',
118
119
  translations,
119
120
  },
120
121
  } satisfies Meta<typeof DefaultStory>;
@@ -128,14 +129,13 @@ export const Default: Story = {
128
129
  };
129
130
 
130
131
  export const WithEcho: Story = {
131
- decorators: [withTheme],
132
132
  render: () => {
133
133
  return (
134
134
  <ClientRepeater
135
135
  count={2}
136
136
  component={EchoStory}
137
137
  createSpace
138
- onSpaceCreated={async ({ space }) => {
138
+ onCreateSpace={async ({ space }) => {
139
139
  space.db.add(
140
140
  Obj.make(Type.Expando, {
141
141
  type: 'test',