feat: improve selection in code block

This commit is contained in:
fantasticit 2022-03-31 23:08:54 +08:00
parent 704be3b435
commit 8022d937c2
3 changed files with 74 additions and 2 deletions

View File

@ -1,6 +1,7 @@
import { Extension } from '@tiptap/core'; import { Extension } from '@tiptap/core';
import { Plugin, PluginKey, NodeSelection, TextSelection, Selection, AllSelection } from 'prosemirror-state'; import { Plugin, PluginKey, NodeSelection, TextSelection, Selection, AllSelection } from 'prosemirror-state';
import { Decoration, DecorationSet } from 'prosemirror-view'; import { Decoration, DecorationSet } from 'prosemirror-view';
import { getCurrentNode, isInCodeBlock } from '../services/node';
import { EXTENSION_PRIORITY_HIGHEST } from '../constants'; import { EXTENSION_PRIORITY_HIGHEST } from '../constants';
export const selectionPluginKey = new PluginKey('selection'); export const selectionPluginKey = new PluginKey('selection');
@ -48,8 +49,55 @@ export const SelectionExtension = Extension.create({
new Plugin({ new Plugin({
key: selectionPluginKey, key: selectionPluginKey,
props: { props: {
handleKeyDown(view, event) {
/**
* Command + A
* Ctrl + A
*/
if ((event.ctrlKey || event.metaKey) && (event.keyCode == 65 || event.keyCode == 97)) {
const node = getCurrentNode(view.state);
// 代码块
if (isInCodeBlock(view.state)) {
const { pos, parentOffset } = view.state.selection.$head;
const newState = view.state;
const next = new TextSelection(
newState.doc.resolve(pos - parentOffset + node.nodeSize - 2), //内容结束点
newState.doc.resolve(pos - parentOffset) // 内容起始点
);
view?.dispatch(newState.tr.setSelection(next));
return true;
}
}
return false;
},
handleDoubleClickOn(view, pos, node, nodePos, event) {
if (node.type.name === 'codeBlock') {
event.preventDefault();
const transaction = view.state.tr.setMeta('selectNode', {
fromPos: nodePos,
toPos: nodePos + node.nodeSize,
attrs: { class: 'selected-node' },
});
view?.dispatch(transaction);
return false;
}
return true;
},
decorations(state) { decorations(state) {
const { doc, selection } = state; return this.getState(state);
},
},
state: {
init() {
return DecorationSet.empty;
},
apply(ctx) {
if (ctx.getMeta('selectNode')) {
const { fromPos, toPos, attrs } = ctx.getMeta('selectNode');
return DecorationSet.create(ctx.doc, [Decoration.node(fromPos, toPos, attrs)]);
}
const { doc, selection } = ctx;
const decorationSet = getDecorations(doc, selection); const decorationSet = getDecorations(doc, selection);
return decorationSet; return decorationSet;
}, },

View File

@ -29,3 +29,17 @@ export function isInTitle(state: EditorState): boolean {
} }
} }
} }
export function getCurrentNode(state: EditorState): Node {
const $head = state.selection.$head;
return $head.node($head.depth);
}
export function isInCodeBlock(state: EditorState): boolean {
const $head = state.selection.$head;
for (let d = $head.depth; d > 0; d--) {
if ($head.node(d).type === state.schema.nodes.codeBlock) {
return true;
}
}
}

View File

@ -50,7 +50,7 @@
.node-iframe, .node-iframe,
.node-mind, .node-mind,
.node-banner { .node-banner {
margin-top: .75em; margin-top: 0.75em;
} }
.node-attachment, .node-attachment,
@ -72,6 +72,7 @@
} }
&.selected-node { &.selected-node {
position: relative;
.render-wrapper { .render-wrapper {
border: 1px solid var(--node-selected-border-color) !important; border: 1px solid var(--node-selected-border-color) !important;
@ -80,6 +81,15 @@
box-shadow: none; box-shadow: none;
} }
} }
&::after {
position: absolute;
content: '';
inset: 0px;
opacity: 0.3;
pointer-events: none;
background-color: rgb(179, 212, 255);
}
} }
&:not(.has-focus) { &:not(.has-focus) {