@dxos/react-ui-editor 0.8.3 → 0.8.4-main.1da679c

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 (269) hide show
  1. package/dist/lib/browser/chunk-22UMM3QJ.mjs +22 -0
  2. package/dist/lib/browser/chunk-22UMM3QJ.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +2502 -1384
  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 +72 -2
  7. package/dist/lib/browser/testing/index.mjs.map +4 -4
  8. package/dist/lib/browser/types/index.mjs +13 -0
  9. package/dist/lib/browser/types/index.mjs.map +7 -0
  10. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs +24 -0
  11. package/dist/lib/node-esm/chunk-YXYQPV6R.mjs.map +7 -0
  12. package/dist/lib/node-esm/index.mjs +2504 -1387
  13. package/dist/lib/node-esm/index.mjs.map +4 -4
  14. package/dist/lib/node-esm/meta.json +1 -1
  15. package/dist/lib/node-esm/testing/index.mjs +72 -2
  16. package/dist/lib/node-esm/testing/index.mjs.map +4 -4
  17. package/dist/lib/node-esm/types/index.mjs +14 -0
  18. package/dist/lib/node-esm/types/index.mjs.map +7 -0
  19. package/dist/types/src/components/{Popover → CommandMenu}/CommandMenu.d.ts +10 -6
  20. package/dist/types/src/components/CommandMenu/CommandMenu.d.ts.map +1 -0
  21. package/dist/types/src/components/CommandMenu/index.d.ts +2 -0
  22. package/dist/types/src/components/CommandMenu/index.d.ts.map +1 -0
  23. package/dist/types/src/components/Editor/Editor.d.ts +19 -0
  24. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -0
  25. package/dist/types/src/components/Editor/index.d.ts +2 -0
  26. package/dist/types/src/components/Editor/index.d.ts.map +1 -0
  27. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  28. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  29. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  30. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  31. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
  32. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
  33. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
  34. package/dist/types/src/components/EditorToolbar/util.d.ts +6 -5
  35. package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
  36. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +1 -1
  37. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  38. package/dist/types/src/components/index.d.ts +2 -1
  39. package/dist/types/src/components/index.d.ts.map +1 -1
  40. package/dist/types/src/defaults.d.ts.map +1 -1
  41. package/dist/types/src/extensions/autocomplete.d.ts +20 -7
  42. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  43. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  44. package/dist/types/src/extensions/automerge/automerge.stories.d.ts +36 -45
  45. package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
  46. package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
  47. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  48. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  49. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  50. package/dist/types/src/extensions/autoscroll.d.ts +10 -0
  51. package/dist/types/src/extensions/autoscroll.d.ts.map +1 -0
  52. package/dist/types/src/extensions/blast.d.ts.map +1 -1
  53. package/dist/types/src/extensions/command/action.d.ts +1 -1
  54. package/dist/types/src/extensions/command/action.d.ts.map +1 -1
  55. package/dist/types/src/extensions/command/command-menu.d.ts +1 -1
  56. package/dist/types/src/extensions/command/command-menu.d.ts.map +1 -1
  57. package/dist/types/src/extensions/command/command.d.ts.map +1 -1
  58. package/dist/types/src/extensions/command/floating-menu.d.ts.map +1 -1
  59. package/dist/types/src/extensions/command/hint.d.ts +2 -7
  60. package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
  61. package/dist/types/src/extensions/command/index.d.ts +1 -1
  62. package/dist/types/src/extensions/command/index.d.ts.map +1 -1
  63. package/dist/types/src/extensions/command/state.d.ts +1 -1
  64. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  65. package/dist/types/src/extensions/command/typeahead.d.ts +7 -2
  66. package/dist/types/src/extensions/command/typeahead.d.ts.map +1 -1
  67. package/dist/types/src/extensions/command/useCommandMenu.d.ts +3 -4
  68. package/dist/types/src/extensions/command/useCommandMenu.d.ts.map +1 -1
  69. package/dist/types/src/extensions/comments.d.ts +1 -1
  70. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  71. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  72. package/dist/types/src/extensions/factories.d.ts +15 -1
  73. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  74. package/dist/types/src/extensions/index.d.ts +2 -0
  75. package/dist/types/src/extensions/index.d.ts.map +1 -1
  76. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  77. package/dist/types/src/extensions/markdown/bundle.d.ts +8 -2
  78. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  79. package/dist/types/src/extensions/markdown/changes.d.ts +1 -1
  80. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  81. package/dist/types/src/extensions/markdown/decorate.d.ts +9 -1
  82. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  83. package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
  84. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  85. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  86. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  87. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  88. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  89. package/dist/types/src/extensions/modes.d.ts +0 -7
  90. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  91. package/dist/types/src/extensions/outliner/outliner.d.ts +1 -1
  92. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  93. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -1
  94. package/dist/types/src/extensions/outliner/tree.d.ts +2 -2
  95. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -1
  96. package/dist/types/src/extensions/preview/preview.d.ts +3 -6
  97. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  98. package/dist/types/src/extensions/tags/extended-markdown.d.ts +10 -0
  99. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -0
  100. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts +2 -0
  101. package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +1 -0
  102. package/dist/types/src/extensions/tags/index.d.ts +4 -0
  103. package/dist/types/src/extensions/tags/index.d.ts.map +1 -0
  104. package/dist/types/src/extensions/tags/streamer.d.ts +12 -0
  105. package/dist/types/src/extensions/tags/streamer.d.ts.map +1 -0
  106. package/dist/types/src/extensions/tags/xml-tags.d.ts +71 -0
  107. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -0
  108. package/dist/types/src/extensions/tags/xml-util.d.ts +10 -0
  109. package/dist/types/src/extensions/tags/xml-util.d.ts.map +1 -0
  110. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  111. package/dist/types/src/index.d.ts +1 -1
  112. package/dist/types/src/index.d.ts.map +1 -1
  113. package/dist/types/src/stories/Command.stories.d.ts +12 -4
  114. package/dist/types/src/stories/Command.stories.d.ts.map +1 -1
  115. package/dist/types/src/stories/CommandMenu.stories.d.ts +11 -4
  116. package/dist/types/src/stories/CommandMenu.stories.d.ts.map +1 -1
  117. package/dist/types/src/stories/Comments.stories.d.ts +21 -9
  118. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  119. package/dist/types/src/stories/EditorToolbar.stories.d.ts +40 -3
  120. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  121. package/dist/types/src/stories/Experimental.stories.d.ts +22 -12
  122. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  123. package/dist/types/src/stories/Markdown.stories.d.ts +32 -42
  124. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  125. package/dist/types/src/stories/Outliner.stories.d.ts +15 -20
  126. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  127. package/dist/types/src/stories/Preview.stories.d.ts +21 -6
  128. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  129. package/dist/types/src/stories/Tags.stories.d.ts +17 -0
  130. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -0
  131. package/dist/types/src/stories/TextEditor.stories.d.ts +38 -51
  132. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  133. package/dist/types/src/stories/components/EditorStory.d.ts +3 -6
  134. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  135. package/dist/types/src/styles/theme.d.ts.map +1 -1
  136. package/dist/types/src/testing/PreviewPopover.d.ts +20 -0
  137. package/dist/types/src/testing/PreviewPopover.d.ts.map +1 -0
  138. package/dist/types/src/testing/index.d.ts +1 -0
  139. package/dist/types/src/testing/index.d.ts.map +1 -1
  140. package/dist/types/src/testing/util.d.ts +1 -0
  141. package/dist/types/src/testing/util.d.ts.map +1 -1
  142. package/dist/types/src/translations.d.ts +28 -29
  143. package/dist/types/src/translations.d.ts.map +1 -1
  144. package/dist/types/src/types/index.d.ts +2 -0
  145. package/dist/types/src/types/index.d.ts.map +1 -0
  146. package/dist/types/src/types/types.d.ts +21 -0
  147. package/dist/types/src/types/types.d.ts.map +1 -0
  148. package/dist/types/src/util/cursor.d.ts.map +1 -1
  149. package/dist/types/src/util/debug.d.ts +1 -1
  150. package/dist/types/src/util/debug.d.ts.map +1 -1
  151. package/dist/types/src/util/decorations.d.ts +4 -0
  152. package/dist/types/src/util/decorations.d.ts.map +1 -0
  153. package/dist/types/src/util/dom.d.ts +2 -12
  154. package/dist/types/src/util/dom.d.ts.map +1 -1
  155. package/dist/types/src/util/domino.d.ts +18 -0
  156. package/dist/types/src/util/domino.d.ts.map +1 -0
  157. package/dist/types/src/util/index.d.ts +2 -0
  158. package/dist/types/src/util/index.d.ts.map +1 -1
  159. package/dist/types/src/util/react.d.ts +1 -1
  160. package/dist/types/src/util/react.d.ts.map +1 -1
  161. package/dist/types/tsconfig.tsbuildinfo +1 -1
  162. package/package.json +65 -55
  163. package/src/components/{Popover → CommandMenu}/CommandMenu.tsx +93 -26
  164. package/src/components/{Popover → CommandMenu}/index.ts +0 -2
  165. package/src/components/Editor/Editor.tsx +39 -0
  166. package/src/components/Editor/index.ts +5 -0
  167. package/src/components/EditorToolbar/EditorToolbar.tsx +40 -30
  168. package/src/components/EditorToolbar/blocks.ts +22 -25
  169. package/src/components/EditorToolbar/formatting.ts +22 -25
  170. package/src/components/EditorToolbar/headings.ts +10 -5
  171. package/src/components/EditorToolbar/image.ts +8 -4
  172. package/src/components/EditorToolbar/lists.ts +16 -19
  173. package/src/components/EditorToolbar/search.ts +8 -4
  174. package/src/components/EditorToolbar/util.ts +21 -9
  175. package/src/components/EditorToolbar/view-mode.ts +12 -7
  176. package/src/components/index.ts +2 -1
  177. package/src/defaults.ts +5 -2
  178. package/src/extensions/autocomplete.ts +204 -54
  179. package/src/extensions/automerge/automerge.stories.tsx +26 -17
  180. package/src/extensions/automerge/automerge.ts +4 -3
  181. package/src/extensions/automerge/defs.ts +1 -1
  182. package/src/extensions/automerge/sync.ts +1 -1
  183. package/src/extensions/automerge/update-automerge.ts +1 -1
  184. package/src/extensions/autoscroll.ts +157 -0
  185. package/src/extensions/awareness/awareness.ts +2 -2
  186. package/src/extensions/blast.ts +3 -16
  187. package/src/extensions/command/action.ts +1 -2
  188. package/src/extensions/command/command-menu.ts +7 -6
  189. package/src/extensions/command/command.ts +3 -3
  190. package/src/extensions/command/floating-menu.ts +10 -15
  191. package/src/extensions/command/hint.ts +2 -1
  192. package/src/extensions/command/index.ts +1 -1
  193. package/src/extensions/command/placeholder.ts +1 -1
  194. package/src/extensions/command/state.ts +4 -3
  195. package/src/extensions/command/typeahead.ts +28 -15
  196. package/src/extensions/command/useCommandMenu.ts +6 -9
  197. package/src/extensions/comments.ts +18 -13
  198. package/src/extensions/dnd.ts +1 -1
  199. package/src/extensions/factories.ts +22 -15
  200. package/src/extensions/folding.tsx +2 -2
  201. package/src/extensions/index.ts +2 -0
  202. package/src/extensions/markdown/action.ts +2 -1
  203. package/src/extensions/markdown/bundle.ts +25 -3
  204. package/src/extensions/markdown/changes.ts +1 -1
  205. package/src/extensions/markdown/decorate.ts +23 -14
  206. package/src/extensions/markdown/formatting.test.ts +7 -7
  207. package/src/extensions/markdown/formatting.ts +16 -14
  208. package/src/extensions/markdown/highlight.ts +1 -1
  209. package/src/extensions/markdown/image.ts +3 -4
  210. package/src/extensions/markdown/link.ts +3 -0
  211. package/src/extensions/markdown/table.ts +7 -1
  212. package/src/extensions/mention.ts +1 -1
  213. package/src/extensions/modes.ts +0 -9
  214. package/src/extensions/outliner/outliner.test.ts +3 -2
  215. package/src/extensions/outliner/outliner.ts +6 -5
  216. package/src/extensions/outliner/selection.ts +1 -1
  217. package/src/extensions/outliner/tree.test.ts +2 -1
  218. package/src/extensions/outliner/tree.ts +2 -2
  219. package/src/extensions/preview/preview.ts +59 -62
  220. package/src/extensions/tags/extended-markdown.test.ts +261 -0
  221. package/src/extensions/tags/extended-markdown.ts +78 -0
  222. package/src/extensions/tags/index.ts +7 -0
  223. package/src/extensions/tags/streamer.ts +244 -0
  224. package/src/extensions/tags/xml-tags.ts +335 -0
  225. package/src/extensions/tags/xml-util.ts +94 -0
  226. package/src/hooks/useTextEditor.ts +3 -15
  227. package/src/index.ts +1 -1
  228. package/src/stories/Command.stories.tsx +24 -31
  229. package/src/stories/CommandMenu.stories.tsx +29 -30
  230. package/src/stories/Comments.stories.tsx +10 -6
  231. package/src/stories/EditorToolbar.stories.tsx +10 -11
  232. package/src/stories/Experimental.stories.tsx +12 -8
  233. package/src/stories/Markdown.stories.tsx +21 -17
  234. package/src/stories/Outliner.stories.tsx +42 -30
  235. package/src/stories/Preview.stories.tsx +34 -33
  236. package/src/stories/Tags.stories.tsx +81 -0
  237. package/src/stories/TextEditor.stories.tsx +41 -35
  238. package/src/stories/components/EditorStory.tsx +9 -10
  239. package/src/styles/theme.ts +11 -10
  240. package/src/testing/PreviewPopover.tsx +78 -0
  241. package/src/testing/index.ts +1 -0
  242. package/src/testing/util.ts +2 -0
  243. package/src/translations.ts +5 -3
  244. package/src/types/index.ts +5 -0
  245. package/src/types/types.ts +32 -0
  246. package/src/util/cursor.ts +2 -1
  247. package/src/util/debug.ts +2 -2
  248. package/src/util/decorations.ts +21 -0
  249. package/src/util/dom.ts +5 -27
  250. package/src/util/domino.ts +51 -0
  251. package/src/util/index.ts +2 -0
  252. package/src/util/react.tsx +1 -1
  253. package/dist/lib/node/index.cjs +0 -7754
  254. package/dist/lib/node/index.cjs.map +0 -7
  255. package/dist/lib/node/meta.json +0 -1
  256. package/dist/lib/node/testing/index.cjs +0 -29
  257. package/dist/lib/node/testing/index.cjs.map +0 -7
  258. package/dist/types/src/components/Popover/CommandMenu.d.ts.map +0 -1
  259. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +0 -21
  260. package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +0 -1
  261. package/dist/types/src/components/Popover/RefPopover.d.ts +0 -34
  262. package/dist/types/src/components/Popover/RefPopover.d.ts.map +0 -1
  263. package/dist/types/src/components/Popover/index.d.ts +0 -4
  264. package/dist/types/src/components/Popover/index.d.ts.map +0 -1
  265. package/dist/types/src/types.d.ts +0 -14
  266. package/dist/types/src/types.d.ts.map +0 -1
  267. package/src/components/Popover/RefDropdownMenu.tsx +0 -79
  268. package/src/components/Popover/RefPopover.tsx +0 -99
  269. package/src/types.ts +0 -23
