ultisuite-client/components/drive/richtext/docs-horizontal-ruler.tsx
R3D347HR4Y 303b2b1074
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
wow
2026-06-11 01:22:40 +02:00

140 lines
4.4 KiB
TypeScript

"use client"
import { memo, useRef } from "react"
import type { DocPageLayout } from "@/lib/drive/doc-page-setup"
import { DOCS_HORIZONTAL_RULER_HEIGHT_PX } from "@/lib/drive/docs-page-layout-constants"
import { docsPageLengthToScreen } from "@/lib/drive/docs-ruler-scale"
import type { DocsParagraphIndents } from "@/lib/drive/use-docs-ruler-sync"
import { buildHorizontalRulerTicks } from "@/lib/drive/docs-ruler-math"
import type { DocsRulerMarginSide } from "@/lib/drive/docs-ruler-margin-math"
import {
DocsRulerDraggableHandle,
DocsRulerFirstLineMarker,
DocsRulerTriangleMarker,
useRulerPointerDrag,
} from "@/components/drive/richtext/docs-ruler-markers"
function DocsHorizontalRulerInner({
pageLayout,
scale,
indents,
editable,
onMarginDragStart,
onMarginDrag,
onMarginDragEnd,
}: {
pageLayout: DocPageLayout
scale: number
indents: DocsParagraphIndents
editable?: boolean
onMarginDragStart?: (side: DocsRulerMarginSide) => void
onMarginDrag?: (side: DocsRulerMarginSide, pagePx: number, clientX: number, clientY: number) => void
onMarginDragEnd?: () => void
}) {
const rulerRef = useRef<HTMLDivElement>(null)
const pageWidth = pageLayout.widthPx
const margins = pageLayout.marginsPx
const scaledWidth = docsPageLengthToScreen(pageWidth, scale)
const ticks = buildHorizontalRulerTicks(pageWidth, pageLayout.format.id)
const s = (px: number) => docsPageLengthToScreen(px, scale)
const leftDrag = useRulerPointerDrag({
rulerRef,
axis: "horizontal",
disabled: !editable,
onDrag: (pagePx, clientX, clientY) => onMarginDrag?.("left", pagePx, clientX, clientY),
onDragEnd: () => onMarginDragEnd?.(),
})
const rightDrag = useRulerPointerDrag({
rulerRef,
axis: "horizontal",
disabled: !editable,
onDrag: (pagePx, clientX, clientY) => onMarginDrag?.("right", pagePx, clientX, clientY),
onDragEnd: () => onMarginDragEnd?.(),
})
const wrapMarginDown =
(side: DocsRulerMarginSide, handler: (e: React.PointerEvent<HTMLDivElement>) => void) =>
(event: React.PointerEvent<HTMLDivElement>) => {
onMarginDragStart?.(side)
handler(event)
}
return (
<div
ref={rulerRef}
data-docs-ruler="horizontal"
data-docs-ruler-scale={scale}
className="docs-horizontal-ruler relative overflow-visible bg-transparent"
style={{
width: scaledWidth,
height: DOCS_HORIZONTAL_RULER_HEIGHT_PX,
}}
>
<div
className="absolute top-0 h-full bg-transparent"
style={{ left: 0, width: s(margins.left) }}
/>
<div
className="absolute top-0 h-full bg-transparent"
style={{ left: s(pageWidth - margins.right), width: s(margins.right) }}
/>
{ticks.map((tick, index) => (
<div
key={`${tick.pos}-${index}`}
className="pointer-events-none absolute bottom-0 w-px bg-[#bdc1c6] dark:bg-muted-foreground/70"
style={{
left: s(tick.pos),
height: tick.major ? 10 : 5,
}}
/>
))}
{ticks
.filter((tick) => tick.major && tick.label != null)
.map((tick) => (
<span
key={`label-${tick.pos}`}
className="pointer-events-none absolute top-[2px] -translate-x-1/2 text-[9px] leading-none text-[#9aa0a6] dark:text-muted-foreground"
style={{ left: s(tick.pos) }}
>
{tick.label}
</span>
))}
<DocsRulerDraggableHandle
style={{ left: s(margins.left) }}
axis="horizontal"
disabled={!editable}
ariaLabel="Marge gauche"
onPointerDown={wrapMarginDown("left", leftDrag.onPointerDown)}
>
<DocsRulerTriangleMarker left={0} className="relative" />
</DocsRulerDraggableHandle>
<DocsRulerDraggableHandle
style={{ left: s(pageWidth - margins.right) }}
axis="horizontal"
disabled={!editable}
ariaLabel="Marge droite"
onPointerDown={wrapMarginDown("right", rightDrag.onPointerDown)}
>
<DocsRulerTriangleMarker left={0} className="relative" />
</DocsRulerDraggableHandle>
<DocsRulerTriangleMarker
left={s(indents.leftPx)}
className="pointer-events-none absolute bottom-0 -translate-x-1/2"
/>
{Math.abs(indents.firstLinePx - indents.leftPx) > 1 ? (
<DocsRulerFirstLineMarker left={s(indents.firstLinePx)} />
) : null}
</div>
)
}
export const DocsHorizontalRuler = memo(DocsHorizontalRulerInner)