@dxos/react-ui-editor 0.8.2-staging.4d6ad0f → 0.8.2
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 +139 -77
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +105 -36
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +139 -77
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/extensions/command/menu.d.ts +1 -10
- package/dist/types/src/extensions/command/menu.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner/commands.d.ts +1 -0
- package/dist/types/src/extensions/outliner/commands.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner/editor.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner/index.d.ts +1 -0
- package/dist/types/src/extensions/outliner/index.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner/outliner.d.ts +4 -1
- package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
- package/package.json +27 -27
- package/src/extensions/command/menu.ts +35 -4
- package/src/extensions/outliner/commands.ts +29 -1
- package/src/extensions/outliner/editor.ts +7 -3
- package/src/extensions/outliner/index.ts +1 -0
- package/src/extensions/outliner/outliner.test.ts +2 -2
- package/src/extensions/outliner/outliner.ts +43 -37
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@dxos/react-ui-editor",
|
3
|
-
"version": "0.8.2
|
3
|
+
"version": "0.8.2",
|
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",
|
@@ -59,20 +59,20 @@
|
|
59
59
|
"lodash.merge": "^4.6.2",
|
60
60
|
"lodash.sortby": "^4.7.0",
|
61
61
|
"style-mod": "^4.1.0",
|
62
|
-
"@dxos/async": "0.8.2
|
63
|
-
"@dxos/
|
64
|
-
"@dxos/
|
65
|
-
"@dxos/
|
66
|
-
"@dxos/
|
67
|
-
"@dxos/
|
68
|
-
"@dxos/
|
69
|
-
"@dxos/
|
70
|
-
"@dxos/log": "0.8.2
|
71
|
-
"@dxos/live-object": "0.8.2
|
72
|
-
"@dxos/
|
73
|
-
"@dxos/
|
74
|
-
"@dxos/react-
|
75
|
-
"@dxos/util": "0.8.2
|
62
|
+
"@dxos/async": "0.8.2",
|
63
|
+
"@dxos/app-graph": "0.8.2",
|
64
|
+
"@dxos/context": "0.8.2",
|
65
|
+
"@dxos/display-name": "0.8.2",
|
66
|
+
"@dxos/debug": "0.8.2",
|
67
|
+
"@dxos/echo-schema": "0.8.2",
|
68
|
+
"@dxos/invariant": "0.8.2",
|
69
|
+
"@dxos/lit-ui": "0.8.2",
|
70
|
+
"@dxos/log": "0.8.2",
|
71
|
+
"@dxos/live-object": "0.8.2",
|
72
|
+
"@dxos/react-ui-menu": "0.8.2",
|
73
|
+
"@dxos/protocols": "0.8.2",
|
74
|
+
"@dxos/react-hooks": "0.8.2",
|
75
|
+
"@dxos/util": "0.8.2"
|
76
76
|
},
|
77
77
|
"devDependencies": {
|
78
78
|
"@automerge/automerge": "3.0.0-beta.4",
|
@@ -101,15 +101,15 @@
|
|
101
101
|
"vite": "5.4.7",
|
102
102
|
"vite-plugin-top-level-await": "^1.4.1",
|
103
103
|
"vite-plugin-wasm": "^3.3.0",
|
104
|
-
"@dxos/
|
105
|
-
"@dxos/
|
106
|
-
"@dxos/
|
107
|
-
"@dxos/
|
108
|
-
"@dxos/react-ui": "0.8.2
|
109
|
-
"@dxos/react-
|
110
|
-
"@dxos/
|
111
|
-
"@dxos/
|
112
|
-
"@dxos/
|
104
|
+
"@dxos/echo-signals": "0.8.2",
|
105
|
+
"@dxos/random": "0.8.2",
|
106
|
+
"@dxos/config": "0.8.2",
|
107
|
+
"@dxos/react-client": "0.8.2",
|
108
|
+
"@dxos/react-ui": "0.8.2",
|
109
|
+
"@dxos/react-ui-syntax-highlighter": "0.8.2",
|
110
|
+
"@dxos/keyboard": "0.8.2",
|
111
|
+
"@dxos/storybook-utils": "0.8.2",
|
112
|
+
"@dxos/react-ui-theme": "0.8.2"
|
113
113
|
},
|
114
114
|
"peerDependencies": {
|
115
115
|
"@effect-rx/rx-react": "^0.34.1",
|
@@ -118,9 +118,9 @@
|
|
118
118
|
"effect": "^3.13.3",
|
119
119
|
"react": "~18.2.0",
|
120
120
|
"react-dom": "~18.2.0",
|
121
|
-
"@dxos/react-
|
122
|
-
"@dxos/react-
|
123
|
-
"@dxos/react-ui": "0.8.2
|
121
|
+
"@dxos/react-ui": "0.8.2",
|
122
|
+
"@dxos/react-client": "0.8.2",
|
123
|
+
"@dxos/react-ui-theme": "0.8.2"
|
124
124
|
},
|
125
125
|
"publishConfig": {
|
126
126
|
"access": "public"
|
@@ -2,7 +2,7 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
|
6
6
|
|
7
7
|
import { closeEffect, openEffect } from './action';
|
8
8
|
|
@@ -33,11 +33,10 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
|
|
33
33
|
|
34
34
|
const button = document.createElement('button');
|
35
35
|
button.appendChild(icon);
|
36
|
-
button.classList.add('grid', 'items-center', 'justify-center', 'w-8', 'h-8');
|
37
36
|
|
38
37
|
// TODO(burdon): Custom tag/styles?
|
39
38
|
this.tag = document.createElement('dx-ref-tag');
|
40
|
-
this.tag.classList.add('
|
39
|
+
this.tag.classList.add('cm-ref-tag');
|
41
40
|
this.tag.appendChild(button);
|
42
41
|
container.appendChild(this.tag);
|
43
42
|
|
@@ -47,12 +46,24 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
|
|
47
46
|
}
|
48
47
|
|
49
48
|
update(update: ViewUpdate) {
|
49
|
+
this.tag.dataset.focused = update.view.hasFocus ? 'true' : 'false';
|
50
|
+
if (!update.view.hasFocus) {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
50
54
|
// TODO(burdon): Timer to fade in/out.
|
51
55
|
if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
|
52
56
|
this.tag.style.display = 'none';
|
57
|
+
this.tag.classList.add('opacity-10');
|
53
58
|
} else if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {
|
54
59
|
this.tag.style.display = 'block';
|
55
|
-
} else if (
|
60
|
+
} else if (
|
61
|
+
update.docChanged ||
|
62
|
+
update.focusChanged ||
|
63
|
+
update.geometryChanged ||
|
64
|
+
update.selectionSet ||
|
65
|
+
update.viewportChanged
|
66
|
+
) {
|
56
67
|
this.scheduleUpdate();
|
57
68
|
}
|
58
69
|
}
|
@@ -94,4 +105,24 @@ export const floatingMenu = (options: FloatingMenuOptions = {}) => [
|
|
94
105
|
}
|
95
106
|
},
|
96
107
|
),
|
108
|
+
|
109
|
+
EditorView.theme({
|
110
|
+
'.cm-ref-tag': {
|
111
|
+
position: 'fixed',
|
112
|
+
padding: '0',
|
113
|
+
border: 'none',
|
114
|
+
transition: 'opacity 0.3s ease-in-out',
|
115
|
+
opacity: 0.1,
|
116
|
+
},
|
117
|
+
'.cm-ref-tag button': {
|
118
|
+
display: 'grid',
|
119
|
+
alignItems: 'center',
|
120
|
+
justifyContent: 'center',
|
121
|
+
width: '2rem',
|
122
|
+
height: '2rem',
|
123
|
+
},
|
124
|
+
'.cm-ref-tag[data-focused="true"]': {
|
125
|
+
opacity: 1,
|
126
|
+
},
|
127
|
+
}),
|
97
128
|
];
|
@@ -123,9 +123,28 @@ export const moveItemUp: Command = (view: EditorView) => {
|
|
123
123
|
// Misc commands.
|
124
124
|
//
|
125
125
|
|
126
|
+
export const deleteItem: Command = (view: EditorView) => {
|
127
|
+
const tree = view.state.facet(treeFacet);
|
128
|
+
const pos = getSelection(view.state).from;
|
129
|
+
const current = tree.find(pos);
|
130
|
+
if (current) {
|
131
|
+
view.dispatch({
|
132
|
+
selection: EditorSelection.cursor(current.lineRange.from),
|
133
|
+
changes: [
|
134
|
+
{
|
135
|
+
from: current.lineRange.from,
|
136
|
+
to: Math.min(current.lineRange.to + 1, view.state.doc.length),
|
137
|
+
},
|
138
|
+
],
|
139
|
+
});
|
140
|
+
}
|
141
|
+
|
142
|
+
return true;
|
143
|
+
};
|
144
|
+
|
126
145
|
export const toggleTask: Command = (view: EditorView) => {
|
127
|
-
const pos = getSelection(view.state)?.from;
|
128
146
|
const tree = view.state.facet(treeFacet);
|
147
|
+
const pos = getSelection(view.state)?.from;
|
129
148
|
const current = tree.find(pos);
|
130
149
|
if (current) {
|
131
150
|
const type = current.type === 'task' ? 'bullet' : 'task';
|
@@ -233,10 +252,19 @@ export const commands = (): Extension =>
|
|
233
252
|
run: moveItemUp,
|
234
253
|
},
|
235
254
|
//
|
255
|
+
// Delete.
|
256
|
+
//
|
257
|
+
{
|
258
|
+
key: 'Mod-Backspace',
|
259
|
+
preventDefault: true,
|
260
|
+
run: deleteItem,
|
261
|
+
},
|
262
|
+
//
|
236
263
|
// Misc.
|
237
264
|
//
|
238
265
|
{
|
239
266
|
key: 'Alt-t',
|
267
|
+
preventDefault: true,
|
240
268
|
run: toggleTask,
|
241
269
|
},
|
242
270
|
]);
|
@@ -101,11 +101,15 @@ export const editor = () => [
|
|
101
101
|
const match = line.text.match(LIST_ITEM_REGEX);
|
102
102
|
if (match) {
|
103
103
|
// Check cursor was in a valid position.
|
104
|
-
|
105
|
-
|
104
|
+
const startTree = tr.startState.facet(treeFacet);
|
105
|
+
const startItem = startTree.find(tr.startState.selection.main.from);
|
106
106
|
|
107
107
|
// Check if entire line was deleted (which is ok).
|
108
|
-
|
108
|
+
const deleteLine = fromA === startItem?.lineRange.from && toA === startItem?.lineRange.to + 1;
|
109
|
+
if (deleteLine) {
|
110
|
+
return;
|
111
|
+
}
|
112
|
+
|
109
113
|
// if (!deleteLine && (!startItem || fromA < startItem.contentRange.from || toA > startItem.contentRange.to)) {
|
110
114
|
// cancel = true;
|
111
115
|
// return;
|
@@ -29,8 +29,8 @@ const getPos = (line: number) => {
|
|
29
29
|
|
30
30
|
const extensions = [createMarkdownExtensions(), outlinerTree()];
|
31
31
|
|
32
|
-
// Flaky
|
33
|
-
describe.
|
32
|
+
// TODO(burdon): Flaky.
|
33
|
+
describe.runIf(!process.env.CI)('outliner', () => {
|
34
34
|
const state = EditorState.create({ doc: str(...lines), extensions });
|
35
35
|
|
36
36
|
test('sanity', ({ expect }) => {
|
@@ -28,6 +28,10 @@ import { decorateMarkdown } from '../markdown';
|
|
28
28
|
// TODO(burdon): Smart Cut-and-paste.
|
29
29
|
// TODO(burdon): DND.
|
30
30
|
|
31
|
+
export type OutlinerProps = {
|
32
|
+
showSelected?: boolean;
|
33
|
+
};
|
34
|
+
|
31
35
|
/**
|
32
36
|
* Outliner extension.
|
33
37
|
* - Stores outline as a standard markdown document with task and list markers.
|
@@ -35,7 +39,7 @@ import { decorateMarkdown } from '../markdown';
|
|
35
39
|
* - Constrains editor to outline structure.
|
36
40
|
* - Supports smart cut-and-paste.
|
37
41
|
*/
|
38
|
-
export const outliner = (): Extension => [
|
42
|
+
export const outliner = (options: OutlinerProps = {}): Extension => [
|
39
43
|
// Commands.
|
40
44
|
Prec.highest(commands()),
|
41
45
|
|
@@ -52,7 +56,7 @@ export const outliner = (): Extension => [
|
|
52
56
|
floatingMenu(),
|
53
57
|
|
54
58
|
// Line decorations.
|
55
|
-
decorations(),
|
59
|
+
decorations(options),
|
56
60
|
|
57
61
|
// Default markdown decorations.
|
58
62
|
decorateMarkdown({ listPaddingLeft: 8 }),
|
@@ -64,7 +68,7 @@ export const outliner = (): Extension => [
|
|
64
68
|
/**
|
65
69
|
* Line decorations (for border and selection).
|
66
70
|
*/
|
67
|
-
const decorations = () => [
|
71
|
+
const decorations = (options: OutlinerProps) => [
|
68
72
|
ViewPlugin.fromClass(
|
69
73
|
class {
|
70
74
|
decorations: DecorationSet = Decoration.none;
|
@@ -125,38 +129,40 @@ const decorations = () => [
|
|
125
129
|
),
|
126
130
|
|
127
131
|
// Theme.
|
128
|
-
EditorView.theme(
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
132
|
+
EditorView.theme(
|
133
|
+
Object.assign({
|
134
|
+
'.cm-list-item': {
|
135
|
+
borderLeftWidth: '1px',
|
136
|
+
borderRightWidth: '1px',
|
137
|
+
paddingLeft: '32px',
|
138
|
+
borderColor: 'transparent',
|
139
|
+
},
|
140
|
+
'.cm-list-item.cm-codeblock-start': {
|
141
|
+
borderRadius: '0',
|
142
|
+
},
|
143
|
+
|
144
|
+
'.cm-list-item-start': {
|
145
|
+
borderTopWidth: '1px',
|
146
|
+
borderTopLeftRadius: '4px',
|
147
|
+
borderTopRightRadius: '4px',
|
148
|
+
paddingTop: '4px',
|
149
|
+
marginTop: '2px',
|
150
|
+
},
|
151
|
+
|
152
|
+
'.cm-list-item-end': {
|
153
|
+
borderBottomWidth: '1px',
|
154
|
+
borderBottomLeftRadius: '4px',
|
155
|
+
borderBottomRightRadius: '4px',
|
156
|
+
paddingBottom: '4px',
|
157
|
+
marginBottom: '2px',
|
158
|
+
},
|
159
|
+
|
160
|
+
'.cm-list-item-selected': {
|
161
|
+
borderColor: options.showSelected ? 'var(--dx-separator)' : undefined,
|
162
|
+
},
|
163
|
+
'.cm-list-item-focused': {
|
164
|
+
borderColor: 'var(--dx-accentFocusIndicator)',
|
165
|
+
},
|
166
|
+
}),
|
167
|
+
),
|
162
168
|
];
|