@@ -6,7 +6,8 @@ import '@dxos-theme';
6
6
 
7
7
  import { syntaxTree } from '@codemirror/language';
8
8
  import { type EditorView } from '@codemirror/view';
9
- import React, { useState, useEffect, useMemo, useCallback } from 'react';
9
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
10
+ import React, { useCallback, useEffect, useMemo, useState } from 'react';
10
11
  import { createPortal } from 'react-dom';
11
12
 
12
13
  import { invariant } from '@dxos/invariant';
@@ -14,12 +15,13 @@ import { faker } from '@dxos/random';
14
15
  import { Popover } from '@dxos/react-ui';
15
16
  import { Card } from '@dxos/react-ui-stack';
16
17
  import { hoverableControlItem, hoverableControlItemTransition, hoverableControls } from '@dxos/react-ui-theme';
17
- import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
18
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
19
+ import { trim } from '@dxos/util';
20
+
21
+ import { type PreviewLinkRef, type PreviewLinkTarget, getLinkRef, image, preview } from '../extensions';
22
+ import { PreviewPopoverProvider, usePreviewPopover } from '../testing';
18
23
 
19
24
  import { EditorStory } from './components';
20
- import { PreviewProvider, useRefPopover } from '../components';
21
- import { preview, image, type PreviewLinkRef, type PreviewLinkTarget, getLinkRef } from '../extensions';
22
- import { str } from '../testing';
23
25
 
