@dxos/react-ui-editor 0.8.4-main.3eb6e50203 → 0.8.4-main.3fbcb4aa9b

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 (147) hide show
  1. package/dist/lib/browser/index.mjs +793 -752
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/translations.mjs +39 -0
  5. package/dist/lib/browser/translations.mjs.map +7 -0
  6. package/dist/lib/node-esm/index.mjs +793 -752
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/translations.mjs +41 -0
  10. package/dist/lib/node-esm/translations.mjs.map +7 -0
  11. package/dist/types/src/components/Editor/Editor.d.ts +36 -25
  12. package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
  13. package/dist/types/src/components/Editor/Editor.stories.d.ts +4 -4
  14. package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
  15. package/dist/types/src/components/{EditorContent/EditorContent.d.ts → Editor/EditorView.d.ts} +5 -5
  16. package/dist/types/src/components/Editor/EditorView.d.ts.map +1 -0
  17. package/dist/types/src/components/Editor/controller.d.ts.map +1 -0
  18. package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +1 -3
  19. package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -1
  20. package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts.map +1 -1
  21. package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -1
  22. package/dist/types/src/components/EditorMenuProvider/popover.d.ts +2 -1
  23. package/dist/types/src/components/EditorMenuProvider/popover.d.ts.map +1 -1
  24. package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
  25. package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -1
  26. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +2 -2
  27. package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
  28. package/dist/types/src/components/EditorToolbar/blocks.d.ts +4 -18
  29. package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
  30. package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -18
  31. package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
  32. package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -18
  33. package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
  34. package/dist/types/src/components/EditorToolbar/image.d.ts +3 -8
  35. package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
  36. package/dist/types/src/components/EditorToolbar/index.d.ts +1 -2
  37. package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
  38. package/dist/types/src/components/EditorToolbar/lists.d.ts +6 -0
  39. package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -0
  40. package/dist/types/src/components/EditorToolbar/search.d.ts +3 -8
  41. package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
  42. package/dist/types/src/components/EditorToolbar/types.d.ts +6 -0
  43. package/dist/types/src/components/EditorToolbar/types.d.ts.map +1 -0
  44. package/dist/types/src/components/EditorToolbar/view-mode.d.ts +5 -19
  45. package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
  46. package/dist/types/src/components/index.d.ts +0 -2
  47. package/dist/types/src/components/index.d.ts.map +1 -1
  48. package/dist/types/src/extensions/Assistant.stories.d.ts +10 -0
  49. package/dist/types/src/extensions/Assistant.stories.d.ts.map +1 -0
  50. package/dist/types/src/extensions/assistant-extension.d.ts +24 -0
  51. package/dist/types/src/extensions/assistant-extension.d.ts.map +1 -0
  52. package/dist/types/src/extensions/index.d.ts +2 -0
  53. package/dist/types/src/extensions/index.d.ts.map +1 -0
  54. package/dist/types/src/hooks/index.d.ts +1 -0
  55. package/dist/types/src/hooks/index.d.ts.map +1 -1
  56. package/dist/types/src/hooks/useBasicMarkdownExtensions.d.ts +25 -0
  57. package/dist/types/src/hooks/useBasicMarkdownExtensions.d.ts.map +1 -0
  58. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  59. package/dist/types/src/index.d.ts +1 -2
  60. package/dist/types/src/index.d.ts.map +1 -1
  61. package/dist/types/src/stories/Automerge.stories.d.ts +25 -24
  62. package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
  63. package/dist/types/src/stories/Comments.stories.d.ts +2 -2
  64. package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
  65. package/dist/types/src/stories/EditorToolbar.stories.d.ts +28 -26
  66. package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
  67. package/dist/types/src/stories/Experimental.stories.d.ts +3 -3
  68. package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
  69. package/dist/types/src/stories/Markdown.stories.d.ts +2 -2
  70. package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -1
  71. package/dist/types/src/stories/Outliner.stories.d.ts +2 -2
  72. package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
  73. package/dist/types/src/stories/Popover.stories.d.ts +2 -2
  74. package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
  75. package/dist/types/src/stories/Preview.stories.d.ts +2 -2
  76. package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
  77. package/dist/types/src/stories/Tags.stories.d.ts.map +1 -1
  78. package/dist/types/src/stories/TextEditor.stories.d.ts +2 -2
  79. package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -1
  80. package/dist/types/src/stories/Theme.stories.d.ts.map +1 -1
  81. package/dist/types/src/stories/components/EditorStory.d.ts +4 -4
  82. package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
  83. package/dist/types/src/stories/components/util.d.ts +3 -2
  84. package/dist/types/src/stories/components/util.d.ts.map +1 -1
  85. package/dist/types/src/translations.d.ts +24 -24
  86. package/dist/types/src/translations.d.ts.map +1 -1
  87. package/dist/types/src/util/react.d.ts +2 -5
  88. package/dist/types/src/util/react.d.ts.map +1 -1
  89. package/dist/types/tsconfig.tsbuildinfo +1 -1
  90. package/package.json +59 -50
  91. package/src/components/Editor/Editor.stories.tsx +15 -21
  92. package/src/components/Editor/Editor.tsx +54 -53
  93. package/src/components/Editor/EditorView.tsx +102 -0
  94. package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +17 -18
  95. package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
  96. package/src/components/EditorMenuProvider/popover.ts +3 -1
  97. package/src/components/EditorMenuProvider/useEditorMenu.ts +8 -1
  98. package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +1 -1
  99. package/src/components/EditorToolbar/EditorToolbar.tsx +31 -65
  100. package/src/components/EditorToolbar/blocks.ts +54 -46
  101. package/src/components/EditorToolbar/formatting.ts +44 -45
  102. package/src/components/EditorToolbar/headings.ts +44 -50
  103. package/src/components/EditorToolbar/image.ts +16 -21
  104. package/src/components/EditorToolbar/index.ts +2 -3
  105. package/src/components/EditorToolbar/lists.ts +58 -0
  106. package/src/components/EditorToolbar/search.ts +16 -21
  107. package/src/components/EditorToolbar/types.ts +8 -0
  108. package/src/components/EditorToolbar/view-mode.ts +37 -43
  109. package/src/components/index.ts +0 -3
  110. package/src/extensions/Assistant.stories.tsx +112 -0
  111. package/src/extensions/assistant-extension.tsx +223 -0
  112. package/src/extensions/index.ts +5 -0
  113. package/src/hooks/index.ts +1 -0
  114. package/src/hooks/useBasicMarkdownExtensions.ts +55 -0
  115. package/src/index.ts +1 -4
  116. package/src/stories/Automerge.stories.tsx +12 -13
  117. package/src/stories/Comments.stories.tsx +6 -6
  118. package/src/stories/EditorToolbar.stories.tsx +37 -65
  119. package/src/stories/Experimental.stories.tsx +12 -12
  120. package/src/stories/Markdown.stories.tsx +2 -2
  121. package/src/stories/Outliner.stories.tsx +4 -5
  122. package/src/stories/Popover.stories.tsx +9 -10
  123. package/src/stories/Preview.stories.tsx +49 -41
  124. package/src/stories/Tags.stories.tsx +5 -5
  125. package/src/stories/TextEditor.stories.tsx +2 -2
  126. package/src/stories/Theme.stories.tsx +4 -4
  127. package/src/stories/components/EditorStory.tsx +19 -12
  128. package/src/stories/components/util.tsx +49 -50
  129. package/src/translations.ts +29 -24
  130. package/src/util/react.tsx +3 -12
  131. package/dist/types/src/components/EditorContent/EditorContent.d.ts.map +0 -1
  132. package/dist/types/src/components/EditorContent/controller.d.ts.map +0 -1
  133. package/dist/types/src/components/EditorContent/index.d.ts +0 -3
  134. package/dist/types/src/components/EditorContent/index.d.ts.map +0 -1
  135. package/dist/types/src/components/EditorToolbar/actions.d.ts +0 -24
  136. package/dist/types/src/components/EditorToolbar/actions.d.ts.map +0 -1
  137. package/dist/types/src/components/EditorToolbar/useEditorToolbar.d.ts +0 -11
  138. package/dist/types/src/components/EditorToolbar/useEditorToolbar.d.ts.map +0 -1
  139. package/dist/types/src/stories/CommandDialog.stories.d.ts +0 -14
  140. package/dist/types/src/stories/CommandDialog.stories.d.ts.map +0 -1
  141. package/src/components/EditorContent/EditorContent.tsx +0 -83
  142. package/src/components/EditorContent/index.ts +0 -6
  143. package/src/components/EditorToolbar/actions.ts +0 -87
  144. package/src/components/EditorToolbar/useEditorToolbar.ts +0 -20
  145. package/src/stories/CommandDialog.stories.tsx +0 -81
  146. /package/dist/types/src/components/{EditorContent → Editor}/controller.d.ts +0 -0
  147. /package/src/components/{EditorContent → Editor}/controller.ts +0 -0
