Files
temetro/frontend/components/charts/series-hover-dim.tsx
T
Khalid Abdi 321a6298a4 frontend: pharmacy inventory, lab add-result & analysis charts
- Pharmacy: the sidebar entry now expands into Pharmacy + a new Inventory page
  (searchable medication stock with derived in-stock/low/out availability,
  backed by /api/inventory). Fix the dispensing-queue "Expiring" badge so it
  only flags courses ending within the next 7 days, not ones already elapsed.
- Lab "Add analysis result": the patient picker no longer lists patients until
  you type and supports arrow-key + Enter selection; the test field offers a
  catalog of common analyses with an Advanced option (custom analysis + ref
  range); submitted results now show immediately in a Recent results feed.
- Analysis: add a Live panel (real-time line chart) and replace the flat trend
  sparklines with bklit-ui area + bar charts (installed from the @bklit shadcn
  registry; chart CSS variables wired into the theme for light and dark).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 19:22:07 +03:00

61 lines
2.0 KiB
TypeScript

"use client";
import { motion } from "motion/react";
import type { ReactNode } from "react";
import { useChartHover } from "./chart-context";
import { useChartLegendHover } from "./chart-legend-hover";
interface SeriesHoverDimProps {
/** Skip the dim entirely. */
enabled?: boolean;
/** Opacity to fade to while the chart is being hovered. */
dimOpacity?: number;
/** Tween duration in seconds. */
durationSec?: number;
/** Series index for multi-series legend hover dimming. */
seriesIndex?: number;
/** Stable chart visuals — area fill, stroke line, dashed tail, etc. */
children: ReactNode;
}
/**
* Wraps stable series visuals with a hover-driven opacity animation.
*
* The wrapper subscribes to chart hover state internally so the parent (Area /
* Line) can stay on the stable context slice. Children come in as a React prop:
* because the parent is not re-rendering on hover, the children element
* reference stays identical and React skips re-rendering them when this
* wrapper re-renders. That keeps expensive subtrees (`SeriesDashTailOverlay`
* and its `getPointAtLength` binary search) quiescent on cursor motion.
*/
export function SeriesHoverDim({
enabled = true,
dimOpacity = 0.5,
durationSec = 0.4,
seriesIndex,
children,
}: SeriesHoverDimProps) {
const { tooltipData, selection } = useChartHover();
const { hoveredIndex: legendHoveredIndex } = useChartLegendHover();
const isChartHovering = tooltipData !== null || selection?.active === true;
const isLegendDimmed =
legendHoveredIndex !== null &&
seriesIndex !== undefined &&
legendHoveredIndex !== seriesIndex;
const opacity =
enabled && (isChartHovering || isLegendDimmed) ? dimOpacity : 1;
return (
<motion.g
animate={{ opacity }}
initial={{ opacity: 1 }}
transition={{ duration: durationSec, ease: "easeInOut" }}
>
{children}
</motion.g>
);
}
SeriesHoverDim.displayName = "SeriesHoverDim";
export default SeriesHoverDim;