@dxos/react-ui-editor 0.8.4-main.bc674ce → 0.8.4-main.bcb3aa67d6
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 +298 -377
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +298 -377
- 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.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/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 +2 -2
- package/src/components/Editor/Editor.tsx +12 -6
- package/src/components/EditorContent/EditorContent.tsx +1 -1
- 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 +54 -46
- package/src/components/EditorToolbar/formatting.ts +43 -44
- package/src/components/EditorToolbar/headings.ts +42 -48
- 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 -40
- package/src/stories/Automerge.stories.tsx +8 -10
- package/src/stories/Comments.stories.tsx +4 -4
- package/src/stories/EditorToolbar.stories.tsx +32 -17
- package/src/stories/Experimental.stories.tsx +3 -3
- package/src/stories/Markdown.stories.tsx +2 -2
- package/src/stories/Outliner.stories.tsx +4 -4
- package/src/stories/Popover.stories.tsx +6 -6
- package/src/stories/Preview.stories.tsx +58 -48
- 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 +19 -22
- 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
|
@@ -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
|
|
|
@@ -13,11 +13,11 @@ import { type EditorController, type EditorMenuGroup, EditorMenuProvider } from
|
|
|
13
13
|
|
|
14
14
|
import { EditorStory } from './components';
|
|
15
15
|
|
|
16
|
-
type
|
|
16
|
+
type DefaultStoryProps = {
|
|
17
17
|
text?: string;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
|
-
const DefaultStory = ({ text }:
|
|
20
|
+
const DefaultStory = ({ text }: DefaultStoryProps) => {
|
|
21
21
|
const [controller, setController] = useState<EditorController | null>(null);
|
|
22
22
|
|
|
23
23
|
const extensions = useMemo(() => [outliner(), hashtag()], []);
|
|
@@ -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,15 +38,15 @@ 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;
|
|
45
45
|
};
|
|
46
46
|
|
|
47
|
-
type
|
|
47
|
+
type DefaultStoryProps = Omit<UseEditorMenuProps, 'viewRef'> & { text: string };
|
|
48
48
|
|
|
49
|
-
const DefaultStory = ({ text, ...props }:
|
|
49
|
+
const DefaultStory = ({ text, ...props }: DefaultStoryProps) => {
|
|
50
50
|
const [controller, setController] = useState<EditorController | null>(null);
|
|
51
51
|
const { groupsRef, extension, ...menuProps } = useEditorMenu(props);
|
|
52
52
|
|
|
@@ -57,7 +57,7 @@ const DefaultStory = ({ text, ...props }: StoryProps) => {
|
|
|
57
57
|
);
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
const LinkStory = (args:
|
|
60
|
+
const LinkStory = (args: DefaultStoryProps) => {
|
|
61
61
|
const { space } = useClientStory();
|
|
62
62
|
|
|
63
63
|
const getMenu = useCallback<NonNullable<UseEditorMenuProps['getMenu']>>(
|
|
@@ -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
|
-
<Card.Icon
|
|
62
|
-
<Card.Title>{target
|
|
64
|
+
<Card.Icon icon='ph--file-text--regular' />
|
|
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 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
|
},
|
|
@@ -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
|
}),
|
|
@@ -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)?.toString() ?? 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('span')
|
|
222
|
+
.attributes({ 'aria-hidden': 'true' })
|
|
223
|
+
.classNames(hover, 'ms-1 inline-block align-[-0.125em]')
|
|
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 }),
|
package/src/translations.ts
CHANGED
|
@@ -10,30 +10,35 @@ export const translations = [
|
|
|
10
10
|
{
|
|
11
11
|
'en-US': {
|
|
12
12
|
[translationKey]: {
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
|
|
17
|
-
'
|
|
18
|
-
'
|
|
19
|
-
'
|
|
20
|
-
'
|
|
21
|
-
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
'
|
|
36
|
-
'
|
|
13
|
+
'comment.label': 'Create comment',
|
|
14
|
+
'image.label': 'Insert image',
|
|
15
|
+
'search.label': 'Search',
|
|
16
|
+
|
|
17
|
+
'block.label': 'Block',
|
|
18
|
+
'block.blockquote.label': 'Block quote',
|
|
19
|
+
'block.codeblock.label': 'Code block',
|
|
20
|
+
'block.table.label': 'Create table',
|
|
21
|
+
|
|
22
|
+
'formatting.label': 'Formatting',
|
|
23
|
+
'formatting.strong.label': 'Bold',
|
|
24
|
+
'formatting.emphasis.label': 'Italics',
|
|
25
|
+
'formatting.strikethrough.label': 'Strikethrough',
|
|
26
|
+
'formatting.code.label': 'Code',
|
|
27
|
+
'formatting.link.label': 'Link',
|
|
28
|
+
|
|
29
|
+
'list.bullet.label': 'Bullet list',
|
|
30
|
+
'list.ordered.label': 'Numbered list',
|
|
31
|
+
'list.task.label': 'Task list',
|
|
32
|
+
|
|
33
|
+
'heading.label': 'Heading level',
|
|
34
|
+
'heading-level.label_zero': 'Paragraph',
|
|
35
|
+
'heading-level.label_one': 'Heading level {{count}}',
|
|
36
|
+
'heading-level.label_other': 'Heading level {{count}}',
|
|
37
|
+
|
|
38
|
+
'view-mode.label': 'Editor view',
|
|
39
|
+
'view-mode.preview.label': 'Markdown',
|
|
40
|
+
'view-mode.source.label': 'Plain text',
|
|
41
|
+
'view-mode.readonly.label': 'Read only',
|
|
37
42
|
},
|
|
38
43
|
},
|
|
39
44
|
},
|
package/src/util/react.tsx
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import React, { type FC
|
|
5
|
+
import React, { type FC } from 'react';
|
|
6
6
|
import { createRoot } from 'react-dom/client';
|
|
7
7
|
|
|
8
8
|
import { ThemeProvider, Tooltip } from '@dxos/react-ui';
|
|
@@ -14,22 +14,13 @@ import { defaultTx } from '@dxos/ui-theme';
|
|
|
14
14
|
*/
|
|
15
15
|
export const str = (...lines: string[]) => lines.join('\n');
|
|
16
16
|
|
|
17
|
-
/** @deprecated */
|
|
18
|
-
// TODO(wittjosiah): Replace with portals which are lighter weight and inherit context from the main react tree.
|
|
19
|
-
export const renderRoot = <T extends Element>(root: T, node: ReactNode): T => {
|
|
20
|
-
createRoot(root).render(<ThemeProvider tx={defaultTx}>{node}</ThemeProvider>);
|
|
21
|
-
return root;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
17
|
/**
|
|
25
|
-
* Utility to create a renderer for a React component.
|
|
26
18
|
* @deprecated
|
|
27
19
|
*/
|
|
28
20
|
export const createRenderer =
|
|
29
21
|
<TProps extends object>(Component: FC<TProps>): RenderCallback<TProps> =>
|
|
30
22
|
(el, props) => {
|
|
31
|
-
|
|
32
|
-
el,
|
|
23
|
+
createRoot(el).render(
|
|
33
24
|
<ThemeProvider tx={defaultTx}>
|
|
34
25
|
<Tooltip.Provider>
|
|
35
26
|
<Component {...props} />
|