@dxos/react-ui-editor 0.8.4-main.69d29f4 → 0.8.4-main.6fa680abb7
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 +100 -79
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +100 -79
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.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/actions.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/actions.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/search.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/stories/Automerge.stories.d.ts +1 -0
- 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/Experimental.stories.d.ts +1 -1
- package/dist/types/src/stories/Markdown.stories.d.ts +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 +2 -2
- 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/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 +1 -1
- package/src/components/Editor/Editor.tsx +12 -6
- package/src/components/EditorContent/EditorContent.tsx +1 -1
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +19 -24
- package/src/components/EditorMenuProvider/useEditorMenu.ts +6 -0
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +5 -7
- package/src/components/EditorToolbar/EditorToolbar.tsx +17 -33
- package/src/components/EditorToolbar/actions.ts +2 -2
- package/src/components/EditorToolbar/blocks.ts +2 -2
- package/src/components/EditorToolbar/formatting.ts +2 -2
- package/src/components/EditorToolbar/headings.ts +9 -9
- package/src/components/EditorToolbar/image.ts +2 -2
- package/src/components/EditorToolbar/search.ts +2 -2
- package/src/components/EditorToolbar/view-mode.ts +2 -2
- package/src/stories/Automerge.stories.tsx +8 -10
- package/src/stories/CommandDialog.stories.tsx +5 -5
- package/src/stories/Comments.stories.tsx +4 -4
- package/src/stories/EditorToolbar.stories.tsx +4 -4
- package/src/stories/Experimental.stories.tsx +3 -3
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +2 -2
- package/src/stories/Popover.stories.tsx +3 -3
- package/src/stories/Preview.stories.tsx +57 -47
- 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 +3 -5
- package/src/stories/components/util.tsx +19 -22
- package/src/util/react.tsx +2 -11
|
@@ -16,8 +16,7 @@ import { Query, useQuery, useSpace } from '@dxos/react-client/echo';
|
|
|
16
16
|
import { type Identity, useIdentity } from '@dxos/react-client/halo';
|
|
17
17
|
import { useClientStory, withMultiClientProvider } from '@dxos/react-client/testing';
|
|
18
18
|
import { Button, useThemeContext } from '@dxos/react-ui';
|
|
19
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
20
|
-
import { render } from '@dxos/storybook-utils';
|
|
19
|
+
import { withLayout, withTheme, Loading } from '@dxos/react-ui/testing';
|
|
21
20
|
import { createBasicExtensions, createDataExtensions, createThemeExtensions } from '@dxos/ui-editor';
|
|
22
21
|
|
|
23
22
|
import { useTextEditor } from '../hooks';
|
|
@@ -51,7 +50,7 @@ const Editor = ({ source, messenger, identity, autoFocus }: EditorProps) => {
|
|
|
51
50
|
[source, themeMode],
|
|
52
51
|
);
|
|
53
52
|
|
|
54
|
-
return <div ref={parentRef} className='flex
|
|
53
|
+
return <div ref={parentRef} className='flex w-full' />;
|
|
55
54
|
};
|
|
56
55
|
|
|
57
56
|
const DefaultStory = () => {
|
|
@@ -77,11 +76,11 @@ const DefaultStory = () => {
|
|
|
77
76
|
}, []);
|
|
78
77
|
|
|
79
78
|
if (!object1 || !object2) {
|
|
80
|
-
return
|
|
79
|
+
return <Loading data={{ object1: !!object1, object2: !!object2 }} />;
|
|
81
80
|
}
|
|
82
81
|
|
|
83
82
|
return (
|
|
84
|
-
<div className='
|
|
83
|
+
<div className='h-full w-full grid grid-cols-2 gap-4'>
|
|
85
84
|
<Editor source={object1} autoFocus />
|
|
86
85
|
<Editor source={object2} />
|
|
87
86
|
</div>
|
|
@@ -117,7 +116,7 @@ const EchoStory = () => {
|
|
|
117
116
|
}, [objects, source]);
|
|
118
117
|
|
|
119
118
|
return (
|
|
120
|
-
<div className='
|
|
119
|
+
<div className='h-full w-full flex flex-col overflow-hidden'>
|
|
121
120
|
<pre className='p-2 text-xs text-subdued'>
|
|
122
121
|
{JSON.stringify({ index, identity: identity?.identityKey.truncate(), spaceId, objects }, null, 2)}
|
|
123
122
|
</pre>
|
|
@@ -137,6 +136,7 @@ const EchoStory = () => {
|
|
|
137
136
|
const meta = {
|
|
138
137
|
title: 'ui/react-ui-editor/Automerge',
|
|
139
138
|
component: Editor as any,
|
|
139
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
140
140
|
parameters: {
|
|
141
141
|
layout: 'fullscreen',
|
|
142
142
|
translations,
|
|
@@ -149,14 +149,12 @@ type Story = StoryObj<typeof meta>;
|
|
|
149
149
|
|
|
150
150
|
// TODO(burdon): ERROR: factories.ts:126 Error: Non-base58 character
|
|
151
151
|
export const Default: Story = {
|
|
152
|
-
|
|
153
|
-
render: render(DefaultStory),
|
|
152
|
+
render: DefaultStory,
|
|
154
153
|
};
|
|
155
154
|
|
|
156
155
|
// TODO(burdon): Failing (doesn't sync)
|
|
157
156
|
export const WithEcho: Story = {
|
|
158
157
|
decorators: [
|
|
159
|
-
withTheme,
|
|
160
158
|
withMultiClientProvider({
|
|
161
159
|
numClients: 2,
|
|
162
160
|
createIdentity: true,
|
|
@@ -171,5 +169,5 @@ export const WithEcho: Story = {
|
|
|
171
169
|
},
|
|
172
170
|
}),
|
|
173
171
|
],
|
|
174
|
-
render:
|
|
172
|
+
render: EchoStory,
|
|
175
173
|
};
|
|
@@ -6,7 +6,7 @@ import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
|
6
6
|
import React, { type KeyboardEvent, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { type Button, IconButton, Input } from '@dxos/react-ui';
|
|
9
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
10
|
import { editorWidth, join } from '@dxos/ui-editor';
|
|
11
11
|
import { mx } from '@dxos/ui-theme';
|
|
12
12
|
|
|
@@ -36,10 +36,10 @@ const CommandDialog = ({ onAction }: { onAction: (action?: any) => void }) => {
|
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
|
-
<div className='flex
|
|
39
|
+
<div className='flex w-full justify-center'>
|
|
40
40
|
<div
|
|
41
41
|
className={mx(
|
|
42
|
-
'flex
|
|
42
|
+
'flex w-full p-2 gap-2 items-center bg-modal-surface border border-separator rounded-md',
|
|
43
43
|
editorWidth,
|
|
44
44
|
)}
|
|
45
45
|
>
|
|
@@ -57,7 +57,7 @@ const CommandDialog = ({ onAction }: { onAction: (action?: any) => void }) => {
|
|
|
57
57
|
label='Cancel'
|
|
58
58
|
iconOnly
|
|
59
59
|
variant='ghost'
|
|
60
|
-
classNames='
|
|
60
|
+
classNames='px-0'
|
|
61
61
|
onClick={() => onAction({ type: 'cancel' })}
|
|
62
62
|
/>
|
|
63
63
|
</div>
|
|
@@ -68,7 +68,7 @@ const CommandDialog = ({ onAction }: { onAction: (action?: any) => void }) => {
|
|
|
68
68
|
const meta = {
|
|
69
69
|
title: 'ui/react-ui-editor/CommandDialog',
|
|
70
70
|
render: () => <EditorStory text={join('# Command', '', '')} extensions={[]} />,
|
|
71
|
-
decorators: [withTheme],
|
|
71
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
72
72
|
parameters: {
|
|
73
73
|
layout: 'fullscreen',
|
|
74
74
|
},
|
|
@@ -9,7 +9,7 @@ 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
|
|
|
@@ -20,7 +20,7 @@ import { EditorStory, content, longText } from './components';
|
|
|
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
|
|
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
|
|
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) => (
|
|
@@ -8,7 +8,7 @@ import React, { useCallback, useContext, useState } from 'react';
|
|
|
8
8
|
|
|
9
9
|
import { invariant } from '@dxos/invariant';
|
|
10
10
|
import { useThemeContext } from '@dxos/react-ui';
|
|
11
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
12
|
import { withRegistry } from '@dxos/storybook-utils';
|
|
13
13
|
import {
|
|
14
14
|
type EditorInputMode,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
formattingKeymap,
|
|
23
23
|
formattingListener,
|
|
24
24
|
} from '@dxos/ui-editor';
|
|
25
|
-
import {
|
|
25
|
+
import { mx } from '@dxos/ui-theme';
|
|
26
26
|
|
|
27
27
|
import { EditorToolbar, type EditorToolbarState, useEditorToolbar } from '../components';
|
|
28
28
|
import { type UseTextEditorProps, useTextEditor } from '../hooks';
|
|
@@ -81,7 +81,7 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
|
|
81
81
|
return (
|
|
82
82
|
<div role='none' className={mx('fixed inset-0 flex flex-col')}>
|
|
83
83
|
{toolbarState && <EditorToolbar state={toolbarState} getView={getView} onViewModeChange={handleViewModeChange} />}
|
|
84
|
-
<div role='none' className=
|
|
84
|
+
<div role='none' className='grow overflow-hidden'>
|
|
85
85
|
<div className={mx(editorWidth)} ref={parentRef} />
|
|
86
86
|
</div>
|
|
87
87
|
</div>
|
|
@@ -91,7 +91,7 @@ const DefaultStory = ({ autoFocus, initialValue, placeholder }: StoryProps) => {
|
|
|
91
91
|
const meta = {
|
|
92
92
|
title: 'ui/react-ui-editor/EditorToolbar',
|
|
93
93
|
render: DefaultStory,
|
|
94
|
-
decorators: [withRegistry, withTheme],
|
|
94
|
+
decorators: [withRegistry, withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
95
95
|
parameters: {
|
|
96
96
|
layout: 'fullscreen',
|
|
97
97
|
translations,
|
|
@@ -8,7 +8,7 @@ import React from 'react';
|
|
|
8
8
|
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { faker } from '@dxos/random';
|
|
11
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
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: () => (
|
|
@@ -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,7 +5,7 @@
|
|
|
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';
|
|
8
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
9
9
|
import { withAttention } from '@dxos/react-ui-attention/testing';
|
|
10
10
|
import { deleteItem, hashtag, join, listItemToString, outliner, treeFacet } from '@dxos/ui-editor';
|
|
11
11
|
|
|
@@ -68,7 +68,7 @@ const DefaultStory = ({ text }: StoryProps) => {
|
|
|
68
68
|
const meta = {
|
|
69
69
|
title: 'ui/react-ui-editor/Outliner',
|
|
70
70
|
render: DefaultStory,
|
|
71
|
-
decorators: [withTheme, withAttention],
|
|
71
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withAttention()],
|
|
72
72
|
parameters: {
|
|
73
73
|
layout: 'fullscreen',
|
|
74
74
|
},
|
|
@@ -8,7 +8,7 @@ import React, { useCallback, useState } from 'react';
|
|
|
8
8
|
import { Obj, Query } from '@dxos/echo';
|
|
9
9
|
import { faker } 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';
|
|
@@ -38,7 +38,7 @@ const customCompletions: EditorMenuGroup = createMenuGroup({
|
|
|
38
38
|
const placeholder = (trigger: string[]) => {
|
|
39
39
|
const pressEl = Domino.of('span').text('Press');
|
|
40
40
|
const triggerEls = trigger.map((trigger) =>
|
|
41
|
-
Domino.of('span').classNames(mx('border border-separator rounded-
|
|
41
|
+
Domino.of('span').classNames(mx('border border-separator rounded-xs mx-1 px-1 py-[2px] pb-[3px]')).text(trigger),
|
|
42
42
|
);
|
|
43
43
|
const forCommandsEl = Domino.of('span').text('for commands');
|
|
44
44
|
return Domino.of('div').children(pressEl, ...triggerEls, forCommandsEl).root;
|
|
@@ -103,7 +103,7 @@ const LinkStory = (args: StoryProps) => {
|
|
|
103
103
|
const meta = {
|
|
104
104
|
title: 'ui/react-ui-editor/Popover',
|
|
105
105
|
render: DefaultStory,
|
|
106
|
-
decorators: [withTheme],
|
|
106
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
107
107
|
parameters: {
|
|
108
108
|
layout: 'fullscreen',
|
|
109
109
|
},
|
|
@@ -10,9 +10,9 @@ import { createPortal } from 'react-dom';
|
|
|
10
10
|
|
|
11
11
|
import { invariant } from '@dxos/invariant';
|
|
12
12
|
import { faker } from '@dxos/random';
|
|
13
|
-
import { Popover } from '@dxos/react-ui';
|
|
14
|
-
import { withTheme } from '@dxos/react-ui/testing';
|
|
15
|
-
import {
|
|
13
|
+
import { Card, Popover, Toolbar } from '@dxos/react-ui';
|
|
14
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
15
|
+
import { Menu, createMenuAction } from '@dxos/react-ui-menu';
|
|
16
16
|
import {
|
|
17
17
|
type PreviewBlock,
|
|
18
18
|
type PreviewLinkRef,
|
|
@@ -22,15 +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
28
|
|
|
29
29
|
import { EditorStory } from './components';
|
|
30
30
|
|
|
31
|
-
const handlePreviewLookup = async ({
|
|
31
|
+
const handlePreviewLookup = async ({ dxn, label }: PreviewLinkRef): Promise<PreviewLinkTarget> => {
|
|
32
32
|
// Random text.
|
|
33
|
-
faker.seed(
|
|
33
|
+
faker.seed(dxn.split('').reduce((acc: number, char: string) => acc + char.charCodeAt(0), 1));
|
|
34
34
|
const text = Array.from({ length: 2 }, () => faker.lorem.paragraphs()).join('\n\n');
|
|
35
35
|
return {
|
|
36
36
|
label,
|
|
@@ -51,24 +51,25 @@ const useRefTarget = (link: PreviewLinkRef): PreviewLinkTarget | undefined => {
|
|
|
51
51
|
|
|
52
52
|
const PreviewCard = () => {
|
|
53
53
|
const { target } = useEditorPreview('PreviewCard');
|
|
54
|
+
if (!target) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
54
57
|
|
|
55
58
|
return (
|
|
56
59
|
<Popover.Portal>
|
|
57
60
|
<Popover.Content onOpenAutoFocus={(event) => event.preventDefault()}>
|
|
58
|
-
<Popover.Viewport classNames='
|
|
61
|
+
<Popover.Viewport classNames='dx-card-popover-width'>
|
|
59
62
|
<Card.Root border={false}>
|
|
60
63
|
<Card.Toolbar>
|
|
61
64
|
<Card.Icon toolbar icon='ph--file-text--regular' />
|
|
62
|
-
<Card.Title>{target
|
|
65
|
+
<Card.Title>{target.label}</Card.Title>
|
|
63
66
|
<Popover.Close asChild>
|
|
64
|
-
<Card.
|
|
67
|
+
<Card.CloseIconButton />
|
|
65
68
|
</Popover.Close>
|
|
66
69
|
</Card.Toolbar>
|
|
67
|
-
|
|
68
|
-
<Card.
|
|
69
|
-
|
|
70
|
-
</Card.Row>
|
|
71
|
-
)}
|
|
70
|
+
<Card.Row>
|
|
71
|
+
<Card.Text variant='description'>{target.text}</Card.Text>
|
|
72
|
+
</Card.Row>
|
|
72
73
|
</Card.Root>
|
|
73
74
|
</Popover.Viewport>
|
|
74
75
|
<Popover.Arrow />
|
|
@@ -101,7 +102,7 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
|
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
const link = getLinkRef(view.state, node);
|
|
104
|
-
if (link?.
|
|
105
|
+
if (link?.dxn !== action.link.dxn) {
|
|
105
106
|
return;
|
|
106
107
|
}
|
|
107
108
|
|
|
@@ -143,36 +144,45 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
|
|
|
143
144
|
}
|
|
144
145
|
}, [handleAction, link, target]);
|
|
145
146
|
|
|
147
|
+
const menuItems = useMemo(
|
|
148
|
+
() => [
|
|
149
|
+
createMenuAction('delete', handleDelete, {
|
|
150
|
+
label: link.suggest ? 'Discard' : 'Delete',
|
|
151
|
+
icon: 'ph--x--regular',
|
|
152
|
+
}),
|
|
153
|
+
...(target
|
|
154
|
+
? [
|
|
155
|
+
createMenuAction('apply', handleInsert, {
|
|
156
|
+
label: 'Apply',
|
|
157
|
+
icon: 'ph--check--regular',
|
|
158
|
+
}),
|
|
159
|
+
]
|
|
160
|
+
: []),
|
|
161
|
+
],
|
|
162
|
+
[handleDelete, handleInsert, link.suggest, target],
|
|
163
|
+
);
|
|
164
|
+
|
|
146
165
|
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>,
|
|
166
|
+
<Menu.Root>
|
|
167
|
+
<Card.Root classNames={hoverableControls}>
|
|
168
|
+
{!view?.state.readOnly && (
|
|
169
|
+
<Card.Toolbar>
|
|
170
|
+
<Card.Icon toolbar icon='ph--bookmark--regular' />
|
|
171
|
+
<Card.Title>{link.label}</Card.Title>
|
|
172
|
+
{/* TODO(wittjosiah): Reconcile with Card.Menu. */}
|
|
173
|
+
<Menu.Trigger asChild disabled={!menuItems?.length}>
|
|
174
|
+
<Toolbar.IconButton iconOnly variant='ghost' icon='ph--dots-three-vertical--regular' label='Menu' />
|
|
175
|
+
</Menu.Trigger>
|
|
176
|
+
<Menu.Content items={menuItems} />
|
|
177
|
+
</Card.Toolbar>
|
|
178
|
+
)}
|
|
179
|
+
{target && (
|
|
180
|
+
<Card.Row>
|
|
181
|
+
<Card.Text className='text-description'>{target.text}</Card.Text>
|
|
182
|
+
</Card.Row>
|
|
183
|
+
)}
|
|
184
|
+
</Card.Root>
|
|
185
|
+
</Menu.Root>,
|
|
176
186
|
el,
|
|
177
187
|
);
|
|
178
188
|
};
|
|
@@ -180,7 +190,7 @@ const PreviewBlockComponent = ({ link, el, view }: { link: PreviewLinkRef; el: H
|
|
|
180
190
|
const meta = {
|
|
181
191
|
title: 'ui/react-ui-editor/Preview',
|
|
182
192
|
component: EditorStory,
|
|
183
|
-
decorators: [withTheme],
|
|
193
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
184
194
|
parameters: {
|
|
185
195
|
layout: 'fullscreen',
|
|
186
196
|
},
|
|
@@ -217,7 +227,7 @@ export const Default: Story = {
|
|
|
217
227
|
setPreviewBlocks((prev) => [...prev, block]);
|
|
218
228
|
},
|
|
219
229
|
removeBlockContainer: (block) => {
|
|
220
|
-
setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.
|
|
230
|
+
setPreviewBlocks((prev) => prev.filter(({ link: prevLink }) => prevLink.dxn !== block.link.dxn));
|
|
221
231
|
},
|
|
222
232
|
}),
|
|
223
233
|
];
|
|
@@ -230,7 +240,7 @@ export const Default: Story = {
|
|
|
230
240
|
<PreviewCard />
|
|
231
241
|
{controller?.view &&
|
|
232
242
|
previewBlocks.map(({ link, el }) => (
|
|
233
|
-
<PreviewBlockComponent key={link.
|
|
243
|
+
<PreviewBlockComponent key={link.dxn} link={link} el={el} view={controller.view!} />
|
|
234
244
|
))}
|
|
235
245
|
</EditorPreviewProvider>
|
|
236
246
|
);
|
|
@@ -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
|
},
|
|
@@ -20,7 +20,6 @@ import {
|
|
|
20
20
|
createMarkdownExtensions,
|
|
21
21
|
createThemeExtensions,
|
|
22
22
|
debugTree,
|
|
23
|
-
decorateMarkdown,
|
|
24
23
|
editorSlots,
|
|
25
24
|
} from '@dxos/ui-editor';
|
|
26
25
|
import { mx } from '@dxos/ui-theme';
|
|
@@ -39,7 +38,7 @@ export type StoryProps = Pick<UseTextEditorProps, 'id' | 'scrollTo' | 'selection
|
|
|
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;
|
|
@@ -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('w-full h-full grid overflow-hidden', 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)}
|
|
@@ -119,7 +118,6 @@ const EditorComponent = forwardRef<EditorController, StoryProps>(
|
|
|
119
118
|
createBasicExtensions({ readOnly, placeholder, lineNumbers, scrollPastEnd: true, search: true }),
|
|
120
119
|
createThemeExtensions({ monospace, themeMode, syntaxHighlighting: true, slots }),
|
|
121
120
|
createMarkdownExtensions(),
|
|
122
|
-
decorateMarkdown(),
|
|
123
121
|
extensions || [],
|
|
124
122
|
],
|
|
125
123
|
}),
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
import { type Completion } from '@codemirror/autocomplete';
|
|
6
6
|
import { type Extension } from '@codemirror/state';
|
|
7
|
-
import React, { type FC } from 'react';
|
|
8
7
|
|
|
9
8
|
import { faker } from '@dxos/random';
|
|
10
|
-
import {
|
|
9
|
+
import { Domino } from '@dxos/ui';
|
|
11
10
|
import {
|
|
12
11
|
type EditorSelectionState,
|
|
12
|
+
type RenderCallback,
|
|
13
13
|
decorateMarkdown,
|
|
14
14
|
folding,
|
|
15
15
|
formattingKeymap,
|
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
linkTooltip,
|
|
18
18
|
table,
|
|
19
19
|
} from '@dxos/ui-editor';
|
|
20
|
-
import {
|
|
20
|
+
import { safeUrl } from '@dxos/util';
|
|
21
21
|
|
|
22
|
-
import {
|
|
22
|
+
import { str } from '../../util';
|
|
23
23
|
|
|
24
24
|
export const num = () => faker.number.int({ min: 0, max: 9999 }).toLocaleString();
|
|
25
25
|
|
|
@@ -204,30 +204,27 @@ export const links: Completion[] = [
|
|
|
204
204
|
export const names = ['adam', 'alice', 'alison', 'bob', 'carol', 'charlie', 'sayuri', 'shoko'];
|
|
205
205
|
|
|
206
206
|
const hover =
|
|
207
|
-
'rounded-
|
|
208
|
-
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
207
|
+
'rounded-xs text-base-surface-text text-primary-600 hover:text-primary-500 dark:text-primary-300 hover:dark:text-primary-200';
|
|
208
|
+
|
|
209
|
+
export const renderLinkTooltip: RenderCallback<{ url: string }> = (el, { url }) => {
|
|
210
|
+
el.appendChild(
|
|
211
|
+
Domino.of('a')
|
|
212
|
+
.attributes({ href: url, target: '_blank', rel: 'noreferrer', 'aria-label': 'Open link' })
|
|
213
|
+
.classNames(hover, 'flex items-center gap-2')
|
|
214
|
+
.text(safeUrl(url)?.origin ?? url)
|
|
215
|
+
.children(Domino.svg('ph--arrow-square-out--regular')).root,
|
|
216
216
|
);
|
|
217
217
|
};
|
|
218
218
|
|
|
219
|
-
export const
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
</a>
|
|
219
|
+
export const renderLinkButton: RenderCallback<{ url: string }> = (el, { url }) => {
|
|
220
|
+
el.appendChild(
|
|
221
|
+
Domino.of('a')
|
|
222
|
+
.attributes({ href: url, target: '_blank', rel: 'noreferrer', 'aria-label': 'Open link' })
|
|
223
|
+
.classNames(hover, 'inline-block ms-1 align-[-0.125em]') // Center icon.
|
|
224
|
+
.children(Domino.svg('ph--arrow-square-out--regular')).root,
|
|
226
225
|
);
|
|
227
226
|
};
|
|
228
227
|
|
|
229
|
-
export const renderLinkButton = createRenderer(LinkButton);
|
|
230
|
-
|
|
231
228
|
// Shared extensions.
|
|
232
229
|
export const defaultExtensions: Extension[] = [
|
|
233
230
|
decorateMarkdown({ renderLinkButton, selectionChangeDelay: 100 }),
|