Beautiful and modern React UI library with comprehensive components, theming, and accessibility support.
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
NextUI provides comprehensive date and time components with internationalization support, accessibility features, and integration with modern date handling libraries for building robust temporal interfaces.
A full-featured calendar component for single date selection with navigation, keyboard support, and customizable appearance.
interface CalendarProps<T extends DateValue = DateValue> {
/** Current selected date */
value?: T | null;
/** Default selected date */
defaultValue?: T | null;
/** Minimum selectable date */
minValue?: DateValue | null;
/** Maximum selectable date */
maxValue?: DateValue | null;
/** Function to determine if a date is unavailable */
isDateUnavailable?: (date: DateValue) => boolean;
/** Auto focus on mount */
autoFocus?: boolean;
/** Currently focused date */
focusedValue?: DateValue | null;
/** Default focused date */
defaultFocusedValue?: DateValue | null;
/** Calendar width */
calendarWidth?: number;
/** Number of months to display */
visibleMonths?: number;
/** Page behavior for navigation */
pageBehavior?: PageBehavior;
/** Weekday display style */
weekdayStyle?: "narrow" | "short" | "long";
/** Show month and year picker dropdowns */
showMonthAndYearPickers?: boolean;
/** Whether calendar is disabled */
isDisabled?: boolean;
/** Whether calendar is read-only */
isReadOnly?: boolean;
/** Whether calendar is invalid */
isInvalid?: boolean;
/** Calendar color theme */
color?: "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Show helper content */
showHelper?: boolean;
/** Content above calendar */
topContent?: React.ReactNode;
/** Content below calendar */
bottomContent?: React.ReactNode;
/** Error message */
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
/** Validation function */
validate?: (value: MappedDateValue<T>) => ValidationError | true | null | undefined;
/** Validation behavior */
validationBehavior?: "aria" | "native";
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<CalendarSlots>;
/** Focus change handler */
onFocusChange?: (date: CalendarDate) => void;
/** Value change handler */
onChange?: (value: MappedDateValue<T>) => void;
}
type CalendarSlots =
| "base" | "prevButton" | "nextButton" | "headerWrapper"
| "header" | "title" | "content" | "gridWrapper" | "grid"
| "gridHeader" | "gridHeaderRow" | "gridHeaderCell" | "gridBody"
| "gridBodyRow" | "cell" | "cellButton" | "pickerWrapper"
| "monthPicker" | "yearPicker" | "helperWrapper" | "errorMessage";
type PageBehavior = "single" | "visible";
function Calendar<T extends DateValue = DateValue>(props: CalendarProps<T>): JSX.Element;
/**
* Hook for Calendar state management
*/
function useCalendar<T extends DateValue = DateValue>(props: CalendarProps<T>): {
Component: React.ElementType;
state: CalendarState;
slots: Record<CalendarSlots, string>;
classNames: SlotsToClasses<CalendarSlots>;
getCalendarProps: () => any;
getButtonProps: (direction: "previous" | "next") => any;
getGridProps: () => any;
getCellProps: (date: CalendarDate) => any;
};A calendar component for selecting date ranges with visual range indicators and dual navigation.
interface RangeCalendarProps<T extends DateValue = DateValue> {
/** Current selected date range */
value?: RangeValue<T> | null;
/** Default selected date range */
defaultValue?: RangeValue<T> | null;
/** Minimum selectable date */
minValue?: DateValue | null;
/** Maximum selectable date */
maxValue?: DateValue | null;
/** Function to determine if a date is unavailable */
isDateUnavailable?: (date: DateValue) => boolean;
/** Auto focus on mount */
autoFocus?: boolean;
/** Currently focused date */
focusedValue?: DateValue | null;
/** Default focused date */
defaultFocusedValue?: DateValue | null;
/** Calendar width */
calendarWidth?: number;
/** Number of months to display */
visibleMonths?: number;
/** Page behavior for navigation */
pageBehavior?: PageBehavior;
/** Weekday display style */
weekdayStyle?: "narrow" | "short" | "long";
/** Show month and year picker dropdowns */
showMonthAndYearPickers?: boolean;
/** Whether calendar is disabled */
isDisabled?: boolean;
/** Whether calendar is read-only */
isReadOnly?: boolean;
/** Whether calendar is invalid */
isInvalid?: boolean;
/** Calendar color theme */
color?: "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Show helper content */
showHelper?: boolean;
/** Content above calendar */
topContent?: React.ReactNode;
/** Content below calendar */
bottomContent?: React.ReactNode;
/** Error message */
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
/** Validation function */
validate?: (value: RangeValue<MappedDateValue<T>>) => ValidationError | true | null | undefined;
/** Validation behavior */
validationBehavior?: "aria" | "native";
/** Allow non-contiguous ranges */
allowsNonContiguousRanges?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<CalendarSlots>;
/** Focus change handler */
onFocusChange?: (date: CalendarDate) => void;
/** Value change handler */
onChange?: (value: RangeValue<MappedDateValue<T>>) => void;
}
function RangeCalendar<T extends DateValue = DateValue>(props: RangeCalendarProps<T>): JSX.Element;
/**
* Hook for RangeCalendar state management
*/
function useRangeCalendar<T extends DateValue = DateValue>(props: RangeCalendarProps<T>): {
Component: React.ElementType;
state: RangeCalendarState;
slots: Record<CalendarSlots, string>;
classNames: SlotsToClasses<CalendarSlots>;
getRangeCalendarProps: () => any;
getButtonProps: (direction: "previous" | "next") => any;
getGridProps: () => any;
getCellProps: (date: CalendarDate) => any;
};Calendar Usage Examples:
import { Calendar, RangeCalendar } from "@nextui-org/react";
import { CalendarDate, today, getLocalTimeZone, isWeekend } from "@internationalized/date";
function CalendarExamples() {
const [date, setDate] = useState<CalendarDate>(today(getLocalTimeZone()));
const [dateRange, setDateRange] = useState<RangeValue<CalendarDate>>({
start: today(getLocalTimeZone()),
end: today(getLocalTimeZone()).add({ weeks: 1 }),
});
// Mark weekends as unavailable
const isDateUnavailable = (date: DateValue) => isWeekend(date, "en-US");
return (
<div className="space-y-8">
{/* Single date calendar */}
<div>
<h3 className="text-lg font-semibold mb-4">Single Date Selection</h3>
<Calendar
aria-label="Date (No Selection)"
value={date}
onChange={setDate}
color="primary"
showMonthAndYearPickers
isDateUnavailable={isDateUnavailable}
/>
</div>
{/* Date range calendar */}
<div>
<h3 className="text-lg font-semibold mb-4">Date Range Selection</h3>
<RangeCalendar
aria-label="Date Range"
value={dateRange}
onChange={setDateRange}
color="secondary"
visibleMonths={2}
pageBehavior="visible"
/>
</div>
{/* Calendar with validation */}
<div>
<h3 className="text-lg font-semibold mb-4">Calendar with Validation</h3>
<Calendar
value={date}
onChange={setDate}
minValue={today(getLocalTimeZone())}
maxValue={today(getLocalTimeZone()).add({ months: 1 })}
validate={(value) => {
if (value && isWeekend(value, "en-US")) {
return "Weekends are not allowed";
}
return true;
}}
errorMessage={(validation) =>
validation.isInvalid ? validation.validationErrors[0] : undefined
}
/>
</div>
</div>
);
}Context system for sharing calendar state and configuration.
interface CalendarProviderProps {
children: React.ReactNode;
value: CalendarContextValue;
}
interface CalendarContextValue {
state: CalendarState | RangeCalendarState;
slots: Record<CalendarSlots, string>;
classNames?: SlotsToClasses<CalendarSlots>;
visibleMonths: number;
weekdayStyle: "narrow" | "short" | "long";
}
const CalendarProvider: React.FC<CalendarProviderProps>;
/**
* Hook to access calendar context
* @throws Error if used outside CalendarProvider
*/
function useCalendarContext(): CalendarContextValue;A specialized input component for entering dates with segment-based editing and keyboard navigation.
interface DateInputProps<T extends DateValue = DateValue> {
/** Input label */
label?: React.ReactNode;
/** Current date value */
value?: T | null;
/** Default date value */
defaultValue?: T | null;
/** Input placeholder when empty */
placeholder?: string;
/** Helper description text */
description?: React.ReactNode;
/** Error message */
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
/** Validation function */
validate?: (value: MappedDateValue<T>) => ValidationError | true | null | undefined;
/** Validation behavior */
validationBehavior?: "aria" | "native";
/** Minimum selectable date */
minValue?: DateValue | null;
/** Maximum selectable date */
maxValue?: DateValue | null;
/** Whether input is required */
isRequired?: boolean;
/** Whether input is read-only */
isReadOnly?: boolean;
/** Whether input is disabled */
isDisabled?: boolean;
/** Whether input is invalid */
isInvalid?: boolean;
/** Auto focus on mount */
autoFocus?: boolean;
/** Input size */
size?: "sm" | "md" | "lg";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Visual variant */
variant?: "flat" | "bordered" | "underlined" | "faded";
/** Color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Label placement */
labelPlacement?: "inside" | "outside" | "outside-left";
/** Whether input takes full width */
fullWidth?: boolean;
/** Show clear button */
isClearable?: boolean;
/** Disable animations */
disableAnimation?: boolean;
/** Start content */
startContent?: React.ReactNode;
/** End content */
endContent?: React.ReactNode;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<DateInputSlots>;
/** Value change handler */
onChange?: (value: MappedDateValue<T>) => void;
}
type DateInputSlots =
| "base" | "label" | "inputWrapper" | "input" | "innerWrapper"
| "segment" | "helperWrapper" | "description" | "errorMessage";
type DateInputValue = CalendarDate | CalendarDateTime | ZonedDateTime;
function DateInput<T extends DateValue = DateValue>(props: DateInputProps<T>): JSX.Element;
/**
* Hook for DateInput state management
*/
function useDateInput<T extends DateValue = DateValue>(props: DateInputProps<T>): {
Component: React.ElementType;
state: DateFieldState;
slots: Record<DateInputSlots, string>;
classNames: SlotsToClasses<DateInputSlots>;
getDateInputProps: () => any;
getLabelProps: () => any;
getInputProps: () => any;
getSegmentProps: (segment: DateSegment) => any;
};A specialized input component for entering time values with segment-based editing.
interface TimeInputProps<T extends TimeValue = TimeValue> {
/** Input label */
label?: React.ReactNode;
/** Current time value */
value?: T | null;
/** Default time value */
defaultValue?: T | null;
/** Input placeholder when empty */
placeholder?: string;
/** Helper description text */
description?: React.ReactNode;
/** Error message */
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
/** Validation function */
validate?: (value: MappedTimeValue<T>) => ValidationError | true | null | undefined;
/** Validation behavior */
validationBehavior?: "aria" | "native";
/** Minimum selectable time */
minValue?: TimeValue | null;
/** Maximum selectable time */
maxValue?: TimeValue | null;
/** Whether input is required */
isRequired?: boolean;
/** Whether input is read-only */
isReadOnly?: boolean;
/** Whether input is disabled */
isDisabled?: boolean;
/** Whether input is invalid */
isInvalid?: boolean;
/** Auto focus on mount */
autoFocus?: boolean;
/** Input size */
size?: "sm" | "md" | "lg";
/** Border radius */
radius?: "none" | "sm" | "md" | "lg" | "full";
/** Visual variant */
variant?: "flat" | "bordered" | "underlined" | "faded";
/** Color theme */
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
/** Label placement */
labelPlacement?: "inside" | "outside" | "outside-left";
/** Whether input takes full width */
fullWidth?: boolean;
/** Show clear button */
isClearable?: boolean;
/** Disable animations */
disableAnimation?: boolean;
/** Start content */
startContent?: React.ReactNode;
/** End content */
endContent?: React.ReactNode;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<DateInputSlots>;
/** Value change handler */
onChange?: (value: MappedTimeValue<T>) => void;
}
type TimeInputValue = Time;
function TimeInput<T extends TimeValue = TimeValue>(props: TimeInputProps<T>): JSX.Element;
/**
* Hook for TimeInput state management
*/
function useTimeInput<T extends TimeValue = TimeValue>(props: TimeInputProps<T>): {
Component: React.ElementType;
state: TimeFieldState;
slots: Record<DateInputSlots, string>;
classNames: SlotsToClasses<DateInputSlots>;
getTimeInputProps: () => any;
getLabelProps: () => any;
getInputProps: () => any;
getSegmentProps: (segment: DateSegment) => any;
};Lower-level components for building custom date input interfaces.
interface DateInputGroupProps {
/** Input group content */
children?: React.ReactNode;
/** Custom CSS class */
className?: string;
}
interface DateInputFieldProps {
/** Field content */
children?: React.ReactNode;
/** Custom CSS class */
className?: string;
}
interface DateInputSegmentProps {
/** Segment content */
segment: DateSegment;
/** Segment state */
state: DateFieldState | TimeFieldState;
/** Custom CSS class */
className?: string;
}
function DateInputGroup(props: DateInputGroupProps): JSX.Element;
function DateInputField(props: DateInputFieldProps): JSX.Element;
function DateInputSegment(props: DateInputSegmentProps): JSX.Element;Date Input Usage Examples:
import { DateInput, TimeInput } from "@nextui-org/react";
import { CalendarDate, Time, now, getLocalTimeZone } from "@internationalized/date";
function DateInputExamples() {
const [date, setDate] = useState<CalendarDate>(new CalendarDate(2024, 4, 4));
const [time, setTime] = useState<Time>(new Time(11, 45));
return (
<div className="space-y-6 max-w-xs">
{/* Basic date input */}
<DateInput
label="Birth date"
value={date}
onChange={setDate}
placeholderValue={new CalendarDate(1995, 11, 6)}
/>
{/* Date input with validation */}
<DateInput
label="Appointment date"
isRequired
description="Select a date for your appointment"
validate={(value) => {
if (!value) return "Please select a date";
const today = now(getLocalTimeZone()).date;
if (value.compare(today) < 0) {
return "Date cannot be in the past";
}
return true;
}}
errorMessage={(validation) =>
validation.isInvalid ? validation.validationErrors[0] : undefined
}
/>
{/* Time input */}
<TimeInput
label="Meeting time"
value={time}
onChange={setTime}
description="Enter the meeting time"
/>
{/* Date input with custom format */}
<DateInput
label="Event date"
variant="bordered"
color="secondary"
size="sm"
showMonthAndYearPickers
maxValue={today(getLocalTimeZone()).add({ years: 1 })}
/>
</div>
);
}A composite component combining date input with calendar popup for intuitive date selection.
interface DatePickerProps<T extends DateValue = DateValue>
extends Omit<DateInputProps<T>, "size"> {
/** Date picker size */
size?: "sm" | "md" | "lg";
/** Selector icon (calendar icon) */
selectorIcon?: React.ReactNode;
/** Calendar width */
calendarWidth?: number;
/** Number of months to display */
visibleMonths?: number;
/** Page behavior for calendar navigation */
pageBehavior?: PageBehavior;
/** Calendar props override */
calendarProps?: Partial<CalendarProps<T>>;
/** Show month and year picker dropdowns */
showMonthAndYearPickers?: boolean;
/** Close calendar on selection */
shouldCloseOnSelect?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<DatePickerSlots>;
}
type DatePickerSlots =
| "base" | "label" | "inputWrapper" | "input" | "innerWrapper"
| "segment" | "helperWrapper" | "description" | "errorMessage"
| "selectorButton" | "selectorIcon" | "popoverContent" | "calendar";
function DatePicker<T extends DateValue = DateValue>(props: DatePickerProps<T>): JSX.Element;
/**
* Hook for DatePicker state management
*/
function useDatePicker<T extends DateValue = DateValue>(props: DatePickerProps<T>): {
Component: React.ElementType;
state: DatePickerState;
slots: Record<DatePickerSlots, string>;
classNames: SlotsToClasses<DatePickerSlots>;
getDatePickerProps: () => any;
getPopoverProps: () => any;
getCalendarProps: () => any;
getSelectorButtonProps: () => any;
};A composite component for selecting date ranges with input fields and calendar popup.
interface DateRangePickerProps<T extends DateValue = DateValue>
extends Omit<DateInputProps<T>, "value" | "defaultValue" | "onChange"> {
/** Current selected date range */
value?: RangeValue<T> | null;
/** Default selected date range */
defaultValue?: RangeValue<T> | null;
/** Date picker size */
size?: "sm" | "md" | "lg";
/** Selector icon (calendar icon) */
selectorIcon?: React.ReactNode;
/** Calendar width */
calendarWidth?: number;
/** Number of months to display */
visibleMonths?: number;
/** Page behavior for calendar navigation */
pageBehavior?: PageBehavior;
/** Calendar props override */
calendarProps?: Partial<RangeCalendarProps<T>>;
/** Show month and year picker dropdowns */
showMonthAndYearPickers?: boolean;
/** Close calendar on selection */
shouldCloseOnSelect?: boolean;
/** Custom CSS class */
className?: string;
/** Slot-based styling */
classNames?: SlotsToClasses<DatePickerSlots>;
/** Value change handler */
onChange?: (value: RangeValue<MappedDateValue<T>>) => void;
}
function DateRangePicker<T extends DateValue = DateValue>(props: DateRangePickerProps<T>): JSX.Element;
/**
* Hook for DateRangePicker state management
*/
function useDateRangePicker<T extends DateValue = DateValue>(props: DateRangePickerProps<T>): {
Component: React.ElementType;
state: DateRangePickerState;
slots: Record<DatePickerSlots, string>;
classNames: SlotsToClasses<DatePickerSlots>;
getDateRangePickerProps: () => any;
getPopoverProps: () => any;
getCalendarProps: () => any;
getSelectorButtonProps: () => any;
};A specialized input field component for the date range picker.
interface DateRangePickerFieldProps {
/** Field content */
children?: React.ReactNode;
/** Custom CSS class */
className?: string;
}
function DateRangePickerField(props: DateRangePickerFieldProps): JSX.Element;Date Picker Usage Examples:
import { DatePicker, DateRangePicker, Button } from "@nextui-org/react";
import { CalendarDate, today, getLocalTimeZone } from "@internationalized/date";
function DatePickerExamples() {
const [selectedDate, setSelectedDate] = useState<CalendarDate | null>(null);
const [dateRange, setDateRange] = useState<RangeValue<CalendarDate> | null>(null);
return (
<div className="space-y-6 max-w-sm">
{/* Basic date picker */}
<DatePicker
label="Birth date"
value={selectedDate}
onChange={setSelectedDate}
showMonthAndYearPickers
/>
{/* Date picker with constraints */}
<DatePicker
label="Appointment date"
variant="bordered"
color="primary"
minValue={today(getLocalTimeZone())}
maxValue={today(getLocalTimeZone()).add({ months: 3 })}
defaultValue={today(getLocalTimeZone())}
description="Select a future date within 3 months"
/>
{/* Date range picker */}
<DateRangePicker
label="Stay duration"
value={dateRange}
onChange={setDateRange}
visibleMonths={2}
pageBehavior="visible"
color="secondary"
/>
{/* Date range picker with validation */}
<DateRangePicker
label="Project timeline"
variant="bordered"
validate={(value) => {
if (!value) return "Please select a date range";
if (value.start && value.end) {
const duration = value.end.calendar.toJulianDay(value.end) -
value.start.calendar.toJulianDay(value.start);
if (duration < 7) {
return "Project must be at least 1 week long";
}
if (duration > 365) {
return "Project cannot exceed 1 year";
}
}
return true;
}}
errorMessage={(validation) =>
validation.isInvalid ? validation.validationErrors[0] : undefined
}
/>
{/* Custom styled date picker */}
<DatePicker
label="Custom Date Picker"
size="lg"
radius="sm"
variant="faded"
shouldCloseOnSelect={false}
calendarProps={{
classNames: {
base: "bg-background",
headerWrapper: "pt-4 bg-background",
prevButton: "border-1 border-default-200",
nextButton: "border-1 border-default-200",
}
}}
classNames={{
inputWrapper: "border-1 border-default-200 bg-background",
input: "text-sm",
}}
/>
</div>
);
}// Core date/time types from @internationalized/date
type DateValue = CalendarDate | CalendarDateTime | ZonedDateTime;
type TimeValue = Time;
type MappedDateValue<T> = T extends ZonedDateTime ? ZonedDateTime :
T extends CalendarDateTime ? CalendarDateTime :
CalendarDate;
type MappedTimeValue<T> = T extends Time ? Time : Time;
// Range types
interface RangeValue<T> {
/** Range start value */
start: T;
/** Range end value */
end: T;
}
// Calendar types
interface CalendarDate {
readonly calendar: Calendar;
readonly era: string;
readonly year: number;
readonly month: number;
readonly day: number;
copy(): CalendarDate;
add(duration: DateDuration): CalendarDate;
subtract(duration: DateDuration): CalendarDate;
set(fields: DateFields): CalendarDate;
cycle(field: DateField, amount: number): CalendarDate;
toString(): string;
toDate(timeZone: string | TimeZone): Date;
compare(other: CalendarDate): number;
}
interface CalendarDateTime extends CalendarDate {
readonly hour: number;
readonly minute: number;
readonly second: number;
readonly millisecond: number;
copy(): CalendarDateTime;
add(duration: DateTimeDuration): CalendarDateTime;
subtract(duration: DateTimeDuration): CalendarDateTime;
set(fields: DateTimeFields): CalendarDateTime;
}
interface ZonedDateTime extends CalendarDateTime {
readonly timeZone: string;
readonly offset: number;
copy(): ZonedDateTime;
add(duration: DateTimeDuration): ZonedDateTime;
subtract(duration: DateTimeDuration): ZonedDateTime;
set(fields: DateTimeFields): ZonedDateTime;
}
interface Time {
readonly hour: number;
readonly minute: number;
readonly second: number;
readonly millisecond: number;
copy(): Time;
add(duration: TimeDuration): Time;
subtract(duration: TimeDuration): Time;
set(fields: TimeFields): Time;
toString(): string;
compare(other: Time): number;
}
// Date field types
interface DateFields {
era?: string;
year?: number;
month?: number;
day?: number;
}
interface TimeFields {
hour?: number;
minute?: number;
second?: number;
millisecond?: number;
}
interface DateTimeFields extends DateFields, TimeFields {}
// Duration types
interface DateDuration {
years?: number;
months?: number;
weeks?: number;
days?: number;
}
interface TimeDuration {
hours?: number;
minutes?: number;
seconds?: number;
milliseconds?: number;
}
interface DateTimeDuration extends DateDuration, TimeDuration {}
// State interfaces
interface CalendarState {
readonly value: CalendarDate | null;
readonly anchorDate: CalendarDate;
readonly isDisabled: boolean;
readonly isReadOnly: boolean;
readonly isInvalid: boolean;
readonly visibleRange: RangeValue<CalendarDate>;
setValue(value: CalendarDate | null): void;
setAnchorDate(date: CalendarDate): void;
focusNextPage(): void;
focusPreviousPage(): void;
selectDate(date: CalendarDate): void;
isSelected(date: CalendarDate): boolean;
isCellDisabled(date: CalendarDate): boolean;
isCellUnavailable(date: CalendarDate): boolean;
}
interface RangeCalendarState {
readonly value: RangeValue<CalendarDate> | null;
readonly anchorDate: CalendarDate;
readonly isDisabled: boolean;
readonly isReadOnly: boolean;
readonly isInvalid: boolean;
readonly visibleRange: RangeValue<CalendarDate>;
readonly highlightedRange: RangeValue<CalendarDate> | null;
setValue(value: RangeValue<CalendarDate> | null): void;
setAnchorDate(date: CalendarDate): void;
highlightDate(date: CalendarDate): void;
selectDate(date: CalendarDate): void;
isSelected(date: CalendarDate): boolean;
isSelectionStart(date: CalendarDate): boolean;
isSelectionEnd(date: CalendarDate): boolean;
}
interface DateFieldState {
readonly value: DateValue | null;
readonly dateValue: CalendarDate | null;
readonly timeValue: Time | null;
readonly segments: DateSegment[];
readonly isDisabled: boolean;
readonly isReadOnly: boolean;
readonly isRequired: boolean;
readonly isInvalid: boolean;
readonly validationErrors: string[];
setValue(value: DateValue | null): void;
setSegment(field: DateField, value: number): void;
increment(field: DateField): void;
decrement(field: DateField): void;
confirmPlaceholder(): void;
}
interface TimeFieldState {
readonly value: Time | null;
readonly segments: DateSegment[];
readonly isDisabled: boolean;
readonly isReadOnly: boolean;
readonly isRequired: boolean;
readonly isInvalid: boolean;
readonly validationErrors: string[];
setValue(value: Time | null): void;
setSegment(field: TimeField, value: number): void;
increment(field: TimeField): void;
decrement(field: TimeField): void;
}
interface DatePickerState extends DateFieldState {
readonly isOpen: boolean;
readonly calendarState: CalendarState;
setOpen(isOpen: boolean): void;
open(): void;
close(): void;
}
interface DateRangePickerState {
readonly value: RangeValue<DateValue> | null;
readonly isOpen: boolean;
readonly calendarState: RangeCalendarState;
readonly startFieldState: DateFieldState;
readonly endFieldState: DateFieldState;
setValue(value: RangeValue<DateValue> | null): void;
setOpen(isOpen: boolean): void;
open(): void;
close(): void;
}
// Segment types
interface DateSegment {
type: DateField | TimeField;
text: string;
value: number | null;
minValue: number;
maxValue: number;
isEditable: boolean;
isPlaceholder: boolean;
}
type DateField = "era" | "year" | "month" | "day";
type TimeField = "dayPeriod" | "hour" | "minute" | "second" | "millisecond";
// Validation types
type ValidationError = string | string[];
interface ValidationResult {
isInvalid: boolean;
validationErrors: string[];
validationDetails: ValidationDetails;
}
interface ValidationDetails {
[key: string]: any;
}import {
DatePicker, DateRangePicker, Calendar, TimeInput,
Card, CardHeader, CardBody, Button, Divider
} from "@nextui-org/react";
import {
CalendarDate, Time, now, getLocalTimeZone,
isWeekend, isSameDay, startOfWeek, endOfWeek
} from "@internationalized/date";
function DateManagementSystem() {
const [selectedDate, setSelectedDate] = useState<CalendarDate | null>(null);
const [meetingTime, setMeetingTime] = useState<Time>(new Time(9, 0));
const [projectRange, setProjectRange] = useState<RangeValue<CalendarDate> | null>(null);
const today = now(getLocalTimeZone()).date;
const isUnavailable = (date: CalendarDate) => {
// Block weekends and holidays
return isWeekend(date, "en-US") ||
isSameDay(date, new CalendarDate(2024, 12, 25)) ||
isSameDay(date, new CalendarDate(2024, 1, 1));
};
const handleScheduleMeeting = () => {
if (selectedDate && meetingTime) {
console.log(`Meeting scheduled for ${selectedDate} at ${meetingTime}`);
}
};
return (
<div className="max-w-4xl mx-auto space-y-6">
<Card>
<CardHeader>
<h2 className="text-xl font-bold">Meeting Scheduler</h2>
</CardHeader>
<CardBody className="space-y-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<DatePicker
label="Meeting Date"
value={selectedDate}
onChange={setSelectedDate}
minValue={today}
isDateUnavailable={isUnavailable}
description="Select a business day"
showMonthAndYearPickers
/>
<TimeInput
label="Meeting Time"
value={meetingTime}
onChange={setMeetingTime}
minValue={new Time(8, 0)}
maxValue={new Time(18, 0)}
description="Business hours only"
/>
</div>
<Button
color="primary"
onPress={handleScheduleMeeting}
isDisabled={!selectedDate}
>
Schedule Meeting
</Button>
</CardBody>
</Card>
<Card>
<CardHeader>
<h2 className="text-xl font-bold">Project Timeline</h2>
</CardHeader>
<CardBody>
<DateRangePicker
label="Project Duration"
value={projectRange}
onChange={setProjectRange}
minValue={today}
visibleMonths={2}
validate={(range) => {
if (!range) return "Please select a project timeline";
const duration = range.end.calendar.toJulianDay(range.end) -
range.start.calendar.toJulianDay(range.start);
if (duration < 7) return "Project must be at least 1 week";
if (duration > 365) return "Project cannot exceed 1 year";
return true;
}}
errorMessage={(validation) =>
validation.isInvalid ? validation.validationErrors[0] : undefined
}
/>
</CardBody>
</Card>
<Card>
<CardHeader>
<h2 className="text-xl font-bold">Calendar Overview</h2>
</CardHeader>
<CardBody>
<Calendar
value={selectedDate}
onChange={setSelectedDate}
minValue={startOfWeek(today, "en-US")}
maxValue={endOfWeek(today.add({ months: 2 }), "en-US")}
isDateUnavailable={isUnavailable}
visibleMonths={2}
color="secondary"
className="w-full"
/>
</CardBody>
</Card>
</div>
);
}