41 lines
1.1 KiB
TypeScript
41 lines
1.1 KiB
TypeScript
type TipTapNode = {
|
|
type?: string
|
|
text?: string
|
|
content?: TipTapNode[]
|
|
}
|
|
|
|
/** True when TipTap JSON has no meaningful text (blank doc / empty paragraph). */
|
|
export function isEmptyTipTapDoc(content: Record<string, unknown> | null | undefined): boolean {
|
|
if (!content) return true
|
|
return !tipTapNodeHasText(content as TipTapNode)
|
|
}
|
|
|
|
/** Ensure TipTap JSON is a valid editable doc (at least one block node). */
|
|
export function ensureMinimalTipTapDoc(
|
|
content: Record<string, unknown> | null | undefined
|
|
): Record<string, unknown> {
|
|
if (
|
|
content &&
|
|
content.type === "doc" &&
|
|
Array.isArray(content.content) &&
|
|
content.content.length > 0
|
|
) {
|
|
return content
|
|
}
|
|
return { type: "doc", content: [{ type: "paragraph" }] }
|
|
}
|
|
|
|
function tipTapNodeHasText(node: TipTapNode | TipTapNode[] | null | undefined): boolean {
|
|
if (!node) return false
|
|
if (Array.isArray(node)) {
|
|
return node.some((child) => tipTapNodeHasText(child))
|
|
}
|
|
if (typeof node.text === "string" && node.text.trim() !== "") {
|
|
return true
|
|
}
|
|
if (Array.isArray(node.content)) {
|
|
return node.content.some((child) => tipTapNodeHasText(child))
|
|
}
|
|
return false
|
|
}
|