mirror of https://github.com/fantasticit/think.git
feat: improve selection in code block
parent
704be3b435
commit
8022d937c2
|
@ -1,6 +1,7 @@
|
|||
import { Extension } from '@tiptap/core';
|
||||
import { Plugin, PluginKey, NodeSelection, TextSelection, Selection, AllSelection } from 'prosemirror-state';
|
||||
import { Decoration, DecorationSet } from 'prosemirror-view';
|
||||
import { getCurrentNode, isInCodeBlock } from '../services/node';
|
||||
import { EXTENSION_PRIORITY_HIGHEST } from '../constants';
|
||||
|
||||
export const selectionPluginKey = new PluginKey('selection');
|
||||
|
@ -48,8 +49,55 @@ export const SelectionExtension = Extension.create({
|
|||
new Plugin({
|
||||
key: selectionPluginKey,
|
||||
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) {
|
||||
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);
|
||||
return decorationSet;
|
||||
},
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
.node-iframe,
|
||||
.node-mind,
|
||||
.node-banner {
|
||||
margin-top: .75em;
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
|
||||
.node-attachment,
|
||||
|
@ -72,6 +72,7 @@
|
|||
}
|
||||
|
||||
&.selected-node {
|
||||
position: relative;
|
||||
.render-wrapper {
|
||||
border: 1px solid var(--node-selected-border-color) !important;
|
||||
|
||||
|
@ -80,6 +81,15 @@
|
|||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
inset: 0px;
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
background-color: rgb(179, 212, 255);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.has-focus) {
|
||||
|
|
Loading…
Reference in New Issue