@dxos/react-ui-editor 0.8.2-main.f081794 → 0.8.2-main.fbd8ed0
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 +1664 -1359
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs.map +2 -2
- package/dist/lib/node/index.cjs +2122 -1819
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs.map +2 -2
- package/dist/lib/node-esm/index.mjs +1664 -1359
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/testing/index.mjs.map +2 -2
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts +1 -1
- package/dist/types/src/components/EditorToolbar/EditorToolbar.d.ts.map +1 -1
- package/dist/types/src/{stories/InputMode.stories.d.ts → components/EditorToolbar/EditorToolbar.stories.d.ts} +3 -7
- package/dist/types/src/components/EditorToolbar/EditorToolbar.stories.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/blocks.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/blocks.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/comment.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/comment.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/formatting.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/formatting.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/headings.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/headings.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/image.d.ts +16 -0
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/lists.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/lists.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/search.d.ts +17 -0
- package/dist/types/src/components/EditorToolbar/search.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/util.d.ts +11 -17
- package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts +4 -3
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -1
- package/dist/types/src/defaults.d.ts.map +1 -1
- package/dist/types/src/extensions/annotations.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts +1 -1
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +1 -1
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts +1 -1
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -1
- package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
- package/dist/types/src/extensions/blast.d.ts.map +1 -1
- package/dist/types/src/extensions/command/command.d.ts.map +1 -1
- package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
- package/dist/types/src/extensions/command/menu.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/debug.d.ts.map +1 -1
- package/dist/types/src/extensions/dnd.d.ts.map +1 -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/listener.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/decorate.d.ts +1 -0
- package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/index.d.ts +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/outliner.d.ts +12 -0
- package/dist/types/src/extensions/markdown/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/modes.d.ts +5 -5
- package/dist/types/src/extensions/modes.d.ts.map +1 -1
- package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
- package/dist/types/src/extensions/selection.d.ts.map +1 -1
- package/dist/types/src/extensions/typewriter.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/stories/TextEditorBasic.stories.d.ts +3 -0
- package/dist/types/src/stories/TextEditorBasic.stories.d.ts.map +1 -1
- package/dist/types/src/stories/story-utils.d.ts.map +1 -1
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/src/testing/RefPopover.d.ts.map +1 -1
- package/dist/types/src/util/cursor.d.ts.map +1 -1
- package/dist/types/src/util/debug.d.ts.map +1 -1
- package/dist/types/src/util/dom.d.ts.map +1 -1
- package/dist/types/src/util/facet.d.ts.map +1 -1
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +32 -28
- package/src/components/EditorToolbar/EditorToolbar.stories.tsx +90 -0
- package/src/components/EditorToolbar/EditorToolbar.tsx +31 -32
- package/src/components/EditorToolbar/blocks.ts +27 -6
- package/src/components/EditorToolbar/comment.ts +11 -4
- package/src/components/EditorToolbar/formatting.ts +34 -7
- package/src/components/EditorToolbar/headings.ts +9 -8
- package/src/components/EditorToolbar/image.ts +16 -0
- package/src/components/EditorToolbar/lists.ts +26 -7
- package/src/components/EditorToolbar/search.ts +19 -0
- package/src/components/EditorToolbar/util.ts +14 -14
- package/src/components/EditorToolbar/view-mode.ts +9 -8
- package/src/defaults.ts +1 -1
- package/src/extensions/automerge/automerge.stories.tsx +9 -7
- package/src/extensions/automerge/automerge.test.tsx +4 -4
- package/src/extensions/automerge/automerge.ts +2 -2
- package/src/extensions/automerge/defs.ts +1 -2
- package/src/extensions/automerge/sync.ts +4 -4
- package/src/extensions/automerge/update-automerge.ts +1 -1
- package/src/extensions/automerge/update-codemirror.ts +3 -4
- package/src/extensions/markdown/changes.ts +3 -2
- package/src/extensions/markdown/decorate.ts +8 -7
- package/src/extensions/markdown/formatting.ts +4 -4
- package/src/extensions/markdown/index.ts +1 -0
- package/src/extensions/markdown/outliner.ts +235 -0
- package/src/extensions/markdown/styles.ts +2 -2
- package/src/extensions/modes.ts +5 -6
- package/src/extensions/preview/preview.ts +1 -1
- package/src/hooks/index.ts +0 -1
- package/src/stories/TextEditorBasic.stories.tsx +44 -0
- package/src/stories/story-utils.tsx +7 -9
- package/src/styles/theme.ts +3 -0
- package/src/testing/RefPopover.tsx +4 -4
- package/dist/types/src/hooks/useActionHandler.d.ts +0 -4
- package/dist/types/src/hooks/useActionHandler.d.ts.map +0 -1
- package/dist/types/src/stories/InputMode.stories.d.ts.map +0 -1
- package/src/hooks/useActionHandler.ts +0 -12
- package/src/stories/InputMode.stories.tsx +0 -124
@@ -2,11 +2,13 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
6
|
+
|
5
7
|
import { type NodeArg } from '@dxos/app-graph';
|
6
8
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
7
9
|
|
8
10
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
9
|
-
import {
|
11
|
+
import { addList, List, removeList } from '../../extensions';
|
10
12
|
|
11
13
|
const listStyles = {
|
12
14
|
bullet: 'ph--list-bullets--regular',
|
@@ -21,15 +23,32 @@ const createListGroupAction = (value: string) =>
|
|
21
23
|
value,
|
22
24
|
} as ToolbarMenuActionGroupProperties);
|
23
25
|
|
24
|
-
const createListActions = (value: string) =>
|
25
|
-
Object.entries(listStyles).map(([listStyle, icon]) =>
|
26
|
-
|
27
|
-
|
26
|
+
const createListActions = (value: string, getView: () => EditorView) =>
|
27
|
+
Object.entries(listStyles).map(([listStyle, icon]) => {
|
28
|
+
const checked = value === listStyle;
|
29
|
+
return createEditorAction(
|
30
|
+
`list-${listStyle}`,
|
31
|
+
() => {
|
32
|
+
const view = getView();
|
33
|
+
if (!view) {
|
34
|
+
return;
|
35
|
+
}
|
36
|
+
|
37
|
+
const listType = listStyle === 'ordered' ? List.Ordered : listStyle === 'bullet' ? List.Bullet : List.Task;
|
38
|
+
if (checked) {
|
39
|
+
removeList(listType)(view);
|
40
|
+
} else {
|
41
|
+
addList(listType)(view);
|
42
|
+
}
|
43
|
+
},
|
44
|
+
{ checked, icon },
|
45
|
+
);
|
46
|
+
});
|
28
47
|
|
29
|
-
export const createLists = (state: EditorToolbarState) => {
|
48
|
+
export const createLists = (state: EditorToolbarState, getView: () => EditorView) => {
|
30
49
|
const value = state.listStyle ?? '';
|
31
50
|
const listGroupAction = createListGroupAction(value);
|
32
|
-
const listActionsMap = createListActions(value);
|
51
|
+
const listActionsMap = createListActions(value, getView);
|
33
52
|
return {
|
34
53
|
nodes: [listGroupAction as NodeArg<any>, ...listActionsMap],
|
35
54
|
edges: [
|
@@ -0,0 +1,19 @@
|
|
1
|
+
//
|
2
|
+
// Copyright 2025 DXOS.org
|
3
|
+
//
|
4
|
+
|
5
|
+
import { openSearchPanel } from '@codemirror/search';
|
6
|
+
import { type EditorView } from '@codemirror/view';
|
7
|
+
|
8
|
+
import { createEditorAction } from './util';
|
9
|
+
|
10
|
+
const createSearchAction = (getView: () => EditorView) =>
|
11
|
+
createEditorAction('search', () => openSearchPanel(getView()), {
|
12
|
+
testId: 'editor.toolbar.search',
|
13
|
+
icon: 'ph--magnifying-glass--regular',
|
14
|
+
});
|
15
|
+
|
16
|
+
export const createSearch = (getView: () => EditorView) => ({
|
17
|
+
nodes: [createSearchAction(getView)],
|
18
|
+
edges: [{ source: 'root', target: 'search' }],
|
19
|
+
});
|
@@ -2,21 +2,23 @@
|
|
2
2
|
// Copyright 2025 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
+
import { type EditorView } from '@codemirror/view';
|
5
6
|
import { useMemo } from 'react';
|
6
7
|
|
8
|
+
import { type Action } from '@dxos/app-graph';
|
7
9
|
import { live, type Live } from '@dxos/live-object';
|
8
|
-
import { type
|
10
|
+
import { type ThemedClassName } from '@dxos/react-ui';
|
9
11
|
import {
|
10
12
|
type MenuSeparator,
|
11
13
|
type MenuItemGroup,
|
12
14
|
type ToolbarMenuActionGroupProperties,
|
13
|
-
type MenuActionProperties,
|
14
15
|
createMenuAction,
|
15
16
|
createMenuItemGroup,
|
16
17
|
type ActionGraphProps,
|
18
|
+
type MenuActionProperties,
|
17
19
|
} from '@dxos/react-ui-menu';
|
18
20
|
|
19
|
-
import type { EditorAction,
|
21
|
+
import type { EditorAction, EditorViewMode, Formatting } from '../../extensions';
|
20
22
|
import { translationKey } from '../../translations';
|
21
23
|
|
22
24
|
export type EditorToolbarState = Formatting &
|
@@ -31,16 +33,18 @@ export type EditorToolbarFeatureFlags = Partial<{
|
|
31
33
|
formatting: boolean;
|
32
34
|
lists: boolean;
|
33
35
|
blocks: boolean;
|
34
|
-
comment: boolean;
|
35
36
|
search: boolean;
|
36
|
-
|
37
|
+
// TODO(wittjosiah): Factor out. Depend on plugin-level capabilities.
|
38
|
+
comment: boolean;
|
39
|
+
image: () => void;
|
40
|
+
viewMode: (mode: EditorViewMode) => void;
|
37
41
|
}>;
|
38
42
|
|
39
43
|
export type EditorToolbarActionGraphProps = {
|
40
44
|
state: Live<EditorToolbarState>;
|
45
|
+
getView: () => EditorView;
|
41
46
|
// TODO(wittjosiah): Control positioning.
|
42
47
|
customActions?: () => ActionGraphProps;
|
43
|
-
onAction: (action: EditorAction) => void;
|
44
48
|
};
|
45
49
|
|
46
50
|
export type EditorToolbarProps = ThemedClassName<
|
@@ -49,17 +53,13 @@ export type EditorToolbarProps = ThemedClassName<
|
|
49
53
|
|
50
54
|
export type EditorToolbarItem = EditorAction | MenuItemGroup | MenuSeparator;
|
51
55
|
|
52
|
-
export const createEditorAction = (
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
id: string = payload.type,
|
57
|
-
) => createMenuAction(id, { icon, label, ...payload }) as EditorAction;
|
56
|
+
export const createEditorAction = (id: string, invoke: () => void, properties: Partial<MenuActionProperties>) => {
|
57
|
+
const { label = [`${id} label`, { ns: translationKey }], ...rest } = properties;
|
58
|
+
return createMenuAction(id, invoke, { label, ...rest }) as Action<MenuActionProperties>;
|
59
|
+
};
|
58
60
|
|
59
61
|
export const createEditorActionGroup = (
|
60
62
|
id: string,
|
61
63
|
props: Omit<ToolbarMenuActionGroupProperties, 'icon'>,
|
62
64
|
icon?: string,
|
63
65
|
) => createMenuItemGroup(id, { icon, iconOnly: true, ...props });
|
64
|
-
|
65
|
-
export const editorToolbarSearch = createEditorAction({ type: 'search' }, 'ph--magnifying-glass--regular');
|
@@ -6,6 +6,7 @@ import { type NodeArg } from '@dxos/app-graph';
|
|
6
6
|
import { type ToolbarMenuActionGroupProperties } from '@dxos/react-ui-menu';
|
7
7
|
|
8
8
|
import { createEditorAction, createEditorActionGroup, type EditorToolbarState } from './util';
|
9
|
+
import { type EditorViewMode } from '../../extensions';
|
9
10
|
import { translationKey } from '../../translations';
|
10
11
|
|
11
12
|
const createViewModeGroupAction = (value: string) =>
|
@@ -20,24 +21,24 @@ const createViewModeGroupAction = (value: string) =>
|
|
20
21
|
'ph--eye--regular',
|
21
22
|
);
|
22
23
|
|
23
|
-
const createViewModeActions = (value: string) =>
|
24
|
+
const createViewModeActions = (value: string, onViewModeChange: (mode: EditorViewMode) => void) =>
|
24
25
|
Object.entries({
|
25
26
|
preview: 'ph--eye--regular',
|
26
27
|
source: 'ph--pencil-simple--regular',
|
27
28
|
readonly: 'ph--pencil-slash--regular',
|
28
29
|
}).map(([viewMode, icon]) => {
|
29
|
-
|
30
|
-
|
30
|
+
const checked = viewMode === value;
|
31
|
+
return createEditorAction(`view-mode--${viewMode}`, () => onViewModeChange(viewMode as EditorViewMode), {
|
32
|
+
label: [`${viewMode} mode label`, { ns: translationKey }],
|
33
|
+
checked,
|
31
34
|
icon,
|
32
|
-
|
33
|
-
`view-mode--${viewMode}`,
|
34
|
-
);
|
35
|
+
});
|
35
36
|
});
|
36
37
|
|
37
|
-
export const createViewMode = (state: EditorToolbarState) => {
|
38
|
+
export const createViewMode = (state: EditorToolbarState, onViewModeChange: (mode: EditorViewMode) => void) => {
|
38
39
|
const value = state.viewMode ?? 'source';
|
39
40
|
const viewModeGroupAction = createViewModeGroupAction(value);
|
40
|
-
const viewModeActions = createViewModeActions(value);
|
41
|
+
const viewModeActions = createViewModeActions(value, onViewModeChange);
|
41
42
|
return {
|
42
43
|
nodes: [viewModeGroupAction as NodeArg<any>, ...viewModeActions],
|
43
44
|
edges: [
|
package/src/defaults.ts
CHANGED
@@ -52,6 +52,6 @@ export const stackItemContentEditorClassNames = (role?: string) =>
|
|
52
52
|
|
53
53
|
export const stackItemContentToolbarClassNames = (role?: string) =>
|
54
54
|
mx(
|
55
|
-
'
|
55
|
+
'relative z-[1] flex is-full bg-toolbarSurface border-be border-separator',
|
56
56
|
role === 'section' && 'sticky block-start-0 -mbe-px min-is-0',
|
57
57
|
);
|
@@ -5,12 +5,13 @@
|
|
5
5
|
import '@dxos-theme';
|
6
6
|
|
7
7
|
import '@preact/signals-react';
|
8
|
+
|
9
|
+
import { Repo } from '@automerge/automerge-repo';
|
10
|
+
import { BroadcastChannelNetworkAdapter } from '@automerge/automerge-repo-network-broadcastchannel';
|
8
11
|
import React, { useEffect, useState } from 'react';
|
9
12
|
|
10
|
-
import { Repo } from '@dxos/automerge/automerge-repo';
|
11
|
-
import { BroadcastChannelNetworkAdapter } from '@dxos/automerge/automerge-repo-network-broadcastchannel';
|
12
13
|
import { Expando } from '@dxos/echo-schema';
|
13
|
-
import { DocAccessor,
|
14
|
+
import { DocAccessor, live, createDocAccessor, useQuery, useSpace, type Space, Query } from '@dxos/react-client/echo';
|
14
15
|
import { useIdentity, type Identity } from '@dxos/react-client/halo';
|
15
16
|
import { ClientRepeater, type ClientRepeatedComponentProps } from '@dxos/react-client/testing';
|
16
17
|
import { useThemeContext } from '@dxos/react-ui';
|
@@ -71,11 +72,12 @@ const Story = () => {
|
|
71
72
|
doc.text = initialContent;
|
72
73
|
});
|
73
74
|
|
74
|
-
const object2 = repo2.find<TestObject>(object1.url);
|
75
|
+
const object2 = await repo2.find<TestObject>(object1.url);
|
75
76
|
await object2.whenReady();
|
76
77
|
|
77
|
-
|
78
|
-
|
78
|
+
// TODO(mykola): Fix types.
|
79
|
+
setObject1({ handle: object1 as any, path: ['text'] });
|
80
|
+
setObject2({ handle: object2 as any, path: ['text'] });
|
79
81
|
});
|
80
82
|
}, []);
|
81
83
|
|
@@ -103,7 +105,7 @@ const EchoStory = ({ spaceKey }: ClientRepeatedComponentProps) => {
|
|
103
105
|
const identity = useIdentity();
|
104
106
|
const space = useSpace(spaceKey);
|
105
107
|
const [source, setSource] = useState<DocAccessor>();
|
106
|
-
const objects = useQuery
|
108
|
+
const objects = useQuery(space, Query.type(Expando, { type: 'test' }));
|
107
109
|
|
108
110
|
useEffect(() => {
|
109
111
|
if (!source && objects.length) {
|
@@ -2,6 +2,7 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
+
import { type DocHandle, Repo } from '@automerge/automerge-repo';
|
5
6
|
import { EditorState } from '@codemirror/state';
|
6
7
|
import { EditorView } from '@codemirror/view';
|
7
8
|
import { render, screen } from '@testing-library/react';
|
@@ -12,8 +13,6 @@ import get from 'lodash.get';
|
|
12
13
|
import React, { type FC, useEffect, useRef, useState } from 'react';
|
13
14
|
import { describe, test } from 'vitest';
|
14
15
|
|
15
|
-
import { type DocHandle, Repo } from '@dxos/automerge/automerge-repo';
|
16
|
-
|
17
16
|
import { automerge } from './automerge';
|
18
17
|
|
19
18
|
type TestObject = {
|
@@ -36,7 +35,8 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
36
35
|
const [view, setView] = useState<EditorView>();
|
37
36
|
useEffect(() => {
|
38
37
|
const extensions = [
|
39
|
-
|
38
|
+
// TODO(mykola): Fix types.
|
39
|
+
automerge({ handle: handle as any, path }),
|
40
40
|
EditorView.updateListener.of((update) => {
|
41
41
|
if (view.state.doc.toString() === 'hello!') {
|
42
42
|
// Update editor.
|
@@ -46,7 +46,7 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
46
46
|
];
|
47
47
|
|
48
48
|
const view = new EditorView({
|
49
|
-
state: EditorState.create({ doc: get(handle.
|
49
|
+
state: EditorState.create({ doc: get(handle.doc()!, path), extensions }),
|
50
50
|
parent: ref.current!,
|
51
51
|
});
|
52
52
|
|
@@ -4,10 +4,10 @@
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
5
5
|
//
|
6
6
|
|
7
|
+
import { next as A } from '@automerge/automerge';
|
7
8
|
import { StateField, type Extension } from '@codemirror/state';
|
8
9
|
import { EditorView, ViewPlugin } from '@codemirror/view';
|
9
10
|
|
10
|
-
import { next as A } from '@dxos/automerge/automerge';
|
11
11
|
import { type DocAccessor } from '@dxos/react-client/echo';
|
12
12
|
|
13
13
|
import { cursorConverter } from './cursor';
|
@@ -19,7 +19,7 @@ export const automerge = (accessor: DocAccessor): Extension => {
|
|
19
19
|
const syncState = StateField.define<State>({
|
20
20
|
create: () => ({
|
21
21
|
path: accessor.path.slice(),
|
22
|
-
lastHeads: A.getHeads(accessor.handle.
|
22
|
+
lastHeads: A.getHeads(accessor.handle.doc()!),
|
23
23
|
unreconciledTransactions: [],
|
24
24
|
}),
|
25
25
|
|
@@ -4,10 +4,9 @@
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
5
5
|
//
|
6
6
|
|
7
|
+
import { type Heads, type Prop } from '@automerge/automerge';
|
7
8
|
import { Annotation, StateEffect, type StateField, type EditorState, type Transaction } from '@codemirror/state';
|
8
9
|
|
9
|
-
import { type Heads, type Prop } from '@dxos/automerge/automerge';
|
10
|
-
|
11
10
|
export type State = {
|
12
11
|
path: Prop[];
|
13
12
|
lastHeads: Heads;
|
@@ -4,10 +4,10 @@
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
5
5
|
//
|
6
6
|
|
7
|
+
import { next as A } from '@automerge/automerge';
|
7
8
|
import { type StateField } from '@codemirror/state';
|
8
9
|
import { type EditorView } from '@codemirror/view';
|
9
10
|
|
10
|
-
import { next as A } from '@dxos/automerge/automerge';
|
11
11
|
import { type IDocHandle } from '@dxos/react-client/echo';
|
12
12
|
|
13
13
|
import { getLastHeads, getPath, isReconcile, reconcileAnnotation, type State, updateHeads } from './defs';
|
@@ -57,15 +57,15 @@ export class Syncer {
|
|
57
57
|
onAutomergeChange(view: EditorView) {
|
58
58
|
// Get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
|
59
59
|
const oldHeads = getLastHeads(view.state, this._state);
|
60
|
-
const newHeads = A.getHeads(this._handle.
|
61
|
-
const diff = A.equals(oldHeads, newHeads) ? [] : A.diff(this._handle.
|
60
|
+
const newHeads = A.getHeads(this._handle.doc()!);
|
61
|
+
const diff = A.equals(oldHeads, newHeads) ? [] : A.diff(this._handle.doc()!, oldHeads, newHeads);
|
62
62
|
|
63
63
|
const selection = view.state.selection;
|
64
64
|
const path = getPath(view.state, this._state);
|
65
65
|
updateCodeMirror(view, selection, path, diff);
|
66
66
|
|
67
67
|
// TODO(burdon): Test conflicts?
|
68
|
-
// A.getConflicts(this._handle.
|
68
|
+
// A.getConflicts(this._handle.doc()!, path[0]);
|
69
69
|
|
70
70
|
view.dispatch({
|
71
71
|
effects: updateHeads(newHeads),
|
@@ -4,9 +4,9 @@
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
5
5
|
//
|
6
6
|
|
7
|
+
import { next as A, type Heads } from '@automerge/automerge';
|
7
8
|
import { type EditorState, type StateField, type Transaction, type Text } from '@codemirror/state';
|
8
9
|
|
9
|
-
import { next as A, type Heads } from '@dxos/automerge/automerge';
|
10
10
|
import { type IDocHandle } from '@dxos/react-client/echo';
|
11
11
|
|
12
12
|
import { type State } from './defs';
|
@@ -4,9 +4,6 @@
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
5
5
|
//
|
6
6
|
|
7
|
-
import { ChangeSet, type ChangeSpec, type EditorSelection, type EditorState } from '@codemirror/state';
|
8
|
-
import { type EditorView } from '@codemirror/view';
|
9
|
-
|
10
7
|
import {
|
11
8
|
type DelPatch,
|
12
9
|
type InsertPatch,
|
@@ -14,7 +11,9 @@ import {
|
|
14
11
|
type Prop,
|
15
12
|
type PutPatch,
|
16
13
|
type SpliceTextPatch,
|
17
|
-
} from '@
|
14
|
+
} from '@automerge/automerge';
|
15
|
+
import { ChangeSet, type ChangeSpec, type EditorSelection, type EditorState } from '@codemirror/state';
|
16
|
+
import { type EditorView } from '@codemirror/view';
|
18
17
|
|
19
18
|
import { reconcileAnnotation } from './defs';
|
20
19
|
|
@@ -56,8 +56,9 @@ export const adjustChanges = () => {
|
|
56
56
|
// Check for URL.
|
57
57
|
const url = getValidUrl(update.view.state.sliceDoc(fromB, toB));
|
58
58
|
if (url) {
|
59
|
+
// Check if pasting inside existing link.
|
59
60
|
const node = tree.resolveInner(fromA, -1);
|
60
|
-
const invalidPositions = new Set(['
|
61
|
+
const invalidPositions = new Set(['Code', 'CodeText', 'FencedCode', 'Link', 'LinkMark', 'URL']);
|
61
62
|
if (!invalidPositions.has(node?.name)) {
|
62
63
|
const replacedText = tr.startState.sliceDoc(fromA, toA);
|
63
64
|
adjustments.push({ from: fromA, to: toB, insert: createLink(url, replacedText) });
|
@@ -84,7 +85,7 @@ export const adjustChanges = () => {
|
|
84
85
|
}
|
85
86
|
}
|
86
87
|
|
87
|
-
// TODO(burdon): Is this the right way to augment changes?
|
88
|
+
// TODO(burdon): Is this the right way to augment changes? Alt: EditorState.transactionFilter
|
88
89
|
if (adjustments.length) {
|
89
90
|
setTimeout(() => {
|
90
91
|
update.view.dispatch(
|
@@ -129,10 +129,10 @@ class TextWidget extends WidgetType {
|
|
129
129
|
}
|
130
130
|
|
131
131
|
const hide = Decoration.replace({});
|
132
|
-
const blockQuote = Decoration.line({ class:
|
133
|
-
const fencedCodeLine = Decoration.line({ class:
|
134
|
-
const fencedCodeLineFirst = Decoration.line({ class: mx('cm-code cm-codeblock-line', 'cm-codeblock-
|
135
|
-
const fencedCodeLineLast = Decoration.line({ class: mx('cm-code cm-codeblock-line', 'cm-codeblock-
|
132
|
+
const blockQuote = Decoration.line({ class: 'cm-blockquote' });
|
133
|
+
const fencedCodeLine = Decoration.line({ class: 'cm-code cm-codeblock-line' });
|
134
|
+
const fencedCodeLineFirst = Decoration.line({ class: mx('cm-code cm-codeblock-line', 'cm-codeblock-start') });
|
135
|
+
const fencedCodeLineLast = Decoration.line({ class: mx('cm-code cm-codeblock-line', 'cm-codeblock-end') });
|
136
136
|
const commentBlockLine = fencedCodeLine;
|
137
137
|
const commentBlockLineFirst = fencedCodeLineFirst;
|
138
138
|
const commentBlockLineLast = fencedCodeLineLast;
|
@@ -277,7 +277,7 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
|
|
277
277
|
// Set indentation.
|
278
278
|
const list = getCurrentListLevel();
|
279
279
|
const width = list.type === 'OrderedList' ? orderedListIndentationWidth : bulletListIndentationWidth;
|
280
|
-
const offset = ((list.level ?? 0) + 1) * width;
|
280
|
+
const offset = (options?.listPaddingLeft ?? 0) + ((list.level ?? 0) + 1) * width;
|
281
281
|
if (node.from === line.to - 1) {
|
282
282
|
// Abort if only the hyphen is typed.
|
283
283
|
return false;
|
@@ -285,7 +285,6 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
|
|
285
285
|
|
286
286
|
// Add line decoration for the continuation indent.
|
287
287
|
// TODO(burdon): Bug if indentation is more than one indentation unit (e.g., 4 spaces) from the previous line.
|
288
|
-
|
289
288
|
deco.add(
|
290
289
|
line.from,
|
291
290
|
line.from,
|
@@ -406,7 +405,7 @@ const buildDecorations = (view: EditorView, options: DecorateOptions, focus: boo
|
|
406
405
|
}
|
407
406
|
|
408
407
|
const first = block.from <= node.from;
|
409
|
-
const last = block.to >= node.to &&
|
408
|
+
const last = block.to >= node.to && /```$/.test(state.doc.sliceString(block.from, block.to));
|
410
409
|
deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
|
411
410
|
|
412
411
|
const editing = editingRange(state, node, focus);
|
@@ -521,6 +520,8 @@ export interface DecorateOptions {
|
|
521
520
|
selectionChangeDelay?: number;
|
522
521
|
numberedHeadings?: { from: number; to?: number };
|
523
522
|
renderLinkButton?: RenderCallback<{ url: string }>;
|
523
|
+
// TODO(burdon): Additional padding for each line.
|
524
|
+
listPaddingLeft?: number;
|
524
525
|
}
|
525
526
|
|
526
527
|
export const decorateMarkdown = (options: DecorateOptions = {}) => {
|
@@ -5,13 +5,13 @@
|
|
5
5
|
import { snippet } from '@codemirror/autocomplete';
|
6
6
|
import { syntaxTree } from '@codemirror/language';
|
7
7
|
import {
|
8
|
-
type Extension,
|
9
|
-
type StateCommand,
|
10
|
-
type EditorState,
|
11
8
|
type ChangeSpec,
|
12
|
-
type Text,
|
13
9
|
EditorSelection,
|
10
|
+
type Extension,
|
11
|
+
type EditorState,
|
14
12
|
type Line,
|
13
|
+
type StateCommand,
|
14
|
+
type Text,
|
15
15
|
} from '@codemirror/state';
|
16
16
|
import { EditorView, keymap } from '@codemirror/view';
|
17
17
|
import { type SyntaxNodeRef, type SyntaxNode } from '@lezer/common';
|