feat: article editor core
This commit is contained in:
1 parent
d493a181e1
commit
a4734b2c91
55 files changed
+4186
-496
No files matched your search
@@ -0,0 +1,97 @@
|
||||
import { Extension } from '@tiptap/core'
|
||||
|
||||
export const INDENT_MAX = 4
|
||||
export const INDENT_TYPES = ['paragraph', 'heading']
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
interface Commands<ReturnType> {
|
||||
articleIndent: {
|
||||
indent: () => ReturnType
|
||||
outdent: () => ReturnType
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function currentIndentableNode(state: {
|
||||
selection: { $from: { parent: unknown } }
|
||||
}) {
|
||||
return state.selection.$from.parent as {
|
||||
type: { name: string }
|
||||
attrs: { indent?: number }
|
||||
}
|
||||
}
|
||||
|
||||
export const ArticleIndent = Extension.create({
|
||||
name: 'articleIndent',
|
||||
addGlobalAttributes() {
|
||||
return [
|
||||
{
|
||||
types: INDENT_TYPES,
|
||||
attributes: {
|
||||
indent: {
|
||||
default: 0,
|
||||
parseHTML: (element) =>
|
||||
Number(element.getAttribute('data-indent')) || 0,
|
||||
renderHTML: (attributes) => {
|
||||
if (!attributes.indent) {
|
||||
return {}
|
||||
}
|
||||
return { 'data-indent': String(attributes.indent) }
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
addCommands() {
|
||||
return {
|
||||
indent:
|
||||
() =>
|
||||
({ state, commands, tr, dispatch }) => {
|
||||
if (commands.sinkListItem('listItem')) {
|
||||
return true
|
||||
}
|
||||
const node = currentIndentableNode(state)
|
||||
if (!INDENT_TYPES.includes(node.type.name)) {
|
||||
return false
|
||||
}
|
||||
const level = Math.min(
|
||||
INDENT_MAX,
|
||||
(node.attrs.indent ?? 0) + 1,
|
||||
)
|
||||
if (dispatch) {
|
||||
const { $from } = state.selection
|
||||
tr.setNodeAttribute(
|
||||
$from.before($from.depth),
|
||||
'indent',
|
||||
level,
|
||||
)
|
||||
dispatch(tr)
|
||||
}
|
||||
return true
|
||||
},
|
||||
outdent:
|
||||
() =>
|
||||
({ state, commands, tr, dispatch }) => {
|
||||
if (commands.liftListItem('listItem')) {
|
||||
return true
|
||||
}
|
||||
const node = currentIndentableNode(state)
|
||||
if (!INDENT_TYPES.includes(node.type.name)) {
|
||||
return false
|
||||
}
|
||||
const level = Math.max(0, (node.attrs.indent ?? 0) - 1)
|
||||
if (dispatch) {
|
||||
const { $from } = state.selection
|
||||
tr.setNodeAttribute(
|
||||
$from.before($from.depth),
|
||||
'indent',
|
||||
level,
|
||||
)
|
||||
dispatch(tr)
|
||||
}
|
||||
return true
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
Reference in new issue
Block a user