@medalsocial/meda
Version:
Shared Meda UI shell and runtime package.
40 lines (39 loc) • 3.17 kB
JavaScript
'use client';
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { cn } from '../lib/utils.js';
export function LaneRow({ lane, windowStart, windowEnd, labelGutterPx, selectedBarId, onSelectBar, }) {
return (_jsxs("div", { className: "grid items-center gap-0 border-border/40 border-b py-3", style: { gridTemplateColumns: `${labelGutterPx}px 1fr` }, children: [_jsxs("div", { className: "flex flex-col gap-0.5 pr-3", children: [_jsxs("div", { className: cn('flex items-center gap-2 text-sm', lane.muted && 'text-muted-foreground'), children: [lane.statusDotClass && (_jsx("span", { className: cn('inline-block size-2 rounded-full', lane.statusDotClass, lane.muted && 'opacity-40') })), _jsx("span", { className: "font-medium", children: lane.label })] }), lane.sublabel && _jsx("div", { className: "text-muted-foreground text-xs", children: lane.sublabel })] }), _jsx("div", { className: "relative h-7", children: lane.bars.map((bar) => {
const placement = placeBar(bar, windowStart, windowEnd);
if (!placement)
return null;
const selected = selectedBarId === bar.id;
const isSelectable = !!onSelectBar;
const barClassName = cn('absolute top-0 flex h-full items-center overflow-hidden rounded-md px-2 text-left text-xs text-white', bar.fillClass, bar.accentClass, isSelectable && [
'data-[selected]:ring-2 data-[selected]:ring-primary data-[selected]:ring-offset-1 data-[selected]:ring-offset-background',
'hover:brightness-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
]);
const barStyle = { left: `${placement.left}%`, width: `${placement.width}%` };
const ariaLabel = `${lane.label} — ${bar.label}`;
if (!isSelectable) {
return (_jsx("div", { role: "img", "aria-label": ariaLabel, className: barClassName, style: barStyle, children: _jsx("span", { "aria-hidden": "true", className: "truncate", children: bar.label }) }, bar.id));
}
return (_jsx("button", { type: "button", onClick: () => onSelectBar(bar, lane), "data-selected": selected || undefined, className: barClassName, style: barStyle, "aria-label": ariaLabel, children: _jsx("span", { "aria-hidden": "true", className: "truncate", children: bar.label }) }, bar.id));
}) })] }));
}
function placeBar(bar, windowStart, windowEnd) {
const ws = windowStart.getTime();
const we = windowEnd.getTime();
const span = we - ws;
if (span <= 0)
return null;
const bs = bar.start.getTime();
const be = bar.end.getTime();
// Bar entirely outside the window (or exactly touching boundary) — skip.
if (be <= ws || bs >= we)
return null;
const clampedStart = Math.max(bs, ws);
const clampedEnd = Math.min(be, we);
const left = ((clampedStart - ws) / span) * 100;
const width = Math.max(((clampedEnd - clampedStart) / span) * 100, 0.5);
return { left, width };
}