UNPKG

@aldabil/react-scheduler

Version:

React scheduler component based on Material-UI & date-fns

324 lines (323 loc) 11 kB
import { DialogProps, GridSize } from '@mui/material'; import { DateCalendarProps } from '@mui/x-date-pickers'; import { Locale } from 'date-fns'; import { DragEvent } from 'react'; import { SelectOption } from './components/inputs/SelectInput'; import { View } from './components/nav/Navigation'; import { Store } from './store/types'; import { StateItem } from './views/Editor'; import { RRule } from 'rrule'; export type DayHours = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24; export type WeekDays = 0 | 1 | 2 | 3 | 4 | 5 | 6; interface CommonWeekViewProps { weekDays: WeekDays[]; weekStartOn: WeekDays; disableGoToDay?: boolean; } interface CommonViewProps { startHour: DayHours; endHour: DayHours; cellRenderer?(props: CellRenderedProps): React.ReactNode; headRenderer?(props: { day: Date; events: ProcessedEvent[]; resource?: DefaultResource; }): React.ReactNode; navigation?: boolean; step: number; } export interface MonthProps extends CommonWeekViewProps, CommonViewProps { } export interface WeekProps extends CommonWeekViewProps, CommonViewProps { hourRenderer?(hour: string): React.ReactNode; } export interface DayProps extends CommonViewProps { hourRenderer?(hour: string): React.ReactNode; } export interface CellRenderedProps { day: Date; start: Date; end: Date; height: number; onClick(): void; onDragOver(e: DragEvent<HTMLButtonElement>): void; onDragEnter(e: DragEvent<HTMLButtonElement>): void; onDragLeave(e: DragEvent<HTMLButtonElement>): void; onDrop(e: DragEvent<HTMLButtonElement>): void; } interface CalendarEvent { event_id: number | string; title: React.ReactNode; subtitle?: React.ReactNode; start: Date; end: Date; recurring?: RRule; disabled?: boolean; color?: string; textColor?: string; editable?: boolean; deletable?: boolean; draggable?: boolean; allDay?: boolean; /** * @default " " * passed as a children to mui <Avatar /> component */ agendaAvatar?: React.ReactElement | string; } export interface Translations { navigation: Record<View, string> & { today: string; agenda: string; }; form: { addTitle: string; editTitle: string; confirm: string; delete: string; cancel: string; }; event: Record<string, string> & { title: string; subtitle: string; start: string; end: string; allDay: string; }; validation?: { required?: string; invalidEmail?: string; onlyNumbers?: string; min?: string | ((min: number) => string); max?: string | ((max: number) => string); }; moreEvents: string; noDataToDisplay: string; loading: string; } export type InputTypes = "input" | "date" | "select" | "hidden"; export interface EventRendererProps extends Pick<React.HTMLAttributes<HTMLElement>, "draggable" | "onDragStart" | "onDragEnd" | "onDragOver" | "onDragEnter" | "onClick"> { event: ProcessedEvent; } export interface FieldInputProps { /** Available to all InputTypes */ label?: string; /** Available to all InputTypes */ placeholder?: string; /** Available to all InputTypes * @default false */ required?: boolean; /** Available to all InputTypes * @default "outline" */ variant?: "standard" | "filled" | "outlined"; /** Available to all InputTypes */ disabled?: boolean; /** Available when @input="text" ONLY - Minimum length */ min?: number; /** Available when @input="text" ONLY - Maximum length */ max?: number; /** Available when @input="text" ONLY - Apply email Regex */ email?: boolean; /** Available when @input="text" ONLY - Only numbers(int/float) allowed */ decimal?: boolean; /** Available when @input="text" ONLY - Allow Multiline input. Use @rows property to set initial rows height */ multiline?: boolean; /** Available when @input="text" ONLY - initial rows height*/ rows?: number; /** Available when @input="date" ONLY * @default "datetime" */ type?: "date" | "datetime"; /** Available when @input="select" ONLY - Multi-Select input style. * if you use "default" property with this, make sure your "default" property is an instance of Array */ multiple?: "chips" | "default"; /** Available when @input="select" ONLY - display loading spinner instead of expand arrow */ loading?: boolean; /** Available when @input="select" ONLY - Custom error message */ errMsg?: string; md?: GridSize; sm?: GridSize; xs?: GridSize; } export interface FieldProps { name: string; type: InputTypes; /** Required for type="select" */ options?: Array<SelectOption>; default?: string | number | Date | any; config?: FieldInputProps; } export type ProcessedEvent = CalendarEvent & Record<string, any>; export type EventActions = "create" | "edit"; export type RemoteQuery = { start: Date; end: Date; view: "day" | "week" | "month"; }; export type DefaultResource = { assignee?: string | number; text?: string; subtext?: string; avatar?: string; color?: string; } & Record<string, any>; export type ResourceFields = { idField: string; textField: string; subTextField?: string; avatarField?: string; colorField?: string; } & Record<string, string>; export interface SchedulerHelpers { state: Record<string, StateItem>; close(): void; loading(status: boolean): void; edited?: ProcessedEvent; onConfirm(event: ProcessedEvent | ProcessedEvent[], action: EventActions): void; [resourceKey: string]: unknown; } export interface SchedulerProps { /**Min height of table * @default 600 */ height: number; /** Initial view to load */ view: View; /**Activate Agenda view */ agenda?: boolean; /** if true, day rows without event will be shown */ alwaysShowAgendaDays?: boolean; /**Month view settings */ month: MonthProps | null; /**Week view settings */ week: WeekProps | null; /**Day view settings */ day: DayProps | null; /**Initial date selected */ selectedDate: Date; /** Show/Hide date navigation */ navigation?: boolean; /** Show/Hide view navigator */ disableViewNavigator?: boolean; /** */ navigationPickerProps?: Partial<Omit<DateCalendarProps<Date>, "open" | "onClose" | "openTo" | "views" | "value" | "readOnly" | "onChange">>; /**Events to display */ events: ProcessedEvent[]; /** Custom event render method */ eventRenderer?: (props: EventRendererProps) => React.ReactNode | null; /**Async function to load remote data with current view data. */ getRemoteEvents?(params: RemoteQuery): Promise<ProcessedEvent[] | void>; /**Custom additional fields with it's settings */ fields: FieldProps[]; /**Table loading state */ loading?: boolean; /** Custom loading component */ loadingComponent?: React.ReactNode; /**Async function triggered when add/edit event */ onConfirm?(event: ProcessedEvent, action: EventActions): Promise<ProcessedEvent>; /**Async function triggered when delete event */ onDelete?(deletedId: string | number): Promise<string | number | void>; /**Override editor modal */ customEditor?(scheduler: SchedulerHelpers): React.ReactNode; /** Custom viewer/popper component. If used, `viewerExtraComponent` & `viewerTitleComponent` will be ignored */ customViewer?(event: ProcessedEvent, close: () => void): React.ReactNode; /**Additional component in event viewer popper */ viewerExtraComponent?: React.ReactNode | ((fields: FieldProps[], event: ProcessedEvent) => React.ReactNode); /**Override viewer title component */ viewerTitleComponent?(event: ProcessedEvent): React.ReactNode; /**Override viewer subtitle component */ viewerSubtitleComponent?(event: ProcessedEvent): React.ReactNode; /** if true, the viewer popover will be disabled globally */ disableViewer?: boolean; /**Resources array to split event views with resources */ resources: DefaultResource[]; /**Map resources fields */ resourceFields: ResourceFields; /**Override header component of resource */ resourceHeaderComponent?(resource: DefaultResource): React.ReactNode; /** Triggered when resource tabs changes */ onResourceChange?(resource: DefaultResource): void; /**Resource header view mode * @default "default" */ resourceViewMode: "default" | "vertical" | "tabs"; /**Direction of table */ direction: "rtl" | "ltr"; /**Editor dialog maxWith * @default "md" */ dialogMaxWidth: DialogProps["maxWidth"]; /** * date-fns Locale object */ locale: Locale; /** * Localization */ translations: Translations; /** * Hour Format */ hourFormat: "12" | "24"; /** * Time zone IANA ID: https://data.iana.org/time-zones/releases */ timeZone?: string; /** * Triggered when event is dropped on time slot. */ onEventDrop?(event: DragEvent<HTMLButtonElement>, droppedOn: Date, updatedEvent: ProcessedEvent, originalEvent: ProcessedEvent): Promise<ProcessedEvent | void>; /** * */ onEventClick?(event: ProcessedEvent): void; /** * Triggered when an event item is being edited from the popover */ onEventEdit?(event: ProcessedEvent): void; /** * If event is deletable, applied to all events globally, overridden by event specific deletable prop * @default true */ deletable?: boolean; /** * If calendar is editable, applied to all events/cells globally, overridden by event specific editable prop * @default true */ editable?: boolean; /** * If event is draggable, applied to all events globally, overridden by event specific draggable prop * @default true */ draggable?: boolean; /** * Triggered when the `selectedDate` prop changes by navigation date picker or `today` button. */ onSelectedDateChange?(date: Date): void; /** * Triggered when navigation view changes. */ onViewChange?(view: View, agenda?: boolean): void; /** * If true, the navigation controller bar will be sticky */ stickyNavigation?: boolean; /** * Overrides the default behavior of more events button */ onClickMore?(date: Date, gotToDay: (date: Date) => void): void; /** * */ onCellClick?(start: Date, end: Date, resourceKey?: string, resourceVal?: string | number): void; } export interface SchedulerRef { el: HTMLDivElement; scheduler: Store; } export interface Scheduler extends Partial<SchedulerProps> { } export {};