mirror of https://github.com/fantasticit/think.git
feat: improve selection in code block
This commit is contained in:
parent
704be3b435
commit
8022d937c2
|
@ -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;
|
||||||
},
|
},
|
||||||
|
|
|
@ -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-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) {
|
||||||
|
|
Loading…
Reference in New Issue