mirror of https://github.com/fantasticit/think.git
feat: improve tiptap
This commit is contained in:
parent
e211f07794
commit
0e54e4af65
|
@ -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,
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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': ` 继续输入进行过滤`,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
|
@ -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);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
});
|
|
@ -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,
|
||||||
|
|
|
@ -38,24 +38,20 @@
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-empty::before {
|
.is-empty {
|
||||||
|
&.has-focus {
|
||||||
|
&::before {
|
||||||
content: attr(data-placeholder);
|
content: attr(data-placeholder);
|
||||||
float: left;
|
float: left;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
height: 0;
|
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 {
|
||||||
|
|
Loading…
Reference in New Issue