@dxos/react-ui-editor 0.8.1-staging.9eaf14f → 0.8.2-main.10c050d
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 +4152 -2852
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +6 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/lib/node/index.cjs +3318 -2009
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/testing/index.cjs +29 -0
- package/dist/lib/node/testing/index.cjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +4152 -2852
- 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 +8 -0
- package/dist/lib/node-esm/testing/index.mjs.map +7 -0
- 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/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/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/{comment.d.ts → image.d.ts} +4 -5
- package/dist/types/src/components/EditorToolbar/image.d.ts.map +1 -0
- package/dist/types/src/components/EditorToolbar/index.d.ts +1 -1
- package/dist/types/src/components/EditorToolbar/index.d.ts.map +1 -1
- 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 +17 -25
- package/dist/types/src/components/EditorToolbar/util.d.ts.map +1 -1
- package/dist/types/src/components/EditorToolbar/{viewMode.d.ts → view-mode.d.ts} +5 -4
- package/dist/types/src/components/EditorToolbar/view-mode.d.ts.map +1 -0
- package/dist/types/src/components/Popover/RefDropdownMenu.d.ts +21 -0
- package/dist/types/src/components/Popover/RefDropdownMenu.d.ts.map +1 -0
- package/dist/types/src/components/Popover/RefPopover.d.ts +21 -0
- package/dist/types/src/components/Popover/RefPopover.d.ts.map +1 -0
- package/dist/types/src/components/Popover/index.d.ts +3 -0
- package/dist/types/src/components/Popover/index.d.ts.map +1 -0
- 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/defaults.d.ts +3 -5
- package/dist/types/src/defaults.d.ts.map +1 -1
- package/dist/types/src/extensions/annotations.d.ts +4 -1
- package/dist/types/src/extensions/annotations.d.ts.map +1 -1
- package/dist/types/src/extensions/autocomplete.d.ts +1 -2
- 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-provider.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/action.d.ts +17 -0
- package/dist/types/src/extensions/command/action.d.ts.map +1 -0
- package/dist/types/src/extensions/command/command.d.ts +4 -10
- package/dist/types/src/extensions/command/command.d.ts.map +1 -1
- package/dist/types/src/extensions/command/hint.d.ts +18 -4
- package/dist/types/src/extensions/command/hint.d.ts.map +1 -1
- package/dist/types/src/extensions/command/index.d.ts +3 -0
- package/dist/types/src/extensions/command/index.d.ts.map +1 -1
- package/dist/types/src/extensions/command/menu.d.ts +6 -11
- package/dist/types/src/extensions/command/menu.d.ts.map +1 -1
- package/dist/types/src/extensions/command/state.d.ts +9 -11
- package/dist/types/src/extensions/command/state.d.ts.map +1 -1
- package/dist/types/src/extensions/command/typeahead.d.ts +17 -0
- package/dist/types/src/extensions/command/typeahead.d.ts.map +1 -0
- package/dist/types/src/extensions/comments.d.ts +9 -17
- 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 +4 -0
- 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/index.d.ts +3 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/json.d.ts +7 -0
- package/dist/types/src/extensions/json.d.ts.map +1 -0
- package/dist/types/src/extensions/listener.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/{editorAction.d.ts → action.d.ts} +1 -1
- package/dist/types/src/extensions/markdown/action.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -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 +5 -1
- package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/formatting.d.ts +3 -3
- 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 -1
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/link.d.ts +4 -1
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
- 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/outliner/commands.d.ts +10 -0
- package/dist/types/src/extensions/outliner/commands.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/editor.d.ts +5 -0
- package/dist/types/src/extensions/outliner/editor.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/editor.test.d.ts +2 -0
- package/dist/types/src/extensions/outliner/editor.test.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/index.d.ts +4 -0
- package/dist/types/src/extensions/outliner/index.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/outliner.d.ts +13 -0
- package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/outliner.test.d.ts +2 -0
- package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/selection.d.ts +12 -0
- package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/tree.d.ts +79 -0
- package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/tree.test.d.ts +2 -0
- package/dist/types/src/extensions/outliner/tree.test.d.ts.map +1 -0
- package/dist/types/src/extensions/preview/index.d.ts +2 -0
- package/dist/types/src/extensions/preview/index.d.ts.map +1 -0
- package/dist/types/src/extensions/preview/preview.d.ts +39 -0
- package/dist/types/src/extensions/preview/preview.d.ts.map +1 -0
- 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 +2 -1
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
- package/dist/types/src/stories/Command.stories.d.ts +7 -0
- package/dist/types/src/stories/Command.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Comments.stories.d.ts +13 -0
- package/dist/types/src/stories/Comments.stories.d.ts.map +1 -0
- package/dist/types/src/stories/EditorToolbar.stories.d.ts +12 -0
- package/dist/types/src/stories/EditorToolbar.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Experimental.stories.d.ts +16 -0
- package/dist/types/src/stories/Experimental.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Markdown.stories.d.ts +46 -0
- package/dist/types/src/stories/Markdown.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Outliner.stories.d.ts +26 -0
- package/dist/types/src/stories/Outliner.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Preview.stories.d.ts +10 -0
- package/dist/types/src/stories/Preview.stories.d.ts.map +1 -0
- package/dist/types/src/stories/TextEditor.stories.d.ts +55 -0
- package/dist/types/src/stories/TextEditor.stories.d.ts.map +1 -0
- package/dist/types/src/stories/util.d.ts +53 -0
- package/dist/types/src/stories/util.d.ts.map +1 -0
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/util.d.ts +2 -0
- package/dist/types/src/testing/util.d.ts.map +1 -0
- package/dist/types/src/types.d.ts +5 -0
- package/dist/types/src/types.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 +6 -1
- package/dist/types/src/util/react.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +46 -30
- package/src/components/EditorToolbar/EditorToolbar.tsx +95 -72
- package/src/components/EditorToolbar/blocks.ts +27 -6
- 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/index.ts +7 -1
- package/src/components/EditorToolbar/lists.ts +26 -7
- package/src/components/EditorToolbar/search.ts +19 -0
- package/src/components/EditorToolbar/util.ts +19 -20
- package/src/components/EditorToolbar/{viewMode.ts → view-mode.ts} +9 -8
- package/src/components/Popover/RefDropdownMenu.tsx +77 -0
- package/src/components/Popover/RefPopover.tsx +75 -0
- package/src/components/Popover/index.ts +6 -0
- package/src/components/index.ts +1 -0
- package/src/defaults.ts +12 -13
- package/src/extensions/annotations.ts +41 -64
- package/src/extensions/autocomplete.ts +5 -6
- package/src/extensions/automerge/automerge.stories.tsx +13 -24
- package/src/extensions/automerge/automerge.test.tsx +6 -5
- package/src/extensions/automerge/automerge.ts +2 -2
- package/src/extensions/automerge/defs.ts +1 -2
- package/src/extensions/automerge/sync.ts +7 -7
- package/src/extensions/automerge/update-automerge.ts +1 -1
- package/src/extensions/automerge/update-codemirror.ts +3 -4
- package/src/extensions/awareness/awareness-provider.ts +4 -4
- package/src/extensions/awareness/awareness.ts +7 -7
- package/src/extensions/blast.ts +9 -9
- package/src/extensions/command/action.ts +49 -0
- package/src/extensions/command/command.ts +7 -27
- package/src/extensions/command/hint.ts +36 -33
- package/src/extensions/command/index.ts +3 -0
- package/src/extensions/command/menu.ts +79 -51
- package/src/extensions/command/state.ts +41 -61
- package/src/extensions/command/typeahead.ts +116 -0
- package/src/extensions/comments.ts +11 -76
- package/src/extensions/factories.ts +13 -0
- package/src/extensions/folding.tsx +1 -1
- package/src/extensions/index.ts +3 -0
- package/src/extensions/json.ts +56 -0
- package/src/extensions/markdown/bundle.ts +13 -9
- package/src/extensions/markdown/changes.ts +3 -2
- package/src/extensions/markdown/decorate.ts +19 -17
- package/src/extensions/markdown/formatting.ts +6 -6
- package/src/extensions/markdown/image.ts +14 -13
- package/src/extensions/markdown/index.ts +1 -1
- package/src/extensions/markdown/link.ts +33 -24
- package/src/extensions/markdown/styles.ts +4 -3
- package/src/extensions/markdown/table.ts +3 -3
- package/src/extensions/modes.ts +5 -6
- package/src/extensions/outliner/commands.ts +270 -0
- package/src/extensions/outliner/editor.test.ts +33 -0
- package/src/extensions/outliner/editor.ts +184 -0
- package/src/extensions/outliner/index.ts +7 -0
- package/src/extensions/outliner/outliner.test.ts +99 -0
- package/src/extensions/outliner/outliner.ts +168 -0
- package/src/extensions/outliner/selection.ts +50 -0
- package/src/extensions/outliner/tree.test.ts +164 -0
- package/src/extensions/outliner/tree.ts +315 -0
- package/src/extensions/preview/index.ts +5 -0
- package/src/extensions/preview/preview.ts +271 -0
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useTextEditor.ts +4 -3
- package/src/stories/Command.stories.tsx +97 -0
- package/src/stories/Comments.stories.tsx +98 -0
- package/src/stories/EditorToolbar.stories.tsx +96 -0
- package/src/stories/Experimental.stories.tsx +86 -0
- package/src/stories/Markdown.stories.tsx +121 -0
- package/src/stories/Outliner.stories.tsx +108 -0
- package/src/stories/Preview.stories.tsx +149 -0
- package/src/stories/TextEditor.stories.tsx +256 -0
- package/src/stories/util.tsx +326 -0
- package/src/styles/theme.ts +15 -5
- package/src/styles/tokens.ts +1 -2
- package/src/testing/index.ts +5 -0
- package/src/testing/util.ts +5 -0
- package/src/types.ts +7 -0
- package/src/util/react.tsx +20 -2
- package/dist/types/src/InputMode.stories.d.ts +0 -57
- package/dist/types/src/InputMode.stories.d.ts.map +0 -1
- package/dist/types/src/TextEditor.stories.d.ts +0 -115
- package/dist/types/src/TextEditor.stories.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/comment.d.ts.map +0 -1
- package/dist/types/src/components/EditorToolbar/viewMode.d.ts.map +0 -1
- package/dist/types/src/extensions/command/preview.d.ts +0 -12
- package/dist/types/src/extensions/command/preview.d.ts.map +0 -1
- package/dist/types/src/extensions/markdown/editorAction.d.ts.map +0 -1
- package/dist/types/src/fragments.d.ts +0 -3
- package/dist/types/src/fragments.d.ts.map +0 -1
- package/dist/types/src/hooks/useActionHandler.d.ts +0 -4
- package/dist/types/src/hooks/useActionHandler.d.ts.map +0 -1
- package/src/InputMode.stories.tsx +0 -124
- package/src/TextEditor.stories.tsx +0 -856
- package/src/components/EditorToolbar/comment.ts +0 -23
- package/src/extensions/command/preview.ts +0 -79
- package/src/fragments.ts +0 -19
- package/src/hooks/useActionHandler.ts +0 -12
- /package/src/extensions/markdown/{editorAction.ts → action.ts} +0 -0
@@ -95,17 +95,17 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
95
95
|
});
|
96
96
|
}
|
97
97
|
|
98
|
-
destroy() {
|
98
|
+
destroy(): void {
|
99
99
|
void this._ctx.dispose();
|
100
100
|
this._provider.close();
|
101
101
|
}
|
102
102
|
|
103
|
-
update(update: ViewUpdate) {
|
103
|
+
update(update: ViewUpdate): void {
|
104
104
|
this._updateLocalSelection(update.view);
|
105
105
|
this._updateRemoteSelections(update.view);
|
106
106
|
}
|
107
107
|
|
108
|
-
private _updateLocalSelection(view: EditorView) {
|
108
|
+
private _updateLocalSelection(view: EditorView): void {
|
109
109
|
const hasFocus = view.hasFocus && view.dom.ownerDocument.hasFocus();
|
110
110
|
const { anchor = undefined, head = undefined } = hasFocus ? view.state.selection.main : {};
|
111
111
|
if (this._lastAnchor === anchor && this._lastHead === head) {
|
@@ -125,7 +125,7 @@ export class RemoteSelectionsDecorator implements PluginValue {
|
|
125
125
|
);
|
126
126
|
}
|
127
127
|
|
128
|
-
private _updateRemoteSelections(view: EditorView) {
|
128
|
+
private _updateRemoteSelections(view: EditorView): void {
|
129
129
|
const decorations: Range<Decoration>[] = [
|
130
130
|
// TODO(burdon): Factor out for testing.
|
131
131
|
// {
|
@@ -239,11 +239,11 @@ class RemoteCaretWidget extends WidgetType {
|
|
239
239
|
return span;
|
240
240
|
}
|
241
241
|
|
242
|
-
override updateDOM() {
|
242
|
+
override updateDOM(): boolean {
|
243
243
|
return false;
|
244
244
|
}
|
245
245
|
|
246
|
-
override eq(widget: this) {
|
246
|
+
override eq(widget: this): boolean {
|
247
247
|
return widget._color === this._color;
|
248
248
|
}
|
249
249
|
|
@@ -251,7 +251,7 @@ class RemoteCaretWidget extends WidgetType {
|
|
251
251
|
return -1;
|
252
252
|
}
|
253
253
|
|
254
|
-
override ignoreEvent() {
|
254
|
+
override ignoreEvent(): boolean {
|
255
255
|
return true;
|
256
256
|
}
|
257
257
|
}
|
package/src/extensions/blast.ts
CHANGED
@@ -136,7 +136,7 @@ class Blaster {
|
|
136
136
|
return this._node;
|
137
137
|
}
|
138
138
|
|
139
|
-
initialize() {
|
139
|
+
initialize(): void {
|
140
140
|
// console.log('initialize');
|
141
141
|
invariant(!this._canvas && !this._ctx);
|
142
142
|
|
@@ -155,7 +155,7 @@ class Blaster {
|
|
155
155
|
this.resize();
|
156
156
|
}
|
157
157
|
|
158
|
-
destroy() {
|
158
|
+
destroy(): void {
|
159
159
|
this.stop();
|
160
160
|
// console.log('destroy');
|
161
161
|
if (this._canvas) {
|
@@ -165,7 +165,7 @@ class Blaster {
|
|
165
165
|
}
|
166
166
|
}
|
167
167
|
|
168
|
-
resize() {
|
168
|
+
resize(): void {
|
169
169
|
if (this._node.parentElement && this._canvas) {
|
170
170
|
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
171
171
|
this._canvas.style.top = `${y}px`;
|
@@ -175,20 +175,20 @@ class Blaster {
|
|
175
175
|
}
|
176
176
|
}
|
177
177
|
|
178
|
-
start() {
|
178
|
+
start(): void {
|
179
179
|
// console.log('start');
|
180
180
|
invariant(this._canvas && this._ctx);
|
181
181
|
this._running = true;
|
182
182
|
this.loop();
|
183
183
|
}
|
184
184
|
|
185
|
-
stop() {
|
185
|
+
stop(): void {
|
186
186
|
// console.log('stop');
|
187
187
|
this._running = false;
|
188
188
|
this._node.style.transform = 'translate(0px, 0px)';
|
189
189
|
}
|
190
190
|
|
191
|
-
loop() {
|
191
|
+
loop(): void {
|
192
192
|
if (!this._running || !this._canvas || !this._ctx) {
|
193
193
|
return;
|
194
194
|
}
|
@@ -230,7 +230,7 @@ class Blaster {
|
|
230
230
|
}
|
231
231
|
}, 100);
|
232
232
|
|
233
|
-
drawParticles() {
|
233
|
+
drawParticles(): void {
|
234
234
|
for (let i = this._particles.length; i--; i > 0) {
|
235
235
|
const particle = this._particles[i];
|
236
236
|
if (!particle) {
|
@@ -282,7 +282,7 @@ class Effect1 extends Effect {
|
|
282
282
|
};
|
283
283
|
}
|
284
284
|
|
285
|
-
update(ctx: CanvasRenderingContext2D, particle: Particle) {
|
285
|
+
update(ctx: CanvasRenderingContext2D, particle: Particle): void {
|
286
286
|
particle.vy += this._options.particleGravity;
|
287
287
|
particle.x += particle.vx;
|
288
288
|
particle.y += particle.vy;
|
@@ -313,7 +313,7 @@ class Effect2 extends Effect {
|
|
313
313
|
};
|
314
314
|
}
|
315
315
|
|
316
|
-
update(ctx: CanvasRenderingContext2D, particle: Particle) {
|
316
|
+
update(ctx: CanvasRenderingContext2D, particle: Particle): void {
|
317
317
|
particle.vy += this._options.particleGravity;
|
318
318
|
particle.x += particle.vx;
|
319
319
|
particle.y += particle.vy;
|
@@ -0,0 +1,49 @@
|
|
1
|
+
//
|
2
|
+
// Copyright 2025 DXOS.org
|
3
|
+
//
|
4
|
+
|
5
|
+
import { StateEffect } from '@codemirror/state';
|
6
|
+
import { type KeyBinding, type Command, type EditorView } from '@codemirror/view';
|
7
|
+
|
8
|
+
import { commandState } from './state';
|
9
|
+
|
10
|
+
export type Action =
|
11
|
+
| {
|
12
|
+
type: 'insert';
|
13
|
+
text: string;
|
14
|
+
}
|
15
|
+
| {
|
16
|
+
type: 'cancel';
|
17
|
+
};
|
18
|
+
|
19
|
+
export type ActionHandler = (action: Action) => void;
|
20
|
+
|
21
|
+
export const openEffect = StateEffect.define<{ pos: number; fullWidth?: boolean }>();
|
22
|
+
export const closeEffect = StateEffect.define<null>();
|
23
|
+
|
24
|
+
export const openCommand: Command = (view: EditorView) => {
|
25
|
+
if (view.state.field(commandState, false)) {
|
26
|
+
const selection = view.state.selection.main;
|
27
|
+
const line = view.state.doc.lineAt(selection.from);
|
28
|
+
if (line.from === selection.from && line.from === line.to) {
|
29
|
+
view.dispatch({ effects: openEffect.of({ pos: selection.anchor, fullWidth: true }) });
|
30
|
+
return true;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
return false;
|
35
|
+
};
|
36
|
+
|
37
|
+
export const closeCommand: Command = (view: EditorView) => {
|
38
|
+
if (view.state.field(commandState, false)) {
|
39
|
+
view.dispatch({ effects: closeEffect.of(null) });
|
40
|
+
return true;
|
41
|
+
}
|
42
|
+
|
43
|
+
return false;
|
44
|
+
};
|
45
|
+
|
46
|
+
export const commandKeyBindings: readonly KeyBinding[] = [
|
47
|
+
{ key: '/', run: openCommand },
|
48
|
+
{ key: 'Escape', run: closeCommand },
|
49
|
+
];
|
@@ -5,35 +5,23 @@
|
|
5
5
|
import { type Extension } from '@codemirror/state';
|
6
6
|
import { EditorView, keymap } from '@codemirror/view';
|
7
7
|
|
8
|
-
import {
|
9
|
-
import {
|
10
|
-
import {
|
11
|
-
import { closeEffect, commandConfig, commandKeyBindings, commandState } from './state';
|
8
|
+
import { closeEffect, commandKeyBindings } from './action';
|
9
|
+
import { hintViewPlugin, type HintOptions } from './hint';
|
10
|
+
import { commandConfig, commandState, type PopupOptions } from './state';
|
12
11
|
|
13
12
|
// TODO(burdon): Create knowledge base for CM notes and ideas.
|
14
13
|
// https://discuss.codemirror.net/t/inline-code-hints-like-vscode/5533/4
|
15
14
|
// https://github.com/saminzadeh/codemirror-extension-inline-suggestion
|
16
15
|
// https://github.com/ChromeDevTools/devtools-frontend/blob/main/front_end/ui/components/text_editor/config.ts#L370
|
17
16
|
|
18
|
-
|
19
|
-
export type CommandAction = {
|
20
|
-
insert?: string;
|
21
|
-
};
|
22
|
-
|
23
|
-
export type CommandOptions = {
|
24
|
-
onHint: () => string | undefined;
|
25
|
-
onRenderDialog: (el: HTMLElement, cb: (action?: CommandAction) => void) => void;
|
26
|
-
onRenderMenu: (el: HTMLElement, cb: () => void) => void;
|
27
|
-
} & Pick<PreviewOptions, 'onRenderPreview'>;
|
17
|
+
export type CommandOptions = Partial<PopupOptions & HintOptions>;
|
28
18
|
|
29
|
-
export const command = (options: CommandOptions): Extension => {
|
19
|
+
export const command = (options: CommandOptions = {}): Extension => {
|
30
20
|
return [
|
21
|
+
keymap.of(commandKeyBindings),
|
31
22
|
commandConfig.of(options),
|
32
23
|
commandState,
|
33
|
-
|
34
|
-
preview(options),
|
35
|
-
floatingMenu(options),
|
36
|
-
hintViewPlugin(options),
|
24
|
+
options.onHint ? hintViewPlugin({ onHint: options.onHint }) : [],
|
37
25
|
EditorView.focusChangeEffect.of((_, focusing) => {
|
38
26
|
return focusing ? closeEffect.of(null) : null;
|
39
27
|
}),
|
@@ -41,14 +29,6 @@ export const command = (options: CommandOptions): Extension => {
|
|
41
29
|
'.cm-tooltip': {
|
42
30
|
background: 'transparent',
|
43
31
|
},
|
44
|
-
'.cm-preview': {
|
45
|
-
marginLeft: '-1rem',
|
46
|
-
marginRight: '-1rem',
|
47
|
-
padding: '1rem',
|
48
|
-
borderRadius: '1rem',
|
49
|
-
background: 'var(--dx-modalSurface)',
|
50
|
-
border: '1px solid var(--dx-separator)',
|
51
|
-
},
|
52
32
|
}),
|
53
33
|
];
|
54
34
|
};
|
@@ -5,16 +5,48 @@
|
|
5
5
|
import { RangeSetBuilder } from '@codemirror/state';
|
6
6
|
import { Decoration, EditorView, ViewPlugin, type ViewUpdate, WidgetType } from '@codemirror/view';
|
7
7
|
|
8
|
-
import { type CommandOptions } from './command';
|
9
8
|
import { commandState } from './state';
|
10
9
|
import { clientRectsFor, flattenRect } from '../../util';
|
11
10
|
|
12
|
-
|
11
|
+
export type HintOptions = {
|
12
|
+
onHint: () => string | undefined;
|
13
|
+
};
|
14
|
+
|
15
|
+
export const hintViewPlugin = ({ onHint }: HintOptions) =>
|
16
|
+
ViewPlugin.fromClass(
|
17
|
+
class {
|
18
|
+
decorations = Decoration.none;
|
19
|
+
update(update: ViewUpdate) {
|
20
|
+
const builder = new RangeSetBuilder<Decoration>();
|
21
|
+
const cState = update.view.state.field(commandState, false);
|
22
|
+
if (!cState?.tooltip) {
|
23
|
+
const selection = update.view.state.selection.main;
|
24
|
+
const line = update.view.state.doc.lineAt(selection.from);
|
25
|
+
// Only show if blank line.
|
26
|
+
// TODO(burdon): Clashes with placeholder if pos === 0.
|
27
|
+
// TODO(burdon): Show after delay or if blank line above?
|
28
|
+
if (selection.from === selection.to && line.from === line.to) {
|
29
|
+
const hint = onHint();
|
30
|
+
if (hint) {
|
31
|
+
builder.add(selection.from, selection.to, Decoration.widget({ widget: new Hint(hint) }));
|
32
|
+
}
|
33
|
+
}
|
34
|
+
}
|
35
|
+
|
36
|
+
this.decorations = builder.finish();
|
37
|
+
}
|
38
|
+
},
|
39
|
+
{
|
40
|
+
provide: (plugin) => [EditorView.decorations.of((view) => view.plugin(plugin)?.decorations ?? Decoration.none)],
|
41
|
+
},
|
42
|
+
);
|
43
|
+
|
44
|
+
export class Hint extends WidgetType {
|
13
45
|
constructor(readonly content: string | HTMLElement) {
|
14
46
|
super();
|
15
47
|
}
|
16
48
|
|
17
|
-
toDOM() {
|
49
|
+
toDOM(): HTMLSpanElement {
|
18
50
|
const wrap = document.createElement('span');
|
19
51
|
wrap.className = 'cm-placeholder';
|
20
52
|
wrap.style.pointerEvents = 'none';
|
@@ -44,36 +76,7 @@ class CommandHint extends WidgetType {
|
|
44
76
|
return rect;
|
45
77
|
}
|
46
78
|
|
47
|
-
override ignoreEvent() {
|
79
|
+
override ignoreEvent(): boolean {
|
48
80
|
return false;
|
49
81
|
}
|
50
82
|
}
|
51
|
-
|
52
|
-
export const hintViewPlugin = ({ onHint }: CommandOptions) =>
|
53
|
-
ViewPlugin.fromClass(
|
54
|
-
class {
|
55
|
-
deco = Decoration.none;
|
56
|
-
update(update: ViewUpdate) {
|
57
|
-
const builder = new RangeSetBuilder<Decoration>();
|
58
|
-
const cState = update.view.state.field(commandState, false);
|
59
|
-
if (!cState?.tooltip) {
|
60
|
-
const selection = update.view.state.selection.main;
|
61
|
-
const line = update.view.state.doc.lineAt(selection.from);
|
62
|
-
// Only show if blank line.
|
63
|
-
// TODO(burdon): Clashes with placeholder if pos === 0.
|
64
|
-
// TODO(burdon): Show after delay or if blank line above?
|
65
|
-
if (selection.from === selection.to && line.from === line.to) {
|
66
|
-
const hint = onHint();
|
67
|
-
if (hint) {
|
68
|
-
builder.add(selection.from, selection.to, Decoration.widget({ widget: new CommandHint(hint) }));
|
69
|
-
}
|
70
|
-
}
|
71
|
-
}
|
72
|
-
|
73
|
-
this.deco = builder.finish();
|
74
|
-
}
|
75
|
-
},
|
76
|
-
{
|
77
|
-
provide: (plugin) => [EditorView.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration.none)],
|
78
|
-
},
|
79
|
-
);
|
@@ -2,99 +2,127 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import {
|
5
|
+
import { EditorView, ViewPlugin, type ViewUpdate } from '@codemirror/view';
|
6
6
|
|
7
|
-
import {
|
8
|
-
import { closeEffect, openCommand, openEffect } from './state';
|
7
|
+
import { closeEffect, openEffect } from './action';
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
export type FloatingMenuOptions = {
|
10
|
+
icon?: string;
|
11
|
+
height?: number;
|
12
|
+
padding?: number;
|
13
|
+
};
|
14
|
+
|
15
|
+
export const floatingMenu = (options: FloatingMenuOptions = {}) => [
|
13
16
|
ViewPlugin.fromClass(
|
14
17
|
class {
|
15
|
-
button: HTMLElement;
|
16
18
|
view: EditorView;
|
19
|
+
tag: HTMLElement;
|
17
20
|
rafId: number | null = null;
|
18
21
|
|
19
22
|
constructor(view: EditorView) {
|
20
23
|
this.view = view;
|
21
24
|
|
22
|
-
// Position context
|
25
|
+
// Position context.
|
23
26
|
const container = view.scrollDOM;
|
24
27
|
if (getComputedStyle(container).position === 'static') {
|
25
28
|
container.style.position = 'relative';
|
26
29
|
}
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
const icon = document.createElement('dx-icon');
|
32
|
+
icon.setAttribute('icon', options.icon ?? 'ph--dots-three-outline--regular');
|
33
|
+
|
34
|
+
const button = document.createElement('button');
|
35
|
+
button.appendChild(icon);
|
33
36
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
37
|
+
// TODO(burdon): Custom tag/styles?
|
38
|
+
this.tag = document.createElement('dx-ref-tag');
|
39
|
+
this.tag.classList.add('cm-ref-tag');
|
40
|
+
this.tag.appendChild(button);
|
41
|
+
container.appendChild(this.tag);
|
38
42
|
|
39
43
|
// Listen for scroll events.
|
40
|
-
container.addEventListener('scroll', this.scheduleUpdate);
|
44
|
+
container.addEventListener('scroll', this.scheduleUpdate.bind(this));
|
41
45
|
this.scheduleUpdate();
|
42
46
|
}
|
43
47
|
|
44
48
|
update(update: ViewUpdate) {
|
49
|
+
this.tag.dataset.focused = update.view.hasFocus ? 'true' : 'false';
|
50
|
+
if (!update.view.hasFocus) {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
45
54
|
// TODO(burdon): Timer to fade in/out.
|
46
55
|
if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(openEffect)))) {
|
47
|
-
this.
|
56
|
+
this.tag.style.display = 'none';
|
57
|
+
this.tag.classList.add('opacity-10');
|
48
58
|
} else if (update.transactions.some((tr) => tr.effects.some((effect) => effect.is(closeEffect)))) {
|
49
|
-
this.
|
50
|
-
} else if (
|
59
|
+
this.tag.style.display = 'block';
|
60
|
+
} else if (
|
61
|
+
update.docChanged ||
|
62
|
+
update.focusChanged ||
|
63
|
+
update.geometryChanged ||
|
64
|
+
update.selectionSet ||
|
65
|
+
update.viewportChanged
|
66
|
+
) {
|
51
67
|
this.scheduleUpdate();
|
52
68
|
}
|
53
69
|
}
|
54
70
|
|
55
|
-
scheduleUpdate() {
|
56
|
-
if (this.rafId != null) {
|
57
|
-
cancelAnimationFrame(this.rafId);
|
58
|
-
}
|
59
|
-
this.rafId = requestAnimationFrame(() => this.updateButtonPosition());
|
60
|
-
}
|
61
|
-
|
62
71
|
updateButtonPosition() {
|
63
|
-
const
|
64
|
-
const lineBlock: BlockInfo = this.view.lineBlockAt(pos);
|
65
|
-
const domInfo = this.view.domAtPos(lineBlock.from);
|
72
|
+
const { x, width } = this.view.contentDOM.getBoundingClientRect();
|
66
73
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
}
|
72
|
-
|
73
|
-
if (!node) {
|
74
|
-
this.button.style.display = 'none';
|
74
|
+
const pos = this.view.state.selection.main.head;
|
75
|
+
const line = this.view.lineBlockAt(pos);
|
76
|
+
const coords = this.view.coordsAtPos(line.from);
|
77
|
+
if (!coords) {
|
75
78
|
return;
|
76
79
|
}
|
77
80
|
|
78
|
-
const
|
79
|
-
const
|
81
|
+
const lineHeight = coords.bottom - coords.top;
|
82
|
+
const dy = (lineHeight - (options.height ?? 32)) / 2;
|
80
83
|
|
81
|
-
|
82
|
-
const
|
83
|
-
const offsetLeft = this.view.scrollDOM.clientWidth + this.view.scrollDOM.scrollLeft - lineRect.x;
|
84
|
+
const offsetTop = coords.top + dy;
|
85
|
+
const offsetLeft = x + width + (options.padding ?? 8);
|
84
86
|
|
85
|
-
|
86
|
-
|
87
|
+
this.tag.style.top = `${offsetTop}px`;
|
88
|
+
this.tag.style.left = `${offsetLeft}px`;
|
89
|
+
this.tag.style.display = 'block';
|
90
|
+
}
|
91
|
+
|
92
|
+
scheduleUpdate() {
|
93
|
+
if (this.rafId != null) {
|
94
|
+
cancelAnimationFrame(this.rafId);
|
95
|
+
}
|
87
96
|
|
88
|
-
this.
|
89
|
-
this.button.style.left = `${offsetLeft}px`;
|
90
|
-
this.button.style.display = 'block';
|
97
|
+
this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
|
91
98
|
}
|
92
99
|
|
93
100
|
destroy() {
|
94
|
-
this.
|
101
|
+
this.tag.remove();
|
95
102
|
if (this.rafId != null) {
|
96
103
|
cancelAnimationFrame(this.rafId);
|
97
104
|
}
|
98
105
|
}
|
99
106
|
},
|
100
|
-
)
|
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
|
+
}),
|
128
|
+
];
|
@@ -2,25 +2,24 @@
|
|
2
2
|
// Copyright 2024 DXOS.org
|
3
3
|
//
|
4
4
|
|
5
|
-
import {
|
6
|
-
import {
|
7
|
-
showTooltip,
|
8
|
-
type Command,
|
9
|
-
type EditorView,
|
10
|
-
type KeyBinding,
|
11
|
-
type Tooltip,
|
12
|
-
type TooltipView,
|
13
|
-
} from '@codemirror/view';
|
5
|
+
import { StateField } from '@codemirror/state';
|
6
|
+
import { showTooltip, type EditorView, type Tooltip, type TooltipView } from '@codemirror/view';
|
14
7
|
|
8
|
+
import { closeEffect, type Action, openEffect } from './action';
|
15
9
|
import { type CommandOptions } from './command';
|
10
|
+
import { type RenderCallback } from '../../types';
|
16
11
|
import { singleValueFacet } from '../../util';
|
17
12
|
|
13
|
+
export const commandConfig = singleValueFacet<CommandOptions>();
|
14
|
+
|
15
|
+
export type PopupOptions = {
|
16
|
+
renderDialog: RenderCallback<{ onAction: (action?: Action) => void }>;
|
17
|
+
};
|
18
|
+
|
18
19
|
type CommandState = {
|
19
20
|
tooltip?: Tooltip | null;
|
20
21
|
};
|
21
22
|
|
22
|
-
export const commandConfig = singleValueFacet<CommandOptions>();
|
23
|
-
|
24
23
|
export const commandState = StateField.define<CommandState>({
|
25
24
|
create: () => ({}),
|
26
25
|
update: (state, tr) => {
|
@@ -29,8 +28,8 @@ export const commandState = StateField.define<CommandState>({
|
|
29
28
|
return {};
|
30
29
|
}
|
31
30
|
|
32
|
-
|
33
|
-
|
31
|
+
const { renderDialog } = tr.state.facet(commandConfig);
|
32
|
+
if (effect.is(openEffect) && renderDialog) {
|
34
33
|
const { pos, fullWidth } = effect.value;
|
35
34
|
const tooltip: Tooltip = {
|
36
35
|
pos,
|
@@ -38,38 +37,49 @@ export const commandState = StateField.define<CommandState>({
|
|
38
37
|
arrow: false,
|
39
38
|
strictSide: true,
|
40
39
|
create: (view: EditorView) => {
|
41
|
-
const
|
40
|
+
const root = document.createElement('div');
|
41
|
+
|
42
42
|
const tooltipView: TooltipView = {
|
43
|
-
dom,
|
43
|
+
dom: root,
|
44
44
|
mount: (view: EditorView) => {
|
45
45
|
if (fullWidth) {
|
46
|
-
const parent =
|
46
|
+
const parent = root.parentElement!;
|
47
47
|
const { paddingLeft, paddingRight } = window.getComputedStyle(parent);
|
48
48
|
const widthWithoutPadding = parent.clientWidth - parseFloat(paddingLeft) - parseFloat(paddingRight);
|
49
|
-
|
49
|
+
root.style.width = `${widthWithoutPadding}px`;
|
50
50
|
}
|
51
51
|
|
52
52
|
// Render react component.
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
53
|
+
renderDialog(
|
54
|
+
root,
|
55
|
+
{
|
56
|
+
onAction: (action) => {
|
57
|
+
view.dispatch({ effects: closeEffect.of(null) });
|
58
|
+
switch (action?.type) {
|
59
|
+
case 'insert': {
|
60
|
+
// Insert into editor.
|
61
|
+
const text = action.text + '\n';
|
62
|
+
view.dispatch({
|
63
|
+
changes: { from: pos, insert: text },
|
64
|
+
selection: { anchor: pos + text.length },
|
65
|
+
});
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
// NOTE: Truncates text if set focus immediately.
|
71
|
+
requestAnimationFrame(() => view.focus());
|
72
|
+
},
|
73
|
+
},
|
74
|
+
view,
|
75
|
+
);
|
67
76
|
},
|
68
77
|
};
|
69
78
|
|
70
79
|
return tooltipView;
|
71
80
|
},
|
72
81
|
};
|
82
|
+
|
73
83
|
return { tooltip };
|
74
84
|
}
|
75
85
|
}
|
@@ -78,33 +88,3 @@ export const commandState = StateField.define<CommandState>({
|
|
78
88
|
},
|
79
89
|
provide: (field) => [showTooltip.from(field, (value) => value.tooltip ?? null)],
|
80
90
|
});
|
81
|
-
|
82
|
-
export const openEffect = StateEffect.define<{ pos: number; fullWidth?: boolean }>();
|
83
|
-
export const closeEffect = StateEffect.define<null>();
|
84
|
-
|
85
|
-
export const openCommand: Command = (view: EditorView) => {
|
86
|
-
if (view.state.field(commandState, false)) {
|
87
|
-
const selection = view.state.selection.main;
|
88
|
-
const line = view.state.doc.lineAt(selection.from);
|
89
|
-
if (line.from === selection.from && line.from === line.to) {
|
90
|
-
view.dispatch({ effects: openEffect.of({ pos: selection.anchor, fullWidth: true }) });
|
91
|
-
return true;
|
92
|
-
}
|
93
|
-
}
|
94
|
-
|
95
|
-
return false;
|
96
|
-
};
|
97
|
-
|
98
|
-
export const closeCommand: Command = (view: EditorView) => {
|
99
|
-
if (view.state.field(commandState, false)) {
|
100
|
-
view.dispatch({ effects: closeEffect.of(null) });
|
101
|
-
return true;
|
102
|
-
}
|
103
|
-
|
104
|
-
return false;
|
105
|
-
};
|
106
|
-
|
107
|
-
export const commandKeyBindings: readonly KeyBinding[] = [
|
108
|
-
{ key: '/', run: openCommand },
|
109
|
-
{ key: 'Escape', run: closeCommand },
|
110
|
-
];
|