feat: improve tiptap

This commit is contained in:
fantasticit 2022-03-22 12:43:03 +08:00
parent e211f07794
commit 0e54e4af65
6 changed files with 119 additions and 27 deletions

View File

@ -13,6 +13,7 @@ import { DocumentReference } from './extensions/documentReference';
import { Dropcursor } from './extensions/dropCursor'; import { Dropcursor } from './extensions/dropCursor';
import { Emoji } from './extensions/emoji'; import { Emoji } from './extensions/emoji';
import { EvokeMenu } from './extensions/evokeMenu'; import { EvokeMenu } from './extensions/evokeMenu';
import { Focus } from './extensions/focus';
import { FontSize } from './extensions/fontSize'; import { FontSize } from './extensions/fontSize';
import { FootnoteDefinition } from './extensions/footnoteDefinition'; import { FootnoteDefinition } from './extensions/footnoteDefinition';
import { FootnoteReference } from './extensions/footnoteReference'; import { FootnoteReference } from './extensions/footnoteReference';
@ -67,6 +68,7 @@ export const BaseKit = [
Dropcursor, Dropcursor,
Emoji, Emoji,
EvokeMenu, EvokeMenu,
Focus,
FontSize, FontSize,
FootnoteDefinition, FootnoteDefinition,
FootnoteReference, FootnoteReference,

View File

@ -15,11 +15,7 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
content={ content={
<> <>
<div style={{ marginBottom: 8 }}> <div style={{ marginBottom: 8 }}>
<Input <Input autofocus placeholder="输入状态" onChange={(v) => updateAttributes({ text: v })} />
autofocus
placeholder="输入状态"
onChange={(v) => updateAttributes({ text: v })}
/>
</div> </div>
<Space> <Space>
{['grey', 'red', 'green', 'orange', 'purple', 'teal'].map((color) => { {['grey', 'red', 'green', 'orange', 'purple', 'teal'].map((color) => {
@ -44,7 +40,7 @@ export const StatusWrapper = ({ editor, node, updateAttributes }) => {
) : ( ) : (
content content
)} )}
<NodeViewContent></NodeViewContent> {/* <NodeViewContent></NodeViewContent> */}
</NodeViewWrapper> </NodeViewWrapper>
); );
}; };

View File

@ -54,21 +54,22 @@ export const EvokeMenu = Node.create({
const isEmpty = parent && parent.node.content.size === 0; const isEmpty = parent && parent.node.content.size === 0;
const isSlash = parent && parent.node.textContent === '/'; const isSlash = parent && parent.node.textContent === '/';
const isTopLevel = state.selection.$from.depth === 1; const isTopLevel = state.selection.$from.depth === 1;
const hasOtherChildren = parent && parent.node.content.childCount > 1;
if (isTopLevel) { if (isTopLevel) {
if (isEmpty) { if (isEmpty) {
decorations.push( decorations.push(
Decoration.node(parent.pos, parent.pos + parent.node.nodeSize, { Decoration.node(parent.pos, parent.pos + parent.node.nodeSize, {
'class': 'placeholder', 'class': 'is-empty',
'data-placeholder': '输入 / 唤起更多', 'data-placeholder': '输入 / 唤起更多',
}) })
); );
} }
if (isSlash) { if (isSlash && !hasOtherChildren) {
decorations.push( decorations.push(
Decoration.node(parent.pos, parent.pos + parent.node.nodeSize, { Decoration.node(parent.pos, parent.pos + parent.node.nodeSize, {
'class': 'placeholder', 'class': 'is-empty',
'data-placeholder': ` 继续输入进行过滤`, 'data-placeholder': ` 继续输入进行过滤`,
}) })
); );

View File

@ -0,0 +1,90 @@
import { Extension } from '@tiptap/core';
import { Plugin, PluginKey } from 'prosemirror-state';
import { DecorationSet, Decoration } from 'prosemirror-view';
export interface FocusOptions {
className: string;
mode: 'all' | 'deepest' | 'shallowest';
}
export const Focus = Extension.create<FocusOptions>({
name: 'focus',
addOptions() {
return {
className: 'has-focus',
mode: 'all',
};
},
addProseMirrorPlugins() {
return [
new Plugin({
key: new PluginKey('focus'),
props: {
decorations: ({ doc, selection }) => {
const { isEditable, isFocused } = this.editor;
const { anchor } = selection;
const decorations: Decoration[] = [];
if (!isEditable || !isFocused) {
return DecorationSet.create(doc, []);
}
// Maximum Levels
let maxLevels = 0;
if (this.options.mode === 'deepest') {
doc.descendants((node, pos) => {
if (node.isText) {
return;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
maxLevels += 1;
});
}
// Loop through current
let currentLevel = 0;
doc.descendants((node, pos) => {
if (node.isText) {
return false;
}
const isCurrent = anchor >= pos && anchor <= pos + node.nodeSize - 1;
if (!isCurrent) {
return false;
}
currentLevel += 1;
const outOfScope =
(this.options.mode === 'deepest' && maxLevels - currentLevel > 0) ||
(this.options.mode === 'shallowest' && currentLevel > 1);
if (outOfScope) {
return this.options.mode === 'deepest';
}
decorations.push(
Decoration.node(pos, pos + node.nodeSize, {
class: this.options.className,
})
);
});
return DecorationSet.create(doc, decorations);
},
},
}),
];
},
});

View File

@ -12,7 +12,6 @@ declare module '@tiptap/core' {
export const Status = Node.create({ export const Status = Node.create({
name: 'status', name: 'status',
content: 'text*',
group: 'inline', group: 'inline',
inline: true, inline: true,
atom: true, atom: true,

View File

@ -38,24 +38,20 @@
outline: none; outline: none;
} }
.is-empty::before { .is-empty {
content: attr(data-placeholder); &.has-focus {
float: left; &::before {
color: #aaa; content: attr(data-placeholder);
pointer-events: none; float: left;
height: 0; color: #aaa;
} pointer-events: none;
height: 0;
}
}
.is-empty.node-codeBlock::before { &.node-codeBlock::before {
transform: translate(10px, 10px); transform: translate(10px, 10px);
} }
.placeholder::before {
content: attr(data-placeholder);
float: left;
color: #aaa;
pointer-events: none;
height: 0;
} }
.hr-line { .hr-line {
@ -108,6 +104,14 @@
color: var(--semi-color-text-0); color: var(--semi-color-text-0);
margin: 10px 0 22px; margin: 10px 0 22px;
border-bottom: 1px solid var(--semi-color-border); border-bottom: 1px solid var(--semi-color-border);
&.is-empty::before {
content: attr(data-placeholder);
float: left;
color: #aaa;
pointer-events: none;
height: 0;
}
} }
h1 { h1 {