0.29.1原版
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { memo } from "react";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { DEFAULT_CELL_SIZE, SMALL_CELL_SIZE } from "./constants";
|
||||
import type { CalendarDayCell, CalendarSize } from "./types";
|
||||
import { getCalendarCellStateClass, getCellIntensityClass } from "./utils";
|
||||
|
||||
export interface CalendarCellProps {
|
||||
day: CalendarDayCell;
|
||||
maxCount: number;
|
||||
tooltipText: string;
|
||||
onClick?: (date: string) => void;
|
||||
size?: CalendarSize;
|
||||
disableTooltip?: boolean;
|
||||
}
|
||||
|
||||
export const CalendarCell = memo((props: CalendarCellProps) => {
|
||||
const { day, maxCount, tooltipText, onClick, size = "default", disableTooltip = false } = props;
|
||||
|
||||
const handleClick = () => {
|
||||
if (onClick) {
|
||||
onClick(day.date);
|
||||
}
|
||||
};
|
||||
|
||||
const sizeConfig = size === "small" ? SMALL_CELL_SIZE : DEFAULT_CELL_SIZE;
|
||||
const smallExtraClasses = size === "small" ? `${SMALL_CELL_SIZE.dimensions} min-h-0` : "";
|
||||
|
||||
const baseClasses = cn(
|
||||
"aspect-square w-full flex items-center justify-center text-center transition-all duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 select-none border border-border/10 bg-muted/20",
|
||||
sizeConfig.font,
|
||||
sizeConfig.borderRadius,
|
||||
smallExtraClasses,
|
||||
);
|
||||
const isInteractive = Boolean(onClick);
|
||||
const ariaLabel = day.isSelected ? `${tooltipText} (selected)` : tooltipText;
|
||||
|
||||
if (!day.isCurrentMonth) {
|
||||
return <div className={cn(baseClasses, "text-muted-foreground/30 bg-transparent border-transparent cursor-default")}>{day.label}</div>;
|
||||
}
|
||||
|
||||
const intensityClass = getCellIntensityClass(day, maxCount);
|
||||
|
||||
const buttonClasses = cn(
|
||||
baseClasses,
|
||||
intensityClass,
|
||||
getCalendarCellStateClass(day),
|
||||
isInteractive ? "cursor-pointer hover:bg-muted/40 hover:border-border/30" : "cursor-default",
|
||||
);
|
||||
|
||||
const button = (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleClick}
|
||||
tabIndex={isInteractive ? 0 : -1}
|
||||
aria-label={ariaLabel}
|
||||
aria-current={day.isToday ? "date" : undefined}
|
||||
aria-disabled={!isInteractive}
|
||||
className={buttonClasses}
|
||||
>
|
||||
{day.label}
|
||||
</button>
|
||||
);
|
||||
|
||||
const shouldShowTooltip = tooltipText && !disableTooltip;
|
||||
|
||||
if (!shouldShowTooltip) {
|
||||
return button;
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
||||
<TooltipContent side="top">
|
||||
<p>{tooltipText}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
});
|
||||
|
||||
CalendarCell.displayName = "CalendarCell";
|
||||
Reference in New Issue
Block a user