91 lines
3.0 KiB
TypeScript
91 lines
3.0 KiB
TypeScript
import type { Editor } from "@tiptap/react"
|
|
import type { Node as ProseMirrorNode } from "@tiptap/pm/model"
|
|
import { getDocsBlockTargets } from "@/lib/drive/docs-block-targets"
|
|
import {
|
|
clampIndentLevel,
|
|
nextIndentLevel,
|
|
} from "@/lib/drive/docs-indent"
|
|
|
|
function applyBlockIndentDelta(editor: Editor, delta: number): boolean {
|
|
const { state } = editor
|
|
const targets = getDocsBlockTargets(state.doc, state.selection.from, state.selection.to)
|
|
if (targets.length === 0) return false
|
|
|
|
let tr = state.tr
|
|
let changed = false
|
|
|
|
for (const { pos, node } of targets) {
|
|
const current = clampIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0)
|
|
const next = nextIndentLevel(current, delta)
|
|
if (next === current) continue
|
|
tr = tr.setNodeMarkup(pos, undefined, { ...node.attrs, indentLevel: next })
|
|
changed = true
|
|
}
|
|
|
|
if (!changed) return false
|
|
editor.view.dispatch(tr.scrollIntoView())
|
|
return true
|
|
}
|
|
|
|
export function increaseDocsIndent(editor: Editor | null): boolean {
|
|
if (!editor || editor.isDestroyed) return false
|
|
|
|
if (editor.isActive("taskItem")) {
|
|
return editor.can().sinkListItem("taskItem")
|
|
? editor.chain().focus().sinkListItem("taskItem").run()
|
|
: false
|
|
}
|
|
|
|
if (editor.isActive("listItem")) {
|
|
return editor.can().sinkListItem("listItem")
|
|
? editor.chain().focus().sinkListItem("listItem").run()
|
|
: false
|
|
}
|
|
|
|
return applyBlockIndentDelta(editor, 1)
|
|
}
|
|
|
|
export function decreaseDocsIndent(editor: Editor | null): boolean {
|
|
if (!editor || editor.isDestroyed) return false
|
|
|
|
if (editor.isActive("taskItem")) {
|
|
return editor.can().liftListItem("taskItem")
|
|
? editor.chain().focus().liftListItem("taskItem").run()
|
|
: false
|
|
}
|
|
|
|
if (editor.isActive("listItem")) {
|
|
return editor.can().liftListItem("listItem")
|
|
? editor.chain().focus().liftListItem("listItem").run()
|
|
: false
|
|
}
|
|
|
|
return applyBlockIndentDelta(editor, -1)
|
|
}
|
|
|
|
export function canIncreaseDocsIndent(editor: Editor | null): boolean {
|
|
if (!editor || editor.isDestroyed) return false
|
|
if (editor.isActive("taskItem")) return editor.can().sinkListItem("taskItem")
|
|
if (editor.isActive("listItem")) return editor.can().sinkListItem("listItem")
|
|
return getDocsBlockTargets(
|
|
editor.state.doc,
|
|
editor.state.selection.from,
|
|
editor.state.selection.to
|
|
).some(
|
|
({ node }) =>
|
|
nextIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0, 1) !==
|
|
clampIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0)
|
|
)
|
|
}
|
|
|
|
export function canDecreaseDocsIndent(editor: Editor | null): boolean {
|
|
if (!editor || editor.isDestroyed) return false
|
|
if (editor.isActive("taskItem")) return editor.can().liftListItem("taskItem")
|
|
if (editor.isActive("listItem")) return editor.can().liftListItem("listItem")
|
|
return getDocsBlockTargets(
|
|
editor.state.doc,
|
|
editor.state.selection.from,
|
|
editor.state.selection.to
|
|
).some(({ node }) => clampIndentLevel((node.attrs.indentLevel as number | undefined) ?? 0) > 0)
|
|
}
|