cal.pub0.org/packages/features/bookings/Booker/components/Section.tsx

64 lines
1.9 KiB
TypeScript

import type { MotionProps } from "framer-motion";
import { m } from "framer-motion";
import { forwardRef } from "react";
import { classNames } from "@calcom/lib";
import { useBookerStore } from "../store";
import type { BookerAreas, BookerLayout } from "../types";
/**
* Define what grid area a section should be in.
* Value is either a string (in case it's always the same area), or an object
* looking like:
* {
* // Where default is the required default area.
* default: "calendar",
* // Any optional overrides for different layouts by their layout name.
* week_view: "main",
* }
*/
type GridArea = BookerAreas | ({ [key in BookerLayout]?: BookerAreas } & { default: BookerAreas });
type BookerSectionProps = {
children: React.ReactNode;
area: GridArea;
visible?: boolean;
className?: string;
} & MotionProps;
// This map with strings is needed so Tailwind generates all classnames,
// If we would concatenate them with JS, Tailwind would not generate them.
const gridAreaClassNameMap: { [key in BookerAreas]: string } = {
calendar: "[grid-area:calendar]",
main: "[grid-area:main]",
meta: "[grid-area:meta]",
timeslots: "[grid-area:timeslots]",
header: "[grid-area:header]",
};
/**
* Small helper compnent that renders a booker section in a specific grid area.
*/
export const BookerSection = forwardRef<HTMLDivElement, BookerSectionProps>(function BookerSection(
{ children, area, visible, className, ...props },
ref
) {
const layout = useBookerStore((state) => state.layout);
let gridClassName: string;
if (typeof area === "string") {
gridClassName = gridAreaClassNameMap[area];
} else {
gridClassName = gridAreaClassNameMap[area[layout] || area.default];
}
if (!visible && typeof visible !== "undefined") return null;
return (
<m.div ref={ref} className={classNames(gridClassName, className)} layout {...props}>
{children}
</m.div>
);
});