ultisuite-client/lib/drive/docs-line-spacing.ts
R3D347HR4Y 303b2b1074
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wow
2026-06-11 01:22:40 +02:00

82 lines
3.0 KiB
TypeScript

/** Default line height for Normal text (matches built-in paragraph styles). */
export const DOCS_DEFAULT_LINE_HEIGHT = 1.15
/** Quick spacing added by « Insérer un espacement avant/après » (Google Docs ≈ 12 pt). */
export const DOCS_QUICK_PARAGRAPH_SPACE_PT = 12
export const DOCS_LINE_HEIGHT_PRESETS = [
{ id: "1", value: 1, label: "Simple" },
{ id: "1.15", value: 1.15, label: "1,15" },
{ id: "1.5", value: 1.5, label: "1,5" },
{ id: "2", value: 2, label: "Double" },
] as const
export type DocsLineHeightPresetId = (typeof DOCS_LINE_HEIGHT_PRESETS)[number]["id"]
export type DocsParagraphSpacingAttrs = {
lineHeight: number | null
spaceBeforePt: number
spaceAfterPt: number
keepWithNext: boolean
keepLinesTogether: boolean
preventWidowOrphan: boolean
pageBreakBefore: boolean
}
export const DOCS_DEFAULT_PARAGRAPH_SPACING: DocsParagraphSpacingAttrs = {
lineHeight: null,
spaceBeforePt: 0,
spaceAfterPt: 0,
keepWithNext: false,
keepLinesTogether: false,
preventWidowOrphan: false,
pageBreakBefore: false,
}
export function lineHeightPresetId(value: number | null | undefined): DocsLineHeightPresetId | "custom" | null {
if (value == null) return null
for (const preset of DOCS_LINE_HEIGHT_PRESETS) {
if (Math.abs(preset.value - value) < 0.001) return preset.id
}
return "custom"
}
export function parseLineHeightAttr(raw: unknown): number | null {
if (raw == null || raw === "") return null
const value = typeof raw === "number" ? raw : Number.parseFloat(String(raw))
return Number.isFinite(value) && value > 0 ? value : null
}
export function parseSpacingPt(raw: unknown): number {
if (raw == null || raw === "") return 0
const value = typeof raw === "number" ? raw : Number.parseFloat(String(raw))
return Number.isFinite(value) && value > 0 ? Math.round(value * 100) / 100 : 0
}
export function readParagraphSpacingAttrs(node: ProseMirrorNodeLike): DocsParagraphSpacingAttrs {
const attrs = node.attrs as Record<string, unknown>
return {
lineHeight: parseLineHeightAttr(attrs.lineHeight),
spaceBeforePt: parseSpacingPt(attrs.spaceBeforePt),
spaceAfterPt: parseSpacingPt(attrs.spaceAfterPt),
keepWithNext: Boolean(attrs.keepWithNext),
keepLinesTogether: Boolean(attrs.keepLinesTogether),
preventWidowOrphan: Boolean(attrs.preventWidowOrphan),
pageBreakBefore: Boolean(attrs.pageBreakBefore),
}
}
type ProseMirrorNodeLike = { attrs: Record<string, unknown> }
export function buildParagraphSpacingStyle(attrs: DocsParagraphSpacingAttrs): string {
const parts: string[] = []
if (attrs.lineHeight != null) parts.push(`line-height: ${attrs.lineHeight}`)
if (attrs.spaceBeforePt > 0) parts.push(`margin-top: ${attrs.spaceBeforePt}pt`)
if (attrs.spaceAfterPt > 0) parts.push(`margin-bottom: ${attrs.spaceAfterPt}pt`)
if (attrs.keepWithNext) parts.push("break-after: avoid")
if (attrs.keepLinesTogether) parts.push("break-inside: avoid")
if (attrs.preventWidowOrphan) parts.push("orphans: 2; widows: 2")
if (attrs.pageBreakBefore) parts.push("break-before: page")
return parts.join("; ")
}