170 lines
5.5 KiB
TypeScript
170 lines
5.5 KiB
TypeScript
"use client"
|
|
|
|
import { useEditorState } from "@tiptap/react"
|
|
import type { Editor } from "@tiptap/react"
|
|
import {
|
|
canStepFontSizePx,
|
|
readFontSizeToolbarState,
|
|
type FontSizeToolbarState,
|
|
} from "@/lib/drive/docs-font-size"
|
|
import {
|
|
readFontFamilyToolbarState,
|
|
type FontFamilyToolbarState,
|
|
} from "@/lib/drive/docs-font-family"
|
|
import { readActiveParagraphStyleId } from "@/lib/drive/docs-paragraph-style-apply"
|
|
import {
|
|
canDecreaseDocsIndent,
|
|
canIncreaseDocsIndent,
|
|
} from "@/lib/drive/docs-indent-actions"
|
|
import { readDocsParagraphSpacingState } from "@/lib/drive/docs-line-spacing-actions"
|
|
import { readDocsListState } from "@/lib/drive/docs-list-actions"
|
|
|
|
export const DOCS_TOOLBAR_DEFAULT_TEXT_COLOR = "#000000"
|
|
|
|
export type DocsToolbarEditorState = {
|
|
canUndo: boolean
|
|
canRedo: boolean
|
|
styleId: string
|
|
fontFamilyState: FontFamilyToolbarState
|
|
fontSizeState: FontSizeToolbarState
|
|
canStepFontSizeDown: boolean
|
|
canStepFontSizeUp: boolean
|
|
textColor: string
|
|
highlightColor: string | null
|
|
isBold: boolean
|
|
isItalic: boolean
|
|
isUnderline: boolean
|
|
isLink: boolean
|
|
alignLeft: boolean
|
|
alignCenter: boolean
|
|
alignRight: boolean
|
|
alignJustify: boolean
|
|
isBulletList: boolean
|
|
isOrderedList: boolean
|
|
isTaskList: boolean
|
|
canIncreaseIndent: boolean
|
|
canDecreaseIndent: boolean
|
|
lineHeightPresetId: string | "mixed" | null
|
|
graphicSelected: boolean
|
|
}
|
|
|
|
function readHighlightColor(editor: Editor): string | null {
|
|
const { storedMarks } = editor.state
|
|
if (storedMarks) {
|
|
const mark = storedMarks.find((m) => m.type.name === "highlight")
|
|
const stored = mark?.attrs.color as string | undefined
|
|
if (stored) return stored
|
|
}
|
|
|
|
if (!editor.isActive("highlight")) return null
|
|
const color = editor.getAttributes("highlight").color as string | undefined
|
|
return color ?? null
|
|
}
|
|
|
|
function selectDocsToolbarState({ editor }: { editor: Editor }): DocsToolbarEditorState {
|
|
const highlightColor = readHighlightColor(editor)
|
|
const spacing = readDocsParagraphSpacingState(editor)
|
|
const listState = readDocsListState(editor)
|
|
|
|
return {
|
|
canUndo: editor.can().chain().focus().undo().run(),
|
|
canRedo: editor.can().chain().focus().redo().run(),
|
|
styleId: readActiveParagraphStyleId(editor),
|
|
fontFamilyState: readFontFamilyToolbarState(editor),
|
|
fontSizeState: readFontSizeToolbarState(editor),
|
|
canStepFontSizeDown: canStepFontSizePx(editor, -1),
|
|
canStepFontSizeUp: canStepFontSizePx(editor, 1),
|
|
textColor:
|
|
(editor.getAttributes("textStyle").color as string | undefined) ||
|
|
DOCS_TOOLBAR_DEFAULT_TEXT_COLOR,
|
|
highlightColor,
|
|
isBold: editor.isActive("bold"),
|
|
isItalic: editor.isActive("italic"),
|
|
isUnderline: editor.isActive("underline"),
|
|
isLink: editor.isActive("link"),
|
|
alignLeft: editor.isActive({ textAlign: "left" }),
|
|
alignCenter: editor.isActive({ textAlign: "center" }),
|
|
alignRight: editor.isActive({ textAlign: "right" }),
|
|
alignJustify: editor.isActive({ textAlign: "justify" }),
|
|
isBulletList: editor.isActive("bulletList"),
|
|
isOrderedList: editor.isActive("orderedList"),
|
|
isTaskList: listState.isTaskList,
|
|
canIncreaseIndent: canIncreaseDocsIndent(editor),
|
|
canDecreaseIndent: canDecreaseDocsIndent(editor),
|
|
lineHeightPresetId: spacing.lineHeightPresetId,
|
|
graphicSelected:
|
|
editor.isActive("docsGraphic") || editor.isActive("docsInlineGraphic"),
|
|
}
|
|
}
|
|
|
|
function fontFamilyStateEqual(a: FontFamilyToolbarState, b: FontFamilyToolbarState): boolean {
|
|
if (a.kind !== b.kind) return false
|
|
if (a.kind === "single" && b.kind === "single") return a.name === b.name
|
|
return true
|
|
}
|
|
|
|
function fontSizeStateEqual(a: FontSizeToolbarState, b: FontSizeToolbarState): boolean {
|
|
if (a.kind !== b.kind) return false
|
|
if (a.kind === "single" && b.kind === "single") return a.size === b.size
|
|
return true
|
|
}
|
|
|
|
function toolbarStateEqual(
|
|
a: DocsToolbarEditorState,
|
|
b: DocsToolbarEditorState | null
|
|
): boolean {
|
|
if (!b) return false
|
|
if (!fontFamilyStateEqual(a.fontFamilyState, b.fontFamilyState)) return false
|
|
if (!fontSizeStateEqual(a.fontSizeState, b.fontSizeState)) return false
|
|
|
|
return (
|
|
a.canUndo === b.canUndo &&
|
|
a.canRedo === b.canRedo &&
|
|
a.styleId === b.styleId &&
|
|
a.canStepFontSizeDown === b.canStepFontSizeDown &&
|
|
a.canStepFontSizeUp === b.canStepFontSizeUp &&
|
|
a.textColor === b.textColor &&
|
|
a.highlightColor === b.highlightColor &&
|
|
a.isBold === b.isBold &&
|
|
a.isItalic === b.isItalic &&
|
|
a.isUnderline === b.isUnderline &&
|
|
a.isLink === b.isLink &&
|
|
a.alignLeft === b.alignLeft &&
|
|
a.alignCenter === b.alignCenter &&
|
|
a.alignRight === b.alignRight &&
|
|
a.alignJustify === b.alignJustify &&
|
|
a.isBulletList === b.isBulletList &&
|
|
a.isOrderedList === b.isOrderedList &&
|
|
a.isTaskList === b.isTaskList &&
|
|
a.canIncreaseIndent === b.canIncreaseIndent &&
|
|
a.canDecreaseIndent === b.canDecreaseIndent &&
|
|
a.lineHeightPresetId === b.lineHeightPresetId &&
|
|
a.graphicSelected === b.graphicSelected
|
|
)
|
|
}
|
|
|
|
function selectDocsToolbarStateOptional({
|
|
editor,
|
|
}: {
|
|
editor: Editor | null
|
|
}): DocsToolbarEditorState | null {
|
|
if (!editor) return null
|
|
return selectDocsToolbarState({ editor })
|
|
}
|
|
|
|
function toolbarStateEqualOptional(
|
|
a: DocsToolbarEditorState | null,
|
|
b: DocsToolbarEditorState | null
|
|
): boolean {
|
|
if (a == null || b == null) return a === b
|
|
return toolbarStateEqual(a, b)
|
|
}
|
|
|
|
export function useDocsToolbarState(editor: Editor | null): DocsToolbarEditorState | null {
|
|
return useEditorState({
|
|
editor,
|
|
selector: selectDocsToolbarStateOptional,
|
|
equalityFn: toolbarStateEqualOptional,
|
|
})
|
|
}
|