@dxos/react-ui-editor 0.8.4-main.937b3ca → 0.8.4-main.9be5663bfe
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.
- package/dist/lib/browser/index.mjs +310 -388
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +310 -388
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Editor/Editor.d.ts +9 -15
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +1 -1
- package/dist/types/src/components/EditorContent/EditorContent.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +1 -3
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/menu-presets.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +3 -8
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts +0 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/lists.d.ts +6 -0
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/search.d.ts +3 -8
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +3 -17
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/stories/Automerge.stories.d.ts +25 -24
- package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts +1 -1
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/EditorToolbar.stories.d.ts +26 -26
- package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Experimental.stories.d.ts +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +1 -1
- package/dist/types/src/stories/Outliner.stories.d.ts +2 -2
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Popover.stories.d.ts +2 -2
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Preview.stories.d.ts +1 -1
- package/dist/types/src/stories/Preview.stories.d.ts.map +1 -1
- package/dist/types/src/stories/TextEditor.stories.d.ts +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts +3 -3
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts +3 -3
- package/dist/types/src/stories/components/util.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +24 -24
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/util/react.d.ts +1 -4
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +45 -45
- package/src/components/Editor/Editor.stories.tsx +6 -7
- package/src/components/Editor/Editor.tsx +21 -27
- package/src/components/EditorContent/EditorContent.tsx +1 -2
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +21 -28
- package/src/components/EditorMenuProvider/menu-presets.ts +1 -0
- package/src/components/EditorMenuProvider/useEditorMenu.ts +8 -1
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +5 -7
- package/src/components/EditorToolbar/EditorToolbar.tsx +24 -61
- package/src/components/EditorToolbar/blocks.ts +53 -46
- package/src/components/EditorToolbar/formatting.ts +44 -46
- package/src/components/EditorToolbar/headings.ts +42 -49
- package/src/components/EditorToolbar/image.ts +16 -21
- package/src/components/EditorToolbar/index.ts +0 -1
- package/src/components/EditorToolbar/lists.ts +57 -0
- package/src/components/EditorToolbar/search.ts +16 -21
- package/src/components/EditorToolbar/view-mode.ts +34 -41
- package/src/stories/Automerge.stories.tsx +10 -12
- package/src/stories/Comments.stories.tsx +4 -5
- package/src/stories/EditorToolbar.stories.tsx +32 -17
- package/src/stories/Experimental.stories.tsx +6 -6
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +4 -5
- package/src/stories/Popover.stories.tsx +9 -10
- package/src/stories/Preview.stories.tsx +60 -51
- package/src/stories/Tags.stories.tsx +5 -5
- package/src/stories/TextEditor.stories.tsx +2 -2
- package/src/stories/Theme.stories.tsx +2 -2
- package/src/stories/components/EditorStory.tsx +17 -12
- package/src/stories/components/util.tsx +49 -50
- package/src/translations.ts +29 -24
- package/src/util/react.tsx +2 -11
- package/dist/types/src/components/EditorToolbar/actions.d.ts +0 -24
- package/dist/types/src/components/EditorToolbar/actions.d.ts.map +0 -1
- package/dist/types/src/stories/CommandDialog.stories.d.ts +0 -14
- package/dist/types/src/stories/CommandDialog.stories.d.ts.map +0 -1
- package/src/components/EditorToolbar/actions.ts +0 -87
- package/src/stories/CommandDialog.stories.tsx +0 -81
|
@@ -9,18 +9,17 @@ 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
14
|
import { type Comment, annotations, comments, createExternalCommentSync } from '@dxos/ui-editor';
|
|
15
15
|
|
|
16
16
|
import { createRenderer, str } from '../util';
|
|
17
|
-
|
|
18
17
|
import { EditorStory, content, longText } from './components';
|
|
19
18
|
|
|
20
19
|
const meta = {
|
|
21
20
|
title: 'ui/react-ui-editor/Comments',
|
|
22
21
|
component: EditorStory,
|
|
23
|
-
decorators: [withRegistry, withTheme],
|
|
22
|
+
decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
24
23
|
parameters: {
|
|
25
24
|
layout: 'fullscreen',
|
|
26
25
|
},
|
|
@@ -77,14 +76,14 @@ export const Comments: Story = {
|
|
|
77
76
|
};
|
|
78
77
|
|
|
79
78
|
const Key: FC<{ char: string }> = ({ char }) => (
|
|
80
|
-
<span className='flex justify-center items-center
|
|
79
|
+
<span className='flex justify-center items-center w-[24px] h-[24px] rounded-sm text-xs bg-neutral-200 text-black'>
|
|
81
80
|
{char}
|
|
82
81
|
</span>
|
|
83
82
|
);
|
|
84
83
|
|
|
85
84
|
const CommentTooltip: FC<{ shortcut: string }> = ({ shortcut }) => {
|
|
86
85
|
return (
|
|
87
|
-
<div className='flex items-center gap-2
|
|
86
|
+
<div className='flex items-center gap-2 px-2 py-2 bg-neutral-700 text-white text-xs rounded-sm'>
|
|
88
87
|
<div>Create comment</div>
|
|
89
88
|
<div className='flex gap-1'>
|
|
90
89
|
{keySymbols(parseShortcut(shortcut)).map((char) => (
|
|
@@ -7,8 +7,8 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
7
7
|
import React, { useCallback, useContext, useState } from 'react';
|
|
8
8
|
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
|
-
import { useThemeContext } from '@dxos/react-ui';
|
|
11
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
import { Panel, useThemeContext } from '@dxos/react-ui';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
12
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
13
13
|
import {
|
|
14
14
|
type EditorInputMode,
|
|
@@ -18,19 +18,18 @@ import {
|
|
|
18
18
|
createMarkdownExtensions,
|
|
19
19
|
createThemeExtensions,
|
|
20
20
|
decorateMarkdown,
|
|
21
|
-
|
|
21
|
+
documentSlots,
|
|
22
22
|
formattingKeymap,
|
|
23
23
|
formattingListener,
|
|
24
24
|
} from '@dxos/ui-editor';
|
|
25
|
-
import { attentionSurface, mx } from '@dxos/ui-theme';
|
|
26
25
|
|
|
27
26
|
import { EditorToolbar, type EditorToolbarState, useEditorToolbar } from '../components';
|
|
28
27
|
import { type UseTextEditorProps, useTextEditor } from '../hooks';
|
|
29
28
|
import { translations } from '../translations';
|
|
30
29
|
|
|
31
|
-
type
|
|
30
|
+
type DefaultStoryProps = { placeholder?: string } & UseTextEditorProps;
|
|
32
31
|
|
|
33
|
-
const DefaultStory = ({ autoFocus, initialValue, placeholder }:
|
|
32
|
+
const DefaultStory = ({ autoFocus, initialValue, placeholder }: DefaultStoryProps) => {
|
|
34
33
|
const { themeMode } = useThemeContext();
|
|
35
34
|
const registry = useContext(RegistryContext);
|
|
36
35
|
|
|
@@ -53,9 +52,18 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
|
|
53
52
|
selectionEnd: true,
|
|
54
53
|
extensions: [
|
|
55
54
|
editorInputMode ? InputModeExtensions[editorInputMode] : [],
|
|
56
|
-
createBasicExtensions({
|
|
55
|
+
createBasicExtensions({
|
|
56
|
+
placeholder,
|
|
57
|
+
lineWrapping: true,
|
|
58
|
+
readOnly: viewMode === 'readonly',
|
|
59
|
+
search: true,
|
|
60
|
+
}),
|
|
61
|
+
createThemeExtensions({
|
|
62
|
+
themeMode,
|
|
63
|
+
syntaxHighlighting: true,
|
|
64
|
+
slots: documentSlots,
|
|
65
|
+
}),
|
|
57
66
|
createMarkdownExtensions(),
|
|
58
|
-
createThemeExtensions({ themeMode, syntaxHighlighting: true }),
|
|
59
67
|
viewMode === 'source' ? [] : decorateMarkdown(),
|
|
60
68
|
formattingKeymap(),
|
|
61
69
|
formattingListener(updateToolbarState),
|
|
@@ -76,22 +84,29 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
|
|
76
84
|
[registry, toolbarState],
|
|
77
85
|
);
|
|
78
86
|
|
|
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
87
|
return (
|
|
82
|
-
<
|
|
83
|
-
{toolbarState &&
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
<Panel.Root>
|
|
89
|
+
{toolbarState && (
|
|
90
|
+
<Panel.Toolbar>
|
|
91
|
+
<EditorToolbar
|
|
92
|
+
classNames='dx-document'
|
|
93
|
+
state={toolbarState}
|
|
94
|
+
getView={getView}
|
|
95
|
+
onViewModeChange={handleViewModeChange}
|
|
96
|
+
/>
|
|
97
|
+
</Panel.Toolbar>
|
|
98
|
+
)}
|
|
99
|
+
<Panel.Content>
|
|
100
|
+
<div role='none' className='dx-container dx-document bg-base-surface' ref={parentRef} />
|
|
101
|
+
</Panel.Content>
|
|
102
|
+
</Panel.Root>
|
|
88
103
|
);
|
|
89
104
|
};
|
|
90
105
|
|
|
91
106
|
const meta = {
|
|
92
107
|
title: 'ui/react-ui-editor/EditorToolbar',
|
|
93
108
|
render: DefaultStory,
|
|
94
|
-
decorators: [withRegistry, withTheme],
|
|
109
|
+
decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen', classNames: 'bg-sidebar-surface' })],
|
|
95
110
|
parameters: {
|
|
96
111
|
layout: 'fullscreen',
|
|
97
112
|
translations,
|
|
@@ -7,8 +7,8 @@ import defaultsDeep from 'lodash.defaultsdeep';
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
|
-
import {
|
|
11
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
import { random } from '@dxos/random';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
12
|
import { blast, defaultOptions, dropFile, join, typewriter } from '@dxos/ui-editor';
|
|
13
13
|
|
|
14
14
|
import { EditorStory, content } from './components';
|
|
@@ -16,7 +16,7 @@ import { EditorStory, content } from './components';
|
|
|
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
|
},
|
|
@@ -30,7 +30,7 @@ type Story = StoryObj<typeof meta>;
|
|
|
30
30
|
// Typewriter
|
|
31
31
|
//
|
|
32
32
|
|
|
33
|
-
const typewriterItems = localStorage.getItem('dxos.
|
|
33
|
+
const typewriterItems = localStorage.getItem('org.dxos.testing.typewriter')?.split(',');
|
|
34
34
|
|
|
35
35
|
export const Typewriter: Story = {
|
|
36
36
|
render: () => (
|
|
@@ -57,8 +57,8 @@ export const Blast: Story = {
|
|
|
57
57
|
effect: 2,
|
|
58
58
|
particleGravity: 0.2,
|
|
59
59
|
particleShrinkRate: 0.995,
|
|
60
|
-
color: () => [
|
|
61
|
-
// color: () => [
|
|
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
|
|
15
|
+
type DefaultStoryProps = {
|
|
17
16
|
text?: string;
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
const DefaultStory = ({ text }:
|
|
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 {
|
|
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 =
|
|
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-
|
|
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').
|
|
43
|
+
return Domino.of('div').append(pressEl, ...triggerEls, forCommandsEl).root;
|
|
45
44
|
};
|
|
46
45
|
|
|
47
|
-
type
|
|
46
|
+
type DefaultStoryProps = Omit<UseEditorMenuProps, 'viewRef'> & { text: string };
|
|
48
47
|
|
|
49
|
-
const DefaultStory = ({ text, ...props }:
|
|
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:
|
|
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 {
|
|
13
|
-
import { Popover } from '@dxos/react-ui';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
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 {
|
|
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
|
-
const handlePreviewLookup = async ({
|
|
30
|
+
const handlePreviewLookup = async ({ dxn, label }: PreviewLinkRef): Promise<PreviewLinkTarget> => {
|
|
32
31
|
// Random text.
|
|
33
|
-
|
|
34
|
-
const text = Array.from({ length: 2 }, () =>
|
|
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,
|
|
@@ -51,24 +50,25 @@ const useRefTarget = (link: PreviewLinkRef): PreviewLinkTarget | undefined => {
|
|
|
51
50
|
|
|
52
51
|
const PreviewCard = () => {
|
|
53
52
|
const { target } = useEditorPreview('PreviewCard');
|
|
53
|
+
if (!target) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
54
56
|
|
|
55
57
|
return (
|
|
56
58
|
<Popover.Portal>
|
|
57
59
|
<Popover.Content onOpenAutoFocus={(event) => event.preventDefault()}>
|
|
58
|
-
<Popover.Viewport classNames='
|
|
60
|
+
<Popover.Viewport classNames='dx-card-popover-width'>
|
|
59
61
|
<Card.Root border={false}>
|
|
60
62
|
<Card.Toolbar>
|
|
61
|
-
<Card.Icon
|
|
62
|
-
<Card.Title>{target
|
|
63
|
+
<Card.Icon icon='ph--file-text--regular' />
|
|
64
|
+
<Card.Title>{target.label}</Card.Title>
|
|
63
65
|
<Popover.Close asChild>
|
|
64
|
-
<Card.
|
|
66
|
+
<Card.CloseIconButton />
|
|
65
67
|
</Popover.Close>
|
|
66
68
|
</Card.Toolbar>
|
|
67
|
-
|
|
68
|
-
<Card.
|
|
69
|
-
|
|
70
|
-
</Card.Row>
|
|
71
|
-
)}
|
|
69
|
+
<Card.Row>
|
|
70
|
+
<Card.Text variant='description'>{target.text}</Card.Text>
|
|
71
|
+
</Card.Row>
|
|
72
72
|
</Card.Root>
|
|
73
73
|
</Popover.Viewport>
|
|
74
74
|
<Popover.Arrow />
|
|
@@ -101,7 +101,7 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
const link = getLinkRef(view.state, node);
|
|
104
|
-
if (link?.
|
|
104
|
+
if (link?.dxn !== action.link.dxn) {
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
|
|
@@ -143,36 +143,45 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
|
|
|
143
143
|
}
|
|
144
144
|
}, [handleAction, link, target]);
|
|
145
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
|
+
|
|
146
164
|
return createPortal(
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<Card.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
/>
|
|
168
|
-
</Card.Toolbar>
|
|
169
|
-
)}
|
|
170
|
-
{target && (
|
|
171
|
-
<Card.Row>
|
|
172
|
-
<Card.Text className='text-description'>{target.text}</Card.Text>
|
|
173
|
-
</Card.Row>
|
|
174
|
-
)}
|
|
175
|
-
</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>,
|
|
176
185
|
el,
|
|
177
186
|
);
|
|
178
187
|
};
|
|
@@ -180,7 +189,7 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
|
|
|
180
189
|
const meta = {
|
|
181
190
|
title: 'ui/react-ui-editor/Preview',
|
|
182
191
|
component: EditorStory,
|
|
183
|
-
decorators: [withTheme],
|
|
192
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
184
193
|
parameters: {
|
|
185
194
|
layout: 'fullscreen',
|
|
186
195
|
},
|
|
@@ -217,7 +226,7 @@ export const Default: Story = {
|
|
|
217
226
|
setPreviewBlocks((prev) => [...prev, block]);
|
|
218
227
|
},
|
|
219
228
|
removeBlockContainer: (block) => {
|
|
220
|
-
setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.
|
|
229
|
+
setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.dxn !== block.link.dxn));
|
|
221
230
|
},
|
|
222
231
|
}),
|
|
223
232
|
];
|
|
@@ -230,7 +239,7 @@ export const Default: Story = {
|
|
|
230
239
|
<PreviewCard />
|
|
231
240
|
{controller?.view &&
|
|
232
241
|
previewBlocks.map(({ link, el }) => (
|
|
233
|
-
<PreviewBlockComponent key={link.
|
|
242
|
+
<PreviewBlockComponent key={link.dxn} link={link} el={el} view={controller.view!} />
|
|
234
243
|
))}
|
|
235
244
|
</EditorPreviewProvider>
|
|
236
245
|
);
|
|
@@ -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
|
-
|
|
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='
|
|
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,7 +32,7 @@ const DefaultStory = () => {
|
|
|
32
32
|
);
|
|
33
33
|
|
|
34
34
|
return (
|
|
35
|
-
<div className='
|
|
35
|
+
<div className='w-full grid grid-cols-2 gap-2'>
|
|
36
36
|
<Editor.Root>
|
|
37
37
|
<Editor.Content classNames='p-2' extensions={ext1} initialValue={createText(false)} />
|
|
38
38
|
</Editor.Root>
|
|
@@ -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
|
},
|
|
@@ -12,7 +12,7 @@ import { PublicKey } from '@dxos/keys';
|
|
|
12
12
|
import { log } from '@dxos/log';
|
|
13
13
|
import { useMergeRefs, useThemeContext } from '@dxos/react-ui';
|
|
14
14
|
import { useAttentionAttributes } from '@dxos/react-ui-attention';
|
|
15
|
-
import {
|
|
15
|
+
import { Json } from '@dxos/react-ui-syntax-highlighter';
|
|
16
16
|
import {
|
|
17
17
|
type DebugNode,
|
|
18
18
|
type ThemeExtensionsOptions,
|
|
@@ -20,8 +20,7 @@ import {
|
|
|
20
20
|
createMarkdownExtensions,
|
|
21
21
|
createThemeExtensions,
|
|
22
22
|
debugTree,
|
|
23
|
-
|
|
24
|
-
editorSlots,
|
|
23
|
+
documentSlots,
|
|
25
24
|
} from '@dxos/ui-editor';
|
|
26
25
|
import { mx } from '@dxos/ui-theme';
|
|
27
26
|
import { isNonNullable } from '@dxos/util';
|
|
@@ -34,12 +33,12 @@ export type DebugMode = 'raw' | 'tree' | 'raw+tree';
|
|
|
34
33
|
|
|
35
34
|
const defaultId = 'editor-' + PublicKey.random().toHex().slice(0, 8);
|
|
36
35
|
|
|
37
|
-
export type
|
|
36
|
+
export type EditorStoryProps = Pick<UseTextEditorProps, 'id' | 'scrollTo' | 'selection' | 'extensions'> &
|
|
38
37
|
Pick<ThemeExtensionsOptions, 'slots'> & {
|
|
39
38
|
debug?: DebugMode;
|
|
40
39
|
debugCustom?: (view: EditorView) => ReactNode;
|
|
41
40
|
text?: string;
|
|
42
|
-
object?: Obj.
|
|
41
|
+
object?: Obj.OfShape<TestSchema.Expando>;
|
|
43
42
|
readOnly?: boolean;
|
|
44
43
|
placeholder?: string;
|
|
45
44
|
lineNumbers?: boolean;
|
|
@@ -47,7 +46,7 @@ export type StoryProps = Pick<UseTextEditorProps, 'id' | 'scrollTo' | 'selection
|
|
|
47
46
|
onReady?: (view: EditorView) => void;
|
|
48
47
|
};
|
|
49
48
|
|
|
50
|
-
export const EditorStory = forwardRef<EditorController,
|
|
49
|
+
export const EditorStory = forwardRef<EditorController, EditorStoryProps>(
|
|
51
50
|
({ debug, debugCustom, text, extensions: extensionsProp, ...props }, forwardedRef) => {
|
|
52
51
|
const controllerRef = useRef<EditorController>(null);
|
|
53
52
|
const mergedRef = useMergeRefs([controllerRef, forwardedRef]);
|
|
@@ -63,12 +62,12 @@ export const EditorStory = forwardRef<EditorController, StoryProps>(
|
|
|
63
62
|
|
|
64
63
|
const view = controllerRef.current?.view;
|
|
65
64
|
return (
|
|
66
|
-
<div className={mx('
|
|
65
|
+
<div className={mx('dx-container grid', debug && 'grid-cols-2 lg:grid-cols-[1fr_600px]')}>
|
|
67
66
|
<EditorComponent ref={mergedRef} object={object} text={text} extensions={extensions} {...props} />
|
|
68
67
|
|
|
69
68
|
{debug && (
|
|
70
69
|
<div
|
|
71
|
-
className='grid
|
|
70
|
+
className='grid h-full auto-rows-fr border-l border-separator divide-y divide-separator overflow-hidden'
|
|
72
71
|
{...attentionAttrs}
|
|
73
72
|
>
|
|
74
73
|
{view && debugCustom?.(view)}
|
|
@@ -77,7 +76,14 @@ export const EditorStory = forwardRef<EditorController, StoryProps>(
|
|
|
77
76
|
{view?.state.doc.toString()}
|
|
78
77
|
</pre>
|
|
79
78
|
)}
|
|
80
|
-
{(debug === 'tree' || debug === 'raw+tree') &&
|
|
79
|
+
{(debug === 'tree' || debug === 'raw+tree') && (
|
|
80
|
+
<Json.Root data={tree}>
|
|
81
|
+
<Json.Content>
|
|
82
|
+
<Json.Filter />
|
|
83
|
+
<Json.Data classNames='p-1 text-xs' />
|
|
84
|
+
</Json.Content>
|
|
85
|
+
</Json.Root>
|
|
86
|
+
)}
|
|
81
87
|
</div>
|
|
82
88
|
)}
|
|
83
89
|
</div>
|
|
@@ -88,7 +94,7 @@ export const EditorStory = forwardRef<EditorController, StoryProps>(
|
|
|
88
94
|
/**
|
|
89
95
|
* Default story component.
|
|
90
96
|
*/
|
|
91
|
-
const EditorComponent = forwardRef<EditorController,
|
|
97
|
+
const EditorComponent = forwardRef<EditorController, EditorStoryProps>(
|
|
92
98
|
(
|
|
93
99
|
{
|
|
94
100
|
id = defaultId,
|
|
@@ -101,7 +107,7 @@ const EditorComponent = forwardRef<EditorController, StoryProps>(
|
|
|
101
107
|
scrollTo,
|
|
102
108
|
selection,
|
|
103
109
|
extensions,
|
|
104
|
-
slots =
|
|
110
|
+
slots = documentSlots,
|
|
105
111
|
onReady,
|
|
106
112
|
},
|
|
107
113
|
forwardedRef,
|
|
@@ -119,7 +125,6 @@ const EditorComponent = forwardRef<EditorController, StoryProps>(
|
|
|
119
125
|
createBasicExtensions({ readOnly, placeholder, lineNumbers, scrollPastEnd: true, search: true }),
|
|
120
126
|
createThemeExtensions({ monospace, themeMode, syntaxHighlighting: true, slots }),
|
|
121
127
|
createMarkdownExtensions(),
|
|
122
|
-
decorateMarkdown(),
|
|
123
128
|
extensions || [],
|
|
124
129
|
],
|
|
125
130
|
}),
|