45 lines
2.4 KiB
TypeScript
45 lines
2.4 KiB
TypeScript
import { Fragment, useRef, type PointerEvent, type RefObject } from "react";
|
||
import { COLW, GRID } from "../constants.ts";
|
||
import { dateText, dateTitle, type DateCol } from "../layout/layout.ts";
|
||
|
||
// липкая полоса подписей дат над доской: сдвиг — как у горизонтальной прокрутки доски; ручка границы меняет ширину колонки
|
||
export function DatesBar({ cols, width, scrollLeft, inRef, onColWidth }: {
|
||
cols: DateCol[]; width: number; scrollLeft: number; inRef: RefObject<HTMLDivElement | null>;
|
||
onColWidth(date: string, w: number | null): void;
|
||
}) {
|
||
const raf = useRef(0);
|
||
const down = (ev: PointerEvent<HTMLDivElement>, c: DateCol) => {
|
||
ev.preventDefault();
|
||
const handle = ev.currentTarget, x0 = ev.clientX;
|
||
handle.classList.add("on"); inRef.current?.classList.add("resizing");
|
||
let last = c.w;
|
||
const apply = (w: number) => onColWidth(c.date, w <= COLW ? null : Math.round(w / GRID) * GRID);
|
||
const move = (e: globalThis.PointerEvent) => {
|
||
last = Math.max(COLW, c.w + e.clientX - x0);
|
||
if (!raf.current) raf.current = requestAnimationFrame(() => { raf.current = 0; apply(last); });
|
||
};
|
||
const stop = () => {
|
||
window.removeEventListener("pointermove", move); window.removeEventListener("pointerup", stop); window.removeEventListener("pointercancel", stop);
|
||
handle.classList.remove("on"); inRef.current?.classList.remove("resizing");
|
||
apply(last);
|
||
};
|
||
window.addEventListener("pointermove", move); window.addEventListener("pointerup", stop); window.addEventListener("pointercancel", stop);
|
||
};
|
||
const cls = (c: DateCol) => (c.cls ? " " + c.cls : "");
|
||
return (
|
||
<div className="dates-bar">
|
||
<div className="dates-in" ref={inRef}>
|
||
<div className="dates-track" style={{ width, transform: `translateX(${-scrollLeft}px)` }}>
|
||
{cols.map((c) => (
|
||
<Fragment key={c.date}>
|
||
<span className={"dlabel" + cls(c)} style={{ left: c.x0 + 8 }} title={dateTitle(c)}>{dateText(c)}<span className="n">{c.count}</span></span>
|
||
<div className="dsplit" style={{ left: c.x0 + c.w }} title="Тянуть — ширина колонки; двойной щелчок — автоматическая"
|
||
onPointerDown={(e) => down(e, c)} onDoubleClick={() => onColWidth(c.date, null)} />
|
||
</Fragment>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
}
|