24
26
  const handlePreviewLookup = async ({ label, ref }: PreviewLinkRef): Promise<PreviewLinkTarget> => {
25
27
  // Random text.
@@ -43,15 +45,15 @@ const useRefTarget = (link: PreviewLinkRef): PreviewLinkTarget | undefined => {
43
45
  };
44
46
 
45
47
  const PreviewCard = () => {
46
- const { target } = useRefPopover('PreviewCard');
48
+ const { target } = usePreviewPopover('PreviewCard');
47
49
  return (
48
50
  <Popover.Portal>
49
51
  <Popover.Content onOpenAutoFocus={(event) => event.preventDefault()}>
50
52
  <Popover.Viewport>
51
- <Card.Container role='popover'>
53
+ <Card.SurfaceRoot role='card--popover'>
52
54
  <Card.Heading>{target?.label}</Card.Heading>
53
55
  {target && <Card.Text classNames='line-clamp-3'>{target.text}</Card.Text>}
54
- </Card.Container>
56
+ </Card.SurfaceRoot>
55
57
  </Popover.Viewport>
56
58
  <Popover.Arrow />
57
59
  </Popover.Content>
@@ -126,13 +128,13 @@ const PreviewBlock = ({ link, el, view }: { link: PreviewLinkRef; el: HTMLElemen
126
128
  }, [handleAction, link, target]);
127
129
 
128
130
  return createPortal(
129
- <Card.Content classNames={hoverableControls}>
131
+ <Card.StaticRoot classNames={hoverableControls}>
130
132
  <div className='flex items-start'>
131
133
  {!view?.state.readOnly && (
132
134
  <Card.Toolbar classNames='is-min p-[--dx-cardSpacingInline]'>
133
135
  {(link.suggest && (
134
136
  <>
135
- <Card.ToolbarIconButton label='Discard' icon={'ph--x--regular'} onClick={handleDelete} />
137
+ <Card.ToolbarIconButton label='Discard' icon='ph--x--regular' onClick={handleDelete} />
136
138
  {target && (
137
139
  <Card.ToolbarIconButton
138
140
  classNames='bg-successSurface text-successSurfaceText'
@@ -159,25 +161,26 @@ const PreviewBlock = ({ link, el, view }: { link: PreviewLinkRef; el: HTMLElemen
159
161
  </Card.Heading>
160
162
  </div>
161
163
  {target && <Card.Text classNames='line-clamp-3 mbs-0'>{target.text}</Card.Text>}
162
- </Card.Content>,
164
+ </Card.StaticRoot>,
163
165
  el,
164
166
  );
165
167
  };
166
168
 
167
- const meta: Meta<typeof EditorStory> = {
169
+ const meta = {
168
170
  title: 'ui/react-ui-editor/Preview',
169
171
  component: EditorStory,
170
172
  decorators: [withTheme, withLayout({ fullscreen: true })],
171
173
  parameters: { layout: 'fullscreen' },
172
- };
174
+ } satisfies Meta<typeof EditorStory>;
173
175
 
174
176
  export default meta;
175
177
 
176
- export const Default = {
178
+ type Story = StoryObj<typeof meta>;
179
+
180
+ export const Default: Story = {
177
181
  render: () => {
178
182
  const [view, setView] = useState<EditorView>();
179
183
  const [previewBlocks, setPreviewBlocks] = useState<{ link: PreviewLinkRef; el: HTMLElement }[]>([]);
180
-
181
184
  const extensions = useMemo(() => {
182
185
  return [
183
186
  image(),
@@ -197,32 +200,30 @@ export const Default = {
197
200
  }, []);
198
201
 
199
202
  return (
200
- <PreviewProvider onLookup={handlePreviewLookup}>
203
+ <PreviewPopoverProvider onLookup={handlePreviewLookup}>
201
204
  <EditorStory
202
205
  ref={handleViewRef}
203
- text={str(
204
- '# Preview',
205
- '',
206
- 'This project is part of the [DXOS][dxn:queue:data:123] SDK.',
207
- '',
208
- '![DXOS][?dxn:queue:data:123]',
209
- '',
210
- 'It consists of [ECHO][dxn:queue:data:echo], [HALO][dxn:queue:data:halo], and [MESH][dxn:queue:data:mesh].',
211
- '',
212
- '## Deep dive',
213
- '',
214
- '![ECHO][dxn:queue:data:echo]',
215
- '',
216
- '',
217
- '',
218
- )}
206
+ text={trim`
207
+ # Preview
208
+
209
+ This project is part of the [DXOS](dxn:queue:data:123) SDK.
210
+
211
+ ![DXOS](dxn:queue:data:123)
212
+
213
+ It consists of [ECHO](dxn:queue:data:echo), [HALO](dxn:queue:data:halo), and [MESH](dxn:queue:data:mesh).
214
+
215
+ ## Deep dive
216
+
217
+ ![ECHO](dxn:queue:data:echo)
218
+
219
+ `}
219
220
  extensions={extensions}
220
221
  />
221
222
  <PreviewCard />
222
223
  {previewBlocks.map(({ link, el }) => (
223
224
  <PreviewBlock key={link.ref} link={link} el={el} view={view} />
224
225
  ))}
225
- </PreviewProvider>
226
+ </PreviewPopoverProvider>
226
227
  );
227
228
  },
228
229
  };
@@ -0,0 +1,81 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import '@dxos-theme';
6
+
7
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
+ import React, { useState } from 'react';
9
+ import { createPortal } from 'react-dom';
10
+
11
+ import { useThemeContext } from '@dxos/react-ui';
12
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
13
+ import { trim } from '@dxos/util';
14
+
15
+ import {
16
+ type XmlWidgetRegistry,
17
+ type XmlWidgetState,
18
+ createBasicExtensions,
19
+ createThemeExtensions,
20
+ decorateMarkdown,
21
+ extendedMarkdown,
22
+ xmlTags,
23
+ } from '../extensions';
24
+ import { useTextEditor } from '../hooks';
25
+
26
+ const registry = {
27
+ // <test/>
28
+ ['test' as const]: {
29
+ block: true,
30
+ Component: () => <div className='p-2 border border-separator rounded'>Test</div>,
31
+ },
32
+ } satisfies XmlWidgetRegistry;
33
+
34
+ const DefaultStory = ({ text }: { text?: string }) => {
35
+ const { themeMode } = useThemeContext();
36
+ const [widgets, setWidgets] = useState<XmlWidgetState[]>([]);
37
+ const { parentRef } = useTextEditor({
38
+ initialValue: text,
39
+ extensions: [
40
+ createThemeExtensions({ themeMode }),
41
+ createBasicExtensions({ lineWrapping: true, readOnly: true }),
42
+ decorateMarkdown(),
43
+ extendedMarkdown({ registry }),
44
+ xmlTags({ registry, setWidgets }),
45
+ ],
46
+ });
47
+
48
+ return (
49
+ <>
50
+ <div ref={parentRef} className='is-full p-4' />
51
+ {widgets.map(({ Component, root, id, ...props }) => (
52
+ <div key={id}>{createPortal(<Component {...props} />, root)}</div>
53
+ ))}
54
+ </>
55
+ );
56
+ };
57
+
58
+ const text = trim`
59
+ # Tags
60
+
61
+ <test id="123" />
62
+
63
+ React widget above.
64
+ `;
65
+
66
+ const meta = {
67
+ title: 'ui/react-ui-editor/Tags',
68
+ render: DefaultStory,
69
+ decorators: [withTheme, withLayout({ fullscreen: true })],
70
+ parameters: { layout: 'fullscreen' },
71
+ } satisfies Meta<typeof DefaultStory>;
72
+
73
+ export default meta;
74
+
75
+ type Story = StoryObj<typeof meta>;
76
+
77
+ export const Default: Story = {
78
+ args: {
79
+ text,
80
+ },
81
+ };
@@ -6,24 +6,12 @@ import '@dxos-theme';
6
6
 
7
7
  import { javascript } from '@codemirror/lang-javascript';
8
8
  import { openSearchPanel } from '@codemirror/search';
9
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
9
10
  import React from 'react';
10
11
 
11
12
  import { log } from '@dxos/log';
12
- import { withLayout, withTheme, type Meta } from '@dxos/storybook-utils';
13
+ import { withLayout, withTheme } from '@dxos/storybook-utils';
13
14
 
14
- import {
15
- EditorStory,
16
- allExtensions,
17
- content,
18
- defaultExtensions,
19
- global,
20
- largeWithImages,
21
- links,
22
- longText,
23
- names,
24
- renderLinkButton,
25
- text,
26
- } from './components';
27
15
  import { editorMonospace } from '../defaults';
28
16
  import {
29
17
  InputModeExtensions,
@@ -39,12 +27,26 @@ import {
39
27
  } from '../extensions';
40
28
  import { str } from '../testing';
41
29
 
42
- const meta: Meta<typeof EditorStory> = {
30
+ import {
31
+ EditorStory,
32
+ allExtensions,
33
+ content,
34
+ defaultExtensions,
35
+ global,
36
+ largeWithImages,
37
+ links,
38
+ longText,
39
+ names,
40
+ renderLinkButton,
41
+ text,
42
+ } from './components';
43
+
44
+ const meta = {
43
45
  title: 'ui/react-ui-editor/TextEditor',
44
46
  component: EditorStory,
45
47
  decorators: [withTheme, withLayout({ fullscreen: true })],
46
48
  parameters: { layout: 'fullscreen', controls: { disable: true } },
47
- };
49
+ } satisfies Meta<typeof EditorStory>;
48
50
 
49
51
  export default meta;
50
52
 
@@ -52,7 +54,9 @@ export default meta;
52
54
  // Default
53
55
  //
54
56
 
55
- export const Default = {
57
+ type Story = StoryObj<typeof meta>;
58
+
59
+ export const Default: Story = {
56
60
  render: () => <EditorStory text={text} extensions={defaultExtensions} />,
57
61
  };
58
62
 
@@ -60,7 +64,7 @@ export const Default = {
60
64
  // Everything
61
65
  //
62
66
 
63
- export const Everything = {
67
+ export const Everything: Story = {
64
68
  render: () => <EditorStory text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
65
69
  };
66
70
 
@@ -68,7 +72,7 @@ export const Everything = {
68
72
  // Empty
69
73
  //
70
74
 
71
- export const Empty = {
75
+ export const Empty: Story = {
72
76
  render: () => <EditorStory extensions={defaultExtensions} />,
73
77
  };
74
78
 
@@ -76,7 +80,7 @@ export const Empty = {
76
80
  // Readonly
77
81
  //
78
82
 
79
- export const Readonly = {
83
+ export const Readonly: Story = {
80
84
  render: () => <EditorStory text={text} extensions={defaultExtensions} readOnly />,
81
85
  };
82
86
 
@@ -84,7 +88,7 @@ export const Readonly = {
84
88
  // No Extensions
85
89
  //
86
90
 
87
- export const NoExtensions = {
91
+ export const NoExtensions: Story = {
88
92
  render: () => <EditorStory text={text} />,
89
93
  };
90
94
 
@@ -92,7 +96,7 @@ export const NoExtensions = {
92
96
  // Vim
93
97
  //
94
98
 
95
- export const Vim = {
99
+ export const Vim: Story = {
96
100
  render: () => (
97
101
  <EditorStory
98
102
  text={str('# Vim Mode', '', 'The distant future. The year 2000.', '', content.paragraphs)}
@@ -105,7 +109,7 @@ export const Vim = {
105
109
  // Listener
106
110
  //
107
111
 
108
- export const Listener = {
112
+ export const Listener: Story = {
109
113
  render: () => (
110
114
  <EditorStory
111
115
  text={str('# Listener', '', content.footer)}
@@ -127,7 +131,7 @@ export const Listener = {
127
131
  // Folding
128
132
  //
129
133
 
130
- export const Folding = {
134
+ export const Folding: Story = {
131
135
  render: () => <EditorStory text={text} extensions={[folding()]} />,
132
136
  };
133
137
 
@@ -135,7 +139,7 @@ export const Folding = {
135
139
  // Scrolling
136
140
  //
137
141
 
138
- export const Scrolling = {
142
+ export const Scrolling: Story = {
139
143
  render: () => (
140
144
  <EditorStory
141
145
  text={str('# Large Document', '', longText)}
@@ -147,13 +151,13 @@ export const Scrolling = {
147
151
  ),
148
152
  };
149
153
 
150
- export const ScrollingWithImages = {
154
+ export const ScrollingWithImages: Story = {
151
155
  render: () => (
152
156
  <EditorStory text={str('# Large Document', '', largeWithImages)} extensions={[decorateMarkdown(), image()]} />
153
157
  ),
154
158
  };
155
159
 
156
- export const ScrollTo = {
160
+ export const ScrollTo: Story = {
157
161
  render: () => {
158
162
  // NOTE: Selection won't appear if text is reformatted.
159
163
  const word = 'Scroll to here...';
@@ -174,7 +178,7 @@ export const ScrollTo = {
174
178
  // Typescript
175
179
  //
176
180
 
177
- export const Typescript = {
181
+ export const Typescript: Story = {
178
182
  render: () => (
179
183
  <EditorStory
180
184
  text={content.typescript}
@@ -188,15 +192,17 @@ export const Typescript = {
188
192
  // Autocomplete
189
193
  //
190
194
 
191
- export const Autocomplete = {
195
+ export const Autocomplete: Story = {
192
196
  render: () => (
193
197
  <EditorStory
194
198
  text={str('# Autocomplete', '', 'Press Ctrl-Space...', content.footer)}
195
199
  extensions={[
196
200
  decorateMarkdown({ renderLinkButton }),
197
201
  autocomplete({
198
- onSearch: (text) => {
199
- return links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase()));
202
+ onSuggest: (text) => {
203
+ return links
204
+ .filter(({ label }) => label.toLowerCase().includes(text.toLowerCase()))
205
+ .map(({ label }) => label);
200
206
  },
201
207
  }),
202
208
  ]}
@@ -210,14 +216,14 @@ export const Autocomplete = {
210
216
 
211
217
  const completions = ['type', 'AND', 'OR', 'NOT', 'dxos.org'];
212
218
 
213
- export const Typeahead = {
219
+ export const Typeahead: Story = {
214
220
  render: () => (
215
221
  <EditorStory
216
222
  text={str('# Typeahead', '')}
217
223
  extensions={[
218
224
  decorateMarkdown({ renderLinkButton }),
219
225
  typeahead({
220
- onComplete: staticCompletion(completions, completions[0]),
226
+ onComplete: staticCompletion(completions, { minLength: 2 }),
221
227
  }),
222
228
  ]}
223
229
  />
@@ -228,7 +234,7 @@ export const Typeahead = {
228
234
  // Mention
229
235
  //
230
236
 
231
- export const Mention = {
237
+ export const Mention: Story = {
232
238
  render: () => (
233
239
  <EditorStory
234
240
  text={str('# Mention', '', 'Type @...', content.footer)}
@@ -245,7 +251,7 @@ export const Mention = {
245
251
  // Search
246
252
  //
247
253
 
248
- export const Search = {
254
+ export const Search: Story = {
249
255
  render: () => (
250
256
  <EditorStory
251
257
  text={str('# Search', text)}
@@ -3,7 +3,7 @@
3
3
  //
4
4
 
5
5
  import { type EditorView } from '@codemirror/view';
6
- import React, { type ReactNode, forwardRef, useEffect, useState, useImperativeHandle, useMemo } from 'react';
6
+ import React, { type ReactNode, forwardRef, useEffect, useImperativeHandle, useMemo, useState } from 'react';
7
7
 
8
8
  import { Expando } from '@dxos/echo-schema';
9
9
  import { invariant } from '@dxos/invariant';
@@ -16,26 +16,25 @@ import { JsonFilter } from '@dxos/react-ui-syntax-highlighter';
16
16
  import { mx } from '@dxos/react-ui-theme';
17
17
  import { isNonNullable } from '@dxos/util';
18
18
 
19
- import { editorSlots, editorGutter } from '../../defaults';
19
+ import { editorGutter, editorSlots } from '../../defaults';
20
20
  import {
21
21
  type DebugNode,
22
22
  type ThemeExtensionsOptions,
23
- createDataExtensions,
24
23
  createBasicExtensions,
24
+ createDataExtensions,
25
25
  createMarkdownExtensions,
26
26
  createThemeExtensions,
27
27
  debugTree,
28
28
  } from '../../extensions';
29
- import { useTextEditor, type UseTextEditorProps } from '../../hooks';
29
+ import { type UseTextEditorProps, useTextEditor } from '../../hooks';
30
30
 
31
31
  // Type definitions.
32
32
  export type DebugMode = 'raw' | 'tree' | 'raw+tree';
33
33
 
34
34
  const defaultId = 'editor-' + PublicKey.random().toHex().slice(0, 8);
35
35
 
36
- export type StoryProps = Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'> &
36
+ export type StoryProps = Pick<UseTextEditorProps, 'id' | 'scrollTo' | 'selection' | 'extensions'> &
37
37
  Pick<ThemeExtensionsOptions, 'slots'> & {
38
- id?: string;
39
38
  debug?: DebugMode;
40
39
  debugCustom?: (view: EditorView) => ReactNode;
41
40
  text?: string;
@@ -48,16 +47,16 @@ export type StoryProps = Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'ex
48
47
 
49
48
  export const EditorStory = forwardRef<EditorView | undefined, StoryProps>(
50
49
  ({ debug, debugCustom, text, extensions: _extensions, ...props }, forwardedRef) => {
51
- const attentionAttrs = useAttentionAttributes('testing');
50
+ const attentionAttrs = useAttentionAttributes('test-panel');
52
51
  const [tree, setTree] = useState<DebugNode>();
53
52
  const [object] = useState(createObject(live(Expando, { content: text ?? '' })));
54
53
  const viewRef = useForwardedRef(forwardedRef);
55
- const view = viewRef.current;
56
54
  const extensions = useMemo(
57
55
  () => (debug ? [_extensions, debugTree(setTree)].filter(isNonNullable) : _extensions),
58
56
  [debug, _extensions],
59
57
  );
60
58
 
59
+ const view = viewRef.current;
61
60
  return (
62
61
  <div className={mx('w-full h-full grid overflow-hidden', debug && 'grid-cols-2 lg:grid-cols-[1fr_600px]')}>
63
62
  <EditorComponent ref={viewRef} object={object} text={text} extensions={extensions} {...props} />
@@ -112,8 +111,8 @@ export const EditorComponent = forwardRef<EditorView | undefined, StoryProps>(
112
111
  initialValue: text,
113
112
  extensions: [
114
113
  createDataExtensions({ id, text: createDocAccessor(object, ['content']) }),
115
- createBasicExtensions({ readOnly, placeholder, lineNumbers, scrollPastEnd: true }),
116
- createMarkdownExtensions({ themeMode }),
114
+ createBasicExtensions({ readOnly, placeholder, lineNumbers, scrollPastEnd: true, search: true }),
115
+ createMarkdownExtensions(),
117
116
  createThemeExtensions({ themeMode, syntaxHighlighting: true, slots }),
118
117
  editorGutter,
119
118
  extensions || [],
@@ -64,7 +64,7 @@ export const defaultTheme: ThemeStyles = {
64
64
  fontFamily: fontBody,
65
65
  // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
66
66
  fontSize: '16px',
67
- lineHeight: 1.5,
67
+ lineHeight: '24px',
68
68
  color: 'unset',
69
69
  },
70
70
 
@@ -74,22 +74,21 @@ export const defaultTheme: ThemeStyles = {
74
74
  */
75
75
  '.cm-gutters': {
76
76
  borderRight: 'none',
77
- background: 'transparent',
77
+ // background: 'transparent',
78
78
  },
79
79
  '.cm-gutter': {},
80
80
  '.cm-gutter.cm-lineNumbers': {
81
81
  paddingRight: '4px',
82
- borderRight: '1px solid var(--dx-separator)',
82
+ borderRight: '1px solid var(--dx-subduedSeparator)',
83
83
  },
84
84
  '.cm-gutter.cm-lineNumbers .cm-gutterElement': {
85
85
  minWidth: '40px',
86
- alignContent: 'center',
87
86
  },
88
87
  /**
89
- * Height is set to match the corresponding line.
88
+ * Height is set to match the corresponding line (which may have wrapped).
90
89
  */
91
90
  '.cm-gutterElement': {
92
- alignItems: 'center',
91
+ lineHeight: '24px',
93
92
  fontSize: '12px',
94
93
  },
95
94
 
@@ -97,6 +96,7 @@ export const defaultTheme: ThemeStyles = {
97
96
  * Line.
98
97
  */
99
98
  '.cm-line': {
99
+ lineHeight: '24px',
100
100
  paddingInline: 0,
101
101
  },
102
102
  '.cm-activeLine': {
@@ -110,7 +110,7 @@ export const defaultTheme: ThemeStyles = {
110
110
  borderLeft: '2px solid var(--dx-cmCursor)',
111
111
  },
112
112
  '.cm-placeholder': {
113
- color: 'var(--dx-subdued)',
113
+ color: 'var(--dx-placeholder)',
114
114
  },
115
115
 
116
116
  /**
@@ -156,7 +156,7 @@ export const defaultTheme: ThemeStyles = {
156
156
  * Tooltip.
157
157
  */
158
158
  '.cm-tooltip': {
159
- background: 'var(--dx-baseSurface)',
159
+ background: 'var(--dx-modalSurface)',
160
160
  },
161
161
  '.cm-tooltip-below': {},
162
162
 
@@ -177,7 +177,8 @@ export const defaultTheme: ThemeStyles = {
177
177
  padding: '4px',
178
178
  },
179
179
  '.cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]': {
180
- background: 'var(--dx-hoverSurface)',
180
+ background: 'var(--dx-accentSurface)',
181
+ color: 'var(--dx-accentSurfaceText)',
181
182
  },
182
183
  '.cm-tooltip.cm-tooltip-autocomplete > ul > completion-section': {
183
184
  paddingLeft: '4px !important',
@@ -233,7 +234,7 @@ export const defaultTheme: ThemeStyles = {
233
234
  outline: '1px solid transparent',
234
235
  },
235
236
  '.cm-panel input, .cm-panel button': {
236
- backgroundColor: 'var(--dx-input)',
237
+ backgroundColor: 'var(--dx-inputSurface)',
237
238
  },
238
239
  '.cm-panel input:focus, .cm-panel button:focus': {
239
240
  outline: '1px solid var(--dx-neutralFocusIndicator)',
@@ -0,0 +1,78 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { createContext } from '@radix-ui/react-context';
6
+ import React, { type PropsWithChildren, type RefObject, useCallback, useEffect, useRef, useState } from 'react';
7
+
8
+ import { addEventListener } from '@dxos/async';
9
+ import { type DxAnchorActivate, Popover } from '@dxos/react-ui';
10
+
11
+ import { type PreviewLinkRef, type PreviewLinkTarget } from '../extensions';
12
+
13
+ type PreviewLookup = (link: PreviewLinkRef) => Promise<PreviewLinkTarget | null | undefined>;
14
+
15
+ type PreviewPopoverValue = Partial<{
16
+ link: PreviewLinkRef;
17
+ target: PreviewLinkTarget;
18
+ pending: boolean;
19
+ }>;
20
+
21
+ const [PreviewPopoverContextProvider, usePreviewPopover] = createContext<PreviewPopoverValue>('PreviewPopover', {});
22
+
23
+ type PopoverLookupProviderProps = PropsWithChildren<{
24
+ onLookup?: PreviewLookup;
25
+ }>;
26
+
27
+ const PreviewPopoverProvider = ({ children, onLookup }: PopoverLookupProviderProps) => {
28
+ const trigger = useRef<HTMLElement | null>(null);
29
+ const [value, setValue] = useState<PreviewPopoverValue>({});
30
+ const [open, setOpen] = useState(false);
31
+
32
+ const handleDxAnchorActivate = useCallback(
33
+ (event: DxAnchorActivate) => {
34
+ const { refId, label, trigger: dxTrigger } = event;
35
+ setValue((value) => ({
36
+ ...value,
37
+ link: { label, ref: refId },
38
+ pending: true,
39
+ }));
40
+ trigger.current = dxTrigger;
41
+ queueMicrotask(() => setOpen(true));
42
+ void onLookup?.({ label, ref: refId }).then((target) =>
43
+ setValue((value) => ({
44
+ ...value,
45
+ target: target ?? undefined,
46
+ pending: false,
47
+ })),
48
+ );
49
+ },
50
+ [onLookup],
51
+ );
52
+
53
+ const [rootRef, setRootRef] = useState<HTMLDivElement | null>(null);
54
+ useEffect(() => {
55
+ if (!rootRef || !handleDxAnchorActivate) {
56
+ return;
57
+ }
58
+
59
+ return addEventListener(rootRef, 'dx-anchor-activate' as any, handleDxAnchorActivate, {
60
+ capture: true,
61
+ passive: false,
62
+ });
63
+ }, [rootRef, handleDxAnchorActivate]);
64
+
65
+ return (
66
+ <PreviewPopoverContextProvider pending={value.pending} link={value.link} target={value.target}>
67
+ <Popover.Root open={open} onOpenChange={setOpen}>
68
+ <Popover.VirtualTrigger virtualRef={trigger as unknown as RefObject<HTMLButtonElement>} />
69
+ <div role='none' className='contents' ref={setRootRef}>
70
+ {children}
71
+ </div>
72
+ </Popover.Root>
73
+ </PreviewPopoverContextProvider>
74
+ );
75
+ };
76
+ export { PreviewPopoverProvider, usePreviewPopover };
77
+
78
+ export type { PopoverLookupProviderProps, PreviewPopoverValue };
@@ -3,3 +3,4 @@
3
3
  //
4
4
 
5
5
  export * from './util';
6
+ export * from './PreviewPopover';
@@ -2,4 +2,6 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ /** deprecated Replace with @dxos/util trim */
6
+ // TODO(burdon): Remove
5
7
  export const str = (...lines: string[]) => lines.join('\n');