@dxos/react-ui-editor 0.6.11-staging.e6894a4 → 0.6.12-main.5cc132e
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 +126 -73
- 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 +30 -25
- package/src/InputMode.stories.tsx +8 -10
- package/src/TextEditor.stories.tsx +58 -32
- package/src/defaults.ts +5 -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 +12 -8
- 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.5cc132e",
|
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/
|
55
|
-
"@dxos/echo-schema": "0.6.
|
56
|
-
"@dxos/
|
57
|
-
"@dxos/
|
58
|
-
"@dxos/
|
59
|
-
"@dxos/
|
60
|
-
"@dxos/
|
61
|
-
"@dxos/react-ui": "0.6.
|
62
|
-
"@dxos/
|
51
|
+
"@dxos/async": "0.6.12-main.5cc132e",
|
52
|
+
"@dxos/context": "0.6.12-main.5cc132e",
|
53
|
+
"@dxos/debug": "0.6.12-main.5cc132e",
|
54
|
+
"@dxos/automerge": "0.6.12-main.5cc132e",
|
55
|
+
"@dxos/invariant": "0.6.12-main.5cc132e",
|
56
|
+
"@dxos/echo-schema": "0.6.12-main.5cc132e",
|
57
|
+
"@dxos/log": "0.6.12-main.5cc132e",
|
58
|
+
"@dxos/protocols": "0.6.12-main.5cc132e",
|
59
|
+
"@dxos/react-hooks": "0.6.12-main.5cc132e",
|
60
|
+
"@dxos/display-name": "0.6.12-main.5cc132e",
|
61
|
+
"@dxos/react-ui": "0.6.12-main.5cc132e",
|
62
|
+
"@dxos/react-ui-theme": "0.6.12-main.5cc132e",
|
63
|
+
"@dxos/util": "0.6.12-main.5cc132e"
|
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/random": "0.6.
|
91
|
-
"@dxos/
|
92
|
-
"@dxos/
|
93
|
-
"@dxos/react-ui": "0.6.11-staging.e6894a4"
|
91
|
+
"@dxos/automerge": "0.6.12-main.5cc132e",
|
92
|
+
"@dxos/config": "0.6.12-main.5cc132e",
|
93
|
+
"@dxos/echo-signals": "0.6.12-main.5cc132e",
|
94
|
+
"@dxos/keyboard": "0.6.12-main.5cc132e",
|
95
|
+
"@dxos/react-ui": "0.6.12-main.5cc132e",
|
96
|
+
"@dxos/random": "0.6.12-main.5cc132e",
|
97
|
+
"@dxos/react-client": "0.6.12-main.5cc132e",
|
98
|
+
"@dxos/storybook-utils": "0.6.12-main.5cc132e"
|
94
99
|
},
|
95
100
|
"peerDependencies": {
|
96
101
|
"@phosphor-icons/react": "^2.1.5",
|
97
102
|
"react": "^18.0.0",
|
98
103
|
"react-dom": "^18.0.0",
|
99
|
-
"@dxos/react-client": "0.6.
|
104
|
+
"@dxos/react-client": "0.6.12-main.5cc132e"
|
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
|
};
|
@@ -3,7 +3,7 @@
|
|
3
3
|
//
|
4
4
|
|
5
5
|
import '@dxos-theme';
|
6
|
-
|
6
|
+
import { javascript } from '@codemirror/lang-javascript';
|
7
7
|
import { markdown } from '@codemirror/lang-markdown';
|
8
8
|
import { openSearchPanel } from '@codemirror/search';
|
9
9
|
import { type Extension } from '@codemirror/state';
|
@@ -22,9 +22,9 @@ import { faker } from '@dxos/random';
|
|
22
22
|
import { createDocAccessor, createEchoObject } from '@dxos/react-client/echo';
|
23
23
|
import { Button, DensityProvider, Input, useThemeContext } from '@dxos/react-ui';
|
24
24
|
import { baseSurface, mx, getSize } from '@dxos/react-ui-theme';
|
25
|
-
import {
|
25
|
+
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
26
26
|
|
27
|
-
import { editorContent, editorGutter } from './defaults';
|
27
|
+
import { editorContent, editorGutter, editorMonospace } from './defaults';
|
28
28
|
import {
|
29
29
|
InputModeExtensions,
|
30
30
|
annotations,
|
@@ -68,6 +68,15 @@ const num = () => faker.number.int({ min: 0, max: 9999 }).toLocaleString();
|
|
68
68
|
|
69
69
|
const img = '';
|
70
70
|
|
71
|
+
const code = str(
|
72
|
+
'// Code',
|
73
|
+
'const Component = () => {',
|
74
|
+
' const x = 100;',
|
75
|
+
'',
|
76
|
+
' return () => <div>Test</div>;',
|
77
|
+
'};',
|
78
|
+
);
|
79
|
+
|
71
80
|
const content = {
|
72
81
|
tasks: str(
|
73
82
|
//
|
@@ -111,22 +120,9 @@ const content = {
|
|
111
120
|
'',
|
112
121
|
),
|
113
122
|
|
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
|
-
),
|
123
|
+
typescript: code,
|
124
|
+
|
125
|
+
codeblocks: str('### Code', '', '```bash', '$ ls -las', '```', '', '```tsx', code, '```', ''),
|
130
126
|
|
131
127
|
comment: str('<!--', 'A comment', '-->', '', 'No comment.', 'Partial comment. <!-- comment. -->'),
|
132
128
|
|
@@ -195,12 +191,9 @@ const text = str(
|
|
195
191
|
content.tasks,
|
196
192
|
content.numbered,
|
197
193
|
|
198
|
-
'---',
|
199
|
-
content.headings,
|
200
|
-
|
201
194
|
'---',
|
202
195
|
'## Misc',
|
203
|
-
content.
|
196
|
+
content.codeblocks,
|
204
197
|
content.table,
|
205
198
|
content.image,
|
206
199
|
content.footer,
|
@@ -261,12 +254,15 @@ const renderLinkButton = (el: Element, url: string) => {
|
|
261
254
|
// Story
|
262
255
|
//
|
263
256
|
|
257
|
+
type DebugMode = 'syntax' | 'raw';
|
258
|
+
|
264
259
|
type StoryProps = {
|
265
260
|
id?: string;
|
266
|
-
debug?:
|
261
|
+
debug?: DebugMode;
|
267
262
|
text?: string;
|
268
263
|
readonly?: boolean;
|
269
264
|
placeholder?: string;
|
265
|
+
lineNumbers?: boolean;
|
270
266
|
onReady?: (view: EditorView) => void;
|
271
267
|
} & Pick<UseTextEditorProps, 'scrollTo' | 'selection' | 'extensions'>;
|
272
268
|
|
@@ -279,6 +275,7 @@ const Story = ({
|
|
279
275
|
placeholder = 'New document.',
|
280
276
|
scrollTo,
|
281
277
|
selection,
|
278
|
+
lineNumbers,
|
282
279
|
onReady,
|
283
280
|
}: StoryProps) => {
|
284
281
|
const [object] = useState(createEchoObject(create(Expando, { content: text ?? '' })));
|
@@ -290,16 +287,18 @@ const Story = ({
|
|
290
287
|
initialValue: text,
|
291
288
|
extensions: [
|
292
289
|
createDataExtensions({ id, text: createDocAccessor(object, ['content']) }),
|
293
|
-
createBasicExtensions({ readonly, placeholder, scrollPastEnd: true }),
|
290
|
+
createBasicExtensions({ readonly, placeholder, lineNumbers, scrollPastEnd: true }),
|
294
291
|
createMarkdownExtensions({ themeMode }),
|
295
292
|
createThemeExtensions({
|
296
293
|
themeMode,
|
294
|
+
syntaxHighlighting: true,
|
297
295
|
slots: {
|
298
296
|
content: {
|
299
297
|
className: editorContent,
|
300
298
|
},
|
301
299
|
},
|
302
300
|
}),
|
301
|
+
editorGutter,
|
303
302
|
extensions || [],
|
304
303
|
debug ? debugTree(setTree) : [],
|
305
304
|
],
|
@@ -318,7 +317,12 @@ const Story = ({
|
|
318
317
|
return (
|
319
318
|
<div className='flex w-full'>
|
320
319
|
<div role='none' className='flex w-full overflow-hidden' ref={parentRef} {...focusAttributes} />
|
321
|
-
{debug && (
|
320
|
+
{debug === 'raw' && (
|
321
|
+
<div className='w-[800px] border-l border-separator overflow-auto'>
|
322
|
+
<pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>{view?.state.doc.toString()}</pre>
|
323
|
+
</div>
|
324
|
+
)}
|
325
|
+
{debug === 'syntax' && (
|
322
326
|
<div className='w-[800px] border-l border-separator overflow-auto'>
|
323
327
|
<pre className='p-1 font-mono text-xs text-green-800 dark:text-green-200'>
|
324
328
|
{JSON.stringify(tree, null, 2)}
|
@@ -331,7 +335,7 @@ const Story = ({
|
|
331
335
|
|
332
336
|
export default {
|
333
337
|
title: 'react-ui-editor/TextEditor',
|
334
|
-
decorators: [withTheme,
|
338
|
+
decorators: [withTheme, withLayout({ fullscreen: true })],
|
335
339
|
render: Story,
|
336
340
|
parameters: { translations, layout: 'fullscreen' },
|
337
341
|
};
|
@@ -345,8 +349,24 @@ const defaultExtensions: Extension[] = [
|
|
345
349
|
linkTooltip(renderLinkTooltip),
|
346
350
|
];
|
347
351
|
|
352
|
+
const allExtensions: Extension[] = [
|
353
|
+
autocomplete({
|
354
|
+
onSearch: (text) => links.filter(({ label }) => label.toLowerCase().includes(text.toLowerCase())),
|
355
|
+
}),
|
356
|
+
decorateMarkdown({ numberedHeadings: { from: 2, to: 4 }, renderLinkButton, selectionChangeDelay: 100 }),
|
357
|
+
formattingKeymap(),
|
358
|
+
linkTooltip(renderLinkTooltip),
|
359
|
+
image(),
|
360
|
+
table(),
|
361
|
+
folding(),
|
362
|
+
];
|
363
|
+
|
348
364
|
export const Default = {
|
349
|
-
render: () => <Story text={text} extensions={defaultExtensions}
|
365
|
+
render: () => <Story text={text} extensions={defaultExtensions} />,
|
366
|
+
};
|
367
|
+
|
368
|
+
export const Everything = {
|
369
|
+
render: () => <Story text={text} extensions={allExtensions} selection={{ anchor: 99, head: 110 }} />,
|
350
370
|
};
|
351
371
|
|
352
372
|
export const Empty = {
|
@@ -390,7 +410,7 @@ const headings = str(
|
|
390
410
|
const global = new Map<string, EditorSelectionState>();
|
391
411
|
|
392
412
|
export const Folding = {
|
393
|
-
render: () => <Story text={text} extensions={[
|
413
|
+
render: () => <Story text={text} extensions={[folding()]} />,
|
394
414
|
};
|
395
415
|
|
396
416
|
export const Scrolling = {
|
@@ -445,7 +465,7 @@ export const Image = {
|
|
445
465
|
};
|
446
466
|
|
447
467
|
export const Code = {
|
448
|
-
render: () => <Story text={str(content.
|
468
|
+
render: () => <Story text={str(content.codeblocks, content.footer)} extensions={[decorateMarkdown()]} />,
|
449
469
|
};
|
450
470
|
|
451
471
|
export const Lists = {
|
@@ -466,7 +486,7 @@ export const OrderedList = {
|
|
466
486
|
};
|
467
487
|
|
468
488
|
export const TaskList = {
|
469
|
-
render: () => <Story text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug />,
|
489
|
+
render: () => <Story text={str(content.tasks, content.footer)} extensions={[decorateMarkdown()]} debug='raw' />,
|
470
490
|
};
|
471
491
|
|
472
492
|
export const Table = {
|
@@ -486,6 +506,12 @@ export const CommentedOut = {
|
|
486
506
|
),
|
487
507
|
};
|
488
508
|
|
509
|
+
export const Typescript = {
|
510
|
+
render: () => (
|
511
|
+
<Story text={content.typescript} lineNumbers extensions={[editorMonospace, javascript({ typescript: true })]} />
|
512
|
+
),
|
513
|
+
};
|
514
|
+
|
489
515
|
//
|
490
516
|
// Custom
|
491
517
|
//
|
@@ -669,7 +695,7 @@ export const Typewriter = {
|
|
669
695
|
export const Blast = {
|
670
696
|
render: () => (
|
671
697
|
<Story
|
672
|
-
text={str('# Blast', '', content.paragraphs, content.
|
698
|
+
text={str('# Blast', '', content.paragraphs, content.codeblocks, content.paragraphs)}
|
673
699
|
extensions={[
|
674
700
|
typewriter({ items: typewriterItems }),
|
675
701
|
blast(
|
package/src/defaults.ts
CHANGED
@@ -8,7 +8,9 @@ import { mx } from '@dxos/react-ui-theme';
|
|
8
8
|
|
9
9
|
import { fontMono } from './styles';
|
10
10
|
|
11
|
-
|
11
|
+
// TODO(burdon): Define scrollMargins for fixed gutter?
|
12
|
+
// https://codemirror.net/docs/ref/#view.EditorView^scrollMargins
|
13
|
+
const margin = '!mt-[1rem]';
|
12
14
|
|
13
15
|
/**
|
14
16
|
* CodeMirror content width.
|
@@ -20,16 +22,16 @@ export const editorContent = mx(margin, '!mli-auto w-full max-w-[min(50rem,100%-
|
|
20
22
|
/**
|
21
23
|
* Margin for numbers.
|
22
24
|
*/
|
23
|
-
export const editorFullWidth = mx(margin
|
25
|
+
export const editorFullWidth = mx(margin);
|
24
26
|
|
25
27
|
export const editorWithToolbarLayout =
|
26
28
|
'grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden';
|
27
29
|
|
28
|
-
// TODO(burdon): Define scrollMargins for fixed gutter.
|
29
30
|
export const editorGutter = EditorView.theme({
|
30
31
|
// Match margin from content.
|
31
32
|
'.cm-gutters': {
|
32
33
|
marginTop: '16px',
|
34
|
+
paddingRight: '1rem',
|
33
35
|
},
|
34
36
|
});
|
35
37
|
|
@@ -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
|
|