mirror of
https://github.com/temetro/temetro.git
synced 2026-08-21 07:26:45 +00:00
321a6298a4
- 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>
93 lines
2.5 KiB
TypeScript
93 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import type { Transition } from "motion/react";
|
|
import { motion } from "motion/react";
|
|
import { clipRevealTransition } from "./animation";
|
|
|
|
export type ChartRevealClipMode = "reveal" | "conceal";
|
|
|
|
export interface ChartRevealClipProps {
|
|
clipPathId: string;
|
|
height: number;
|
|
targetWidth: number;
|
|
enterTransition?: Transition;
|
|
/** Bumps when motion settings change to replay the reveal. */
|
|
revealEpoch: number;
|
|
/** Extra inset around the clip rect so edge glyphs are not cut off. */
|
|
padding?: number;
|
|
/** When false, clip stays at full width (no grow animation). */
|
|
animating?: boolean;
|
|
/** Reveal grows 0 → full; conceal shrinks full → 0 (ready → loading). */
|
|
mode?: ChartRevealClipMode;
|
|
/** Called when a conceal animation finishes. */
|
|
onComplete?: () => void;
|
|
}
|
|
|
|
/**
|
|
* Left-to-right clip reveal for cartesian series.
|
|
* Grows clip rect width from 0 → full (true LTR; scaleX is avoided — it reveals from center).
|
|
*/
|
|
export function ChartRevealClip({
|
|
clipPathId,
|
|
height,
|
|
targetWidth,
|
|
enterTransition,
|
|
revealEpoch,
|
|
padding = 0,
|
|
animating = true,
|
|
mode = "reveal",
|
|
onComplete,
|
|
}: ChartRevealClipProps) {
|
|
const transition = clipRevealTransition(enterTransition);
|
|
const paddedWidth = Math.max(0, targetWidth + padding * 2);
|
|
const paddedHeight = height + padding * 2;
|
|
|
|
if (!animating) {
|
|
return (
|
|
<clipPath id={clipPathId}>
|
|
<rect
|
|
height={paddedHeight}
|
|
width={paddedWidth}
|
|
x={-padding}
|
|
y={-padding}
|
|
/>
|
|
</clipPath>
|
|
);
|
|
}
|
|
|
|
if (mode === "conceal") {
|
|
// Mirror the LTR reveal: advance the clip's left edge rightward while width
|
|
// shrinks (same geometry as `LineLoadingPulseStroke` exit half-cycle).
|
|
const rightEdge = -padding + paddedWidth;
|
|
|
|
return (
|
|
<clipPath id={clipPathId}>
|
|
<motion.rect
|
|
animate={{ width: 0, x: rightEdge }}
|
|
height={paddedHeight}
|
|
initial={{ width: paddedWidth, x: -padding }}
|
|
key={`conceal-${revealEpoch}`}
|
|
onAnimationComplete={() => onComplete?.()}
|
|
transition={transition}
|
|
y={-padding}
|
|
/>
|
|
</clipPath>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<clipPath id={clipPathId}>
|
|
<motion.rect
|
|
animate={{ width: paddedWidth }}
|
|
height={paddedHeight}
|
|
initial={{ width: 0 }}
|
|
key={`reveal-${revealEpoch}`}
|
|
transition={transition}
|
|
width={paddedWidth}
|
|
x={-padding}
|
|
y={-padding}
|
|
/>
|
|
</clipPath>
|
|
);
|
|
}
|