@@ -9,18 +9,18 @@ import React, { type FC, useContext, useMemo } from 'react';
9
9
  import { keySymbols, parseShortcut } from '@dxos/keyboard';
10
10
  import { PublicKey } from '@dxos/keys';
11
11
  import { log } from '@dxos/log';
12
- import { withTheme } from '@dxos/react-ui/testing';
12
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
13
13
  import { withRegistry } from '@dxos/storybook-utils';
14
- import { type Comment, annotations, comments, createExternalCommentSync } from '@dxos/ui-editor';
14
+ import { annotations, comments, createExternalCommentSync } from '@dxos/ui-editor';
15
+ import { type Comment } from '@dxos/ui-editor/types';
15
16
 
16
17
  import { createRenderer, str } from '../util';
17
-
18
18
  import { EditorStory, content, longText } from './components';
19
19
 
20
20
  const meta = {
21
21
  title: 'ui/react-ui-editor/Comments',
22
22
  component: EditorStory,
23
- decorators: [withRegistry, withTheme()],
23
+ decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen' })],
24
24
  parameters: {
25
25
  layout: 'fullscreen',
26
26
  },
@@ -77,14 +77,14 @@ export const Comments: Story = {
77
77
  };
78
78
 
79
79
  const Key: FC<{ char: string }> = ({ char }) => (
80
- <span className='flex justify-center items-center is-[24px] bs-[24px] rounded text-xs bg-neutral-200 text-black'>
80
+ <span className='flex justify-center items-center w-[24px] h-[24px] rounded-sm text-xs bg-neutral-200 text-black'>
81
81
  {char}
82
82
  </span>
83
83
  );
84
84
 
85
85
  const CommentTooltip: FC<{ shortcut: string }> = ({ shortcut }) => {
86
86
  return (
87
- <div className='flex items-center gap-2 pli-2 plb-2 bg-neutral-700 text-white text-xs rounded'>
87
+ <div className='flex items-center gap-2 px-2 py-2 bg-neutral-700 text-white text-xs rounded-sm'>
88
88
  <div>Create comment</div>
89
89
  <div className='flex gap-1'>
90
90
  {keySymbols(parseShortcut(shortcut)).map((char) => (
@@ -2,96 +2,68 @@
2
2
  // Copyright 2024 DXOS.org
3
3
  //
4
4
 
5
- import { RegistryContext, useAtomValue } from '@effect-atom/atom-react';
6
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
7
- import React, { useCallback, useContext, useState } from 'react';
6
+ import React, { useMemo } from 'react';
8
7
 
9
- import { invariant } from '@dxos/invariant';
10
8
  import { useThemeContext } from '@dxos/react-ui';
11
- import { withTheme } from '@dxos/react-ui/testing';
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
10
  import { withRegistry } from '@dxos/storybook-utils';
13
11
  import {
14
- type EditorInputMode,
15
- type EditorViewMode,
16
- InputModeExtensions,
17
12
  createBasicExtensions,
18
13
  createMarkdownExtensions,
19
14
  createThemeExtensions,
20
15
  decorateMarkdown,
21
- editorWidth,
16
+ documentSlots,
22
17
  formattingKeymap,
23
- formattingListener,
24
18
  } from '@dxos/ui-editor';
25
- import { attentionSurface, mx } from '@dxos/ui-theme';
19
+ import { type EditorViewMode } from '@dxos/ui-editor/types';
26
20
 
27
- import { EditorToolbar, type EditorToolbarState, useEditorToolbar } from '../components';
28
- import { type UseTextEditorProps, useTextEditor } from '../hooks';
29
- import { translations } from '../translations';
21
+ import { translations } from '#translations';
30
22
 
31
- type StoryProps = { placeholder?: string } & UseTextEditorProps;
23
+ import { Editor } from '../components';
24
+ import { type UseTextEditorProps } from '../hooks';
32
25
 
33
- const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
34
- const { themeMode } = useThemeContext();
35
- const registry = useContext(RegistryContext);
36
-
37
- const toolbarState = useEditorToolbar({ viewMode: 'source' });
38
- const { viewMode } = useAtomValue(toolbarState);
39
-
40
- const updateToolbarState = useCallback(
41
- (formatting: EditorToolbarState) => {
42
- registry.update(toolbarState, (state) => ({ ...state, ...formatting }));
43
- },
44
- [registry, toolbarState],
45
- );
26
+ type DefaultStoryProps = { placeholder?: string; viewMode?: EditorViewMode } & UseTextEditorProps;
46
27
 
47
- // TODO(wittjosiah): Provide way to change the input mode.
48
- const [editorInputMode, _setEditorInputMode] = useState<EditorInputMode>('default');
49
- const { parentRef, view } = useTextEditor(
50
- () => ({
51
- autoFocus,
52
- initialValue,
53
- selectionEnd: true,
54
- extensions: [
55
- editorInputMode ? InputModeExtensions[editorInputMode] : [],
56
- createBasicExtensions({ placeholder, lineWrapping: true, readOnly: viewMode === 'readonly', search: true }),
57
- createMarkdownExtensions(),
58
- createThemeExtensions({ themeMode, syntaxHighlighting: true }),
59
- viewMode === 'source' ? [] : decorateMarkdown(),
60
- formattingKeymap(),
61
- formattingListener(updateToolbarState),
62
- ],
63
- }),
64
- [editorInputMode, viewMode, themeMode, placeholder],
65
- );
66
-
67
- const getView = useCallback(() => {
68
- invariant(view);
69
- return view;
70
- }, [view]);
28
+ const DefaultStory = ({ autoFocus, initialValue, placeholder, viewMode = 'source' }: DefaultStoryProps) => {
29
+ const { themeMode } = useThemeContext();
71
30
 
72
- const handleViewModeChange = useCallback(
73
- (mode: EditorViewMode) => {
74
- registry.update(toolbarState, (state) => ({ ...state, viewMode: mode }));
75
- },
76
- [registry, toolbarState],
31
+ const extensions = useMemo(
32
+ () => [
33
+ createBasicExtensions({
34
+ placeholder,
35
+ lineWrapping: true,
36
+ readOnly: viewMode === 'readonly',
37
+ search: true,
38
+ }),
39
+ createThemeExtensions({
40
+ themeMode,
41
+ syntaxHighlighting: true,
42
+ slots: documentSlots,
43
+ }),
44
+ createMarkdownExtensions(),
45
+ viewMode === 'source' ? [] : decorateMarkdown(),
46
+ formattingKeymap(),
47
+ ],
48
+ [viewMode, themeMode, placeholder],
77
49
  );
78
50
 
79
- // TODO(marijn): This doesn't update the state on view changes.
80
- // Also not sure if view is even guaranteed to exist at this point.
81
51
  return (
82
- <div role='none' className={mx('fixed inset-0 flex flex-col')}>
83
- {toolbarState && <EditorToolbar state={toolbarState} getView={getView} onViewModeChange={handleViewModeChange} />}
84
- <div role='none' className={mx('grow overflow-hidden', attentionSurface)}>
85
- <div className={mx(editorWidth)} ref={parentRef} />
86
- </div>
87
- </div>
52
+ <Editor.Root extensions={extensions} viewMode={viewMode}>
53
+ <Editor.Content>
54
+ <Editor.Toolbar classNames='dx-document' />
55
+ <div className='dx-container dx-document bg-base-surface'>
56
+ <Editor.View autoFocus={autoFocus} initialValue={initialValue} selectionEnd />
57
+ </div>
58
+ </Editor.Content>
59
+ </Editor.Root>
88
60
  );
89
61
  };
90
62
 
91
63
  const meta = {
92
64
  title: 'ui/react-ui-editor/EditorToolbar',
93
65
  render: DefaultStory,
94
- decorators: [withRegistry, withTheme()],
66
+ decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen', classNames: 'bg-sidebar-surface' })],
95
67
  parameters: {
96
68
  layout: 'fullscreen',
97
69
  translations,
@@ -7,16 +7,16 @@ import defaultsDeep from 'lodash.defaultsdeep';
7
7
  import React from 'react';
8
8
 
9
9
  import { log } from '@dxos/log';
10
- import { faker } from '@dxos/random';
11
- import { withTheme } from '@dxos/react-ui/testing';
12
- import { blast, defaultOptions, dropFile, join, typewriter } from '@dxos/ui-editor';
10
+ import { random } from '@dxos/random';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
+ import { blast, defaultOptions, dropFile, join, snippets } from '@dxos/ui-editor';
13
13
 
14
14
  import { EditorStory, content } from './components';
15
15
 
16
16
  const meta = {
17
17
  title: 'ui/react-ui-editor/Experimental',
18
18
  component: EditorStory,
19
- decorators: [withTheme()],
19
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
20
20
  parameters: {
21
21
  layout: 'fullscreen',
22
22
  },
@@ -27,16 +27,16 @@ export default meta;
27
27
  type Story = StoryObj<typeof meta>;
28
28
 
29
29
  //
30
- // Typewriter
30
+ // Snippets
31
31
  //
32
32
 
33
- const typewriterItems = localStorage.getItem('dxos.org/testing/typewriter')?.split(',');
33
+ const snippetItems = localStorage.getItem('org.dxos.testing.snippets')?.split(',');
34
34
 
35
- export const Typewriter: Story = {
35
+ export const Snippets: Story = {
36
36
  render: () => (
37
37
  <EditorStory
38
- text={join('# Typewriter', '', content.paragraphs, content.footer)}
39
- extensions={[typewriter({ items: typewriterItems })]}
38
+ text={join('# Snippets', '', content.paragraphs, content.footer)}
39
+ extensions={[snippets({ items: snippetItems })]}
40
40
  />
41
41
  ),
42
42
  };
@@ -50,15 +50,15 @@ export const Blast: Story = {
50
50
  <EditorStory
51
51
  text={join('# Blast', '', content.paragraphs, content.codeblocks, content.paragraphs)}
52
52
  extensions={[
53
- typewriter({ items: typewriterItems }),
53
+ snippets({ items: snippetItems }),
54
54
  blast(
55
55
  defaultsDeep(
56
56
  {
57
57
  effect: 2,
58
58
  particleGravity: 0.2,
59
59
  particleShrinkRate: 0.995,
60
- color: () => [faker.number.int({ min: 100, max: 200 }), 0, 0],
61
- // color: () => [faker.number.int(256), faker.number.int(256), faker.number.int(256)],
60
+ color: () => [random.number.int({ min: 100, max: 200 }), 0, 0],
61
+ // color: () => [random.number.int(256), random.number.int(256), random.number.int(256)],
62
62
  },
63
63
  defaultOptions,
64
64
  ),
@@ -6,7 +6,7 @@ import { markdown } from '@codemirror/lang-markdown';
6
6
  import { type Meta, type StoryObj } from '@storybook/react-vite';
7
7
  import React from 'react';
8
8
 
9
- import { withTheme } from '@dxos/react-ui/testing';
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
10
  import { decorateMarkdown, image, join, linkTooltip, table } from '@dxos/ui-editor';
11
11
 
12
12
  import { EditorStory, content, defaultExtensions, headings, renderLinkTooltip, text } from './components';
@@ -14,7 +14,7 @@ import { EditorStory, content, defaultExtensions, headings, renderLinkTooltip, t
14
14
  const meta = {
15
15
  title: 'ui/react-ui-editor/Markdown',
16
16
  component: EditorStory,
17
- decorators: [withTheme()],
17
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
18
18
  parameters: {
19
19
  layout: 'fullscreen',
20
20
  },
@@ -5,19 +5,18 @@
5
5
  import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useMemo, useState } from 'react';
7
7
 
8
- import { withTheme } from '@dxos/react-ui/testing';
9
8
  import { withAttention } from '@dxos/react-ui-attention/testing';
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
10
  import { deleteItem, hashtag, join, listItemToString, outliner, treeFacet } from '@dxos/ui-editor';
11
11
 
12
12
  import { type EditorController, type EditorMenuGroup, EditorMenuProvider } from '../components';
13
-
14
13
  import { EditorStory } from './components';
15
14
 
16
- type StoryProps = {
15
+ type DefaultStoryProps = {
17
16
  text?: string;
18
17
  };
19
18
 
20
- const DefaultStory = ({ text }: StoryProps) => {
19
+ const DefaultStory = ({ text }: DefaultStoryProps) => {
21
20
  const [controller, setController] = useState<EditorController | null>(null);
22
21
 
23
22
  const extensions = useMemo(() => [outliner(), hashtag()], []);
@@ -68,7 +67,7 @@ const DefaultStory = ({ text }: StoryProps) => {
68
67
  const meta = {
69
68
  title: 'ui/react-ui-editor/Outliner',
70
69
  render: DefaultStory,
71
- decorators: [withTheme(), withAttention()],
70
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withAttention()],
72
71
  parameters: {
73
72
  layout: 'fullscreen',
74
73
  },
@@ -6,9 +6,9 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
6
  import React, { useCallback, useState } from 'react';
7
7
 
8
8
  import { Obj, Query } from '@dxos/echo';
9
- import { faker } from '@dxos/random';
9
+ import { random } from '@dxos/random';
10
10
  import { useClientStory, withClientProvider } from '@dxos/react-client/testing';
11
- import { withTheme } from '@dxos/react-ui/testing';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
12
  import { TestSchema, type ValueGenerator, createObjectFactory } from '@dxos/schema/testing';
13
13
  import { Domino, mx } from '@dxos/ui';
14
14
  import { insertAtCursor, insertAtLineStart, join } from '@dxos/ui-editor';
@@ -25,10 +25,9 @@ import {
25
25
  linkSlashCommands,
26
26
  useEditorMenu,
27
27
  } from '../components';
28
-
29
28
  import { EditorStory } from './components';
30
29
 
31
- const generator: ValueGenerator = faker as any;
30
+ const generator: ValueGenerator = random as any;
32
31
 
33
32
  const customCompletions: EditorMenuGroup = createMenuGroup({
34
33
  id: 'test',
@@ -38,15 +37,15 @@ const customCompletions: EditorMenuGroup = createMenuGroup({
38
37
  const placeholder = (trigger: string[]) => {
39
38
  const pressEl = Domino.of('span').text('Press');
40
39
  const triggerEls = trigger.map((trigger) =>
41
- Domino.of('span').classNames(mx('border border-separator rounded-sm mx-1 pli-1 pbs-[2px] pbe-[3px]')).text(trigger),
40
+ Domino.of('span').classNames(mx('border border-separator rounded-xs mx-1 px-1 py-[2px] pb-[3px]')).text(trigger),
42
41
  );
43
42
  const forCommandsEl = Domino.of('span').text('for commands');
44
- return Domino.of('div').children(pressEl, ...triggerEls, forCommandsEl).root;
43
+ return Domino.of('div').append(pressEl, ...triggerEls, forCommandsEl).root;
45
44
  };
46
45
 
47
- type StoryProps = Omit<UseEditorMenuProps, 'viewRef'> & { text: string };
46
+ type DefaultStoryProps = Omit<UseEditorMenuProps, 'viewRef'> & { text: string };
48
47
 
49
- const DefaultStory = ({ text, ...props }: StoryProps) => {
48
+ const DefaultStory = ({ text, ...props }: DefaultStoryProps) => {
50
49
  const [controller, setController] = useState<EditorController | null>(null);
51
50
  const { groupsRef, extension, ...menuProps } = useEditorMenu(props);
52
51
 
@@ -57,7 +56,7 @@ const DefaultStory = ({ text, ...props }: StoryProps) => {
57
56
  );
58
57
  };
59
58
 
60
- const LinkStory = (args: StoryProps) => {
59
+ const LinkStory = (args: DefaultStoryProps) => {
61
60
  const { space } = useClientStory();
62
61
 
63
62
  const getMenu = useCallback<NonNullable<UseEditorMenuProps['getMenu']>>(
@@ -103,7 +102,7 @@ const LinkStory = (args: StoryProps) => {
103
102
  const meta = {
104
103
  title: 'ui/react-ui-editor/Popover',
105
104
  render: DefaultStory,
106
- decorators: [withTheme()],
105
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
107
106
  parameters: {
108
107
  layout: 'fullscreen',
109
108
  },
@@ -9,10 +9,10 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
9
9
  import { createPortal } from 'react-dom';
10
10
 
11
11
  import { invariant } from '@dxos/invariant';
12
- import { faker } from '@dxos/random';
13
- import { Popover } from '@dxos/react-ui';
14
- import { withTheme } from '@dxos/react-ui/testing';
15
- import { Card } from '@dxos/react-ui-mosaic';
12
+ import { random } from '@dxos/random';
13
+ import { Card, Popover, Toolbar } from '@dxos/react-ui';
14
+ import { Menu, createMenuAction } from '@dxos/react-ui-menu';
15
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
16
16
  import {
17
17
  type PreviewBlock,
18
18
  type PreviewLinkRef,
@@ -22,16 +22,15 @@ import {
22
22
  preview,
23
23
  } from '@dxos/ui-editor';
24
24
  import { hoverableControls } from '@dxos/ui-theme';
25
- import { isTruthy, trim } from '@dxos/util';
25
+ import { trim } from '@dxos/util';
26
26
 
27
27
  import { type EditorController, EditorPreviewProvider, useEditorPreview } from '../components';
28
-
29
28
  import { EditorStory } from './components';
30
29
 
31
30
  const handlePreviewLookup = async ({ dxn, label }: PreviewLinkRef): Promise<PreviewLinkTarget> => {
32
31
  // Random text.
33
- faker.seed(dxn.split('').reduce((acc: number, char: string) => acc + char.charCodeAt(0), 1));
34
- const text = Array.from({ length: 2 }, () => faker.lorem.paragraphs()).join('\n\n');
32
+ random.seed(dxn.split('').reduce((acc: number, char: string) => acc + char.charCodeAt(0), 1));
33
+ const text = Array.from({ length: 2 }, () => random.lorem.paragraphs()).join('\n\n');
35
34
  return {
36
35
  label,
37
36
  text,
@@ -58,13 +57,13 @@ const PreviewCard = () => {
58
57
  return (
59
58
  <Popover.Portal>
60
59
  <Popover.Content onOpenAutoFocus={(event) => event.preventDefault()}>
61
- <Popover.Viewport classNames='popover-card-width'>
60
+ <Popover.Viewport classNames='dx-card-popover-width'>
62
61
  <Card.Root border={false}>
63
62
  <Card.Toolbar>
64
- <Card.Icon toolbar icon='ph--file-text--regular' />
63
+ <Card.Icon icon='ph--file-text--regular' />
65
64
  <Card.Title>{target.label}</Card.Title>
66
65
  <Popover.Close asChild>
67
- <Card.Close />
66
+ <Card.CloseIconButton />
68
67
  </Popover.Close>
69
68
  </Card.Toolbar>
70
69
  <Card.Row>
@@ -144,36 +143,45 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
144
143
  }
145
144
  }, [handleAction, link, target]);
146
145
 
146
+ const menuItems = useMemo(
147
+ () => [
148
+ createMenuAction('delete', handleDelete, {
149
+ label: link.suggest ? 'Discard' : 'Delete',
150
+ icon: 'ph--x--regular',
151
+ }),
152
+ ...(target
153
+ ? [
154
+ createMenuAction('apply', handleInsert, {
155
+ label: 'Apply',
156
+ icon: 'ph--check--regular',
157
+ }),
158
+ ]
159
+ : []),
160
+ ],
161
+ [handleDelete, handleInsert, link.suggest, target],
162
+ );
163
+
147
164
  return createPortal(
148
- <Card.Root classNames={hoverableControls}>
149
- {!view?.state.readOnly && (
150
- <Card.Toolbar>
151
- <Card.Icon toolbar icon='ph--bookmark--regular' />
152
- <Card.Title>{link.label}</Card.Title>
153
- <Card.Menu
154
- items={[
155
- {
156
- id: 'delete',
157
- label: link.suggest ? 'Discard' : 'Delete',
158
- icon: 'ph--x--regular',
159
- onClick: handleDelete,
160
- },
161
- target && {
162
- id: 'apply',
163
- label: 'Apply',
164
- icon: 'ph--check--regular',
165
- onClick: handleInsert,
166
- },
167
- ].filter(isTruthy)}
168
- />
169
- </Card.Toolbar>
170
- )}
171
- {target && (
172
- <Card.Row>
173
- <Card.Text className='text-description'>{target.text}</Card.Text>
174
- </Card.Row>
175
- )}
176
- </Card.Root>,
165
+ <Menu.Root>
166
+ <Card.Root classNames={hoverableControls}>
167
+ {!view?.state.readOnly && (
168
+ <Card.Toolbar>
169
+ <Card.Icon icon='ph--bookmark--regular' />
170
+ <Card.Title>{link.label}</Card.Title>
171
+ {/* TODO(wittjosiah): Reconcile with Card.Menu. */}
172
+ <Menu.Trigger asChild disabled={!menuItems?.length}>
173
+ <Toolbar.IconButton iconOnly variant='ghost' icon='ph--dots-three-vertical--regular' label='Menu' />
174
+ </Menu.Trigger>
175
+ <Menu.Content items={menuItems} />
176
+ </Card.Toolbar>
177
+ )}
178
+ {target && (
179
+ <Card.Row>
180
+ <Card.Text className='text-description'>{target.text}</Card.Text>
181
+ </Card.Row>
182
+ )}
183
+ </Card.Root>
184
+ </Menu.Root>,
177
185
  el,
178
186
  );
179
187
  };
@@ -181,7 +189,7 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
181
189
  const meta = {
182
190
  title: 'ui/react-ui-editor/Preview',
183
191
  component: EditorStory,
184
- decorators: [withTheme()],
192
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
185
193
  parameters: {
186
194
  layout: 'fullscreen',
187
195
  },
@@ -7,7 +7,7 @@ import React, { useEffect, useState } from 'react';
7
7
  import { createPortal } from 'react-dom';
8
8
 
9
9
  import { useThemeContext } from '@dxos/react-ui';
10
- import { withTheme } from '@dxos/react-ui/testing';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
11
  import {
12
12
  type XmlWidgetRegistry,
13
13
  type XmlWidgetState,
@@ -25,7 +25,7 @@ const registry = {
25
25
  /**
26
26
  * Custom tag: <test/>
27
27
  */
28
- ['test' as const]: {
28
+ test: {
29
29
  block: true,
30
30
  Component: ({ start = '0' }) => {
31
31
  const [count, setCount] = useState<number>(safeParseInt(start, 0));
@@ -43,7 +43,7 @@ const registry = {
43
43
  return () => clearInterval(interval);
44
44
  }, []);
45
45
 
46
- return <div className='p-2 border border-separator rounded'>Test {count}</div>;
46
+ return <div className='p-2 border border-separator rounded-sm'>Test {count}</div>;
47
47
  },
48
48
  },
49
49
  } satisfies XmlWidgetRegistry;
@@ -64,7 +64,7 @@ const DefaultStory = ({ text }: { text?: string }) => {
64
64
 
65
65
  return (
66
66
  <>
67
- <div ref={parentRef} className='is-full p-4' />
67
+ <div ref={parentRef} className='w-full p-4' />
68
68
  {widgets.map(({ id, root, Component, props }) => (
69
69
  <div key={id}>{createPortal(<Component {...props} />, root)}</div>
70
70
  ))}
@@ -87,7 +87,7 @@ const text = trim`
87
87
  const meta = {
88
88
  title: 'ui/react-ui-editor/Tags',
89
89
  render: DefaultStory,
90
- decorators: [withTheme()],
90
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
91
91
  parameters: {
92
92
  layout: 'fullscreen',
93
93
  },
@@ -8,7 +8,7 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
8
8
  import React from 'react';
9
9
 
10
10
  import { log } from '@dxos/log';
11
- import { withTheme } from '@dxos/react-ui/testing';
11
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
12
12
  import {
13
13
  InputModeExtensions,
14
14
  decorateMarkdown,
@@ -37,7 +37,7 @@ import {
37
37
  const meta = {
38
38
  title: 'ui/react-ui-editor/TextEditor',
39
39
  component: EditorStory,
40
- decorators: [withTheme()],
40
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
41
41
  parameters: {
42
42
  layout: 'fullscreen',
43
43
  controls: { disable: true },
@@ -32,12 +32,12 @@ const DefaultStory = () => {
32
32
  );
33
33
 
34
34
  return (
35
- <div className='is-full grid grid-cols-2 gap-2'>
35
+ <div className='w-full grid grid-cols-2 gap-2'>
36
36
  <Editor.Root>
37
- <Editor.Content classNames='p-2' extensions={ext1} initialValue={createText(false)} />
37
+ <Editor.View classNames='p-2' extensions={ext1} initialValue={createText(false)} />
38
38
  </Editor.Root>
39
39
  <Editor.Root>
40
- <Editor.Content classNames='p-2' extensions={ext2} initialValue={createText(true)} />
40
+ <Editor.View classNames='p-2' extensions={ext2} initialValue={createText(true)} />
41
41
  </Editor.Root>
42
42
  </div>
43
43
  );
@@ -46,7 +46,7 @@ const DefaultStory = () => {
46
46
  const meta: Meta<typeof DefaultStory> = {
47
47
  title: 'ui/react-ui-editor/Theme',
48
48
  component: DefaultStory,
49
- decorators: [withTheme(), withLayout()],
49
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
50
50
  parameters: {
51
51
  layout: 'fullscreen',
52
52
  },