@dxos/react-ui-editor 0.10.0 → 0.11.0
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/index.mjs +1477 -0
- package/dist/lib/index.mjs.map +1 -0
- package/dist/lib/translations.mjs +32 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/types/src/components/Editor/Editor.d.ts +22 -17
- package/dist/types/src/components/Editor/Editor.d.ts.map +1 -1
- package/dist/types/src/components/Editor/EditorContext.d.ts +20 -0
- package/dist/types/src/components/Editor/EditorContext.d.ts.map +1 -0
- package/dist/types/src/components/Editor/EditorView.d.ts +1 -2
- package/dist/types/src/components/Editor/EditorView.d.ts.map +1 -1
- package/dist/types/src/components/Editor/index.d.ts +2 -0
- package/dist/types/src/components/Editor/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts +7 -1
- package/dist/types/src/components/EditorMenuProvider/EditorMenuProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts +4 -2
- package/dist/types/src/components/EditorMenuProvider/menu.d.ts.map +1 -1
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts +7 -2
- package/dist/types/src/components/EditorMenuProvider/useEditorMenu.d.ts.map +1 -1
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewContext.d.ts +18 -0
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewContext.d.ts.map +1 -0
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts +0 -6
- package/dist/types/src/components/EditorPreviewProvider/EditorPreviewProvider.d.ts.map +1 -1
- package/dist/types/src/components/EditorPreviewProvider/index.d.ts +1 -0
- package/dist/types/src/components/EditorPreviewProvider/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +4 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts +1 -0
- package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +27 -2
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +1 -0
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/stories/Assistant.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Automerge.stories.d.ts +16 -39
- package/dist/types/src/stories/Automerge.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Blocks.stories.d.ts +10 -0
- package/dist/types/src/stories/Blocks.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Comments.stories.d.ts +53 -14
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Diff.stories.d.ts +32 -0
- package/dist/types/src/stories/Diff.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Experimental.stories.d.ts +1 -0
- package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Folding.stories.d.ts +18 -0
- package/dist/types/src/stories/Folding.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Outliner.stories.d.ts +4 -4
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Popover.stories.d.ts +3 -3
- package/dist/types/src/stories/Popover.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Suggest.stories.d.ts +27 -0
- package/dist/types/src/stories/Suggest.stories.d.ts.map +1 -0
- package/dist/types/src/stories/TrackChanges.stories.d.ts +44 -0
- package/dist/types/src/stories/TrackChanges.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Widgets.stories.d.ts +12 -0
- package/dist/types/src/stories/Widgets.stories.d.ts.map +1 -1
- package/dist/types/src/stories/components/EditorStory.d.ts.map +1 -1
- package/dist/types/src/stories/components/util.d.ts +16 -0
- package/dist/types/src/stories/components/util.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +40 -83
- package/src/components/Editor/Editor.tsx +142 -35
- package/src/components/Editor/EditorContext.ts +34 -0
- package/src/components/Editor/EditorView.tsx +9 -6
- package/src/components/Editor/index.ts +3 -0
- package/src/components/EditorMenuProvider/EditorMenuProvider.tsx +98 -8
- package/src/components/EditorMenuProvider/menu.ts +4 -2
- package/src/components/EditorMenuProvider/useEditorMenu.ts +114 -29
- package/src/components/EditorPreviewProvider/EditorPreviewContext.ts +21 -0
- package/src/components/EditorPreviewProvider/EditorPreviewProvider.tsx +1 -10
- package/src/components/EditorPreviewProvider/index.ts +2 -0
- package/src/components/EditorToolbar/EditorToolbar.tsx +6 -3
- package/src/components/EditorToolbar/index.ts +1 -0
- package/src/components/EditorToolbar/lists.ts +2 -6
- package/src/components/EditorToolbar/view-mode.ts +41 -12
- package/src/components/index.ts +1 -0
- package/src/index.ts +0 -1
- package/src/{extensions → stories}/Assistant.stories.tsx +7 -2
- package/src/stories/Automerge.stories.tsx +99 -78
- package/src/stories/Blocks.stories.tsx +83 -0
- package/src/stories/Comments.stories.tsx +273 -74
- package/src/stories/Diff.stories.tsx +48 -0
- package/src/stories/EditorToolbar.stories.tsx +2 -2
- package/src/stories/Experimental.stories.tsx +13 -2
- package/src/stories/Folding.stories.tsx +120 -0
- package/src/stories/Markdown.stories.tsx +1 -1
- package/src/stories/Outliner.stories.tsx +18 -7
- package/src/stories/Popover.stories.tsx +27 -5
- package/src/stories/Suggest.stories.tsx +199 -0
- package/src/stories/TrackChanges.stories.tsx +226 -0
- package/src/stories/Widgets.stories.tsx +162 -10
- package/src/stories/components/EditorStory.tsx +15 -6
- package/src/stories/components/util.tsx +40 -2
- package/dist/lib/browser/index.mjs +0 -1676
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/translations.mjs +0 -39
- package/dist/lib/browser/translations.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -1678
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/translations.mjs +0 -41
- package/dist/lib/node-esm/translations.mjs.map +0 -7
- package/dist/types/src/extensions/Assistant.stories.d.ts.map +0 -1
- package/dist/types/src/extensions/assistant-extension.d.ts +0 -24
- package/dist/types/src/extensions/assistant-extension.d.ts.map +0 -1
- package/dist/types/src/extensions/index.d.ts +0 -2
- package/dist/types/src/extensions/index.d.ts.map +0 -1
- package/src/extensions/assistant-extension.tsx +0 -223
- package/src/extensions/index.ts +0 -5
- /package/dist/types/src/{extensions → stories}/Assistant.stories.d.ts +0 -0
|
@@ -2,41 +2,44 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { Repo, initSubduction } from '@automerge/automerge-repo';
|
|
6
|
-
import { BroadcastChannelNetworkAdapter } from '@automerge/automerge-repo-network-broadcastchannel';
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
|
-
import React, {
|
|
6
|
+
import React, { useEffect, useMemo, useState } from 'react';
|
|
7
|
+
import { expect, waitFor } from 'storybook/test';
|
|
9
8
|
|
|
10
9
|
import { Obj, Query, Ref } from '@dxos/echo';
|
|
10
|
+
import { createObject } from '@dxos/echo-client';
|
|
11
11
|
import { Doc } from '@dxos/echo-doc';
|
|
12
|
+
import { useQuery, useResolveRef } from '@dxos/echo-react';
|
|
12
13
|
import { TestSchema } from '@dxos/echo/testing';
|
|
13
|
-
import { log } from '@dxos/log';
|
|
14
14
|
import { type Messenger } from '@dxos/protocols';
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { useSpace } from '@dxos/react-client/echo';
|
|
16
|
+
import { useIdentity } from '@dxos/react-client/halo';
|
|
17
17
|
import { useClientStory, withMultiClientProvider } from '@dxos/react-client/testing';
|
|
18
|
-
import {
|
|
18
|
+
import { type ThemedClassName, useThemeContext } from '@dxos/react-ui';
|
|
19
19
|
import { Loading, withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
20
|
-
import {
|
|
20
|
+
import { Text } from '@dxos/schema';
|
|
21
|
+
import {
|
|
22
|
+
type DataExtensionsIdentity,
|
|
23
|
+
createBasicExtensions,
|
|
24
|
+
createDataExtensions,
|
|
25
|
+
createThemeExtensions,
|
|
26
|
+
} from '@dxos/ui-editor';
|
|
27
|
+
import { mx } from '@dxos/ui-theme';
|
|
21
28
|
|
|
22
29
|
import { translations } from '#translations';
|
|
23
30
|
|
|
24
31
|
import { useTextEditor } from '../hooks';
|
|
25
32
|
|
|
26
|
-
const initialContent = 'Hello world!';
|
|
33
|
+
const initialContent = ['# Hello world!', 'Hello Automerge', ''].join('\n\n');
|
|
27
34
|
|
|
28
|
-
type
|
|
29
|
-
text: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
type EditorProps = {
|
|
35
|
+
type EditorProps = ThemedClassName<{
|
|
33
36
|
source: Doc.Accessor;
|
|
34
37
|
messenger?: Messenger;
|
|
35
|
-
identity?:
|
|
38
|
+
identity?: DataExtensionsIdentity;
|
|
36
39
|
autoFocus?: boolean;
|
|
37
|
-
}
|
|
40
|
+
}>;
|
|
38
41
|
|
|
39
|
-
const Editor = ({ source, messenger, identity, autoFocus }: EditorProps) => {
|
|
42
|
+
const Editor = ({ classNames, source, messenger, identity, autoFocus }: EditorProps) => {
|
|
40
43
|
const { themeMode } = useThemeContext();
|
|
41
44
|
const { parentRef } = useTextEditor(
|
|
42
45
|
() => ({
|
|
@@ -51,42 +54,29 @@ const Editor = ({ source, messenger, identity, autoFocus }: EditorProps) => {
|
|
|
51
54
|
[source, themeMode],
|
|
52
55
|
);
|
|
53
56
|
|
|
54
|
-
return <div ref={parentRef} className='
|
|
57
|
+
return <div ref={parentRef} className={mx('w-full', classNames)} />;
|
|
55
58
|
};
|
|
56
59
|
|
|
60
|
+
/**
|
|
61
|
+
* Two editors bound to the same in-process Automerge document (no client or networking). Editing
|
|
62
|
+
* either column mutates the shared handle; the automerge data extension on the other column observes
|
|
63
|
+
* the handle's `change` event and reconciles, so the columns stay in sync. For true cross-peer
|
|
64
|
+
* replication over a transport, see the `WithEcho` story.
|
|
65
|
+
*/
|
|
57
66
|
const DefaultStory = () => {
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
queueMicrotask(async () => {
|
|
63
|
-
// Subduction-fork `Repo` constructs a `MemorySigner` internally; WASM must be
|
|
64
|
-
// initialized first or the constructor throws `'set_subduction_logger' of undefined`.
|
|
65
|
-
await initSubduction();
|
|
66
|
-
const repo1 = new Repo({ network: [new BroadcastChannelNetworkAdapter()] });
|
|
67
|
-
const repo2 = new Repo({ network: [new BroadcastChannelNetworkAdapter()] });
|
|
68
|
-
|
|
69
|
-
const object1 = repo1.create<TestObject>();
|
|
70
|
-
object1.change((doc: TestObject) => {
|
|
71
|
-
doc.text = initialContent;
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const object2 = await repo2.find<TestObject>(object1.url);
|
|
75
|
-
await object2.whenReady();
|
|
76
|
-
|
|
77
|
-
setObject1({ handle: object1, path: ['text'] });
|
|
78
|
-
setObject2({ handle: object2, path: ['text'] });
|
|
79
|
-
});
|
|
80
|
-
}, []);
|
|
81
|
-
|
|
82
|
-
if (!object1 || !object2) {
|
|
83
|
-
return <Loading data={{ object1: !!object1, object2: !!object2 }} />;
|
|
84
|
-
}
|
|
67
|
+
const source = useMemo<Doc.Accessor>(
|
|
68
|
+
() => Doc.createAccessor(createObject(Text.make({ content: initialContent })), ['content']),
|
|
69
|
+
[],
|
|
70
|
+
);
|
|
85
71
|
|
|
86
72
|
return (
|
|
87
|
-
<div className='
|
|
88
|
-
<
|
|
89
|
-
|
|
73
|
+
<div className='dx-container grid grid-cols-2 gap-3 p-3'>
|
|
74
|
+
<div className='dx-container p-2 dx-base-surface rounded-md border border-subdued-separator'>
|
|
75
|
+
<Editor source={source} autoFocus />
|
|
76
|
+
</div>
|
|
77
|
+
<div className='dx-container p-2 dx-base-surface rounded-md border border-subdued-separator'>
|
|
78
|
+
<Editor source={source} />
|
|
79
|
+
</div>
|
|
90
80
|
</div>
|
|
91
81
|
);
|
|
92
82
|
};
|
|
@@ -96,28 +86,16 @@ const EchoStory = () => {
|
|
|
96
86
|
const identity = useIdentity();
|
|
97
87
|
const space = useSpace(spaceId);
|
|
98
88
|
const objects = useQuery(space?.db, Query.type(TestSchema.Expando, { type: 'test' }));
|
|
89
|
+
// NOTE: `objects[0]?.content.target` is not reactive to the ref loading; `useResolveRef`
|
|
90
|
+
// subscribes to the ref's load event so the editor mounts once the target arrives.
|
|
91
|
+
const content = useResolveRef(objects[0]?.content);
|
|
99
92
|
|
|
100
93
|
const [source, setSource] = useState<Doc.Accessor>();
|
|
101
|
-
const init = useCallback(() => {
|
|
102
|
-
const content = objects[0]?.content.target;
|
|
103
|
-
if (!content) {
|
|
104
|
-
if (objects.length) {
|
|
105
|
-
// TODO(burdon): Initially ref isn't ready.
|
|
106
|
-
log.warn('no content', { index, objects: JSON.stringify(objects) });
|
|
107
|
-
}
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
setSource(Doc.createAccessor(content, ['content']));
|
|
112
|
-
}, [objects]);
|
|
113
|
-
|
|
114
94
|
useEffect(() => {
|
|
115
|
-
if (source) {
|
|
116
|
-
|
|
95
|
+
if (!source && content) {
|
|
96
|
+
setSource(Doc.createAccessor(content, ['content']));
|
|
117
97
|
}
|
|
118
|
-
|
|
119
|
-
init();
|
|
120
|
-
}, [objects, source]);
|
|
98
|
+
}, [content, source]);
|
|
121
99
|
|
|
122
100
|
return (
|
|
123
101
|
<div className='h-full w-full flex flex-col overflow-hidden'>
|
|
@@ -126,43 +104,52 @@ const EchoStory = () => {
|
|
|
126
104
|
</pre>
|
|
127
105
|
{identity && source ? (
|
|
128
106
|
<div className='p-2 flex grow overflow-hidden'>
|
|
129
|
-
<Editor
|
|
107
|
+
<Editor
|
|
108
|
+
identity={{
|
|
109
|
+
identityKey: identity.identityKey.toHex(),
|
|
110
|
+
displayName: identity.profile?.displayName,
|
|
111
|
+
data: identity.profile?.data,
|
|
112
|
+
}}
|
|
113
|
+
messenger={space}
|
|
114
|
+
source={source}
|
|
115
|
+
/>
|
|
130
116
|
</div>
|
|
131
117
|
) : (
|
|
132
|
-
<
|
|
133
|
-
<Button onClick={init}>Init</Button>
|
|
134
|
-
</div>
|
|
118
|
+
<Loading data={{ identity: !!identity, content: !!content }} />
|
|
135
119
|
)}
|
|
136
120
|
</div>
|
|
137
121
|
);
|
|
138
122
|
};
|
|
139
123
|
|
|
140
|
-
const meta = {
|
|
124
|
+
const meta: Meta<typeof DefaultStory> = {
|
|
141
125
|
title: 'ui/react-ui-editor/Automerge',
|
|
142
|
-
|
|
126
|
+
render: DefaultStory,
|
|
143
127
|
decorators: [withTheme(), withLayout({ layout: 'fullscreen' })],
|
|
144
128
|
parameters: {
|
|
145
129
|
layout: 'fullscreen',
|
|
146
130
|
translations,
|
|
147
131
|
},
|
|
148
|
-
}
|
|
132
|
+
};
|
|
149
133
|
|
|
150
134
|
export default meta;
|
|
151
135
|
|
|
152
136
|
type Story = StoryObj<typeof meta>;
|
|
153
137
|
|
|
154
|
-
|
|
155
|
-
export const Default: Story = {
|
|
156
|
-
render: DefaultStory,
|
|
157
|
-
};
|
|
138
|
+
export const Default: Story = {};
|
|
158
139
|
|
|
159
|
-
|
|
140
|
+
/**
|
|
141
|
+
* Two in-memory ECHO peers (no real networking, see `withMultiClientProvider`) sharing a
|
|
142
|
+
* document, exercising the `Space.postMessage`/`listen` gossip channel and the CodeMirror
|
|
143
|
+
* `awareness` extension end to end. This covers the same wiring as the (currently skipped,
|
|
144
|
+
* flaky) composer-app e2e collaboration cursor test, deterministically and without a browser.
|
|
145
|
+
*/
|
|
160
146
|
export const WithEcho: Story = {
|
|
161
147
|
decorators: [
|
|
162
148
|
withMultiClientProvider({
|
|
163
149
|
numClients: 2,
|
|
164
150
|
createIdentity: true,
|
|
165
151
|
createSpace: true,
|
|
152
|
+
types: [TestSchema.Expando],
|
|
166
153
|
onCreateSpace: async ({ space }) => {
|
|
167
154
|
space.db.add(
|
|
168
155
|
Obj.make(TestSchema.Expando, {
|
|
@@ -174,4 +161,38 @@ export const WithEcho: Story = {
|
|
|
174
161
|
}),
|
|
175
162
|
],
|
|
176
163
|
render: EchoStory,
|
|
164
|
+
play: async ({ canvasElement }) => {
|
|
165
|
+
// ECHO identity/space creation and invitation are async; wait for both peers to mount an editor.
|
|
166
|
+
const editors = await waitFor(
|
|
167
|
+
() => {
|
|
168
|
+
const found = Array.from(canvasElement.querySelectorAll<HTMLElement>('.cm-editor'));
|
|
169
|
+
void expect(found).toHaveLength(2);
|
|
170
|
+
return found;
|
|
171
|
+
},
|
|
172
|
+
{ timeout: 15_000 },
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const [contentA, contentB] = editors.map((editor) => editor.querySelector<HTMLElement>('.cm-content')!);
|
|
176
|
+
|
|
177
|
+
// Initial content replicated from the host's space to the guest. CodeMirror concatenates its
|
|
178
|
+
// per-line elements without newline separators, so the multiline `initialContent` (with literal
|
|
179
|
+
// `\n`s) never matches as substring text content; assert on each non-empty line instead.
|
|
180
|
+
for (const line of initialContent.split('\n').filter(Boolean)) {
|
|
181
|
+
await expect(contentA).toHaveTextContent(line);
|
|
182
|
+
await expect(contentB).toHaveTextContent(line);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Focusing peer A broadcasts its cursor position over the gossip channel; peer B renders it
|
|
186
|
+
// as a `.cm-collab-selectionInfo` decoration.
|
|
187
|
+
contentA.focus();
|
|
188
|
+
await waitFor(() => expect(editors[1].querySelector('.cm-collab-selectionInfo')).toBeInTheDocument(), {
|
|
189
|
+
timeout: 10_000,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// And symmetrically in the other direction.
|
|
193
|
+
contentB.focus();
|
|
194
|
+
await waitFor(() => expect(editors[0].querySelector('.cm-collab-selectionInfo')).toBeInTheDocument(), {
|
|
195
|
+
timeout: 10_000,
|
|
196
|
+
});
|
|
197
|
+
},
|
|
177
198
|
};
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2026 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React, { useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
import { random } from '@dxos/random';
|
|
9
|
+
import { useThemeContext } from '@dxos/react-ui';
|
|
10
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
|
+
import {
|
|
12
|
+
blocks,
|
|
13
|
+
createBasicExtensions,
|
|
14
|
+
createMarkdownExtensions,
|
|
15
|
+
createThemeExtensions,
|
|
16
|
+
decorateMarkdown,
|
|
17
|
+
} from '@dxos/ui-editor';
|
|
18
|
+
|
|
19
|
+
import { translations } from '#translations';
|
|
20
|
+
|
|
21
|
+
import { Editor, type EditorViewProps } from '../components';
|
|
22
|
+
|
|
23
|
+
random.seed(123);
|
|
24
|
+
|
|
25
|
+
// `blocks` composes the gutter drag grip (`blockDrag`), the whole-block selection + clipboard
|
|
26
|
+
// (`blockSelection`), and the border/background behind selected blocks (`blockSelectionHighlight`).
|
|
27
|
+
type StoryArgs = Pick<EditorViewProps, 'value'>;
|
|
28
|
+
|
|
29
|
+
const DefaultStory = (props: StoryArgs) => {
|
|
30
|
+
const { themeMode } = useThemeContext();
|
|
31
|
+
const extensions = useMemo(
|
|
32
|
+
() => [
|
|
33
|
+
createBasicExtensions({ placeholder: 'Type here...' }),
|
|
34
|
+
createThemeExtensions({ themeMode }),
|
|
35
|
+
createMarkdownExtensions(),
|
|
36
|
+
decorateMarkdown(),
|
|
37
|
+
blocks(),
|
|
38
|
+
],
|
|
39
|
+
[themeMode],
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<Editor.Root>
|
|
44
|
+
<Editor.View {...props} classNames='dx-container' extensions={extensions} />
|
|
45
|
+
</Editor.Root>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const meta: Meta<typeof DefaultStory> = {
|
|
50
|
+
title: 'ui/react-ui-editor/Blocks',
|
|
51
|
+
render: DefaultStory,
|
|
52
|
+
decorators: [withTheme(), withLayout({ layout: 'column' })],
|
|
53
|
+
parameters: {
|
|
54
|
+
layout: 'fullscreen',
|
|
55
|
+
translations,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default meta;
|
|
60
|
+
|
|
61
|
+
type Story = StoryObj<typeof meta>;
|
|
62
|
+
|
|
63
|
+
const content = Array.from({ length: 30 }, (_, index) => {
|
|
64
|
+
const roll = random.number.int(10);
|
|
65
|
+
if (index === 0 || roll < 2) {
|
|
66
|
+
return `# Header ${index + 1}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (roll > 8) {
|
|
70
|
+
return Array.from(
|
|
71
|
+
{
|
|
72
|
+
length: random.number.int({ min: 2, max: 8 }),
|
|
73
|
+
},
|
|
74
|
+
(_, itemIndex) => `- Item ${itemIndex + 1}`,
|
|
75
|
+
).join('\n');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return random.lorem.paragraph();
|
|
79
|
+
}).join('\n\n');
|
|
80
|
+
|
|
81
|
+
export const Default: Story = {
|
|
82
|
+
args: { value: content },
|
|
83
|
+
};
|