@dxos/react-ui-editor 0.6.11-staging.e6894a4 → 0.6.12-main.15a606f
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 +127 -74
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/InputMode.stories.d.ts.map +1 -1
- package/dist/types/src/TextEditor.stories.d.ts +10 -2
- package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/defaults.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts +0 -1
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -1
- package/dist/types/src/extensions/factories.d.ts +5 -1
- package/dist/types/src/extensions/factories.d.ts.map +1 -1
- package/dist/types/src/extensions/folding.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
- package/dist/types/src/extensions/util/react.d.ts +4 -0
- package/dist/types/src/extensions/util/react.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +2 -2
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/package.json +32 -27
- package/src/InputMode.stories.tsx +8 -10
- package/src/TextEditor.stories.tsx +61 -34
- package/src/defaults.ts +3 -3
- package/src/extensions/automerge/automerge.stories.tsx +5 -6
- package/src/extensions/automerge/{automerge.spec.tsx → automerge.test.tsx} +1 -0
- package/src/extensions/automerge/automerge.ts +1 -1
- package/src/extensions/factories.ts +15 -4
- package/src/extensions/folding.tsx +17 -4
- package/src/extensions/markdown/bundle.ts +1 -5
- package/src/extensions/markdown/changes.test.ts +1 -3
- package/src/extensions/markdown/decorate.ts +40 -23
- package/src/extensions/markdown/formatting.test.ts +1 -3
- package/src/extensions/markdown/parser.test.ts +1 -2
- package/src/extensions/util/react.tsx +15 -0
- package/src/hooks/useTextEditor.ts +3 -5
- package/src/styles/markdown.ts +0 -2
- package/src/styles/theme.ts +13 -9
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts +0 -2
- package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +0 -1
- package/src/extensions/automerge/automerge.test.ts +0 -13
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dxos/react-ui-editor",
|
3
|
-
"version": "0.6.
|
3
|
+
"version": "0.6.12-main.15a606f",
|
4
4
|
"description": "Document editing experience within a DXOS shell.",
|
5
5
|
"homepage": "https://dxos.org",
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
@@ -34,6 +34,7 @@
|
|
34
34
|
"@codemirror/view": "^6.29.1",
|
35
35
|
"@fluentui/react-tabster": "^9.19.0",
|
36
36
|
"@lezer/common": "^1.2.1",
|
37
|
+
"@lezer/generator": "^1.7.1",
|
37
38
|
"@lezer/highlight": "^1.2.0",
|
38
39
|
"@lezer/markdown": "^1.3.0",
|
39
40
|
"@radix-ui/react-context": "^1.0.0",
|
@@ -47,19 +48,19 @@
|
|
47
48
|
"lodash.sortby": "^4.7.0",
|
48
49
|
"react-dropzone": "^14.2.3",
|
49
50
|
"style-mod": "^4.1.0",
|
50
|
-
"@dxos/async": "0.6.
|
51
|
-
"@dxos/
|
52
|
-
"@dxos/debug": "0.6.
|
53
|
-
"@dxos/
|
54
|
-
"@dxos/display-name": "0.6.
|
55
|
-
"@dxos/
|
56
|
-
"@dxos/
|
57
|
-
"@dxos/
|
58
|
-
"@dxos/protocols": "0.6.
|
59
|
-
"@dxos/react-
|
60
|
-
"@dxos/
|
61
|
-
"@dxos/
|
62
|
-
"@dxos/react-ui
|
51
|
+
"@dxos/async": "0.6.12-main.15a606f",
|
52
|
+
"@dxos/context": "0.6.12-main.15a606f",
|
53
|
+
"@dxos/debug": "0.6.12-main.15a606f",
|
54
|
+
"@dxos/automerge": "0.6.12-main.15a606f",
|
55
|
+
"@dxos/display-name": "0.6.12-main.15a606f",
|
56
|
+
"@dxos/log": "0.6.12-main.15a606f",
|
57
|
+
"@dxos/echo-schema": "0.6.12-main.15a606f",
|
58
|
+
"@dxos/invariant": "0.6.12-main.15a606f",
|
59
|
+
"@dxos/protocols": "0.6.12-main.15a606f",
|
60
|
+
"@dxos/react-ui-theme": "0.6.12-main.15a606f",
|
61
|
+
"@dxos/react-hooks": "0.6.12-main.15a606f",
|
62
|
+
"@dxos/util": "0.6.12-main.15a606f",
|
63
|
+
"@dxos/react-ui": "0.6.12-main.15a606f"
|
63
64
|
},
|
64
65
|
"devDependencies": {
|
65
66
|
"@phosphor-icons/react": "^2.1.5",
|
@@ -67,6 +68,8 @@
|
|
67
68
|
"@testing-library/dom": "^8.17.1",
|
68
69
|
"@testing-library/react": "^13.4.0",
|
69
70
|
"@testing-library/user-event": "^14.4.3",
|
71
|
+
"@types/chai": "^4.2.15",
|
72
|
+
"@types/chai-dom": "^1.11.0",
|
70
73
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
71
74
|
"@types/lodash.get": "^4.4.7",
|
72
75
|
"@types/lodash.merge": "^4.6.6",
|
@@ -74,29 +77,31 @@
|
|
74
77
|
"@types/react": "~18.2.0",
|
75
78
|
"@types/react-dom": "~18.2.0",
|
76
79
|
"@types/react-test-renderer": "^17.0.2",
|
80
|
+
"chai": "^4.4.1",
|
81
|
+
"chai-dom": "^1.11.0",
|
77
82
|
"happy-dom": "^13.3.1",
|
78
83
|
"jsdom": "^24.0.0",
|
84
|
+
"mocha": "^10.6.0",
|
79
85
|
"react": "~18.2.0",
|
80
86
|
"react-dom": "~18.2.0",
|
81
87
|
"react-test-renderer": "~18.2.0",
|
82
|
-
"vite": "
|
88
|
+
"vite": "5.4.7",
|
83
89
|
"vite-plugin-top-level-await": "^1.4.1",
|
84
90
|
"vite-plugin-wasm": "^3.3.0",
|
85
|
-
"@dxos/
|
86
|
-
"@dxos/
|
87
|
-
"@dxos/echo-signals": "0.6.
|
88
|
-
"@dxos/
|
89
|
-
"@dxos/
|
90
|
-
"@dxos/
|
91
|
-
"@dxos/storybook-utils": "0.6.
|
92
|
-
"@dxos/react-
|
93
|
-
"@dxos/react-ui": "0.6.11-staging.e6894a4"
|
91
|
+
"@dxos/automerge": "0.6.12-main.15a606f",
|
92
|
+
"@dxos/config": "0.6.12-main.15a606f",
|
93
|
+
"@dxos/echo-signals": "0.6.12-main.15a606f",
|
94
|
+
"@dxos/keyboard": "0.6.12-main.15a606f",
|
95
|
+
"@dxos/random": "0.6.12-main.15a606f",
|
96
|
+
"@dxos/react-client": "0.6.12-main.15a606f",
|
97
|
+
"@dxos/storybook-utils": "0.6.12-main.15a606f",
|
98
|
+
"@dxos/react-ui": "0.6.12-main.15a606f"
|
94
99
|
},
|
95
100
|
"peerDependencies": {
|
96
101
|
"@phosphor-icons/react": "^2.1.5",
|
97
|
-
"react": "
|
98
|
-
"react-dom": "
|
99
|
-
"@dxos/react-client": "0.6.
|
102
|
+
"react": "~18.2.0",
|
103
|
+
"react-dom": "~18.2.0",
|
104
|
+
"@dxos/react-client": "0.6.12-main.15a606f"
|
100
105
|
},
|
101
106
|
"publishConfig": {
|
102
107
|
"access": "public"
|
@@ -6,9 +6,9 @@ import '@dxos-theme';
|
|
6
6
|
|
7
7
|
import React, { useState } from 'react';
|
8
8
|
|
9
|
-
import { Toolbar as NaturalToolbar, Select, useThemeContext
|
9
|
+
import { Toolbar as NaturalToolbar, Select, useThemeContext } from '@dxos/react-ui';
|
10
10
|
import { attentionSurface, mx, textBlockWidth } from '@dxos/react-ui-theme';
|
11
|
-
import {
|
11
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
12
12
|
|
13
13
|
import { Toolbar } from './components';
|
14
14
|
import {
|
@@ -39,7 +39,7 @@ const Story = ({ autoFocus, initialValue, placeholder, readonly }: StoryProps) =
|
|
39
39
|
editorInputMode ? InputModeExtensions[editorInputMode] : [],
|
40
40
|
createBasicExtensions({ placeholder, lineWrapping: true, readonly }),
|
41
41
|
createMarkdownExtensions({ themeMode }),
|
42
|
-
createThemeExtensions({ themeMode }),
|
42
|
+
createThemeExtensions({ themeMode, syntaxHighlighting: true }),
|
43
43
|
decorateMarkdown(),
|
44
44
|
formattingKeymap(),
|
45
45
|
trackFormatting,
|
@@ -54,12 +54,10 @@ const Story = ({ autoFocus, initialValue, placeholder, readonly }: StoryProps) =
|
|
54
54
|
// Also not sure if view is even guaranteed to exist at this point.
|
55
55
|
return (
|
56
56
|
<div role='none' className={mx('fixed inset-0 flex flex-col')}>
|
57
|
-
<
|
58
|
-
<Toolbar.
|
59
|
-
|
60
|
-
|
61
|
-
</Toolbar.Root>
|
62
|
-
</Tooltip.Provider>
|
57
|
+
<Toolbar.Root onAction={handleAction} state={formattingState} classNames={textBlockWidth}>
|
58
|
+
<Toolbar.Markdown />
|
59
|
+
<EditorInputModeToolbar editorInputMode={editorInputMode} setEditorInputMode={setEditorInputMode} />
|
60
|
+
</Toolbar.Root>
|
63
61
|
|
64
62
|
<div role='none' className='grow overflow-hidden'>
|
65
63
|
<div className={attentionSurface} ref={parentRef} />
|
@@ -100,7 +98,7 @@ const EditorInputModeToolbar = ({
|
|
100
98
|
|
101
99
|
export default {
|
102
100
|
title: 'react-ui-editor/InputMode',
|
103
|
-
decorators: [withTheme,
|
101
|
+
decorators: [withTheme, withLayout({ fullscreen: true, tooltips: true })],
|
104
102
|
parameters: { translations, layout: 'fullscreen' },
|
105
103
|
render: Story,
|
106
104
|
};
|
@@ -4,6 +4,7 @@
|
|
4
4
|
|
5
5
|
import '@dxos-theme';
|
6
6
|
|
7
|
+
import { javascript } from '@codemirror/lang-javascript';
|
7
8
|
import { markdown } from '@codemirror/lang-markdown';
|
8
9
|
import { openSearchPanel } from '@codemirror/search';
|
9
10
|
import { type Extension } from '@codemirror/state';
|
@@ -22,9 +23,9 @@ import { faker } from '@dxos/random';
|
|
22
23
|
import { createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
|
23
24
|
import { Button, DensityProvider, Input, useThemeContext } from '@dxos/react-ui';
|
24
25
|
import { baseSurface, mx, getSize } from '@dxos/react-ui-theme';
|
25
|
-
import {
|
26
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
26
27
|
|
27
|
-
import { editorContent, editorGutter } from './defaults';
|
28
|
+
import { editorContent, editorGutter, editorMonospace } from './defaults';
|
28
29
|
import {
|
29
30
|
InputModeExtensions,
|
30
31
|
annotations,
|
@@ -68,6 +69,15 @@ const num = () => faker.number.int({ min: 0, max: 9999 }).toLocaleString();
|
|
68
69
|
|
69
70
|
const img = '';
|
70
71
|
|
72
|
+
const code = str(
|
73
|
+
'// Code',
|
74
|
+
'const Component = () => {',
|
75
|
+
' const x = 100;',
|
76
|
+
'',
|
77
|
+
' return () => <div>Test</div>;',
|
78
|
+
'};',
|
79
|
+
);
|
80
|
+
|
71
81
|
const content = {
|
72
82
|
tasks: str(
|
73
83
|
//
|
@@ -111,22 +121,9 @@ const content = {
|
|
111
121
|
'',
|
112
122
|
),
|
113
123
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
'```bash',
|
118
|
-
'$ ls -las',
|
119
|
-
'```',
|
120
|
-
'',
|
121
|
-
'```tsx',
|
122
|
-
'const Component = () => {',
|
123
|
-
' const x = 100;',
|
124
|
-
'',
|
125
|
-
' return () => <div>Test</div>;',
|
126
|
-
'};',
|
127
|
-
'```',
|
128
|
-
'',
|
129
|
-
),
|
124
|
+
typescript: code,
|
125
|
+
|
126
|
+
codeblocks: str('### Code', '', '```bash', '$ ls -las', '```', '', '```tsx', code, '```', ''),
|
130
127
|
|
131
128
|
comment: str('<!--', 'A comment', '-->', '', 'No comment.', 'Partial comment. <!-- comment. -->'),
|
132
129
|
|
@@ -195,12 +192,9 @@ const text = str(
|
|
195
192
|
content.tasks,
|
196
193
|
content.numbered,
|
197
194
|
|
198
|
-
'---',
|
199
|
-
content.headings,
|
200
|
-
|
201
195
|
'---',
|
202
196
|
'## Misc',
|
203
|
-
content.
|
197
|
+
content.codeblocks,
|
204
198
|
content.table,
|
205
199
|
content.image,
|
206
200
|
content.footer,
|
@@ -261,12 +255,15 @@ const renderLinkButton = (el: Element, url: string) => {
|
|
261
255
|
// Story
|
262
256
|
//
|
263
257
|
|
258
|
+
type DebugMode = 'raw' | 'tree' | 'raw+tree';
|
259
|
+
|
264
260
|
type StoryProps = {
|
265
261
|
id?: string;
|
266
|
-
debug?:
|
262
|
+
debug?: DebugMode;
|
267
263
|
text?: string;
|
268
264
|
readonly?: boolean;
|
269
265
|
placeholder?: string;
|
266
|
+
lineNumbers?: boolean;
|
270
267
|
onReady?: (view: EditorView) => void;
|
271
268
|
} & Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'>;
|
272
269
|
|
@@ -279,6 +276,7 @@ const Story = ({
|
|
279
276
|
placeholder = 'New document.',
|
280
277
|
scrollTo,
|
281
278
|
selection,
|
279
|
+
lineNumbers,
|
282
280
|
onReady,
|
283
281
|
}: StoryProps) => {
|
284
282
|
const [object] = useState(createEchoObject(create(Expando, { content: text ?? '' })));
|
@@ -290,16 +288,18 @@ const Story = ({
|
|
290
288
|
initialValue: text,
|
291
289
|
extensions: [
|
292
290
|
createDataExtensions({ id, text: createDocAccessor(object, ['content']) }),
|
293
|
-
createBasicExtensions({ readonly, placeholder, scrollPastEnd: true }),
|
291
|
+
createBasicExtensions({ readonly, placeholder, lineNumbers, scrollPastEnd: true }),
|
294
292
|
createMarkdownExtensions({ themeMode }),
|
295
293
|
createThemeExtensions({
|
296
294
|
themeMode,
|
295
|
+
syntaxHighlighting: true,
|
297
296
|
slots: {
|
298
297
|
content: {
|
299
298
|
className: editorContent,
|
300
299
|
},
|
301
300
|
},
|
302
301
|
}),
|
302
|
+
editorGutter,
|
303
303
|
extensions || [],
|
304
304
|
debug ? debugTree(setTree) : [],
|
305
305
|
],
|
@@ -319,10 +319,15 @@ const Story = ({
|
|
319
319
|
<div className='flex w-full'>
|
320
320
|
<div role='none' className='flex w-full overflow-hidden' ref={parentRef} {...focusAttributes} />
|
321
321
|
{debug && (
|
322
|
-
<div className='w-[800px] border-l border-separator overflow-auto'>
|
323
|
-
|
324
|
-
{
|
325
|
-
|
322
|
+
<div className='flex flex-col w-[800px] border-l border-separator divide-y divide-separator overflow-auto'>
|
323
|
+
{(debug === 'raw' || debug === 'raw+tree') && (
|
324
|
+
<pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>{view?.state.doc.toString()}</pre>
|
325
|
+
)}
|
326
|
+
{(debug === 'tree' || debug === 'raw+tree') && (
|
327
|
+
<pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>
|
328
|
+
{JSON.stringify(tree, null, 2)}
|
329
|
+
</pre>
|
330
|
+
)}
|
326
331
|
</div>
|
327
332
|
)}
|
328
333
|
</div>
|
@@ -331,7 +336,7 @@ const Story = ({
|
|
331
336
|
|
332
337
|
export default {
|
333
338
|
title: 'react-ui-editor/TextEditor',
|
334
|
-
decorators: [withTheme,
|
339
|
+
decorators: [withTheme, withLayout({ fullscreen: true })],
|
335
340
|
render: Story,
|
336
341
|
parameters: { translations, layout: 'fullscreen' },
|
337
342
|
};
|
@@ -345,8 +350,24 @@ const defaultExtensions: Extension[] = [
|
|
345
350
|
linkTooltip(renderLinkTooltip),
|
346
351
|
];
|
347
352
|
|
353
|
+
const allExtensions: Extension[] = [
|
354
|
+
autocomplete({
|
355
|
+
onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
|
356
|
+
}),
|
357
|
+
decorateMarkdown({ numberedHeadings: { from: 2, to: 4 }, renderLinkButton, selectionChangeDelay: 100 }),
|
358
|
+
formattingKeymap(),
|
359
|
+
linkTooltip(renderLinkTooltip),
|
360
|
+
image(),
|
361
|
+
table(),
|
362
|
+
folding(),
|
363
|
+
];
|
364
|
+
|
348
365
|
export const Default = {
|
349
|
-
render: () => <Story text={text} extensions={defaultExtensions}
|
366
|
+
render: () => <Story text={text} extensions={defaultExtensions} />,
|
367
|
+
};
|
368
|
+
|
369
|
+
export const Everything = {
|
370
|
+
render: () => <Story text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
|
350
371
|
};
|
351
372
|
|
352
373
|
export const Empty = {
|
@@ -390,7 +411,7 @@ const headings = str(
|
|
390
411
|
const global = new Map<string, EditorSelectionState>();
|
391
412
|
|
392
413
|
export const Folding = {
|
393
|
-
render: () => <Story text={text} extensions={[
|
414
|
+
render: () => <Story text={text} extensions={[folding()]} />,
|
394
415
|
};
|
395
416
|
|
396
417
|
export const Scrolling = {
|
@@ -445,7 +466,7 @@ export const Image = {
|
|
445
466
|
};
|
446
467
|
|
447
468
|
export const Code = {
|
448
|
-
render: () => <Story text={str(content.
|
469
|
+
render: () => <Story text={str(content.codeblocks, content.footer)} extensions={[decorateMarkdown()]} />,
|
449
470
|
};
|
450
471
|
|
451
472
|
export const Lists = {
|
@@ -466,7 +487,7 @@ export const OrderedList = {
|
|
466
487
|
};
|
467
488
|
|
468
489
|
export const TaskList = {
|
469
|
-
render: () => <Story text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug />,
|
490
|
+
render: () => <Story text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug='raw+tree' />,
|
470
491
|
};
|
471
492
|
|
472
493
|
export const Table = {
|
@@ -486,6 +507,12 @@ export const CommentedOut = {
|
|
486
507
|
),
|
487
508
|
};
|
488
509
|
|
510
|
+
export const Typescript = {
|
511
|
+
render: () => (
|
512
|
+
<Story text={content.typescript} lineNumbers extensions={[editorMonospace, javascript({ typescript: true })]} />
|
513
|
+
),
|
514
|
+
};
|
515
|
+
|
489
516
|
//
|
490
517
|
// Custom
|
491
518
|
//
|
@@ -669,7 +696,7 @@ export const Typewriter = {
|
|
669
696
|
export const Blast = {
|
670
697
|
render: () => (
|
671
698
|
<Story
|
672
|
-
text={str('# Blast', '', content.paragraphs, content.
|
699
|
+
text={str('# Blast', '', content.paragraphs, content.codeblocks, content.paragraphs)}
|
673
700
|
extensions={[
|
674
701
|
typewriter({ items: typewriterItems }),
|
675
702
|
blast(
|
package/src/defaults.ts
CHANGED
@@ -8,7 +8,7 @@ import { mx } from '@dxos/react-ui-theme';
|
|
8
8
|
|
9
9
|
import { fontMono } from './styles';
|
10
10
|
|
11
|
-
const margin = '!mt-[
|
11
|
+
const margin = '!mt-[1rem]';
|
12
12
|
|
13
13
|
/**
|
14
14
|
* CodeMirror content width.
|
@@ -20,16 +20,16 @@ export const editorContent = mx(margin, '!mli-auto w-full max-w-[min(50rem,100%-
|
|
20
20
|
/**
|
21
21
|
* Margin for numbers.
|
22
22
|
*/
|
23
|
-
export const editorFullWidth = mx(margin
|
23
|
+
export const editorFullWidth = mx(margin);
|
24
24
|
|
25
25
|
export const editorWithToolbarLayout =
|
26
26
|
'grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden';
|
27
27
|
|
28
|
-
// TODO(burdon): Define scrollMargins for fixed gutter.
|
29
28
|
export const editorGutter = EditorView.theme({
|
30
29
|
// Match margin from content.
|
31
30
|
'.cm-gutters': {
|
32
31
|
marginTop: '16px',
|
32
|
+
paddingRight: '1rem',
|
33
33
|
},
|
34
34
|
});
|
35
35
|
|
@@ -10,12 +10,11 @@ import React, { useEffect, useState } from 'react';
|
|
10
10
|
import { Repo } from '@dxos/automerge/automerge-repo';
|
11
11
|
import { BroadcastChannelNetworkAdapter } from '@dxos/automerge/automerge-repo-network-broadcastchannel';
|
12
12
|
import { Expando, create } from '@dxos/echo-schema';
|
13
|
-
import { type PublicKey } from '@dxos/keys';
|
14
13
|
import { Filter, DocAccessor, createDocAccessor, useSpace, useQuery, type Space } from '@dxos/react-client/echo';
|
15
14
|
import { useIdentity, type Identity } from '@dxos/react-client/halo';
|
16
|
-
import { ClientRepeater } from '@dxos/react-client/testing';
|
15
|
+
import { type ClientRepeatedComponentProps, ClientRepeater } from '@dxos/react-client/testing';
|
17
16
|
import { useThemeContext } from '@dxos/react-ui';
|
18
|
-
import { withTheme } from '@dxos/storybook-utils';
|
17
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
19
18
|
|
20
19
|
import { editorContent } from '../../defaults';
|
21
20
|
import { useTextEditor } from '../../hooks';
|
@@ -95,12 +94,12 @@ const Story = () => {
|
|
95
94
|
export default {
|
96
95
|
title: 'react-ui-editor/Automerge',
|
97
96
|
component: Editor,
|
98
|
-
decorators: [withTheme],
|
97
|
+
decorators: [withTheme, withLayout({ fullscreen: true })],
|
99
98
|
render: () => <Story />,
|
100
|
-
parameters: { translations
|
99
|
+
parameters: { translations },
|
101
100
|
};
|
102
101
|
|
103
|
-
const EchoStory = ({ spaceKey }:
|
102
|
+
const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
|
104
103
|
const identity = useIdentity();
|
105
104
|
const space = useSpace(spaceKey);
|
106
105
|
const [source, setSource] = useState<DocAccessor>();
|
@@ -5,6 +5,7 @@
|
|
5
5
|
import { EditorState } from '@codemirror/state';
|
6
6
|
import { EditorView } from '@codemirror/view';
|
7
7
|
import { render, screen } from '@testing-library/react';
|
8
|
+
// TODO(wittjosiah): Move to vitest expect.
|
8
9
|
import chai, { expect } from 'chai';
|
9
10
|
import chaiDom from 'chai-dom';
|
10
11
|
import get from 'lodash.get';
|
@@ -4,9 +4,10 @@
|
|
4
4
|
|
5
5
|
import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
|
6
6
|
import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap } from '@codemirror/commands';
|
7
|
-
import { bracketMatching } from '@codemirror/language';
|
7
|
+
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
8
8
|
import { searchKeymap } from '@codemirror/search';
|
9
9
|
import { EditorState, type Extension } from '@codemirror/state';
|
10
|
+
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
|
10
11
|
import {
|
11
12
|
EditorView,
|
12
13
|
type KeyBinding,
|
@@ -131,6 +132,7 @@ export const createBasicExtensions = (_props?: BasicExtensionsOptions): Extensio
|
|
131
132
|
export type ThemeExtensionsOptions = {
|
132
133
|
themeMode?: ThemeMode;
|
133
134
|
styles?: ThemeStyles;
|
135
|
+
syntaxHighlighting?: boolean;
|
134
136
|
slots?: {
|
135
137
|
editor?: {
|
136
138
|
className?: string;
|
@@ -147,13 +149,22 @@ const defaultThemeSlots = {
|
|
147
149
|
},
|
148
150
|
};
|
149
151
|
|
150
|
-
|
151
|
-
|
152
|
-
|
152
|
+
/**
|
153
|
+
* https://codemirror.net/examples/styling
|
154
|
+
*/
|
155
|
+
export const createThemeExtensions = ({
|
156
|
+
themeMode,
|
157
|
+
styles,
|
158
|
+
syntaxHighlighting: _syntaxHighlighting,
|
159
|
+
slots: _slots,
|
160
|
+
}: ThemeExtensionsOptions = {}): Extension => {
|
153
161
|
const slots = defaultsDeep({}, _slots, defaultThemeSlots);
|
154
162
|
return [
|
155
163
|
EditorView.darkTheme.of(themeMode === 'dark'),
|
156
164
|
EditorView.baseTheme(styles ? merge({}, defaultTheme, styles) : defaultTheme),
|
165
|
+
// https://github.com/codemirror/theme-one-dark
|
166
|
+
_syntaxHighlighting &&
|
167
|
+
(themeMode === 'dark' ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)),
|
157
168
|
slots.editor?.className && EditorView.editorAttributes.of({ class: slots.editor.className }),
|
158
169
|
slots.content?.className && EditorView.contentAttributes.of({ class: slots.content.className }),
|
159
170
|
].filter(isNotFalsy);
|
@@ -4,28 +4,41 @@
|
|
4
4
|
|
5
5
|
import { codeFolding, foldGutter } from '@codemirror/language';
|
6
6
|
import { type Extension } from '@codemirror/state';
|
7
|
+
import { EditorView } from '@codemirror/view';
|
7
8
|
import React from 'react';
|
8
9
|
|
9
10
|
import { Icon } from '@dxos/react-ui';
|
10
11
|
import { getSize } from '@dxos/react-ui-theme';
|
11
12
|
|
12
|
-
import { renderRoot } from './util';
|
13
|
+
import { createElement, renderRoot } from './util';
|
13
14
|
|
14
15
|
export type FoldingOptions = {};
|
15
16
|
|
16
17
|
/**
|
17
18
|
* https://codemirror.net/examples/gutter
|
18
19
|
*/
|
20
|
+
// TODO(burdon): Remember folding state.
|
19
21
|
export const folding = (_props: FoldingOptions = {}): Extension => [
|
20
22
|
codeFolding({
|
21
|
-
placeholderDOM: () =>
|
23
|
+
placeholderDOM: () => {
|
24
|
+
return document.createElement('span'); // Collapse content.
|
25
|
+
},
|
22
26
|
}),
|
23
27
|
foldGutter({
|
24
28
|
markerDOM: (open) => {
|
25
29
|
return renderRoot(
|
26
|
-
|
27
|
-
<Icon icon='ph--caret-right--regular' classNames={[getSize(3), '
|
30
|
+
createElement('div', { className: 'flex h-full items-center' }),
|
31
|
+
<Icon icon='ph--caret-right--regular' classNames={[getSize(3), 'mx-3 cursor-pointer', open && 'rotate-90']} />,
|
28
32
|
);
|
29
33
|
},
|
30
34
|
}),
|
35
|
+
EditorView.theme({
|
36
|
+
'.cm-foldGutter': {
|
37
|
+
opacity: 0.3,
|
38
|
+
transition: 'opacity 0.3s',
|
39
|
+
},
|
40
|
+
'.cm-foldGutter:hover': {
|
41
|
+
opacity: 1,
|
42
|
+
},
|
43
|
+
}),
|
31
44
|
];
|
@@ -5,11 +5,10 @@
|
|
5
5
|
import { completionKeymap } from '@codemirror/autocomplete';
|
6
6
|
import { defaultKeymap, indentWithTab } from '@codemirror/commands';
|
7
7
|
import { markdownLanguage, markdown } from '@codemirror/lang-markdown';
|
8
|
-
import {
|
8
|
+
import { syntaxHighlighting } from '@codemirror/language';
|
9
9
|
import { languages } from '@codemirror/language-data';
|
10
10
|
import { lintKeymap } from '@codemirror/lint';
|
11
11
|
import { type Extension } from '@codemirror/state';
|
12
|
-
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark';
|
13
12
|
import { keymap } from '@codemirror/view';
|
14
13
|
|
15
14
|
import { type ThemeMode } from '@dxos/react-ui';
|
@@ -54,9 +53,6 @@ export const createMarkdownExtensions = ({ themeMode }: MarkdownBundleOptions =
|
|
54
53
|
],
|
55
54
|
}),
|
56
55
|
|
57
|
-
// https://github.com/codemirror/theme-one-dark
|
58
|
-
themeMode === 'dark' ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle),
|
59
|
-
|
60
56
|
// Custom styles.
|
61
57
|
syntaxHighlighting(markdownHighlightStyle()),
|
62
58
|
|