first commit
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { DayPicker } from "react-day-picker";
|
||||
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { classNames as cn } from "@calcom/lib";
|
||||
|
||||
import { Icon } from "../../../index";
|
||||
import { buttonClasses } from "../../button/Button";
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||
|
||||
function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
|
||||
return (
|
||||
<DayPicker
|
||||
fromDate={new Date()}
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn("p-3", className)}
|
||||
classNames={{
|
||||
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
||||
month: "space-y-4",
|
||||
caption: "flex pt-1 relative items-center justify-between",
|
||||
caption_label: "text-sm font-medium",
|
||||
nav: "flex items-center",
|
||||
head: "",
|
||||
head_row: "flex w-full items-center justify-between",
|
||||
head_cell: "w-8 md:w-11 h-8 text-sm font-medium text-default",
|
||||
nav_button: cn(buttonClasses({ color: "minimal", variant: "icon" })),
|
||||
table: "w-full border-collapse space-y-1",
|
||||
row: "flex w-full mt-2 gap-0.5",
|
||||
cell: "h-8 w-8 md:h-11 md:w-11 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
|
||||
day: cn(
|
||||
buttonClasses({ color: "minimal" }),
|
||||
"w-8 h-8 md:h-11 md:w-11 p-0 text-sm font-medium aria-selected:opacity-100 inline-flex items-center justify-center"
|
||||
),
|
||||
day_range_end: "day-range-end",
|
||||
day_selected: "bg-inverted text-inverted",
|
||||
day_today: "",
|
||||
day_outside: "",
|
||||
day_disabled: "text-muted opacity-50",
|
||||
day_range_middle: "aria-selected:bg-emphasis aria-selected:text-emphasis",
|
||||
day_hidden: "invisible",
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
CaptionLabel: (capLabelProps) => (
|
||||
<div className="px-2">
|
||||
<span className="text-emphasis leadning-none font-semibold">
|
||||
{dayjs(capLabelProps.displayMonth).format("MMMM")}{" "}
|
||||
</span>
|
||||
<span className="text-subtle font-medium leading-none">
|
||||
{dayjs(capLabelProps.displayMonth).format("YYYY")}
|
||||
</span>
|
||||
</div>
|
||||
),
|
||||
IconLeft: () => <Icon name="chevron-left" className="h-4 w-4 stroke-2" />,
|
||||
IconRight: () => <Icon name="chevron-right" className="h-4 w-4 stroke-2" />,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Calendar.displayName = "Calendar";
|
||||
|
||||
export { Calendar };
|
||||
@@ -0,0 +1,70 @@
|
||||
"use client";
|
||||
|
||||
import { format } from "date-fns";
|
||||
import * as React from "react";
|
||||
import type { DateRange } from "react-day-picker";
|
||||
|
||||
import { classNames as cn } from "@calcom/lib";
|
||||
|
||||
import { Button } from "../../button";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../../popover";
|
||||
import { Calendar } from "./Calendar";
|
||||
|
||||
type DatePickerWithRangeProps = {
|
||||
dates: { startDate: Date; endDate?: Date };
|
||||
onDatesChange: ({ startDate, endDate }: { startDate?: Date; endDate?: Date }) => void;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
export function DatePickerWithRange({
|
||||
className,
|
||||
dates,
|
||||
onDatesChange,
|
||||
disabled,
|
||||
}: React.HTMLAttributes<HTMLDivElement> & DatePickerWithRangeProps) {
|
||||
// Even though this is uncontrolled we need to do a bit of logic to improve the UX when selecting dates
|
||||
function _onDatesChange(onChangeValues: DateRange | undefined) {
|
||||
if (onChangeValues?.from && !onChangeValues?.to) {
|
||||
onDatesChange({ startDate: onChangeValues.from, endDate: onChangeValues.from });
|
||||
} else {
|
||||
onDatesChange({ startDate: onChangeValues?.from, endDate: onChangeValues?.to });
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn("grid gap-2", className)}>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
id="date"
|
||||
color="secondary"
|
||||
EndIcon="calendar"
|
||||
className={cn("justify-between text-left font-normal", !dates && "text-subtle")}>
|
||||
{dates?.startDate ? (
|
||||
dates?.endDate ? (
|
||||
<>
|
||||
{format(dates.startDate, "LLL dd, y")} - {format(dates.endDate, "LLL dd, y")}
|
||||
</>
|
||||
) : (
|
||||
format(dates.startDate, "LLL dd, y")
|
||||
)
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
initialFocus
|
||||
mode="range"
|
||||
defaultMonth={dates?.startDate}
|
||||
selected={{ from: dates?.startDate, to: dates?.endDate }}
|
||||
onSelect={(values) => _onDatesChange(values)}
|
||||
numberOfMonths={1}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
export const DateRangePickerLazy = dynamic(() =>
|
||||
import("./DateRangePicker").then((mod) => mod.DatePickerWithRange)
|
||||
);
|
||||
265
calcom/packages/ui/components/form/date-range-picker/styles.css
Normal file
265
calcom/packages/ui/components/form/date-range-picker/styles.css
Normal file
@@ -0,0 +1,265 @@
|
||||
.react-calendar {
|
||||
width: 350px;
|
||||
max-width: 100%;
|
||||
background: var(--cal-bg);
|
||||
border: 1px solid var(--cal-bg-inverted);
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
line-height: 1.125em;
|
||||
}
|
||||
|
||||
.react-calendar,
|
||||
.react-calendar *,
|
||||
.react-calendar ::before,
|
||||
.react-calendar ::after {
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.react-calendar--doubleView {
|
||||
width: 700px;
|
||||
}
|
||||
|
||||
.react-calendar--doubleView .react-calendar__viewContainer {
|
||||
display: flex;
|
||||
margin: -0.5em;
|
||||
}
|
||||
|
||||
.react-calendar--doubleView .react-calendar__viewContainer > * {
|
||||
width: 50%;
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.react-calendar button {
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.react-calendar__navigation {
|
||||
display: flex;
|
||||
height: 44px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.react-calendar__navigation button {
|
||||
min-width: 44px;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.react-calendar button:enabled:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.react-calendar__navigation button:disabled {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.react-calendar__navigation button:enabled:hover,
|
||||
.react-calendar__navigation button:enabled:focus {
|
||||
background-color: #1d5ad8;
|
||||
color: var(--cal-text-emphasis);
|
||||
}
|
||||
|
||||
.react-calendar__tile {
|
||||
max-width: 100%;
|
||||
padding: 10px 6.6667px;
|
||||
background: none;
|
||||
text-align: center;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.react-calendar__month-view__weekdays {
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.react-calendar__month-view__weekdays__weekday {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.react-calendar__month-view__weekNumbers .react-calendar__tile {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.75em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.react-calendar__year-view .react-calendar__tile,
|
||||
.react-calendar__decade-view .react-calendar__tile,
|
||||
.react-calendar__century-view .react-calendar__tile {
|
||||
padding: 2em 0.5em;
|
||||
}
|
||||
|
||||
.react-calendar__tile:disabled {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.react-calendar__tile:enabled:hover,
|
||||
.react-calendar__tile:enabled:focus {
|
||||
background-color: var(--cal-bg-subtle);
|
||||
}
|
||||
|
||||
.react-daterange-picker {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.react-daterange-picker > .react-daterange-picker__wrapper {
|
||||
padding: 0.625rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
border-radius: 0.375rem;
|
||||
width: 100%;
|
||||
border-color: var(--cal-border);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
}
|
||||
|
||||
.react-daterange-picker__wrapper > .react-daterange-picker__calendar-button.react-daterange-picker__button {
|
||||
padding: 4px 0;
|
||||
}
|
||||
|
||||
.react-daterange-picker > .react-daterange-picker__wrapper > .react-daterange-picker__inputGroup {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.react-daterange-picker.react-daterange-picker--disabled {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.react-daterange-picker.react-daterange-picker--disabled > .react-daterange-picker__wrapper {
|
||||
background-color: #f3f4f6;
|
||||
}
|
||||
|
||||
.react-daterange-picker > .react-daterange-picker__wrapper:focus-within,
|
||||
.react-daterange-picker > .react-daterange-picker__wrapper:focus-within:hover {
|
||||
border-color: var(--cal-bg-subtle);
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.react-daterange-picker > .react-daterange-picker__wrapper input {
|
||||
margin: 0;
|
||||
height: auto;
|
||||
border-radius: 0.125rem;
|
||||
}
|
||||
|
||||
.react-daterange-picker__calendar.react-daterange-picker__calendar--open {
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
.react-daterange-picker__calendar > .react-calendar {
|
||||
padding: 0.5rem;
|
||||
border-radius: 0.375rem;
|
||||
border-width: 1px;
|
||||
border-color: var(--cal-border);
|
||||
width: 360px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.react-calendar__navigation > .react-calendar__navigation__arrow {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.react-calendar__navigation > .react-calendar__navigation__arrow.react-calendar__navigation__prev2-button,
|
||||
.react-calendar__navigation > .react-calendar__navigation__arrow.react-calendar__navigation__next2-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.react-calendar__navigation > .react-calendar__navigation__label {
|
||||
display: flex;
|
||||
padding-left: 0.5rem;
|
||||
padding-right: 0.5rem;
|
||||
color: var(--cal-text);
|
||||
order: -9999;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.react-calendar__navigation > .react-calendar__navigation__arrow {
|
||||
text-align: center;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.react-calendar__month-view__weekdays__weekday > abbr {
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.react-calendar__month-view__days {
|
||||
padding: 0.25rem;
|
||||
gap: 0.25rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
button.react-calendar__tile.react-calendar__month-view__days__day {
|
||||
flex: 0 0 13.25% !important;
|
||||
border-radius: 0.375rem;
|
||||
padding-top: 13px;
|
||||
padding-bottom: 13px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.react-calendar__tile.react-calendar__tile--hover:not(.react-calendar__tile--active) {
|
||||
background-color: var(--cal-bg-subtle) !important;
|
||||
}
|
||||
|
||||
.react-calendar__month-view__days > .react-calendar__tile.react-calendar__tile--hasActive,
|
||||
.react-calendar__month-view__days > .react-calendar__tile.react-calendar__tile--active,
|
||||
.react-calendar__month-view__days > button.react-calendar__tile.react-calendar__tile--active:hover {
|
||||
background-color: var(--cal-bg-inverted);
|
||||
color: var(--cal-text-inverted);
|
||||
}
|
||||
|
||||
.react-calendar__tile.react-calendar__tile--active.react-calendar__month-view__days__day--weekend {
|
||||
color: var(--cal-text-inverted);
|
||||
}
|
||||
|
||||
.react-calendar__tile.react-calendar__month-view__days__day--weekend {
|
||||
color: var(--cal-text-emphasis);
|
||||
}
|
||||
|
||||
.react-calendar__tile.react-calendar__month-view__days__day--neighboringMonth {
|
||||
color: var(--cal-text-muted);
|
||||
}
|
||||
|
||||
.react-calendar__tile--now::before {
|
||||
content: "\A";
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
position: absolute;
|
||||
background-color: var(--cal-text-emphasis);
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
bottom: 0;
|
||||
z-index: inherit;
|
||||
}
|
||||
|
||||
button.react-calendar__tile.react-calendar__month-view__days__day:hover,
|
||||
.react-calendar__tile.react-calendar__year-view__months__month:hover {
|
||||
background-color: var(--cal-bg-subtle);
|
||||
color: var(--cal-text-emphasis);
|
||||
}
|
||||
|
||||
.react-daterange-picker > .react-daterange-picker__wrapper:hover {
|
||||
border-color: var(--cal-bg-inverted);
|
||||
}
|
||||
|
||||
.react-daterange-picker.react-daterange-picker--disabled > .react-daterange-picker__wrapper:hover {
|
||||
border-color: var(--cal-bg-subtle);
|
||||
}
|
||||
|
||||
.react-calendar__navigation button.react-calendar__navigation__label:enabled:hover,
|
||||
.react-calendar__navigation button.react-calendar__navigation__label:enabled:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
Reference in New Issue
Block a user