@schedule-x/resize
Advanced tools
Comparing version
@@ -1,56 +0,56 @@ | ||
import { Signal, ReadonlySignal } from "@preact/signals"; | ||
import { JSXInternal } from "preact/src/jsx"; | ||
import { Signal, ReadonlySignal } from '@preact/signals' | ||
import { JSXInternal } from 'preact/src/jsx' | ||
declare enum WeekDay { | ||
SUNDAY = 0, | ||
MONDAY = 1, | ||
TUESDAY = 2, | ||
WEDNESDAY = 3, | ||
THURSDAY = 4, | ||
FRIDAY = 5, | ||
SATURDAY = 6 | ||
SUNDAY = 0, | ||
MONDAY = 1, | ||
TUESDAY = 2, | ||
WEDNESDAY = 3, | ||
THURSDAY = 4, | ||
FRIDAY = 5, | ||
SATURDAY = 6, | ||
} | ||
type WeekWithDates = Date[]; | ||
type MonthWithDates = Date[][]; | ||
type WeekWithDates = Date[] | ||
type MonthWithDates = Date[][] | ||
declare enum Month { | ||
JANUARY = 0, | ||
FEBRUARY = 1, | ||
MARCH = 2, | ||
APRIL = 3, | ||
MAY = 4, | ||
JUNE = 5, | ||
JULY = 6, | ||
AUGUST = 7, | ||
SEPTEMBER = 8, | ||
OCTOBER = 9, | ||
NOVEMBER = 10, | ||
DECEMBER = 11 | ||
JANUARY = 0, | ||
FEBRUARY = 1, | ||
MARCH = 2, | ||
APRIL = 3, | ||
MAY = 4, | ||
JUNE = 5, | ||
JULY = 6, | ||
AUGUST = 7, | ||
SEPTEMBER = 8, | ||
OCTOBER = 9, | ||
NOVEMBER = 10, | ||
DECEMBER = 11, | ||
} | ||
interface TimeUnits { | ||
firstDayOfWeek: WeekDay; | ||
getMonthWithTrailingAndLeadingDays(year: number, month: Month): MonthWithDates; | ||
getWeekFor(date: Date): WeekWithDates; | ||
getMonthsFor(year: number): Date[]; | ||
firstDayOfWeek: WeekDay | ||
getMonthWithTrailingAndLeadingDays(year: number, month: Month): MonthWithDates | ||
getWeekFor(date: Date): WeekWithDates | ||
getMonthsFor(year: number): Date[] | ||
} | ||
declare enum DatePickerView { | ||
MONTH_DAYS = "month-days", | ||
YEARS = "years" | ||
MONTH_DAYS = 'month-days', | ||
YEARS = 'years', | ||
} | ||
interface DatePickerState { | ||
isOpen: Signal<boolean>; | ||
isDisabled: Signal<boolean>; | ||
selectedDate: Signal<string>; | ||
inputDisplayedValue: Signal<string>; | ||
datePickerDate: Signal<string>; | ||
datePickerView: Signal<DatePickerView>; | ||
inputWrapperElement: Signal<HTMLDivElement | undefined>; | ||
isDark: Signal<boolean>; | ||
open(): void; | ||
close(): void; | ||
toggle(): void; | ||
setView(view: DatePickerView): void; | ||
isOpen: Signal<boolean> | ||
isDisabled: Signal<boolean> | ||
selectedDate: Signal<string> | ||
inputDisplayedValue: Signal<string> | ||
datePickerDate: Signal<string> | ||
datePickerView: Signal<DatePickerView> | ||
inputWrapperElement: Signal<HTMLDivElement | undefined> | ||
isDark: Signal<boolean> | ||
open(): void | ||
close(): void | ||
toggle(): void | ||
setView(view: DatePickerView): void | ||
} | ||
type TranslationVariables = { | ||
[key: string]: string | number; | ||
}; | ||
type TranslateFn = (key: string, variables?: TranslationVariables) => string; | ||
[key: string]: string | number | ||
} | ||
type TranslateFn = (key: string, variables?: TranslationVariables) => string | ||
/** | ||
@@ -60,5 +60,5 @@ * This interface serves as a bridge between the AppSingleton for the date picker and calendar | ||
interface AppSingleton { | ||
timeUnitsImpl: TimeUnits; | ||
datePickerState: DatePickerState; | ||
translate: TranslateFn; | ||
timeUnitsImpl: TimeUnits | ||
datePickerState: DatePickerState | ||
translate: TranslateFn | ||
} | ||
@@ -69,319 +69,350 @@ /** | ||
interface Config { | ||
locale: string; | ||
firstDayOfWeek: WeekDay; | ||
locale: string | ||
firstDayOfWeek: WeekDay | ||
} | ||
declare enum Placement { | ||
TOP_START = "top-start", | ||
TOP_END = "top-end", | ||
BOTTOM_START = "bottom-start", | ||
BOTTOM_END = "bottom-end" | ||
TOP_START = 'top-start', | ||
TOP_END = 'top-end', | ||
BOTTOM_START = 'bottom-start', | ||
BOTTOM_END = 'bottom-end', | ||
} | ||
interface DatePickerAppSingleton extends AppSingleton { | ||
config: DatePickerConfigInternal; | ||
config: DatePickerConfigInternal | ||
} | ||
type DatePickerListeners = { | ||
onChange?: (date: string) => void; | ||
onEscapeKeyDown?: ($app: DatePickerAppSingleton) => void; | ||
}; | ||
onChange?: (date: string) => void | ||
onEscapeKeyDown?: ($app: DatePickerAppSingleton) => void | ||
} | ||
type DatePickerStyle = { | ||
dark?: boolean; | ||
fullWidth?: boolean; | ||
}; | ||
dark?: boolean | ||
fullWidth?: boolean | ||
} | ||
interface DatePickerConfigInternal extends Config { | ||
min: string; | ||
max: string; | ||
placement: Placement; | ||
listeners: DatePickerListeners; | ||
style: DatePickerStyle; | ||
teleportTo?: HTMLElement; | ||
label?: string; | ||
name?: string; | ||
disabled?: boolean; | ||
min: string | ||
max: string | ||
placement: Placement | ||
listeners: DatePickerListeners | ||
style: DatePickerStyle | ||
teleportTo?: HTMLElement | ||
label?: string | ||
name?: string | ||
disabled?: boolean | ||
} | ||
// This enum is used to represent names of all internally built views of the calendar | ||
declare enum InternalViewName { | ||
Day = "day", | ||
Week = "week", | ||
MonthGrid = "month-grid", | ||
MonthAgenda = "month-agenda" | ||
Day = 'day', | ||
Week = 'week', | ||
MonthGrid = 'month-grid', | ||
MonthAgenda = 'month-agenda', | ||
} | ||
// Since implementers can use custom views, we need to have a type that combines the internal views with these custom views | ||
type ViewName = InternalViewName | string; | ||
type ViewName = InternalViewName | string | ||
type DateRange = { | ||
start: string; | ||
end: string; | ||
}; | ||
start: string | ||
end: string | ||
} | ||
interface RangeSetterConfig { | ||
date: string; | ||
timeUnitsImpl: TimeUnits; | ||
calendarConfig: CalendarConfigInternal; | ||
range: Signal<DateRange | null>; | ||
date: string | ||
timeUnitsImpl: TimeUnits | ||
calendarConfig: CalendarConfigInternal | ||
range: Signal<DateRange | null> | ||
} | ||
type PreactViewComponent = (props: { | ||
$app: CalendarAppSingleton; | ||
id: string; | ||
}) => JSXInternal.Element; | ||
declare const addMonths: (to: string, nMonths: number) => string; | ||
declare const addDays: (to: string, nDays: number) => string; | ||
$app: CalendarAppSingleton | ||
id: string | ||
}) => JSXInternal.Element | ||
declare const addMonths: (to: string, nMonths: number) => string | ||
declare const addDays: (to: string, nDays: number) => string | ||
type ViewConfig<FrameworkComponent = PreactViewComponent> = { | ||
/** | ||
* a unique identifier for the view | ||
* */ | ||
name: ViewName; | ||
/** | ||
* text that will be displayed in the view dropdown | ||
* */ | ||
label: string; | ||
/** | ||
* function that is called when a new date is selected | ||
* */ | ||
setDateRange: (config: RangeSetterConfig) => DateRange; | ||
/** | ||
* should the view be displayed on small screens (< 700px calendar width) | ||
* */ | ||
hasSmallScreenCompat: boolean; | ||
/** | ||
* should the view be displayed on wide screens (> 700px calendar width) | ||
* */ | ||
hasWideScreenCompat: boolean; | ||
/** | ||
* The component you want to render | ||
* */ | ||
Component: FrameworkComponent; | ||
/** | ||
* function that is called when the user clicks the backward/forward button | ||
* */ | ||
backwardForwardFn: typeof addDays | typeof addMonths; | ||
/** | ||
* number of units to add into the backwardForwardFn function. Result behind the scenes for example: | ||
* backwardForwardFn = addDays | ||
* backwardForwardUnits = 1 | ||
* result (behind the scenes) = addDays(date, 1) | ||
* */ | ||
backwardForwardUnits: number; | ||
}; | ||
type View<FrameworkComponent = PreactViewComponent> = ViewConfig<FrameworkComponent> & { | ||
render(onElement: HTMLElement, $app: CalendarAppSingleton): void; | ||
destroy(): void; | ||
}; | ||
type EventId = number | string; | ||
type startDate = string; | ||
type nDays = number; | ||
type EventFragments = Record<startDate, nDays>; | ||
/** | ||
* a unique identifier for the view | ||
* */ | ||
name: ViewName | ||
/** | ||
* text that will be displayed in the view dropdown | ||
* */ | ||
label: string | ||
/** | ||
* function that is called when a new date is selected | ||
* */ | ||
setDateRange: (config: RangeSetterConfig) => DateRange | ||
/** | ||
* should the view be displayed on small screens (< 700px calendar width) | ||
* */ | ||
hasSmallScreenCompat: boolean | ||
/** | ||
* should the view be displayed on wide screens (> 700px calendar width) | ||
* */ | ||
hasWideScreenCompat: boolean | ||
/** | ||
* The component you want to render | ||
* */ | ||
Component: FrameworkComponent | ||
/** | ||
* function that is called when the user clicks the backward/forward button | ||
* */ | ||
backwardForwardFn: typeof addDays | typeof addMonths | ||
/** | ||
* number of units to add into the backwardForwardFn function. Result behind the scenes for example: | ||
* backwardForwardFn = addDays | ||
* backwardForwardUnits = 1 | ||
* result (behind the scenes) = addDays(date, 1) | ||
* */ | ||
backwardForwardUnits: number | ||
} | ||
type View<FrameworkComponent = PreactViewComponent> = | ||
ViewConfig<FrameworkComponent> & { | ||
render(onElement: HTMLElement, $app: CalendarAppSingleton): void | ||
destroy(): void | ||
} | ||
type EventId = number | string | ||
type startDate = string | ||
type nDays = number | ||
type EventFragments = Record<startDate, nDays> | ||
type CalendarEventOptions = { | ||
disableDND?: boolean; | ||
disableResize?: boolean; | ||
additionalClasses?: string[]; | ||
}; | ||
disableDND?: boolean | ||
disableResize?: boolean | ||
additionalClasses?: string[] | ||
} | ||
interface CalendarEventExternal { | ||
id: EventId; | ||
start: string; | ||
end: string; | ||
title?: string; | ||
people?: string[]; | ||
location?: string; | ||
description?: string; | ||
calendarId?: string; | ||
_options?: CalendarEventOptions; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: string]: any; | ||
id: EventId | ||
start: string | ||
end: string | ||
title?: string | ||
people?: string[] | ||
location?: string | ||
description?: string | ||
calendarId?: string | ||
_options?: CalendarEventOptions | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: string]: any | ||
} | ||
interface CalendarEventInternal extends CalendarEventExternal { | ||
// event duration | ||
_isSingleDayTimed: boolean; | ||
_isSingleDayFullDay: boolean; | ||
_isSingleHybridDayTimed: boolean; | ||
_isMultiDayTimed: boolean; | ||
_isMultiDayFullDay: boolean; | ||
// week time grid | ||
_previousConcurrentEvents: number | undefined; | ||
_totalConcurrentEvents: number | undefined; | ||
// week date grid | ||
_nDaysInGrid: number | undefined; | ||
// month grid | ||
_eventFragments: EventFragments; | ||
_color: string; | ||
_getForeignProperties(): Record<string, unknown>; | ||
_getExternalEvent(): CalendarEventExternal; | ||
// event duration | ||
_isSingleDayTimed: boolean | ||
_isSingleDayFullDay: boolean | ||
_isSingleHybridDayTimed: boolean | ||
_isMultiDayTimed: boolean | ||
_isMultiDayFullDay: boolean | ||
// week time grid | ||
_previousConcurrentEvents: number | undefined | ||
_totalConcurrentEvents: number | undefined | ||
// week date grid | ||
_nDaysInGrid: number | undefined | ||
// month grid | ||
_eventFragments: EventFragments | ||
_color: string | ||
_getForeignProperties(): Record<string, unknown> | ||
_getExternalEvent(): CalendarEventExternal | ||
} | ||
type DayBoundariesInternal = { | ||
start: number; | ||
end: number; | ||
}; | ||
interface TimeGridDragHandler { | ||
start: number | ||
end: number | ||
} | ||
interface TimeGridDragHandler {} | ||
type DayBoundariesDateTime = { | ||
start: string; | ||
end: string; | ||
}; | ||
interface DateGridDragHandler { | ||
start: string | ||
end: string | ||
} | ||
interface DateGridDragHandler {} | ||
interface EventCoordinates { | ||
clientX: number; | ||
clientY: number; | ||
clientX: number | ||
clientY: number | ||
} | ||
interface DragHandlerDependencies { | ||
$app: CalendarAppSingleton; | ||
eventCoordinates: EventCoordinates; | ||
eventCopy: CalendarEventInternal; | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void; | ||
$app: CalendarAppSingleton | ||
eventCoordinates: EventCoordinates | ||
eventCopy: CalendarEventInternal | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void | ||
} | ||
interface MonthGridDragHandler { | ||
} | ||
interface MonthGridDragHandler {} | ||
interface DragAndDropPlugin extends PluginBase { | ||
createTimeGridDragHandler(dependencies: DragHandlerDependencies, dayBoundariesDateTime: DayBoundariesDateTime): TimeGridDragHandler; | ||
createDateGridDragHandler(dependencies: DragHandlerDependencies): DateGridDragHandler; | ||
createMonthGridDragHandler(calendarEvent: CalendarEventInternal, $app: CalendarAppSingleton): MonthGridDragHandler; | ||
createTimeGridDragHandler( | ||
dependencies: DragHandlerDependencies, | ||
dayBoundariesDateTime: DayBoundariesDateTime | ||
): TimeGridDragHandler | ||
createDateGridDragHandler( | ||
dependencies: DragHandlerDependencies | ||
): DateGridDragHandler | ||
createMonthGridDragHandler( | ||
calendarEvent: CalendarEventInternal, | ||
$app: CalendarAppSingleton | ||
): MonthGridDragHandler | ||
} | ||
type EventModalProps = { | ||
$app: CalendarAppSingleton; | ||
}; | ||
$app: CalendarAppSingleton | ||
} | ||
interface EventModalPlugin extends PluginBase { | ||
calendarEvent: Signal<CalendarEventInternal | null>; | ||
calendarEventDOMRect: Signal<DOMRect | null>; | ||
calendarEventElement: Signal<HTMLElement | null>; | ||
close(): void; | ||
setCalendarEvent(event: CalendarEventInternal | null, eventTargetDOMRect: DOMRect | null): void; | ||
ComponentFn(props: EventModalProps): JSXInternal.Element; | ||
calendarEvent: Signal<CalendarEventInternal | null> | ||
calendarEventDOMRect: Signal<DOMRect | null> | ||
calendarEventElement: Signal<HTMLElement | null> | ||
close(): void | ||
setCalendarEvent( | ||
event: CalendarEventInternal | null, | ||
eventTargetDOMRect: DOMRect | null | ||
): void | ||
ComponentFn(props: EventModalProps): JSXInternal.Element | ||
} | ||
interface CalendarCallbacks { | ||
onEventUpdate?: (event: CalendarEventExternal) => void; | ||
onEventClick?: (event: CalendarEventExternal) => void; | ||
onRangeUpdate?: (range: DateRange) => void; | ||
onSelectedDateUpdate?: (date: string) => void; | ||
onClickDate?: (date: string) => void; | ||
onDoubleClickDate?: (date: string) => void; | ||
onClickDateTime?: (dateTime: string) => void; | ||
onDoubleClickDateTime?: (dateTime: string) => void; | ||
onClickAgendaDate?: (date: string) => void; | ||
onClickPlusEvents?: (date: string) => void; | ||
isCalendarSmall?: ($app: CalendarAppSingleton) => boolean; | ||
onEventUpdate?: (event: CalendarEventExternal) => void | ||
onEventClick?: (event: CalendarEventExternal) => void | ||
onRangeUpdate?: (range: DateRange) => void | ||
onSelectedDateUpdate?: (date: string) => void | ||
onClickDate?: (date: string) => void | ||
onDoubleClickDate?: (date: string) => void | ||
onClickDateTime?: (dateTime: string) => void | ||
onDoubleClickDateTime?: (dateTime: string) => void | ||
onClickAgendaDate?: (date: string) => void | ||
onClickPlusEvents?: (date: string) => void | ||
isCalendarSmall?: ($app: CalendarAppSingleton) => boolean | ||
} | ||
type CustomComponentFns = { | ||
timeGridEvent?: CustomComponentFn; | ||
dateGridEvent?: CustomComponentFn; | ||
monthGridEvent?: CustomComponentFn; | ||
monthAgendaEvent?: CustomComponentFn; | ||
eventModal?: CustomComponentFn; | ||
headerContentLeftPrepend?: CustomComponentFn; | ||
headerContentLeftAppend?: CustomComponentFn; | ||
headerContentRightPrepend?: CustomComponentFn; | ||
headerContentRightAppend?: CustomComponentFn; | ||
}; | ||
timeGridEvent?: CustomComponentFn | ||
dateGridEvent?: CustomComponentFn | ||
monthGridEvent?: CustomComponentFn | ||
monthAgendaEvent?: CustomComponentFn | ||
eventModal?: CustomComponentFn | ||
headerContentLeftPrepend?: CustomComponentFn | ||
headerContentLeftAppend?: CustomComponentFn | ||
headerContentRightPrepend?: CustomComponentFn | ||
headerContentRightAppend?: CustomComponentFn | ||
} | ||
interface EventsFacade { | ||
get(id: EventId): CalendarEventExternal | undefined; | ||
getAll(): CalendarEventExternal[]; | ||
add(event: CalendarEventExternal): void; | ||
update(event: CalendarEventExternal): void; | ||
remove(id: EventId): void; | ||
set(events: CalendarEventExternal[]): void; | ||
get(id: EventId): CalendarEventExternal | undefined | ||
getAll(): CalendarEventExternal[] | ||
add(event: CalendarEventExternal): void | ||
update(event: CalendarEventExternal): void | ||
remove(id: EventId): void | ||
set(events: CalendarEventExternal[]): void | ||
} | ||
interface EventRecurrencePlugin extends PluginBase { | ||
updateRecurrenceDND(eventId: EventId, oldEventStart: string, newEventStart: string): void; | ||
updateRecurrenceOnResize(eventId: EventId, oldEventEnd: string, newEventEnd: string): void; | ||
eventsFacade: EventsFacade; | ||
updateRecurrenceDND( | ||
eventId: EventId, | ||
oldEventStart: string, | ||
newEventStart: string | ||
): void | ||
updateRecurrenceOnResize( | ||
eventId: EventId, | ||
oldEventEnd: string, | ||
newEventEnd: string | ||
): void | ||
eventsFacade: EventsFacade | ||
} | ||
type WeekOptions = { | ||
gridHeight: number; | ||
nDays: number; | ||
eventWidth: number; | ||
}; | ||
gridHeight: number | ||
nDays: number | ||
eventWidth: number | ||
} | ||
type MonthGridOptions = { | ||
nEventsPerDay: number; | ||
}; | ||
nEventsPerDay: number | ||
} | ||
type ColorDefinition = { | ||
main: string; | ||
container: string; | ||
onContainer: string; | ||
}; | ||
main: string | ||
container: string | ||
onContainer: string | ||
} | ||
type CalendarType = { | ||
colorName: string; | ||
label?: string; | ||
lightColors?: ColorDefinition; | ||
darkColors?: ColorDefinition; | ||
}; | ||
colorName: string | ||
label?: string | ||
lightColors?: ColorDefinition | ||
darkColors?: ColorDefinition | ||
} | ||
type Plugins = { | ||
dragAndDrop?: DragAndDropPlugin; | ||
eventModal?: EventModalPlugin; | ||
scrollController?: PluginBase; | ||
eventRecurrence?: EventRecurrencePlugin; | ||
resize?: ResizePlugin; | ||
[key: string]: PluginBase | undefined; | ||
}; | ||
type CustomComponentFn = (wrapperElement: HTMLElement, props: Record<string, unknown>) => void; | ||
dragAndDrop?: DragAndDropPlugin | ||
eventModal?: EventModalPlugin | ||
scrollController?: PluginBase | ||
eventRecurrence?: EventRecurrencePlugin | ||
resize?: ResizePlugin | ||
[key: string]: PluginBase | undefined | ||
} | ||
type CustomComponentFn = ( | ||
wrapperElement: HTMLElement, | ||
props: Record<string, unknown> | ||
) => void | ||
interface CalendarConfigInternal extends Config { | ||
defaultView: ViewName; | ||
views: View[]; | ||
dayBoundaries: DayBoundariesInternal; | ||
weekOptions: WeekOptions; | ||
monthGridOptions: MonthGridOptions; | ||
calendars: Signal<Record<string, CalendarType>>; | ||
plugins: Plugins; | ||
isDark: boolean; | ||
isResponsive: boolean; | ||
callbacks: CalendarCallbacks; | ||
_customComponentFns: CustomComponentFns; | ||
minDate?: string; | ||
maxDate?: string; | ||
// Getters | ||
isHybridDay: boolean; | ||
timePointsPerDay: number; | ||
defaultView: ViewName | ||
views: View[] | ||
dayBoundaries: DayBoundariesInternal | ||
weekOptions: WeekOptions | ||
monthGridOptions: MonthGridOptions | ||
calendars: Signal<Record<string, CalendarType>> | ||
plugins: Plugins | ||
isDark: boolean | ||
isResponsive: boolean | ||
callbacks: CalendarCallbacks | ||
_customComponentFns: CustomComponentFns | ||
minDate?: string | ||
maxDate?: string | ||
// Getters | ||
isHybridDay: boolean | ||
timePointsPerDay: number | ||
} | ||
interface CalendarState { | ||
isCalendarSmall: Signal<boolean | undefined>; | ||
view: ReadonlySignal<ViewName>; | ||
setView: (view: ViewName, selectedDate: string) => void; | ||
range: Signal<DateRange | null>; | ||
isDark: Signal<boolean>; | ||
setRange: (date: string) => void; | ||
isCalendarSmall: Signal<boolean | undefined> | ||
view: ReadonlySignal<ViewName> | ||
setView: (view: ViewName, selectedDate: string) => void | ||
range: Signal<DateRange | null> | ||
isDark: Signal<boolean> | ||
setRange: (date: string) => void | ||
} | ||
type EventsFilterPredicate = ((event: CalendarEventInternal) => boolean) | undefined; | ||
type EventsFilterPredicate = | ||
| ((event: CalendarEventInternal) => boolean) | ||
| undefined | ||
interface CalendarEvents { | ||
list: Signal<CalendarEventInternal[]>; | ||
filterPredicate: Signal<EventsFilterPredicate>; | ||
list: Signal<CalendarEventInternal[]> | ||
filterPredicate: Signal<EventsFilterPredicate> | ||
} | ||
interface CalendarElements { | ||
calendarWrapper: HTMLDivElement | undefined; | ||
calendarWrapper: HTMLDivElement | undefined | ||
} | ||
interface CalendarAppSingleton extends AppSingleton { | ||
config: CalendarConfigInternal; | ||
datePickerConfig: DatePickerConfigInternal; | ||
calendarState: CalendarState; | ||
calendarEvents: CalendarEvents; | ||
elements: CalendarElements; | ||
config: CalendarConfigInternal | ||
datePickerConfig: DatePickerConfigInternal | ||
calendarState: CalendarState | ||
calendarEvents: CalendarEvents | ||
elements: CalendarElements | ||
} | ||
interface PluginBase { | ||
name: string; | ||
// TODO v2: change to `beforeRender` | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
beforeInit?($app: CalendarAppSingleton | any): void; | ||
// TODO v2: change to `onRender` and remove $app parameter | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
init?($app: CalendarAppSingleton | any): void; | ||
destroy?(): void; | ||
name: string | ||
// TODO v2: change to `beforeRender` | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
beforeInit?($app: CalendarAppSingleton | any): void | ||
// TODO v2: change to `onRender` and remove $app parameter | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
init?($app: CalendarAppSingleton | any): void | ||
destroy?(): void | ||
} | ||
interface ResizePlugin extends PluginBase { | ||
createTimeGridEventResizer(calendarEvent: CalendarEventInternal, updateCopy: (newCopy: CalendarEventInternal | undefined) => void, mouseDownEvent: MouseEvent, dayBoundariesDateTime: { | ||
start: string; | ||
end: string; | ||
}): void; | ||
createDateGridEventResizer(calendarEvent: CalendarEventInternal, updateCopy: (newCopy: CalendarEventInternal | undefined) => void, mouseDownEvent: MouseEvent): void; | ||
createTimeGridEventResizer( | ||
calendarEvent: CalendarEventInternal, | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void, | ||
mouseDownEvent: MouseEvent, | ||
dayBoundariesDateTime: { | ||
start: string | ||
end: string | ||
} | ||
): void | ||
createDateGridEventResizer( | ||
calendarEvent: CalendarEventInternal, | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void, | ||
mouseDownEvent: MouseEvent | ||
): void | ||
} | ||
declare const createResizePlugin: (minutesPerInterval?: number) => ResizePlugin; | ||
export { createResizePlugin }; | ||
declare const createResizePlugin: (minutesPerInterval?: number) => ResizePlugin | ||
export { createResizePlugin } |
@@ -1,389 +0,460 @@ | ||
'use strict'; | ||
'use strict' | ||
require('preact/jsx-runtime'); | ||
require('preact/jsx-runtime') | ||
const getTimePointsPerPixel = ($app) => { | ||
return $app.config.timePointsPerDay / $app.config.weekOptions.gridHeight; | ||
}; | ||
return $app.config.timePointsPerDay / $app.config.weekOptions.gridHeight | ||
} | ||
const DateFormats = { | ||
DATE_STRING: /^\d{4}-\d{2}-\d{2}$/, | ||
TIME_STRING: /^\d{2}:\d{2}$/, | ||
DATE_TIME_STRING: /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, | ||
}; | ||
DATE_STRING: /^\d{4}-\d{2}-\d{2}$/, | ||
TIME_STRING: /^\d{2}:\d{2}$/, | ||
DATE_TIME_STRING: /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, | ||
} | ||
class InvalidDateTimeError extends Error { | ||
constructor(dateTimeSpecification) { | ||
super(`Invalid date time specification: ${dateTimeSpecification}`); | ||
} | ||
constructor(dateTimeSpecification) { | ||
super(`Invalid date time specification: ${dateTimeSpecification}`) | ||
} | ||
} | ||
const toJSDate = (dateTimeSpecification) => { | ||
if (!DateFormats.DATE_TIME_STRING.test(dateTimeSpecification) && | ||
!DateFormats.DATE_STRING.test(dateTimeSpecification)) | ||
throw new InvalidDateTimeError(dateTimeSpecification); | ||
return new Date(Number(dateTimeSpecification.slice(0, 4)), Number(dateTimeSpecification.slice(5, 7)) - 1, Number(dateTimeSpecification.slice(8, 10)), Number(dateTimeSpecification.slice(11, 13)), // for date strings this will be 0 | ||
if ( | ||
!DateFormats.DATE_TIME_STRING.test(dateTimeSpecification) && | ||
!DateFormats.DATE_STRING.test(dateTimeSpecification) | ||
) | ||
throw new InvalidDateTimeError(dateTimeSpecification) | ||
return new Date( | ||
Number(dateTimeSpecification.slice(0, 4)), | ||
Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
Number(dateTimeSpecification.slice(8, 10)), | ||
Number(dateTimeSpecification.slice(11, 13)), // for date strings this will be 0 | ||
Number(dateTimeSpecification.slice(14, 16)) // for date strings this will be 0 | ||
); | ||
}; | ||
) | ||
} | ||
const toIntegers = (dateTimeSpecification) => { | ||
const hours = dateTimeSpecification.slice(11, 13), minutes = dateTimeSpecification.slice(14, 16); | ||
return { | ||
year: Number(dateTimeSpecification.slice(0, 4)), | ||
month: Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
date: Number(dateTimeSpecification.slice(8, 10)), | ||
hours: hours !== '' ? Number(hours) : undefined, | ||
minutes: minutes !== '' ? Number(minutes) : undefined, | ||
}; | ||
}; | ||
const hours = dateTimeSpecification.slice(11, 13), | ||
minutes = dateTimeSpecification.slice(14, 16) | ||
return { | ||
year: Number(dateTimeSpecification.slice(0, 4)), | ||
month: Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
date: Number(dateTimeSpecification.slice(8, 10)), | ||
hours: hours !== '' ? Number(hours) : undefined, | ||
minutes: minutes !== '' ? Number(minutes) : undefined, | ||
} | ||
} | ||
class NumberRangeError extends Error { | ||
constructor(min, max) { | ||
super(`Number must be between ${min} and ${max}.`); | ||
Object.defineProperty(this, "min", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: min | ||
}); | ||
Object.defineProperty(this, "max", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: max | ||
}); | ||
} | ||
constructor(min, max) { | ||
super(`Number must be between ${min} and ${max}.`) | ||
Object.defineProperty(this, 'min', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: min, | ||
}) | ||
Object.defineProperty(this, 'max', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: max, | ||
}) | ||
} | ||
} | ||
const doubleDigit = (number) => { | ||
if (number < 0 || number > 99) | ||
throw new NumberRangeError(0, 99); | ||
return String(number).padStart(2, '0'); | ||
}; | ||
if (number < 0 || number > 99) throw new NumberRangeError(0, 99) | ||
return String(number).padStart(2, '0') | ||
} | ||
const toDateString = (date) => { | ||
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())}`; | ||
}; | ||
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())}` | ||
} | ||
const toTimeString = (date) => { | ||
return `${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}`; | ||
}; | ||
return `${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}` | ||
} | ||
const toDateTimeString = (date) => { | ||
return `${toDateString(date)} ${toTimeString(date)}`; | ||
}; | ||
return `${toDateString(date)} ${toTimeString(date)}` | ||
} | ||
const minuteTimePointMultiplier = 1.6666666666666667; // 100 / 60 | ||
const minuteTimePointMultiplier = 1.6666666666666667 // 100 / 60 | ||
const addTimePointsToDateTime = (dateTimeString, pointsToAdd) => { | ||
const minutesToAdd = pointsToAdd / minuteTimePointMultiplier; | ||
const jsDate = toJSDate(dateTimeString); | ||
jsDate.setMinutes(jsDate.getMinutes() + minutesToAdd); | ||
return toDateTimeString(jsDate); | ||
}; | ||
const minutesToAdd = pointsToAdd / minuteTimePointMultiplier | ||
const jsDate = toJSDate(dateTimeString) | ||
jsDate.setMinutes(jsDate.getMinutes() + minutesToAdd) | ||
return toDateTimeString(jsDate) | ||
} | ||
const updateEventsList = ($app, eventCopy, oldEventEnd, newEventEnd) => { | ||
const rrule = eventCopy._getForeignProperties().rrule; | ||
if (rrule && $app.config.plugins.eventRecurrence) { | ||
$app.config.plugins.eventRecurrence.updateRecurrenceOnResize(eventCopy.id, oldEventEnd, newEventEnd); | ||
return; | ||
} | ||
const eventToUpdate = $app.calendarEvents.list.value.find((event) => event.id === eventCopy.id); | ||
if (!eventToUpdate) | ||
return; | ||
eventToUpdate.end = eventCopy.end; | ||
$app.calendarEvents.list.value = [...$app.calendarEvents.list.value]; | ||
}; | ||
const rrule = eventCopy._getForeignProperties().rrule | ||
if (rrule && $app.config.plugins.eventRecurrence) { | ||
$app.config.plugins.eventRecurrence.updateRecurrenceOnResize( | ||
eventCopy.id, | ||
oldEventEnd, | ||
newEventEnd | ||
) | ||
return | ||
} | ||
const eventToUpdate = $app.calendarEvents.list.value.find( | ||
(event) => event.id === eventCopy.id | ||
) | ||
if (!eventToUpdate) return | ||
eventToUpdate.end = eventCopy.end | ||
$app.calendarEvents.list.value = [...$app.calendarEvents.list.value] | ||
} | ||
class TimeGridEventResizer { | ||
constructor($app, eventCopy, updateCopy, initialY, CHANGE_THRESHOLD_IN_TIME_POINTS, dayBoundariesDateTime) { | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app | ||
}); | ||
Object.defineProperty(this, "eventCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy | ||
}); | ||
Object.defineProperty(this, "updateCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy | ||
}); | ||
Object.defineProperty(this, "initialY", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialY | ||
}); | ||
Object.defineProperty(this, "CHANGE_THRESHOLD_IN_TIME_POINTS", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: CHANGE_THRESHOLD_IN_TIME_POINTS | ||
}); | ||
Object.defineProperty(this, "dayBoundariesDateTime", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: dayBoundariesDateTime | ||
}); | ||
Object.defineProperty(this, "originalEventEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "lastIntervalDiff", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "lastValidEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '' | ||
}); | ||
Object.defineProperty(this, "handleMouseMove", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const pixelDiffY = event.clientY - this.initialY; | ||
const timePointsDiffY = pixelDiffY * getTimePointsPerPixel(this.$app); | ||
const currentIntervalDiff = Math.round(timePointsDiffY / this.CHANGE_THRESHOLD_IN_TIME_POINTS); | ||
const timeDidNotChange = currentIntervalDiff === this.lastIntervalDiff; | ||
if (timeDidNotChange) | ||
return; | ||
this.lastIntervalDiff = currentIntervalDiff; | ||
this.setNewTimeForEventEnd(this.CHANGE_THRESHOLD_IN_TIME_POINTS * currentIntervalDiff); | ||
} | ||
}); | ||
Object.defineProperty(this, "handleMouseUp", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.setNewTimeForEventEnd(this.CHANGE_THRESHOLD_IN_TIME_POINTS * this.lastIntervalDiff); | ||
updateEventsList(this.$app, this.eventCopy, this.originalEventEnd, this.lastValidEnd); | ||
this.updateCopy(undefined); | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing'); | ||
this.$app.elements.calendarWrapper.removeEventListener('mousemove', this.handleMouseMove); | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate(this.eventCopy._getExternalEvent()); | ||
} | ||
} | ||
}); | ||
this.originalEventEnd = this.eventCopy.end; | ||
this.lastValidEnd = this.eventCopy.end; | ||
const calendarWrapper = this.$app.elements.calendarWrapper; | ||
if (!calendarWrapper) | ||
return; | ||
calendarWrapper.classList.add('sx__is-resizing'); | ||
this.setupEventListeners(); | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener('mousemove', this.handleMouseMove); | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }); | ||
} | ||
setNewTimeForEventEnd(pointsToAdd) { | ||
const newEnd = addTimePointsToDateTime(this.originalEventEnd, pointsToAdd); | ||
if (newEnd > this.dayBoundariesDateTime.end || | ||
newEnd <= this.eventCopy.start) | ||
return; | ||
this.lastValidEnd = newEnd; | ||
this.eventCopy.end = this.lastValidEnd; | ||
this.updateCopy(this.eventCopy); | ||
} | ||
constructor( | ||
$app, | ||
eventCopy, | ||
updateCopy, | ||
initialY, | ||
CHANGE_THRESHOLD_IN_TIME_POINTS, | ||
dayBoundariesDateTime | ||
) { | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app, | ||
}) | ||
Object.defineProperty(this, 'eventCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy, | ||
}) | ||
Object.defineProperty(this, 'updateCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy, | ||
}) | ||
Object.defineProperty(this, 'initialY', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialY, | ||
}) | ||
Object.defineProperty(this, 'CHANGE_THRESHOLD_IN_TIME_POINTS', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: CHANGE_THRESHOLD_IN_TIME_POINTS, | ||
}) | ||
Object.defineProperty(this, 'dayBoundariesDateTime', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: dayBoundariesDateTime, | ||
}) | ||
Object.defineProperty(this, 'originalEventEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'lastIntervalDiff', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'lastValidEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '', | ||
}) | ||
Object.defineProperty(this, 'handleMouseMove', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const pixelDiffY = event.clientY - this.initialY | ||
const timePointsDiffY = pixelDiffY * getTimePointsPerPixel(this.$app) | ||
const currentIntervalDiff = Math.round( | ||
timePointsDiffY / this.CHANGE_THRESHOLD_IN_TIME_POINTS | ||
) | ||
const timeDidNotChange = currentIntervalDiff === this.lastIntervalDiff | ||
if (timeDidNotChange) return | ||
this.lastIntervalDiff = currentIntervalDiff | ||
this.setNewTimeForEventEnd( | ||
this.CHANGE_THRESHOLD_IN_TIME_POINTS * currentIntervalDiff | ||
) | ||
}, | ||
}) | ||
Object.defineProperty(this, 'handleMouseUp', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.setNewTimeForEventEnd( | ||
this.CHANGE_THRESHOLD_IN_TIME_POINTS * this.lastIntervalDiff | ||
) | ||
updateEventsList( | ||
this.$app, | ||
this.eventCopy, | ||
this.originalEventEnd, | ||
this.lastValidEnd | ||
) | ||
this.updateCopy(undefined) | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing') | ||
this.$app.elements.calendarWrapper.removeEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate( | ||
this.eventCopy._getExternalEvent() | ||
) | ||
} | ||
}, | ||
}) | ||
this.originalEventEnd = this.eventCopy.end | ||
this.lastValidEnd = this.eventCopy.end | ||
const calendarWrapper = this.$app.elements.calendarWrapper | ||
if (!calendarWrapper) return | ||
calendarWrapper.classList.add('sx__is-resizing') | ||
this.setupEventListeners() | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }) | ||
} | ||
setNewTimeForEventEnd(pointsToAdd) { | ||
const newEnd = addTimePointsToDateTime(this.originalEventEnd, pointsToAdd) | ||
if ( | ||
newEnd > this.dayBoundariesDateTime.end || | ||
newEnd <= this.eventCopy.start | ||
) | ||
return | ||
this.lastValidEnd = newEnd | ||
this.eventCopy.end = this.lastValidEnd | ||
this.updateCopy(this.eventCopy) | ||
} | ||
} | ||
var PluginName; | ||
(function (PluginName) { | ||
PluginName["DragAndDrop"] = "dragAndDrop"; | ||
PluginName["EventModal"] = "eventModal"; | ||
PluginName["ScrollController"] = "scrollController"; | ||
PluginName["EventRecurrence"] = "eventRecurrence"; | ||
PluginName["Resize"] = "resize"; | ||
PluginName["CalendarControls"] = "calendarControls"; | ||
})(PluginName || (PluginName = {})); | ||
var PluginName | ||
;(function (PluginName) { | ||
PluginName['DragAndDrop'] = 'dragAndDrop' | ||
PluginName['EventModal'] = 'eventModal' | ||
PluginName['ScrollController'] = 'scrollController' | ||
PluginName['EventRecurrence'] = 'eventRecurrence' | ||
PluginName['Resize'] = 'resize' | ||
PluginName['CalendarControls'] = 'calendarControls' | ||
})(PluginName || (PluginName = {})) | ||
const getTimeGridDayWidth = ($app) => { | ||
return $app.elements.calendarWrapper.querySelector('.sx__time-grid-day').clientWidth; | ||
}; | ||
return $app.elements.calendarWrapper.querySelector('.sx__time-grid-day') | ||
.clientWidth | ||
} | ||
var WeekDay; | ||
(function (WeekDay) { | ||
WeekDay[WeekDay["SUNDAY"] = 0] = "SUNDAY"; | ||
WeekDay[WeekDay["MONDAY"] = 1] = "MONDAY"; | ||
WeekDay[WeekDay["TUESDAY"] = 2] = "TUESDAY"; | ||
WeekDay[WeekDay["WEDNESDAY"] = 3] = "WEDNESDAY"; | ||
WeekDay[WeekDay["THURSDAY"] = 4] = "THURSDAY"; | ||
WeekDay[WeekDay["FRIDAY"] = 5] = "FRIDAY"; | ||
WeekDay[WeekDay["SATURDAY"] = 6] = "SATURDAY"; | ||
})(WeekDay || (WeekDay = {})); | ||
var WeekDay | ||
;(function (WeekDay) { | ||
WeekDay[(WeekDay['SUNDAY'] = 0)] = 'SUNDAY' | ||
WeekDay[(WeekDay['MONDAY'] = 1)] = 'MONDAY' | ||
WeekDay[(WeekDay['TUESDAY'] = 2)] = 'TUESDAY' | ||
WeekDay[(WeekDay['WEDNESDAY'] = 3)] = 'WEDNESDAY' | ||
WeekDay[(WeekDay['THURSDAY'] = 4)] = 'THURSDAY' | ||
WeekDay[(WeekDay['FRIDAY'] = 5)] = 'FRIDAY' | ||
WeekDay[(WeekDay['SATURDAY'] = 6)] = 'SATURDAY' | ||
})(WeekDay || (WeekDay = {})) | ||
WeekDay.MONDAY; | ||
WeekDay.MONDAY | ||
const addDays = (to, nDays) => { | ||
const { year, month, date, hours, minutes } = toIntegers(to); | ||
const isDateTimeString = hours !== undefined && minutes !== undefined; | ||
const jsDate = new Date(year, month, date, hours !== null && hours !== void 0 ? hours : 0, minutes !== null && minutes !== void 0 ? minutes : 0); | ||
jsDate.setDate(jsDate.getDate() + nDays); | ||
if (isDateTimeString) { | ||
return toDateTimeString(jsDate); | ||
} | ||
return toDateString(jsDate); | ||
}; | ||
const { year, month, date, hours, minutes } = toIntegers(to) | ||
const isDateTimeString = hours !== undefined && minutes !== undefined | ||
const jsDate = new Date( | ||
year, | ||
month, | ||
date, | ||
hours !== null && hours !== void 0 ? hours : 0, | ||
minutes !== null && minutes !== void 0 ? minutes : 0 | ||
) | ||
jsDate.setDate(jsDate.getDate() + nDays) | ||
if (isDateTimeString) { | ||
return toDateTimeString(jsDate) | ||
} | ||
return toDateString(jsDate) | ||
} | ||
class DateGridEventResizer { | ||
constructor($app, eventCopy, updateCopy, initialX) { | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app | ||
}); | ||
Object.defineProperty(this, "eventCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy | ||
}); | ||
Object.defineProperty(this, "updateCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy | ||
}); | ||
Object.defineProperty(this, "initialX", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialX | ||
}); | ||
Object.defineProperty(this, "dayWidth", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "originalEventEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "ORIGINAL_NDAYS", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "lastNDaysDiff", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "handleMouseMove", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const xDifference = event.clientX - this.initialX; | ||
this.lastNDaysDiff = Math.floor(xDifference / this.dayWidth); | ||
this.setNewTimeForEventEnd(); | ||
} | ||
}); | ||
Object.defineProperty(this, "handleMouseUp", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
updateEventsList(this.$app, this.eventCopy, this.originalEventEnd, this.eventCopy.end); | ||
this.updateCopy(undefined); | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing'); | ||
this.$app.elements.calendarWrapper.removeEventListener('mousemove', this.handleMouseMove); | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate(this.eventCopy._getExternalEvent()); | ||
} | ||
} | ||
}); | ||
this.originalEventEnd = eventCopy.end; | ||
this.ORIGINAL_NDAYS = eventCopy._nDaysInGrid || 0; | ||
const calendarWrapper = this.$app.elements.calendarWrapper; | ||
if (!calendarWrapper) | ||
return; | ||
calendarWrapper.classList.add('sx__is-resizing'); | ||
this.dayWidth = getTimeGridDayWidth(this.$app); | ||
this.setupEventListeners(); | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener('mousemove', this.handleMouseMove); | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }); | ||
} | ||
setNewTimeForEventEnd() { | ||
const newEnd = addDays(this.originalEventEnd, this.lastNDaysDiff); | ||
if (newEnd > this.$app.calendarState.range.value.end || | ||
newEnd < this.eventCopy.start || | ||
newEnd < | ||
toDateString(toJSDate(this.$app.calendarState.range.value.start))) | ||
return; | ||
this.eventCopy.end = newEnd; | ||
this.eventCopy._nDaysInGrid = this.ORIGINAL_NDAYS + this.lastNDaysDiff; | ||
this.updateCopy(this.eventCopy); | ||
} | ||
constructor($app, eventCopy, updateCopy, initialX) { | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app, | ||
}) | ||
Object.defineProperty(this, 'eventCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy, | ||
}) | ||
Object.defineProperty(this, 'updateCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy, | ||
}) | ||
Object.defineProperty(this, 'initialX', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialX, | ||
}) | ||
Object.defineProperty(this, 'dayWidth', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'originalEventEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'ORIGINAL_NDAYS', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'lastNDaysDiff', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'handleMouseMove', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const xDifference = event.clientX - this.initialX | ||
this.lastNDaysDiff = Math.floor(xDifference / this.dayWidth) | ||
this.setNewTimeForEventEnd() | ||
}, | ||
}) | ||
Object.defineProperty(this, 'handleMouseUp', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
updateEventsList( | ||
this.$app, | ||
this.eventCopy, | ||
this.originalEventEnd, | ||
this.eventCopy.end | ||
) | ||
this.updateCopy(undefined) | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing') | ||
this.$app.elements.calendarWrapper.removeEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate( | ||
this.eventCopy._getExternalEvent() | ||
) | ||
} | ||
}, | ||
}) | ||
this.originalEventEnd = eventCopy.end | ||
this.ORIGINAL_NDAYS = eventCopy._nDaysInGrid || 0 | ||
const calendarWrapper = this.$app.elements.calendarWrapper | ||
if (!calendarWrapper) return | ||
calendarWrapper.classList.add('sx__is-resizing') | ||
this.dayWidth = getTimeGridDayWidth(this.$app) | ||
this.setupEventListeners() | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }) | ||
} | ||
setNewTimeForEventEnd() { | ||
const newEnd = addDays(this.originalEventEnd, this.lastNDaysDiff) | ||
if ( | ||
newEnd > this.$app.calendarState.range.value.end || | ||
newEnd < this.eventCopy.start || | ||
newEnd < toDateString(toJSDate(this.$app.calendarState.range.value.start)) | ||
) | ||
return | ||
this.eventCopy.end = newEnd | ||
this.eventCopy._nDaysInGrid = this.ORIGINAL_NDAYS + this.lastNDaysDiff | ||
this.updateCopy(this.eventCopy) | ||
} | ||
} | ||
class ResizePluginImpl { | ||
constructor(minutesPerInterval) { | ||
Object.defineProperty(this, "minutesPerInterval", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: minutesPerInterval | ||
}); | ||
Object.defineProperty(this, "name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: PluginName.Resize | ||
}); | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: null | ||
}); | ||
} | ||
init($app) { | ||
this.$app = $app; | ||
} | ||
createTimeGridEventResizer(calendarEvent, updateCopy, mouseDownEvent, dayBoundariesDateTime) { | ||
if (!this.$app) | ||
return this.logError(); | ||
new TimeGridEventResizer(this.$app, calendarEvent, updateCopy, mouseDownEvent.clientY, this.getTimePointsForIntervalConfig(), dayBoundariesDateTime); | ||
} | ||
createDateGridEventResizer(calendarEvent, updateCopy, mouseDownEvent) { | ||
if (!this.$app) | ||
return this.logError(); | ||
new DateGridEventResizer(this.$app, calendarEvent, updateCopy, mouseDownEvent.clientX); | ||
} | ||
getTimePointsForIntervalConfig() { | ||
if (this.minutesPerInterval === 60) | ||
return 100; | ||
if (this.minutesPerInterval === 30) | ||
return 50; | ||
return 25; | ||
} | ||
logError() { | ||
console.error('The calendar is not yet initialized. Cannot resize events.'); | ||
} | ||
constructor(minutesPerInterval) { | ||
Object.defineProperty(this, 'minutesPerInterval', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: minutesPerInterval, | ||
}) | ||
Object.defineProperty(this, 'name', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: PluginName.Resize, | ||
}) | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: null, | ||
}) | ||
} | ||
init($app) { | ||
this.$app = $app | ||
} | ||
createTimeGridEventResizer( | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent, | ||
dayBoundariesDateTime | ||
) { | ||
if (!this.$app) return this.logError() | ||
new TimeGridEventResizer( | ||
this.$app, | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent.clientY, | ||
this.getTimePointsForIntervalConfig(), | ||
dayBoundariesDateTime | ||
) | ||
} | ||
createDateGridEventResizer(calendarEvent, updateCopy, mouseDownEvent) { | ||
if (!this.$app) return this.logError() | ||
new DateGridEventResizer( | ||
this.$app, | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent.clientX | ||
) | ||
} | ||
getTimePointsForIntervalConfig() { | ||
if (this.minutesPerInterval === 60) return 100 | ||
if (this.minutesPerInterval === 30) return 50 | ||
return 25 | ||
} | ||
logError() { | ||
console.error('The calendar is not yet initialized. Cannot resize events.') | ||
} | ||
} | ||
const createResizePlugin = (minutesPerInterval = 15) => new ResizePluginImpl(minutesPerInterval); | ||
const createResizePlugin = (minutesPerInterval = 15) => | ||
new ResizePluginImpl(minutesPerInterval) | ||
exports.createResizePlugin = createResizePlugin; | ||
exports.createResizePlugin = createResizePlugin |
@@ -1,56 +0,56 @@ | ||
import { Signal, ReadonlySignal } from "@preact/signals"; | ||
import { JSXInternal } from "preact/src/jsx"; | ||
import { Signal, ReadonlySignal } from '@preact/signals' | ||
import { JSXInternal } from 'preact/src/jsx' | ||
declare enum WeekDay { | ||
SUNDAY = 0, | ||
MONDAY = 1, | ||
TUESDAY = 2, | ||
WEDNESDAY = 3, | ||
THURSDAY = 4, | ||
FRIDAY = 5, | ||
SATURDAY = 6 | ||
SUNDAY = 0, | ||
MONDAY = 1, | ||
TUESDAY = 2, | ||
WEDNESDAY = 3, | ||
THURSDAY = 4, | ||
FRIDAY = 5, | ||
SATURDAY = 6, | ||
} | ||
type WeekWithDates = Date[]; | ||
type MonthWithDates = Date[][]; | ||
type WeekWithDates = Date[] | ||
type MonthWithDates = Date[][] | ||
declare enum Month { | ||
JANUARY = 0, | ||
FEBRUARY = 1, | ||
MARCH = 2, | ||
APRIL = 3, | ||
MAY = 4, | ||
JUNE = 5, | ||
JULY = 6, | ||
AUGUST = 7, | ||
SEPTEMBER = 8, | ||
OCTOBER = 9, | ||
NOVEMBER = 10, | ||
DECEMBER = 11 | ||
JANUARY = 0, | ||
FEBRUARY = 1, | ||
MARCH = 2, | ||
APRIL = 3, | ||
MAY = 4, | ||
JUNE = 5, | ||
JULY = 6, | ||
AUGUST = 7, | ||
SEPTEMBER = 8, | ||
OCTOBER = 9, | ||
NOVEMBER = 10, | ||
DECEMBER = 11, | ||
} | ||
interface TimeUnits { | ||
firstDayOfWeek: WeekDay; | ||
getMonthWithTrailingAndLeadingDays(year: number, month: Month): MonthWithDates; | ||
getWeekFor(date: Date): WeekWithDates; | ||
getMonthsFor(year: number): Date[]; | ||
firstDayOfWeek: WeekDay | ||
getMonthWithTrailingAndLeadingDays(year: number, month: Month): MonthWithDates | ||
getWeekFor(date: Date): WeekWithDates | ||
getMonthsFor(year: number): Date[] | ||
} | ||
declare enum DatePickerView { | ||
MONTH_DAYS = "month-days", | ||
YEARS = "years" | ||
MONTH_DAYS = 'month-days', | ||
YEARS = 'years', | ||
} | ||
interface DatePickerState { | ||
isOpen: Signal<boolean>; | ||
isDisabled: Signal<boolean>; | ||
selectedDate: Signal<string>; | ||
inputDisplayedValue: Signal<string>; | ||
datePickerDate: Signal<string>; | ||
datePickerView: Signal<DatePickerView>; | ||
inputWrapperElement: Signal<HTMLDivElement | undefined>; | ||
isDark: Signal<boolean>; | ||
open(): void; | ||
close(): void; | ||
toggle(): void; | ||
setView(view: DatePickerView): void; | ||
isOpen: Signal<boolean> | ||
isDisabled: Signal<boolean> | ||
selectedDate: Signal<string> | ||
inputDisplayedValue: Signal<string> | ||
datePickerDate: Signal<string> | ||
datePickerView: Signal<DatePickerView> | ||
inputWrapperElement: Signal<HTMLDivElement | undefined> | ||
isDark: Signal<boolean> | ||
open(): void | ||
close(): void | ||
toggle(): void | ||
setView(view: DatePickerView): void | ||
} | ||
type TranslationVariables = { | ||
[key: string]: string | number; | ||
}; | ||
type TranslateFn = (key: string, variables?: TranslationVariables) => string; | ||
[key: string]: string | number | ||
} | ||
type TranslateFn = (key: string, variables?: TranslationVariables) => string | ||
/** | ||
@@ -60,5 +60,5 @@ * This interface serves as a bridge between the AppSingleton for the date picker and calendar | ||
interface AppSingleton { | ||
timeUnitsImpl: TimeUnits; | ||
datePickerState: DatePickerState; | ||
translate: TranslateFn; | ||
timeUnitsImpl: TimeUnits | ||
datePickerState: DatePickerState | ||
translate: TranslateFn | ||
} | ||
@@ -69,319 +69,350 @@ /** | ||
interface Config { | ||
locale: string; | ||
firstDayOfWeek: WeekDay; | ||
locale: string | ||
firstDayOfWeek: WeekDay | ||
} | ||
declare enum Placement { | ||
TOP_START = "top-start", | ||
TOP_END = "top-end", | ||
BOTTOM_START = "bottom-start", | ||
BOTTOM_END = "bottom-end" | ||
TOP_START = 'top-start', | ||
TOP_END = 'top-end', | ||
BOTTOM_START = 'bottom-start', | ||
BOTTOM_END = 'bottom-end', | ||
} | ||
interface DatePickerAppSingleton extends AppSingleton { | ||
config: DatePickerConfigInternal; | ||
config: DatePickerConfigInternal | ||
} | ||
type DatePickerListeners = { | ||
onChange?: (date: string) => void; | ||
onEscapeKeyDown?: ($app: DatePickerAppSingleton) => void; | ||
}; | ||
onChange?: (date: string) => void | ||
onEscapeKeyDown?: ($app: DatePickerAppSingleton) => void | ||
} | ||
type DatePickerStyle = { | ||
dark?: boolean; | ||
fullWidth?: boolean; | ||
}; | ||
dark?: boolean | ||
fullWidth?: boolean | ||
} | ||
interface DatePickerConfigInternal extends Config { | ||
min: string; | ||
max: string; | ||
placement: Placement; | ||
listeners: DatePickerListeners; | ||
style: DatePickerStyle; | ||
teleportTo?: HTMLElement; | ||
label?: string; | ||
name?: string; | ||
disabled?: boolean; | ||
min: string | ||
max: string | ||
placement: Placement | ||
listeners: DatePickerListeners | ||
style: DatePickerStyle | ||
teleportTo?: HTMLElement | ||
label?: string | ||
name?: string | ||
disabled?: boolean | ||
} | ||
// This enum is used to represent names of all internally built views of the calendar | ||
declare enum InternalViewName { | ||
Day = "day", | ||
Week = "week", | ||
MonthGrid = "month-grid", | ||
MonthAgenda = "month-agenda" | ||
Day = 'day', | ||
Week = 'week', | ||
MonthGrid = 'month-grid', | ||
MonthAgenda = 'month-agenda', | ||
} | ||
// Since implementers can use custom views, we need to have a type that combines the internal views with these custom views | ||
type ViewName = InternalViewName | string; | ||
type ViewName = InternalViewName | string | ||
type DateRange = { | ||
start: string; | ||
end: string; | ||
}; | ||
start: string | ||
end: string | ||
} | ||
interface RangeSetterConfig { | ||
date: string; | ||
timeUnitsImpl: TimeUnits; | ||
calendarConfig: CalendarConfigInternal; | ||
range: Signal<DateRange | null>; | ||
date: string | ||
timeUnitsImpl: TimeUnits | ||
calendarConfig: CalendarConfigInternal | ||
range: Signal<DateRange | null> | ||
} | ||
type PreactViewComponent = (props: { | ||
$app: CalendarAppSingleton; | ||
id: string; | ||
}) => JSXInternal.Element; | ||
declare const addMonths: (to: string, nMonths: number) => string; | ||
declare const addDays: (to: string, nDays: number) => string; | ||
$app: CalendarAppSingleton | ||
id: string | ||
}) => JSXInternal.Element | ||
declare const addMonths: (to: string, nMonths: number) => string | ||
declare const addDays: (to: string, nDays: number) => string | ||
type ViewConfig<FrameworkComponent = PreactViewComponent> = { | ||
/** | ||
* a unique identifier for the view | ||
* */ | ||
name: ViewName; | ||
/** | ||
* text that will be displayed in the view dropdown | ||
* */ | ||
label: string; | ||
/** | ||
* function that is called when a new date is selected | ||
* */ | ||
setDateRange: (config: RangeSetterConfig) => DateRange; | ||
/** | ||
* should the view be displayed on small screens (< 700px calendar width) | ||
* */ | ||
hasSmallScreenCompat: boolean; | ||
/** | ||
* should the view be displayed on wide screens (> 700px calendar width) | ||
* */ | ||
hasWideScreenCompat: boolean; | ||
/** | ||
* The component you want to render | ||
* */ | ||
Component: FrameworkComponent; | ||
/** | ||
* function that is called when the user clicks the backward/forward button | ||
* */ | ||
backwardForwardFn: typeof addDays | typeof addMonths; | ||
/** | ||
* number of units to add into the backwardForwardFn function. Result behind the scenes for example: | ||
* backwardForwardFn = addDays | ||
* backwardForwardUnits = 1 | ||
* result (behind the scenes) = addDays(date, 1) | ||
* */ | ||
backwardForwardUnits: number; | ||
}; | ||
type View<FrameworkComponent = PreactViewComponent> = ViewConfig<FrameworkComponent> & { | ||
render(onElement: HTMLElement, $app: CalendarAppSingleton): void; | ||
destroy(): void; | ||
}; | ||
type EventId = number | string; | ||
type startDate = string; | ||
type nDays = number; | ||
type EventFragments = Record<startDate, nDays>; | ||
/** | ||
* a unique identifier for the view | ||
* */ | ||
name: ViewName | ||
/** | ||
* text that will be displayed in the view dropdown | ||
* */ | ||
label: string | ||
/** | ||
* function that is called when a new date is selected | ||
* */ | ||
setDateRange: (config: RangeSetterConfig) => DateRange | ||
/** | ||
* should the view be displayed on small screens (< 700px calendar width) | ||
* */ | ||
hasSmallScreenCompat: boolean | ||
/** | ||
* should the view be displayed on wide screens (> 700px calendar width) | ||
* */ | ||
hasWideScreenCompat: boolean | ||
/** | ||
* The component you want to render | ||
* */ | ||
Component: FrameworkComponent | ||
/** | ||
* function that is called when the user clicks the backward/forward button | ||
* */ | ||
backwardForwardFn: typeof addDays | typeof addMonths | ||
/** | ||
* number of units to add into the backwardForwardFn function. Result behind the scenes for example: | ||
* backwardForwardFn = addDays | ||
* backwardForwardUnits = 1 | ||
* result (behind the scenes) = addDays(date, 1) | ||
* */ | ||
backwardForwardUnits: number | ||
} | ||
type View<FrameworkComponent = PreactViewComponent> = | ||
ViewConfig<FrameworkComponent> & { | ||
render(onElement: HTMLElement, $app: CalendarAppSingleton): void | ||
destroy(): void | ||
} | ||
type EventId = number | string | ||
type startDate = string | ||
type nDays = number | ||
type EventFragments = Record<startDate, nDays> | ||
type CalendarEventOptions = { | ||
disableDND?: boolean; | ||
disableResize?: boolean; | ||
additionalClasses?: string[]; | ||
}; | ||
disableDND?: boolean | ||
disableResize?: boolean | ||
additionalClasses?: string[] | ||
} | ||
interface CalendarEventExternal { | ||
id: EventId; | ||
start: string; | ||
end: string; | ||
title?: string; | ||
people?: string[]; | ||
location?: string; | ||
description?: string; | ||
calendarId?: string; | ||
_options?: CalendarEventOptions; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: string]: any; | ||
id: EventId | ||
start: string | ||
end: string | ||
title?: string | ||
people?: string[] | ||
location?: string | ||
description?: string | ||
calendarId?: string | ||
_options?: CalendarEventOptions | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: string]: any | ||
} | ||
interface CalendarEventInternal extends CalendarEventExternal { | ||
// event duration | ||
_isSingleDayTimed: boolean; | ||
_isSingleDayFullDay: boolean; | ||
_isSingleHybridDayTimed: boolean; | ||
_isMultiDayTimed: boolean; | ||
_isMultiDayFullDay: boolean; | ||
// week time grid | ||
_previousConcurrentEvents: number | undefined; | ||
_totalConcurrentEvents: number | undefined; | ||
// week date grid | ||
_nDaysInGrid: number | undefined; | ||
// month grid | ||
_eventFragments: EventFragments; | ||
_color: string; | ||
_getForeignProperties(): Record<string, unknown>; | ||
_getExternalEvent(): CalendarEventExternal; | ||
// event duration | ||
_isSingleDayTimed: boolean | ||
_isSingleDayFullDay: boolean | ||
_isSingleHybridDayTimed: boolean | ||
_isMultiDayTimed: boolean | ||
_isMultiDayFullDay: boolean | ||
// week time grid | ||
_previousConcurrentEvents: number | undefined | ||
_totalConcurrentEvents: number | undefined | ||
// week date grid | ||
_nDaysInGrid: number | undefined | ||
// month grid | ||
_eventFragments: EventFragments | ||
_color: string | ||
_getForeignProperties(): Record<string, unknown> | ||
_getExternalEvent(): CalendarEventExternal | ||
} | ||
type DayBoundariesInternal = { | ||
start: number; | ||
end: number; | ||
}; | ||
interface TimeGridDragHandler { | ||
start: number | ||
end: number | ||
} | ||
interface TimeGridDragHandler {} | ||
type DayBoundariesDateTime = { | ||
start: string; | ||
end: string; | ||
}; | ||
interface DateGridDragHandler { | ||
start: string | ||
end: string | ||
} | ||
interface DateGridDragHandler {} | ||
interface EventCoordinates { | ||
clientX: number; | ||
clientY: number; | ||
clientX: number | ||
clientY: number | ||
} | ||
interface DragHandlerDependencies { | ||
$app: CalendarAppSingleton; | ||
eventCoordinates: EventCoordinates; | ||
eventCopy: CalendarEventInternal; | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void; | ||
$app: CalendarAppSingleton | ||
eventCoordinates: EventCoordinates | ||
eventCopy: CalendarEventInternal | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void | ||
} | ||
interface MonthGridDragHandler { | ||
} | ||
interface MonthGridDragHandler {} | ||
interface DragAndDropPlugin extends PluginBase { | ||
createTimeGridDragHandler(dependencies: DragHandlerDependencies, dayBoundariesDateTime: DayBoundariesDateTime): TimeGridDragHandler; | ||
createDateGridDragHandler(dependencies: DragHandlerDependencies): DateGridDragHandler; | ||
createMonthGridDragHandler(calendarEvent: CalendarEventInternal, $app: CalendarAppSingleton): MonthGridDragHandler; | ||
createTimeGridDragHandler( | ||
dependencies: DragHandlerDependencies, | ||
dayBoundariesDateTime: DayBoundariesDateTime | ||
): TimeGridDragHandler | ||
createDateGridDragHandler( | ||
dependencies: DragHandlerDependencies | ||
): DateGridDragHandler | ||
createMonthGridDragHandler( | ||
calendarEvent: CalendarEventInternal, | ||
$app: CalendarAppSingleton | ||
): MonthGridDragHandler | ||
} | ||
type EventModalProps = { | ||
$app: CalendarAppSingleton; | ||
}; | ||
$app: CalendarAppSingleton | ||
} | ||
interface EventModalPlugin extends PluginBase { | ||
calendarEvent: Signal<CalendarEventInternal | null>; | ||
calendarEventDOMRect: Signal<DOMRect | null>; | ||
calendarEventElement: Signal<HTMLElement | null>; | ||
close(): void; | ||
setCalendarEvent(event: CalendarEventInternal | null, eventTargetDOMRect: DOMRect | null): void; | ||
ComponentFn(props: EventModalProps): JSXInternal.Element; | ||
calendarEvent: Signal<CalendarEventInternal | null> | ||
calendarEventDOMRect: Signal<DOMRect | null> | ||
calendarEventElement: Signal<HTMLElement | null> | ||
close(): void | ||
setCalendarEvent( | ||
event: CalendarEventInternal | null, | ||
eventTargetDOMRect: DOMRect | null | ||
): void | ||
ComponentFn(props: EventModalProps): JSXInternal.Element | ||
} | ||
interface CalendarCallbacks { | ||
onEventUpdate?: (event: CalendarEventExternal) => void; | ||
onEventClick?: (event: CalendarEventExternal) => void; | ||
onRangeUpdate?: (range: DateRange) => void; | ||
onSelectedDateUpdate?: (date: string) => void; | ||
onClickDate?: (date: string) => void; | ||
onDoubleClickDate?: (date: string) => void; | ||
onClickDateTime?: (dateTime: string) => void; | ||
onDoubleClickDateTime?: (dateTime: string) => void; | ||
onClickAgendaDate?: (date: string) => void; | ||
onClickPlusEvents?: (date: string) => void; | ||
isCalendarSmall?: ($app: CalendarAppSingleton) => boolean; | ||
onEventUpdate?: (event: CalendarEventExternal) => void | ||
onEventClick?: (event: CalendarEventExternal) => void | ||
onRangeUpdate?: (range: DateRange) => void | ||
onSelectedDateUpdate?: (date: string) => void | ||
onClickDate?: (date: string) => void | ||
onDoubleClickDate?: (date: string) => void | ||
onClickDateTime?: (dateTime: string) => void | ||
onDoubleClickDateTime?: (dateTime: string) => void | ||
onClickAgendaDate?: (date: string) => void | ||
onClickPlusEvents?: (date: string) => void | ||
isCalendarSmall?: ($app: CalendarAppSingleton) => boolean | ||
} | ||
type CustomComponentFns = { | ||
timeGridEvent?: CustomComponentFn; | ||
dateGridEvent?: CustomComponentFn; | ||
monthGridEvent?: CustomComponentFn; | ||
monthAgendaEvent?: CustomComponentFn; | ||
eventModal?: CustomComponentFn; | ||
headerContentLeftPrepend?: CustomComponentFn; | ||
headerContentLeftAppend?: CustomComponentFn; | ||
headerContentRightPrepend?: CustomComponentFn; | ||
headerContentRightAppend?: CustomComponentFn; | ||
}; | ||
timeGridEvent?: CustomComponentFn | ||
dateGridEvent?: CustomComponentFn | ||
monthGridEvent?: CustomComponentFn | ||
monthAgendaEvent?: CustomComponentFn | ||
eventModal?: CustomComponentFn | ||
headerContentLeftPrepend?: CustomComponentFn | ||
headerContentLeftAppend?: CustomComponentFn | ||
headerContentRightPrepend?: CustomComponentFn | ||
headerContentRightAppend?: CustomComponentFn | ||
} | ||
interface EventsFacade { | ||
get(id: EventId): CalendarEventExternal | undefined; | ||
getAll(): CalendarEventExternal[]; | ||
add(event: CalendarEventExternal): void; | ||
update(event: CalendarEventExternal): void; | ||
remove(id: EventId): void; | ||
set(events: CalendarEventExternal[]): void; | ||
get(id: EventId): CalendarEventExternal | undefined | ||
getAll(): CalendarEventExternal[] | ||
add(event: CalendarEventExternal): void | ||
update(event: CalendarEventExternal): void | ||
remove(id: EventId): void | ||
set(events: CalendarEventExternal[]): void | ||
} | ||
interface EventRecurrencePlugin extends PluginBase { | ||
updateRecurrenceDND(eventId: EventId, oldEventStart: string, newEventStart: string): void; | ||
updateRecurrenceOnResize(eventId: EventId, oldEventEnd: string, newEventEnd: string): void; | ||
eventsFacade: EventsFacade; | ||
updateRecurrenceDND( | ||
eventId: EventId, | ||
oldEventStart: string, | ||
newEventStart: string | ||
): void | ||
updateRecurrenceOnResize( | ||
eventId: EventId, | ||
oldEventEnd: string, | ||
newEventEnd: string | ||
): void | ||
eventsFacade: EventsFacade | ||
} | ||
type WeekOptions = { | ||
gridHeight: number; | ||
nDays: number; | ||
eventWidth: number; | ||
}; | ||
gridHeight: number | ||
nDays: number | ||
eventWidth: number | ||
} | ||
type MonthGridOptions = { | ||
nEventsPerDay: number; | ||
}; | ||
nEventsPerDay: number | ||
} | ||
type ColorDefinition = { | ||
main: string; | ||
container: string; | ||
onContainer: string; | ||
}; | ||
main: string | ||
container: string | ||
onContainer: string | ||
} | ||
type CalendarType = { | ||
colorName: string; | ||
label?: string; | ||
lightColors?: ColorDefinition; | ||
darkColors?: ColorDefinition; | ||
}; | ||
colorName: string | ||
label?: string | ||
lightColors?: ColorDefinition | ||
darkColors?: ColorDefinition | ||
} | ||
type Plugins = { | ||
dragAndDrop?: DragAndDropPlugin; | ||
eventModal?: EventModalPlugin; | ||
scrollController?: PluginBase; | ||
eventRecurrence?: EventRecurrencePlugin; | ||
resize?: ResizePlugin; | ||
[key: string]: PluginBase | undefined; | ||
}; | ||
type CustomComponentFn = (wrapperElement: HTMLElement, props: Record<string, unknown>) => void; | ||
dragAndDrop?: DragAndDropPlugin | ||
eventModal?: EventModalPlugin | ||
scrollController?: PluginBase | ||
eventRecurrence?: EventRecurrencePlugin | ||
resize?: ResizePlugin | ||
[key: string]: PluginBase | undefined | ||
} | ||
type CustomComponentFn = ( | ||
wrapperElement: HTMLElement, | ||
props: Record<string, unknown> | ||
) => void | ||
interface CalendarConfigInternal extends Config { | ||
defaultView: ViewName; | ||
views: View[]; | ||
dayBoundaries: DayBoundariesInternal; | ||
weekOptions: WeekOptions; | ||
monthGridOptions: MonthGridOptions; | ||
calendars: Signal<Record<string, CalendarType>>; | ||
plugins: Plugins; | ||
isDark: boolean; | ||
isResponsive: boolean; | ||
callbacks: CalendarCallbacks; | ||
_customComponentFns: CustomComponentFns; | ||
minDate?: string; | ||
maxDate?: string; | ||
// Getters | ||
isHybridDay: boolean; | ||
timePointsPerDay: number; | ||
defaultView: ViewName | ||
views: View[] | ||
dayBoundaries: DayBoundariesInternal | ||
weekOptions: WeekOptions | ||
monthGridOptions: MonthGridOptions | ||
calendars: Signal<Record<string, CalendarType>> | ||
plugins: Plugins | ||
isDark: boolean | ||
isResponsive: boolean | ||
callbacks: CalendarCallbacks | ||
_customComponentFns: CustomComponentFns | ||
minDate?: string | ||
maxDate?: string | ||
// Getters | ||
isHybridDay: boolean | ||
timePointsPerDay: number | ||
} | ||
interface CalendarState { | ||
isCalendarSmall: Signal<boolean | undefined>; | ||
view: ReadonlySignal<ViewName>; | ||
setView: (view: ViewName, selectedDate: string) => void; | ||
range: Signal<DateRange | null>; | ||
isDark: Signal<boolean>; | ||
setRange: (date: string) => void; | ||
isCalendarSmall: Signal<boolean | undefined> | ||
view: ReadonlySignal<ViewName> | ||
setView: (view: ViewName, selectedDate: string) => void | ||
range: Signal<DateRange | null> | ||
isDark: Signal<boolean> | ||
setRange: (date: string) => void | ||
} | ||
type EventsFilterPredicate = ((event: CalendarEventInternal) => boolean) | undefined; | ||
type EventsFilterPredicate = | ||
| ((event: CalendarEventInternal) => boolean) | ||
| undefined | ||
interface CalendarEvents { | ||
list: Signal<CalendarEventInternal[]>; | ||
filterPredicate: Signal<EventsFilterPredicate>; | ||
list: Signal<CalendarEventInternal[]> | ||
filterPredicate: Signal<EventsFilterPredicate> | ||
} | ||
interface CalendarElements { | ||
calendarWrapper: HTMLDivElement | undefined; | ||
calendarWrapper: HTMLDivElement | undefined | ||
} | ||
interface CalendarAppSingleton extends AppSingleton { | ||
config: CalendarConfigInternal; | ||
datePickerConfig: DatePickerConfigInternal; | ||
calendarState: CalendarState; | ||
calendarEvents: CalendarEvents; | ||
elements: CalendarElements; | ||
config: CalendarConfigInternal | ||
datePickerConfig: DatePickerConfigInternal | ||
calendarState: CalendarState | ||
calendarEvents: CalendarEvents | ||
elements: CalendarElements | ||
} | ||
interface PluginBase { | ||
name: string; | ||
// TODO v2: change to `beforeRender` | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
beforeInit?($app: CalendarAppSingleton | any): void; | ||
// TODO v2: change to `onRender` and remove $app parameter | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
init?($app: CalendarAppSingleton | any): void; | ||
destroy?(): void; | ||
name: string | ||
// TODO v2: change to `beforeRender` | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
beforeInit?($app: CalendarAppSingleton | any): void | ||
// TODO v2: change to `onRender` and remove $app parameter | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
init?($app: CalendarAppSingleton | any): void | ||
destroy?(): void | ||
} | ||
interface ResizePlugin extends PluginBase { | ||
createTimeGridEventResizer(calendarEvent: CalendarEventInternal, updateCopy: (newCopy: CalendarEventInternal | undefined) => void, mouseDownEvent: MouseEvent, dayBoundariesDateTime: { | ||
start: string; | ||
end: string; | ||
}): void; | ||
createDateGridEventResizer(calendarEvent: CalendarEventInternal, updateCopy: (newCopy: CalendarEventInternal | undefined) => void, mouseDownEvent: MouseEvent): void; | ||
createTimeGridEventResizer( | ||
calendarEvent: CalendarEventInternal, | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void, | ||
mouseDownEvent: MouseEvent, | ||
dayBoundariesDateTime: { | ||
start: string | ||
end: string | ||
} | ||
): void | ||
createDateGridEventResizer( | ||
calendarEvent: CalendarEventInternal, | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void, | ||
mouseDownEvent: MouseEvent | ||
): void | ||
} | ||
declare const createResizePlugin: (minutesPerInterval?: number) => ResizePlugin; | ||
export { createResizePlugin }; | ||
declare const createResizePlugin: (minutesPerInterval?: number) => ResizePlugin | ||
export { createResizePlugin } |
763
dist/core.js
@@ -1,387 +0,458 @@ | ||
import 'preact/jsx-runtime'; | ||
import 'preact/jsx-runtime' | ||
const getTimePointsPerPixel = ($app) => { | ||
return $app.config.timePointsPerDay / $app.config.weekOptions.gridHeight; | ||
}; | ||
return $app.config.timePointsPerDay / $app.config.weekOptions.gridHeight | ||
} | ||
const DateFormats = { | ||
DATE_STRING: /^\d{4}-\d{2}-\d{2}$/, | ||
TIME_STRING: /^\d{2}:\d{2}$/, | ||
DATE_TIME_STRING: /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, | ||
}; | ||
DATE_STRING: /^\d{4}-\d{2}-\d{2}$/, | ||
TIME_STRING: /^\d{2}:\d{2}$/, | ||
DATE_TIME_STRING: /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, | ||
} | ||
class InvalidDateTimeError extends Error { | ||
constructor(dateTimeSpecification) { | ||
super(`Invalid date time specification: ${dateTimeSpecification}`); | ||
} | ||
constructor(dateTimeSpecification) { | ||
super(`Invalid date time specification: ${dateTimeSpecification}`) | ||
} | ||
} | ||
const toJSDate = (dateTimeSpecification) => { | ||
if (!DateFormats.DATE_TIME_STRING.test(dateTimeSpecification) && | ||
!DateFormats.DATE_STRING.test(dateTimeSpecification)) | ||
throw new InvalidDateTimeError(dateTimeSpecification); | ||
return new Date(Number(dateTimeSpecification.slice(0, 4)), Number(dateTimeSpecification.slice(5, 7)) - 1, Number(dateTimeSpecification.slice(8, 10)), Number(dateTimeSpecification.slice(11, 13)), // for date strings this will be 0 | ||
if ( | ||
!DateFormats.DATE_TIME_STRING.test(dateTimeSpecification) && | ||
!DateFormats.DATE_STRING.test(dateTimeSpecification) | ||
) | ||
throw new InvalidDateTimeError(dateTimeSpecification) | ||
return new Date( | ||
Number(dateTimeSpecification.slice(0, 4)), | ||
Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
Number(dateTimeSpecification.slice(8, 10)), | ||
Number(dateTimeSpecification.slice(11, 13)), // for date strings this will be 0 | ||
Number(dateTimeSpecification.slice(14, 16)) // for date strings this will be 0 | ||
); | ||
}; | ||
) | ||
} | ||
const toIntegers = (dateTimeSpecification) => { | ||
const hours = dateTimeSpecification.slice(11, 13), minutes = dateTimeSpecification.slice(14, 16); | ||
return { | ||
year: Number(dateTimeSpecification.slice(0, 4)), | ||
month: Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
date: Number(dateTimeSpecification.slice(8, 10)), | ||
hours: hours !== '' ? Number(hours) : undefined, | ||
minutes: minutes !== '' ? Number(minutes) : undefined, | ||
}; | ||
}; | ||
const hours = dateTimeSpecification.slice(11, 13), | ||
minutes = dateTimeSpecification.slice(14, 16) | ||
return { | ||
year: Number(dateTimeSpecification.slice(0, 4)), | ||
month: Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
date: Number(dateTimeSpecification.slice(8, 10)), | ||
hours: hours !== '' ? Number(hours) : undefined, | ||
minutes: minutes !== '' ? Number(minutes) : undefined, | ||
} | ||
} | ||
class NumberRangeError extends Error { | ||
constructor(min, max) { | ||
super(`Number must be between ${min} and ${max}.`); | ||
Object.defineProperty(this, "min", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: min | ||
}); | ||
Object.defineProperty(this, "max", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: max | ||
}); | ||
} | ||
constructor(min, max) { | ||
super(`Number must be between ${min} and ${max}.`) | ||
Object.defineProperty(this, 'min', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: min, | ||
}) | ||
Object.defineProperty(this, 'max', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: max, | ||
}) | ||
} | ||
} | ||
const doubleDigit = (number) => { | ||
if (number < 0 || number > 99) | ||
throw new NumberRangeError(0, 99); | ||
return String(number).padStart(2, '0'); | ||
}; | ||
if (number < 0 || number > 99) throw new NumberRangeError(0, 99) | ||
return String(number).padStart(2, '0') | ||
} | ||
const toDateString = (date) => { | ||
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())}`; | ||
}; | ||
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())}` | ||
} | ||
const toTimeString = (date) => { | ||
return `${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}`; | ||
}; | ||
return `${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}` | ||
} | ||
const toDateTimeString = (date) => { | ||
return `${toDateString(date)} ${toTimeString(date)}`; | ||
}; | ||
return `${toDateString(date)} ${toTimeString(date)}` | ||
} | ||
const minuteTimePointMultiplier = 1.6666666666666667; // 100 / 60 | ||
const minuteTimePointMultiplier = 1.6666666666666667 // 100 / 60 | ||
const addTimePointsToDateTime = (dateTimeString, pointsToAdd) => { | ||
const minutesToAdd = pointsToAdd / minuteTimePointMultiplier; | ||
const jsDate = toJSDate(dateTimeString); | ||
jsDate.setMinutes(jsDate.getMinutes() + minutesToAdd); | ||
return toDateTimeString(jsDate); | ||
}; | ||
const minutesToAdd = pointsToAdd / minuteTimePointMultiplier | ||
const jsDate = toJSDate(dateTimeString) | ||
jsDate.setMinutes(jsDate.getMinutes() + minutesToAdd) | ||
return toDateTimeString(jsDate) | ||
} | ||
const updateEventsList = ($app, eventCopy, oldEventEnd, newEventEnd) => { | ||
const rrule = eventCopy._getForeignProperties().rrule; | ||
if (rrule && $app.config.plugins.eventRecurrence) { | ||
$app.config.plugins.eventRecurrence.updateRecurrenceOnResize(eventCopy.id, oldEventEnd, newEventEnd); | ||
return; | ||
} | ||
const eventToUpdate = $app.calendarEvents.list.value.find((event) => event.id === eventCopy.id); | ||
if (!eventToUpdate) | ||
return; | ||
eventToUpdate.end = eventCopy.end; | ||
$app.calendarEvents.list.value = [...$app.calendarEvents.list.value]; | ||
}; | ||
const rrule = eventCopy._getForeignProperties().rrule | ||
if (rrule && $app.config.plugins.eventRecurrence) { | ||
$app.config.plugins.eventRecurrence.updateRecurrenceOnResize( | ||
eventCopy.id, | ||
oldEventEnd, | ||
newEventEnd | ||
) | ||
return | ||
} | ||
const eventToUpdate = $app.calendarEvents.list.value.find( | ||
(event) => event.id === eventCopy.id | ||
) | ||
if (!eventToUpdate) return | ||
eventToUpdate.end = eventCopy.end | ||
$app.calendarEvents.list.value = [...$app.calendarEvents.list.value] | ||
} | ||
class TimeGridEventResizer { | ||
constructor($app, eventCopy, updateCopy, initialY, CHANGE_THRESHOLD_IN_TIME_POINTS, dayBoundariesDateTime) { | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app | ||
}); | ||
Object.defineProperty(this, "eventCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy | ||
}); | ||
Object.defineProperty(this, "updateCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy | ||
}); | ||
Object.defineProperty(this, "initialY", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialY | ||
}); | ||
Object.defineProperty(this, "CHANGE_THRESHOLD_IN_TIME_POINTS", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: CHANGE_THRESHOLD_IN_TIME_POINTS | ||
}); | ||
Object.defineProperty(this, "dayBoundariesDateTime", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: dayBoundariesDateTime | ||
}); | ||
Object.defineProperty(this, "originalEventEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "lastIntervalDiff", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "lastValidEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '' | ||
}); | ||
Object.defineProperty(this, "handleMouseMove", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const pixelDiffY = event.clientY - this.initialY; | ||
const timePointsDiffY = pixelDiffY * getTimePointsPerPixel(this.$app); | ||
const currentIntervalDiff = Math.round(timePointsDiffY / this.CHANGE_THRESHOLD_IN_TIME_POINTS); | ||
const timeDidNotChange = currentIntervalDiff === this.lastIntervalDiff; | ||
if (timeDidNotChange) | ||
return; | ||
this.lastIntervalDiff = currentIntervalDiff; | ||
this.setNewTimeForEventEnd(this.CHANGE_THRESHOLD_IN_TIME_POINTS * currentIntervalDiff); | ||
} | ||
}); | ||
Object.defineProperty(this, "handleMouseUp", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.setNewTimeForEventEnd(this.CHANGE_THRESHOLD_IN_TIME_POINTS * this.lastIntervalDiff); | ||
updateEventsList(this.$app, this.eventCopy, this.originalEventEnd, this.lastValidEnd); | ||
this.updateCopy(undefined); | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing'); | ||
this.$app.elements.calendarWrapper.removeEventListener('mousemove', this.handleMouseMove); | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate(this.eventCopy._getExternalEvent()); | ||
} | ||
} | ||
}); | ||
this.originalEventEnd = this.eventCopy.end; | ||
this.lastValidEnd = this.eventCopy.end; | ||
const calendarWrapper = this.$app.elements.calendarWrapper; | ||
if (!calendarWrapper) | ||
return; | ||
calendarWrapper.classList.add('sx__is-resizing'); | ||
this.setupEventListeners(); | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener('mousemove', this.handleMouseMove); | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }); | ||
} | ||
setNewTimeForEventEnd(pointsToAdd) { | ||
const newEnd = addTimePointsToDateTime(this.originalEventEnd, pointsToAdd); | ||
if (newEnd > this.dayBoundariesDateTime.end || | ||
newEnd <= this.eventCopy.start) | ||
return; | ||
this.lastValidEnd = newEnd; | ||
this.eventCopy.end = this.lastValidEnd; | ||
this.updateCopy(this.eventCopy); | ||
} | ||
constructor( | ||
$app, | ||
eventCopy, | ||
updateCopy, | ||
initialY, | ||
CHANGE_THRESHOLD_IN_TIME_POINTS, | ||
dayBoundariesDateTime | ||
) { | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app, | ||
}) | ||
Object.defineProperty(this, 'eventCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy, | ||
}) | ||
Object.defineProperty(this, 'updateCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy, | ||
}) | ||
Object.defineProperty(this, 'initialY', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialY, | ||
}) | ||
Object.defineProperty(this, 'CHANGE_THRESHOLD_IN_TIME_POINTS', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: CHANGE_THRESHOLD_IN_TIME_POINTS, | ||
}) | ||
Object.defineProperty(this, 'dayBoundariesDateTime', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: dayBoundariesDateTime, | ||
}) | ||
Object.defineProperty(this, 'originalEventEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'lastIntervalDiff', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'lastValidEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '', | ||
}) | ||
Object.defineProperty(this, 'handleMouseMove', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const pixelDiffY = event.clientY - this.initialY | ||
const timePointsDiffY = pixelDiffY * getTimePointsPerPixel(this.$app) | ||
const currentIntervalDiff = Math.round( | ||
timePointsDiffY / this.CHANGE_THRESHOLD_IN_TIME_POINTS | ||
) | ||
const timeDidNotChange = currentIntervalDiff === this.lastIntervalDiff | ||
if (timeDidNotChange) return | ||
this.lastIntervalDiff = currentIntervalDiff | ||
this.setNewTimeForEventEnd( | ||
this.CHANGE_THRESHOLD_IN_TIME_POINTS * currentIntervalDiff | ||
) | ||
}, | ||
}) | ||
Object.defineProperty(this, 'handleMouseUp', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.setNewTimeForEventEnd( | ||
this.CHANGE_THRESHOLD_IN_TIME_POINTS * this.lastIntervalDiff | ||
) | ||
updateEventsList( | ||
this.$app, | ||
this.eventCopy, | ||
this.originalEventEnd, | ||
this.lastValidEnd | ||
) | ||
this.updateCopy(undefined) | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing') | ||
this.$app.elements.calendarWrapper.removeEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate( | ||
this.eventCopy._getExternalEvent() | ||
) | ||
} | ||
}, | ||
}) | ||
this.originalEventEnd = this.eventCopy.end | ||
this.lastValidEnd = this.eventCopy.end | ||
const calendarWrapper = this.$app.elements.calendarWrapper | ||
if (!calendarWrapper) return | ||
calendarWrapper.classList.add('sx__is-resizing') | ||
this.setupEventListeners() | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }) | ||
} | ||
setNewTimeForEventEnd(pointsToAdd) { | ||
const newEnd = addTimePointsToDateTime(this.originalEventEnd, pointsToAdd) | ||
if ( | ||
newEnd > this.dayBoundariesDateTime.end || | ||
newEnd <= this.eventCopy.start | ||
) | ||
return | ||
this.lastValidEnd = newEnd | ||
this.eventCopy.end = this.lastValidEnd | ||
this.updateCopy(this.eventCopy) | ||
} | ||
} | ||
var PluginName; | ||
(function (PluginName) { | ||
PluginName["DragAndDrop"] = "dragAndDrop"; | ||
PluginName["EventModal"] = "eventModal"; | ||
PluginName["ScrollController"] = "scrollController"; | ||
PluginName["EventRecurrence"] = "eventRecurrence"; | ||
PluginName["Resize"] = "resize"; | ||
PluginName["CalendarControls"] = "calendarControls"; | ||
})(PluginName || (PluginName = {})); | ||
var PluginName | ||
;(function (PluginName) { | ||
PluginName['DragAndDrop'] = 'dragAndDrop' | ||
PluginName['EventModal'] = 'eventModal' | ||
PluginName['ScrollController'] = 'scrollController' | ||
PluginName['EventRecurrence'] = 'eventRecurrence' | ||
PluginName['Resize'] = 'resize' | ||
PluginName['CalendarControls'] = 'calendarControls' | ||
})(PluginName || (PluginName = {})) | ||
const getTimeGridDayWidth = ($app) => { | ||
return $app.elements.calendarWrapper.querySelector('.sx__time-grid-day').clientWidth; | ||
}; | ||
return $app.elements.calendarWrapper.querySelector('.sx__time-grid-day') | ||
.clientWidth | ||
} | ||
var WeekDay; | ||
(function (WeekDay) { | ||
WeekDay[WeekDay["SUNDAY"] = 0] = "SUNDAY"; | ||
WeekDay[WeekDay["MONDAY"] = 1] = "MONDAY"; | ||
WeekDay[WeekDay["TUESDAY"] = 2] = "TUESDAY"; | ||
WeekDay[WeekDay["WEDNESDAY"] = 3] = "WEDNESDAY"; | ||
WeekDay[WeekDay["THURSDAY"] = 4] = "THURSDAY"; | ||
WeekDay[WeekDay["FRIDAY"] = 5] = "FRIDAY"; | ||
WeekDay[WeekDay["SATURDAY"] = 6] = "SATURDAY"; | ||
})(WeekDay || (WeekDay = {})); | ||
var WeekDay | ||
;(function (WeekDay) { | ||
WeekDay[(WeekDay['SUNDAY'] = 0)] = 'SUNDAY' | ||
WeekDay[(WeekDay['MONDAY'] = 1)] = 'MONDAY' | ||
WeekDay[(WeekDay['TUESDAY'] = 2)] = 'TUESDAY' | ||
WeekDay[(WeekDay['WEDNESDAY'] = 3)] = 'WEDNESDAY' | ||
WeekDay[(WeekDay['THURSDAY'] = 4)] = 'THURSDAY' | ||
WeekDay[(WeekDay['FRIDAY'] = 5)] = 'FRIDAY' | ||
WeekDay[(WeekDay['SATURDAY'] = 6)] = 'SATURDAY' | ||
})(WeekDay || (WeekDay = {})) | ||
WeekDay.MONDAY; | ||
WeekDay.MONDAY | ||
const addDays = (to, nDays) => { | ||
const { year, month, date, hours, minutes } = toIntegers(to); | ||
const isDateTimeString = hours !== undefined && minutes !== undefined; | ||
const jsDate = new Date(year, month, date, hours !== null && hours !== void 0 ? hours : 0, minutes !== null && minutes !== void 0 ? minutes : 0); | ||
jsDate.setDate(jsDate.getDate() + nDays); | ||
if (isDateTimeString) { | ||
return toDateTimeString(jsDate); | ||
} | ||
return toDateString(jsDate); | ||
}; | ||
const { year, month, date, hours, minutes } = toIntegers(to) | ||
const isDateTimeString = hours !== undefined && minutes !== undefined | ||
const jsDate = new Date( | ||
year, | ||
month, | ||
date, | ||
hours !== null && hours !== void 0 ? hours : 0, | ||
minutes !== null && minutes !== void 0 ? minutes : 0 | ||
) | ||
jsDate.setDate(jsDate.getDate() + nDays) | ||
if (isDateTimeString) { | ||
return toDateTimeString(jsDate) | ||
} | ||
return toDateString(jsDate) | ||
} | ||
class DateGridEventResizer { | ||
constructor($app, eventCopy, updateCopy, initialX) { | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app | ||
}); | ||
Object.defineProperty(this, "eventCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy | ||
}); | ||
Object.defineProperty(this, "updateCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy | ||
}); | ||
Object.defineProperty(this, "initialX", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialX | ||
}); | ||
Object.defineProperty(this, "dayWidth", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "originalEventEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "ORIGINAL_NDAYS", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "lastNDaysDiff", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "handleMouseMove", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const xDifference = event.clientX - this.initialX; | ||
this.lastNDaysDiff = Math.floor(xDifference / this.dayWidth); | ||
this.setNewTimeForEventEnd(); | ||
} | ||
}); | ||
Object.defineProperty(this, "handleMouseUp", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
updateEventsList(this.$app, this.eventCopy, this.originalEventEnd, this.eventCopy.end); | ||
this.updateCopy(undefined); | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing'); | ||
this.$app.elements.calendarWrapper.removeEventListener('mousemove', this.handleMouseMove); | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate(this.eventCopy._getExternalEvent()); | ||
} | ||
} | ||
}); | ||
this.originalEventEnd = eventCopy.end; | ||
this.ORIGINAL_NDAYS = eventCopy._nDaysInGrid || 0; | ||
const calendarWrapper = this.$app.elements.calendarWrapper; | ||
if (!calendarWrapper) | ||
return; | ||
calendarWrapper.classList.add('sx__is-resizing'); | ||
this.dayWidth = getTimeGridDayWidth(this.$app); | ||
this.setupEventListeners(); | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener('mousemove', this.handleMouseMove); | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }); | ||
} | ||
setNewTimeForEventEnd() { | ||
const newEnd = addDays(this.originalEventEnd, this.lastNDaysDiff); | ||
if (newEnd > this.$app.calendarState.range.value.end || | ||
newEnd < this.eventCopy.start || | ||
newEnd < | ||
toDateString(toJSDate(this.$app.calendarState.range.value.start))) | ||
return; | ||
this.eventCopy.end = newEnd; | ||
this.eventCopy._nDaysInGrid = this.ORIGINAL_NDAYS + this.lastNDaysDiff; | ||
this.updateCopy(this.eventCopy); | ||
} | ||
constructor($app, eventCopy, updateCopy, initialX) { | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app, | ||
}) | ||
Object.defineProperty(this, 'eventCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy, | ||
}) | ||
Object.defineProperty(this, 'updateCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy, | ||
}) | ||
Object.defineProperty(this, 'initialX', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialX, | ||
}) | ||
Object.defineProperty(this, 'dayWidth', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'originalEventEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'ORIGINAL_NDAYS', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'lastNDaysDiff', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'handleMouseMove', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const xDifference = event.clientX - this.initialX | ||
this.lastNDaysDiff = Math.floor(xDifference / this.dayWidth) | ||
this.setNewTimeForEventEnd() | ||
}, | ||
}) | ||
Object.defineProperty(this, 'handleMouseUp', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
updateEventsList( | ||
this.$app, | ||
this.eventCopy, | ||
this.originalEventEnd, | ||
this.eventCopy.end | ||
) | ||
this.updateCopy(undefined) | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing') | ||
this.$app.elements.calendarWrapper.removeEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate( | ||
this.eventCopy._getExternalEvent() | ||
) | ||
} | ||
}, | ||
}) | ||
this.originalEventEnd = eventCopy.end | ||
this.ORIGINAL_NDAYS = eventCopy._nDaysInGrid || 0 | ||
const calendarWrapper = this.$app.elements.calendarWrapper | ||
if (!calendarWrapper) return | ||
calendarWrapper.classList.add('sx__is-resizing') | ||
this.dayWidth = getTimeGridDayWidth(this.$app) | ||
this.setupEventListeners() | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }) | ||
} | ||
setNewTimeForEventEnd() { | ||
const newEnd = addDays(this.originalEventEnd, this.lastNDaysDiff) | ||
if ( | ||
newEnd > this.$app.calendarState.range.value.end || | ||
newEnd < this.eventCopy.start || | ||
newEnd < toDateString(toJSDate(this.$app.calendarState.range.value.start)) | ||
) | ||
return | ||
this.eventCopy.end = newEnd | ||
this.eventCopy._nDaysInGrid = this.ORIGINAL_NDAYS + this.lastNDaysDiff | ||
this.updateCopy(this.eventCopy) | ||
} | ||
} | ||
class ResizePluginImpl { | ||
constructor(minutesPerInterval) { | ||
Object.defineProperty(this, "minutesPerInterval", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: minutesPerInterval | ||
}); | ||
Object.defineProperty(this, "name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: PluginName.Resize | ||
}); | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: null | ||
}); | ||
} | ||
init($app) { | ||
this.$app = $app; | ||
} | ||
createTimeGridEventResizer(calendarEvent, updateCopy, mouseDownEvent, dayBoundariesDateTime) { | ||
if (!this.$app) | ||
return this.logError(); | ||
new TimeGridEventResizer(this.$app, calendarEvent, updateCopy, mouseDownEvent.clientY, this.getTimePointsForIntervalConfig(), dayBoundariesDateTime); | ||
} | ||
createDateGridEventResizer(calendarEvent, updateCopy, mouseDownEvent) { | ||
if (!this.$app) | ||
return this.logError(); | ||
new DateGridEventResizer(this.$app, calendarEvent, updateCopy, mouseDownEvent.clientX); | ||
} | ||
getTimePointsForIntervalConfig() { | ||
if (this.minutesPerInterval === 60) | ||
return 100; | ||
if (this.minutesPerInterval === 30) | ||
return 50; | ||
return 25; | ||
} | ||
logError() { | ||
console.error('The calendar is not yet initialized. Cannot resize events.'); | ||
} | ||
constructor(minutesPerInterval) { | ||
Object.defineProperty(this, 'minutesPerInterval', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: minutesPerInterval, | ||
}) | ||
Object.defineProperty(this, 'name', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: PluginName.Resize, | ||
}) | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: null, | ||
}) | ||
} | ||
init($app) { | ||
this.$app = $app | ||
} | ||
createTimeGridEventResizer( | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent, | ||
dayBoundariesDateTime | ||
) { | ||
if (!this.$app) return this.logError() | ||
new TimeGridEventResizer( | ||
this.$app, | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent.clientY, | ||
this.getTimePointsForIntervalConfig(), | ||
dayBoundariesDateTime | ||
) | ||
} | ||
createDateGridEventResizer(calendarEvent, updateCopy, mouseDownEvent) { | ||
if (!this.$app) return this.logError() | ||
new DateGridEventResizer( | ||
this.$app, | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent.clientX | ||
) | ||
} | ||
getTimePointsForIntervalConfig() { | ||
if (this.minutesPerInterval === 60) return 100 | ||
if (this.minutesPerInterval === 30) return 50 | ||
return 25 | ||
} | ||
logError() { | ||
console.error('The calendar is not yet initialized. Cannot resize events.') | ||
} | ||
} | ||
const createResizePlugin = (minutesPerInterval = 15) => new ResizePluginImpl(minutesPerInterval); | ||
const createResizePlugin = (minutesPerInterval = 15) => | ||
new ResizePluginImpl(minutesPerInterval) | ||
export { createResizePlugin }; | ||
export { createResizePlugin } |
@@ -1,56 +0,56 @@ | ||
import { Signal, ReadonlySignal } from "@preact/signals"; | ||
import { JSXInternal } from "preact/src/jsx"; | ||
import { Signal, ReadonlySignal } from '@preact/signals' | ||
import { JSXInternal } from 'preact/src/jsx' | ||
declare enum WeekDay { | ||
SUNDAY = 0, | ||
MONDAY = 1, | ||
TUESDAY = 2, | ||
WEDNESDAY = 3, | ||
THURSDAY = 4, | ||
FRIDAY = 5, | ||
SATURDAY = 6 | ||
SUNDAY = 0, | ||
MONDAY = 1, | ||
TUESDAY = 2, | ||
WEDNESDAY = 3, | ||
THURSDAY = 4, | ||
FRIDAY = 5, | ||
SATURDAY = 6, | ||
} | ||
type WeekWithDates = Date[]; | ||
type MonthWithDates = Date[][]; | ||
type WeekWithDates = Date[] | ||
type MonthWithDates = Date[][] | ||
declare enum Month { | ||
JANUARY = 0, | ||
FEBRUARY = 1, | ||
MARCH = 2, | ||
APRIL = 3, | ||
MAY = 4, | ||
JUNE = 5, | ||
JULY = 6, | ||
AUGUST = 7, | ||
SEPTEMBER = 8, | ||
OCTOBER = 9, | ||
NOVEMBER = 10, | ||
DECEMBER = 11 | ||
JANUARY = 0, | ||
FEBRUARY = 1, | ||
MARCH = 2, | ||
APRIL = 3, | ||
MAY = 4, | ||
JUNE = 5, | ||
JULY = 6, | ||
AUGUST = 7, | ||
SEPTEMBER = 8, | ||
OCTOBER = 9, | ||
NOVEMBER = 10, | ||
DECEMBER = 11, | ||
} | ||
interface TimeUnits { | ||
firstDayOfWeek: WeekDay; | ||
getMonthWithTrailingAndLeadingDays(year: number, month: Month): MonthWithDates; | ||
getWeekFor(date: Date): WeekWithDates; | ||
getMonthsFor(year: number): Date[]; | ||
firstDayOfWeek: WeekDay | ||
getMonthWithTrailingAndLeadingDays(year: number, month: Month): MonthWithDates | ||
getWeekFor(date: Date): WeekWithDates | ||
getMonthsFor(year: number): Date[] | ||
} | ||
declare enum DatePickerView { | ||
MONTH_DAYS = "month-days", | ||
YEARS = "years" | ||
MONTH_DAYS = 'month-days', | ||
YEARS = 'years', | ||
} | ||
interface DatePickerState { | ||
isOpen: Signal<boolean>; | ||
isDisabled: Signal<boolean>; | ||
selectedDate: Signal<string>; | ||
inputDisplayedValue: Signal<string>; | ||
datePickerDate: Signal<string>; | ||
datePickerView: Signal<DatePickerView>; | ||
inputWrapperElement: Signal<HTMLDivElement | undefined>; | ||
isDark: Signal<boolean>; | ||
open(): void; | ||
close(): void; | ||
toggle(): void; | ||
setView(view: DatePickerView): void; | ||
isOpen: Signal<boolean> | ||
isDisabled: Signal<boolean> | ||
selectedDate: Signal<string> | ||
inputDisplayedValue: Signal<string> | ||
datePickerDate: Signal<string> | ||
datePickerView: Signal<DatePickerView> | ||
inputWrapperElement: Signal<HTMLDivElement | undefined> | ||
isDark: Signal<boolean> | ||
open(): void | ||
close(): void | ||
toggle(): void | ||
setView(view: DatePickerView): void | ||
} | ||
type TranslationVariables = { | ||
[key: string]: string | number; | ||
}; | ||
type TranslateFn = (key: string, variables?: TranslationVariables) => string; | ||
[key: string]: string | number | ||
} | ||
type TranslateFn = (key: string, variables?: TranslationVariables) => string | ||
/** | ||
@@ -60,5 +60,5 @@ * This interface serves as a bridge between the AppSingleton for the date picker and calendar | ||
interface AppSingleton { | ||
timeUnitsImpl: TimeUnits; | ||
datePickerState: DatePickerState; | ||
translate: TranslateFn; | ||
timeUnitsImpl: TimeUnits | ||
datePickerState: DatePickerState | ||
translate: TranslateFn | ||
} | ||
@@ -69,319 +69,350 @@ /** | ||
interface Config { | ||
locale: string; | ||
firstDayOfWeek: WeekDay; | ||
locale: string | ||
firstDayOfWeek: WeekDay | ||
} | ||
declare enum Placement { | ||
TOP_START = "top-start", | ||
TOP_END = "top-end", | ||
BOTTOM_START = "bottom-start", | ||
BOTTOM_END = "bottom-end" | ||
TOP_START = 'top-start', | ||
TOP_END = 'top-end', | ||
BOTTOM_START = 'bottom-start', | ||
BOTTOM_END = 'bottom-end', | ||
} | ||
interface DatePickerAppSingleton extends AppSingleton { | ||
config: DatePickerConfigInternal; | ||
config: DatePickerConfigInternal | ||
} | ||
type DatePickerListeners = { | ||
onChange?: (date: string) => void; | ||
onEscapeKeyDown?: ($app: DatePickerAppSingleton) => void; | ||
}; | ||
onChange?: (date: string) => void | ||
onEscapeKeyDown?: ($app: DatePickerAppSingleton) => void | ||
} | ||
type DatePickerStyle = { | ||
dark?: boolean; | ||
fullWidth?: boolean; | ||
}; | ||
dark?: boolean | ||
fullWidth?: boolean | ||
} | ||
interface DatePickerConfigInternal extends Config { | ||
min: string; | ||
max: string; | ||
placement: Placement; | ||
listeners: DatePickerListeners; | ||
style: DatePickerStyle; | ||
teleportTo?: HTMLElement; | ||
label?: string; | ||
name?: string; | ||
disabled?: boolean; | ||
min: string | ||
max: string | ||
placement: Placement | ||
listeners: DatePickerListeners | ||
style: DatePickerStyle | ||
teleportTo?: HTMLElement | ||
label?: string | ||
name?: string | ||
disabled?: boolean | ||
} | ||
// This enum is used to represent names of all internally built views of the calendar | ||
declare enum InternalViewName { | ||
Day = "day", | ||
Week = "week", | ||
MonthGrid = "month-grid", | ||
MonthAgenda = "month-agenda" | ||
Day = 'day', | ||
Week = 'week', | ||
MonthGrid = 'month-grid', | ||
MonthAgenda = 'month-agenda', | ||
} | ||
// Since implementers can use custom views, we need to have a type that combines the internal views with these custom views | ||
type ViewName = InternalViewName | string; | ||
type ViewName = InternalViewName | string | ||
type DateRange = { | ||
start: string; | ||
end: string; | ||
}; | ||
start: string | ||
end: string | ||
} | ||
interface RangeSetterConfig { | ||
date: string; | ||
timeUnitsImpl: TimeUnits; | ||
calendarConfig: CalendarConfigInternal; | ||
range: Signal<DateRange | null>; | ||
date: string | ||
timeUnitsImpl: TimeUnits | ||
calendarConfig: CalendarConfigInternal | ||
range: Signal<DateRange | null> | ||
} | ||
type PreactViewComponent = (props: { | ||
$app: CalendarAppSingleton; | ||
id: string; | ||
}) => JSXInternal.Element; | ||
declare const addMonths: (to: string, nMonths: number) => string; | ||
declare const addDays: (to: string, nDays: number) => string; | ||
$app: CalendarAppSingleton | ||
id: string | ||
}) => JSXInternal.Element | ||
declare const addMonths: (to: string, nMonths: number) => string | ||
declare const addDays: (to: string, nDays: number) => string | ||
type ViewConfig<FrameworkComponent = PreactViewComponent> = { | ||
/** | ||
* a unique identifier for the view | ||
* */ | ||
name: ViewName; | ||
/** | ||
* text that will be displayed in the view dropdown | ||
* */ | ||
label: string; | ||
/** | ||
* function that is called when a new date is selected | ||
* */ | ||
setDateRange: (config: RangeSetterConfig) => DateRange; | ||
/** | ||
* should the view be displayed on small screens (< 700px calendar width) | ||
* */ | ||
hasSmallScreenCompat: boolean; | ||
/** | ||
* should the view be displayed on wide screens (> 700px calendar width) | ||
* */ | ||
hasWideScreenCompat: boolean; | ||
/** | ||
* The component you want to render | ||
* */ | ||
Component: FrameworkComponent; | ||
/** | ||
* function that is called when the user clicks the backward/forward button | ||
* */ | ||
backwardForwardFn: typeof addDays | typeof addMonths; | ||
/** | ||
* number of units to add into the backwardForwardFn function. Result behind the scenes for example: | ||
* backwardForwardFn = addDays | ||
* backwardForwardUnits = 1 | ||
* result (behind the scenes) = addDays(date, 1) | ||
* */ | ||
backwardForwardUnits: number; | ||
}; | ||
type View<FrameworkComponent = PreactViewComponent> = ViewConfig<FrameworkComponent> & { | ||
render(onElement: HTMLElement, $app: CalendarAppSingleton): void; | ||
destroy(): void; | ||
}; | ||
type EventId = number | string; | ||
type startDate = string; | ||
type nDays = number; | ||
type EventFragments = Record<startDate, nDays>; | ||
/** | ||
* a unique identifier for the view | ||
* */ | ||
name: ViewName | ||
/** | ||
* text that will be displayed in the view dropdown | ||
* */ | ||
label: string | ||
/** | ||
* function that is called when a new date is selected | ||
* */ | ||
setDateRange: (config: RangeSetterConfig) => DateRange | ||
/** | ||
* should the view be displayed on small screens (< 700px calendar width) | ||
* */ | ||
hasSmallScreenCompat: boolean | ||
/** | ||
* should the view be displayed on wide screens (> 700px calendar width) | ||
* */ | ||
hasWideScreenCompat: boolean | ||
/** | ||
* The component you want to render | ||
* */ | ||
Component: FrameworkComponent | ||
/** | ||
* function that is called when the user clicks the backward/forward button | ||
* */ | ||
backwardForwardFn: typeof addDays | typeof addMonths | ||
/** | ||
* number of units to add into the backwardForwardFn function. Result behind the scenes for example: | ||
* backwardForwardFn = addDays | ||
* backwardForwardUnits = 1 | ||
* result (behind the scenes) = addDays(date, 1) | ||
* */ | ||
backwardForwardUnits: number | ||
} | ||
type View<FrameworkComponent = PreactViewComponent> = | ||
ViewConfig<FrameworkComponent> & { | ||
render(onElement: HTMLElement, $app: CalendarAppSingleton): void | ||
destroy(): void | ||
} | ||
type EventId = number | string | ||
type startDate = string | ||
type nDays = number | ||
type EventFragments = Record<startDate, nDays> | ||
type CalendarEventOptions = { | ||
disableDND?: boolean; | ||
disableResize?: boolean; | ||
additionalClasses?: string[]; | ||
}; | ||
disableDND?: boolean | ||
disableResize?: boolean | ||
additionalClasses?: string[] | ||
} | ||
interface CalendarEventExternal { | ||
id: EventId; | ||
start: string; | ||
end: string; | ||
title?: string; | ||
people?: string[]; | ||
location?: string; | ||
description?: string; | ||
calendarId?: string; | ||
_options?: CalendarEventOptions; | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: string]: any; | ||
id: EventId | ||
start: string | ||
end: string | ||
title?: string | ||
people?: string[] | ||
location?: string | ||
description?: string | ||
calendarId?: string | ||
_options?: CalendarEventOptions | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
[key: string]: any | ||
} | ||
interface CalendarEventInternal extends CalendarEventExternal { | ||
// event duration | ||
_isSingleDayTimed: boolean; | ||
_isSingleDayFullDay: boolean; | ||
_isSingleHybridDayTimed: boolean; | ||
_isMultiDayTimed: boolean; | ||
_isMultiDayFullDay: boolean; | ||
// week time grid | ||
_previousConcurrentEvents: number | undefined; | ||
_totalConcurrentEvents: number | undefined; | ||
// week date grid | ||
_nDaysInGrid: number | undefined; | ||
// month grid | ||
_eventFragments: EventFragments; | ||
_color: string; | ||
_getForeignProperties(): Record<string, unknown>; | ||
_getExternalEvent(): CalendarEventExternal; | ||
// event duration | ||
_isSingleDayTimed: boolean | ||
_isSingleDayFullDay: boolean | ||
_isSingleHybridDayTimed: boolean | ||
_isMultiDayTimed: boolean | ||
_isMultiDayFullDay: boolean | ||
// week time grid | ||
_previousConcurrentEvents: number | undefined | ||
_totalConcurrentEvents: number | undefined | ||
// week date grid | ||
_nDaysInGrid: number | undefined | ||
// month grid | ||
_eventFragments: EventFragments | ||
_color: string | ||
_getForeignProperties(): Record<string, unknown> | ||
_getExternalEvent(): CalendarEventExternal | ||
} | ||
type DayBoundariesInternal = { | ||
start: number; | ||
end: number; | ||
}; | ||
interface TimeGridDragHandler { | ||
start: number | ||
end: number | ||
} | ||
interface TimeGridDragHandler {} | ||
type DayBoundariesDateTime = { | ||
start: string; | ||
end: string; | ||
}; | ||
interface DateGridDragHandler { | ||
start: string | ||
end: string | ||
} | ||
interface DateGridDragHandler {} | ||
interface EventCoordinates { | ||
clientX: number; | ||
clientY: number; | ||
clientX: number | ||
clientY: number | ||
} | ||
interface DragHandlerDependencies { | ||
$app: CalendarAppSingleton; | ||
eventCoordinates: EventCoordinates; | ||
eventCopy: CalendarEventInternal; | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void; | ||
$app: CalendarAppSingleton | ||
eventCoordinates: EventCoordinates | ||
eventCopy: CalendarEventInternal | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void | ||
} | ||
interface MonthGridDragHandler { | ||
} | ||
interface MonthGridDragHandler {} | ||
interface DragAndDropPlugin extends PluginBase { | ||
createTimeGridDragHandler(dependencies: DragHandlerDependencies, dayBoundariesDateTime: DayBoundariesDateTime): TimeGridDragHandler; | ||
createDateGridDragHandler(dependencies: DragHandlerDependencies): DateGridDragHandler; | ||
createMonthGridDragHandler(calendarEvent: CalendarEventInternal, $app: CalendarAppSingleton): MonthGridDragHandler; | ||
createTimeGridDragHandler( | ||
dependencies: DragHandlerDependencies, | ||
dayBoundariesDateTime: DayBoundariesDateTime | ||
): TimeGridDragHandler | ||
createDateGridDragHandler( | ||
dependencies: DragHandlerDependencies | ||
): DateGridDragHandler | ||
createMonthGridDragHandler( | ||
calendarEvent: CalendarEventInternal, | ||
$app: CalendarAppSingleton | ||
): MonthGridDragHandler | ||
} | ||
type EventModalProps = { | ||
$app: CalendarAppSingleton; | ||
}; | ||
$app: CalendarAppSingleton | ||
} | ||
interface EventModalPlugin extends PluginBase { | ||
calendarEvent: Signal<CalendarEventInternal | null>; | ||
calendarEventDOMRect: Signal<DOMRect | null>; | ||
calendarEventElement: Signal<HTMLElement | null>; | ||
close(): void; | ||
setCalendarEvent(event: CalendarEventInternal | null, eventTargetDOMRect: DOMRect | null): void; | ||
ComponentFn(props: EventModalProps): JSXInternal.Element; | ||
calendarEvent: Signal<CalendarEventInternal | null> | ||
calendarEventDOMRect: Signal<DOMRect | null> | ||
calendarEventElement: Signal<HTMLElement | null> | ||
close(): void | ||
setCalendarEvent( | ||
event: CalendarEventInternal | null, | ||
eventTargetDOMRect: DOMRect | null | ||
): void | ||
ComponentFn(props: EventModalProps): JSXInternal.Element | ||
} | ||
interface CalendarCallbacks { | ||
onEventUpdate?: (event: CalendarEventExternal) => void; | ||
onEventClick?: (event: CalendarEventExternal) => void; | ||
onRangeUpdate?: (range: DateRange) => void; | ||
onSelectedDateUpdate?: (date: string) => void; | ||
onClickDate?: (date: string) => void; | ||
onDoubleClickDate?: (date: string) => void; | ||
onClickDateTime?: (dateTime: string) => void; | ||
onDoubleClickDateTime?: (dateTime: string) => void; | ||
onClickAgendaDate?: (date: string) => void; | ||
onClickPlusEvents?: (date: string) => void; | ||
isCalendarSmall?: ($app: CalendarAppSingleton) => boolean; | ||
onEventUpdate?: (event: CalendarEventExternal) => void | ||
onEventClick?: (event: CalendarEventExternal) => void | ||
onRangeUpdate?: (range: DateRange) => void | ||
onSelectedDateUpdate?: (date: string) => void | ||
onClickDate?: (date: string) => void | ||
onDoubleClickDate?: (date: string) => void | ||
onClickDateTime?: (dateTime: string) => void | ||
onDoubleClickDateTime?: (dateTime: string) => void | ||
onClickAgendaDate?: (date: string) => void | ||
onClickPlusEvents?: (date: string) => void | ||
isCalendarSmall?: ($app: CalendarAppSingleton) => boolean | ||
} | ||
type CustomComponentFns = { | ||
timeGridEvent?: CustomComponentFn; | ||
dateGridEvent?: CustomComponentFn; | ||
monthGridEvent?: CustomComponentFn; | ||
monthAgendaEvent?: CustomComponentFn; | ||
eventModal?: CustomComponentFn; | ||
headerContentLeftPrepend?: CustomComponentFn; | ||
headerContentLeftAppend?: CustomComponentFn; | ||
headerContentRightPrepend?: CustomComponentFn; | ||
headerContentRightAppend?: CustomComponentFn; | ||
}; | ||
timeGridEvent?: CustomComponentFn | ||
dateGridEvent?: CustomComponentFn | ||
monthGridEvent?: CustomComponentFn | ||
monthAgendaEvent?: CustomComponentFn | ||
eventModal?: CustomComponentFn | ||
headerContentLeftPrepend?: CustomComponentFn | ||
headerContentLeftAppend?: CustomComponentFn | ||
headerContentRightPrepend?: CustomComponentFn | ||
headerContentRightAppend?: CustomComponentFn | ||
} | ||
interface EventsFacade { | ||
get(id: EventId): CalendarEventExternal | undefined; | ||
getAll(): CalendarEventExternal[]; | ||
add(event: CalendarEventExternal): void; | ||
update(event: CalendarEventExternal): void; | ||
remove(id: EventId): void; | ||
set(events: CalendarEventExternal[]): void; | ||
get(id: EventId): CalendarEventExternal | undefined | ||
getAll(): CalendarEventExternal[] | ||
add(event: CalendarEventExternal): void | ||
update(event: CalendarEventExternal): void | ||
remove(id: EventId): void | ||
set(events: CalendarEventExternal[]): void | ||
} | ||
interface EventRecurrencePlugin extends PluginBase { | ||
updateRecurrenceDND(eventId: EventId, oldEventStart: string, newEventStart: string): void; | ||
updateRecurrenceOnResize(eventId: EventId, oldEventEnd: string, newEventEnd: string): void; | ||
eventsFacade: EventsFacade; | ||
updateRecurrenceDND( | ||
eventId: EventId, | ||
oldEventStart: string, | ||
newEventStart: string | ||
): void | ||
updateRecurrenceOnResize( | ||
eventId: EventId, | ||
oldEventEnd: string, | ||
newEventEnd: string | ||
): void | ||
eventsFacade: EventsFacade | ||
} | ||
type WeekOptions = { | ||
gridHeight: number; | ||
nDays: number; | ||
eventWidth: number; | ||
}; | ||
gridHeight: number | ||
nDays: number | ||
eventWidth: number | ||
} | ||
type MonthGridOptions = { | ||
nEventsPerDay: number; | ||
}; | ||
nEventsPerDay: number | ||
} | ||
type ColorDefinition = { | ||
main: string; | ||
container: string; | ||
onContainer: string; | ||
}; | ||
main: string | ||
container: string | ||
onContainer: string | ||
} | ||
type CalendarType = { | ||
colorName: string; | ||
label?: string; | ||
lightColors?: ColorDefinition; | ||
darkColors?: ColorDefinition; | ||
}; | ||
colorName: string | ||
label?: string | ||
lightColors?: ColorDefinition | ||
darkColors?: ColorDefinition | ||
} | ||
type Plugins = { | ||
dragAndDrop?: DragAndDropPlugin; | ||
eventModal?: EventModalPlugin; | ||
scrollController?: PluginBase; | ||
eventRecurrence?: EventRecurrencePlugin; | ||
resize?: ResizePlugin; | ||
[key: string]: PluginBase | undefined; | ||
}; | ||
type CustomComponentFn = (wrapperElement: HTMLElement, props: Record<string, unknown>) => void; | ||
dragAndDrop?: DragAndDropPlugin | ||
eventModal?: EventModalPlugin | ||
scrollController?: PluginBase | ||
eventRecurrence?: EventRecurrencePlugin | ||
resize?: ResizePlugin | ||
[key: string]: PluginBase | undefined | ||
} | ||
type CustomComponentFn = ( | ||
wrapperElement: HTMLElement, | ||
props: Record<string, unknown> | ||
) => void | ||
interface CalendarConfigInternal extends Config { | ||
defaultView: ViewName; | ||
views: View[]; | ||
dayBoundaries: DayBoundariesInternal; | ||
weekOptions: WeekOptions; | ||
monthGridOptions: MonthGridOptions; | ||
calendars: Signal<Record<string, CalendarType>>; | ||
plugins: Plugins; | ||
isDark: boolean; | ||
isResponsive: boolean; | ||
callbacks: CalendarCallbacks; | ||
_customComponentFns: CustomComponentFns; | ||
minDate?: string; | ||
maxDate?: string; | ||
// Getters | ||
isHybridDay: boolean; | ||
timePointsPerDay: number; | ||
defaultView: ViewName | ||
views: View[] | ||
dayBoundaries: DayBoundariesInternal | ||
weekOptions: WeekOptions | ||
monthGridOptions: MonthGridOptions | ||
calendars: Signal<Record<string, CalendarType>> | ||
plugins: Plugins | ||
isDark: boolean | ||
isResponsive: boolean | ||
callbacks: CalendarCallbacks | ||
_customComponentFns: CustomComponentFns | ||
minDate?: string | ||
maxDate?: string | ||
// Getters | ||
isHybridDay: boolean | ||
timePointsPerDay: number | ||
} | ||
interface CalendarState { | ||
isCalendarSmall: Signal<boolean | undefined>; | ||
view: ReadonlySignal<ViewName>; | ||
setView: (view: ViewName, selectedDate: string) => void; | ||
range: Signal<DateRange | null>; | ||
isDark: Signal<boolean>; | ||
setRange: (date: string) => void; | ||
isCalendarSmall: Signal<boolean | undefined> | ||
view: ReadonlySignal<ViewName> | ||
setView: (view: ViewName, selectedDate: string) => void | ||
range: Signal<DateRange | null> | ||
isDark: Signal<boolean> | ||
setRange: (date: string) => void | ||
} | ||
type EventsFilterPredicate = ((event: CalendarEventInternal) => boolean) | undefined; | ||
type EventsFilterPredicate = | ||
| ((event: CalendarEventInternal) => boolean) | ||
| undefined | ||
interface CalendarEvents { | ||
list: Signal<CalendarEventInternal[]>; | ||
filterPredicate: Signal<EventsFilterPredicate>; | ||
list: Signal<CalendarEventInternal[]> | ||
filterPredicate: Signal<EventsFilterPredicate> | ||
} | ||
interface CalendarElements { | ||
calendarWrapper: HTMLDivElement | undefined; | ||
calendarWrapper: HTMLDivElement | undefined | ||
} | ||
interface CalendarAppSingleton extends AppSingleton { | ||
config: CalendarConfigInternal; | ||
datePickerConfig: DatePickerConfigInternal; | ||
calendarState: CalendarState; | ||
calendarEvents: CalendarEvents; | ||
elements: CalendarElements; | ||
config: CalendarConfigInternal | ||
datePickerConfig: DatePickerConfigInternal | ||
calendarState: CalendarState | ||
calendarEvents: CalendarEvents | ||
elements: CalendarElements | ||
} | ||
interface PluginBase { | ||
name: string; | ||
// TODO v2: change to `beforeRender` | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
beforeInit?($app: CalendarAppSingleton | any): void; | ||
// TODO v2: change to `onRender` and remove $app parameter | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
init?($app: CalendarAppSingleton | any): void; | ||
destroy?(): void; | ||
name: string | ||
// TODO v2: change to `beforeRender` | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
beforeInit?($app: CalendarAppSingleton | any): void | ||
// TODO v2: change to `onRender` and remove $app parameter | ||
/** | ||
* Allow implementers to dynamically add any properties to the global app object as they see fit. | ||
* In order to avoid conflict with future properties added to the library, we recommend | ||
* using the unique prefix `$` for any custom properties added to the global app object. | ||
* for example $app['$websocketService'] = new WebsocketService(). | ||
* Adding properties to existing sub-objects is discouraged, since this will make your application more | ||
* brittle to future changes in the library. | ||
* */ | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
init?($app: CalendarAppSingleton | any): void | ||
destroy?(): void | ||
} | ||
interface ResizePlugin extends PluginBase { | ||
createTimeGridEventResizer(calendarEvent: CalendarEventInternal, updateCopy: (newCopy: CalendarEventInternal | undefined) => void, mouseDownEvent: MouseEvent, dayBoundariesDateTime: { | ||
start: string; | ||
end: string; | ||
}): void; | ||
createDateGridEventResizer(calendarEvent: CalendarEventInternal, updateCopy: (newCopy: CalendarEventInternal | undefined) => void, mouseDownEvent: MouseEvent): void; | ||
createTimeGridEventResizer( | ||
calendarEvent: CalendarEventInternal, | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void, | ||
mouseDownEvent: MouseEvent, | ||
dayBoundariesDateTime: { | ||
start: string | ||
end: string | ||
} | ||
): void | ||
createDateGridEventResizer( | ||
calendarEvent: CalendarEventInternal, | ||
updateCopy: (newCopy: CalendarEventInternal | undefined) => void, | ||
mouseDownEvent: MouseEvent | ||
): void | ||
} | ||
declare const createResizePlugin: (minutesPerInterval?: number) => ResizePlugin; | ||
export { createResizePlugin }; | ||
declare const createResizePlugin: (minutesPerInterval?: number) => ResizePlugin | ||
export { createResizePlugin } |
@@ -1,393 +0,471 @@ | ||
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('preact/jsx-runtime')) : | ||
typeof define === 'function' && define.amd ? define(['exports', 'preact/jsx-runtime'], factory) : | ||
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["@schedule-x/resize"] = {})); | ||
})(this, (function (exports) { 'use strict'; | ||
;(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' | ||
? factory(exports, require('preact/jsx-runtime')) | ||
: typeof define === 'function' && define.amd | ||
? define(['exports', 'preact/jsx-runtime'], factory) | ||
: ((global = | ||
typeof globalThis !== 'undefined' ? globalThis : global || self), | ||
factory((global['@schedule-x/resize'] = {}))) | ||
})(this, function (exports) { | ||
'use strict' | ||
const getTimePointsPerPixel = ($app) => { | ||
return $app.config.timePointsPerDay / $app.config.weekOptions.gridHeight; | ||
}; | ||
return $app.config.timePointsPerDay / $app.config.weekOptions.gridHeight | ||
} | ||
const DateFormats = { | ||
DATE_STRING: /^\d{4}-\d{2}-\d{2}$/, | ||
TIME_STRING: /^\d{2}:\d{2}$/, | ||
DATE_TIME_STRING: /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, | ||
}; | ||
DATE_STRING: /^\d{4}-\d{2}-\d{2}$/, | ||
TIME_STRING: /^\d{2}:\d{2}$/, | ||
DATE_TIME_STRING: /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/, | ||
} | ||
class InvalidDateTimeError extends Error { | ||
constructor(dateTimeSpecification) { | ||
super(`Invalid date time specification: ${dateTimeSpecification}`); | ||
} | ||
constructor(dateTimeSpecification) { | ||
super(`Invalid date time specification: ${dateTimeSpecification}`) | ||
} | ||
} | ||
const toJSDate = (dateTimeSpecification) => { | ||
if (!DateFormats.DATE_TIME_STRING.test(dateTimeSpecification) && | ||
!DateFormats.DATE_STRING.test(dateTimeSpecification)) | ||
throw new InvalidDateTimeError(dateTimeSpecification); | ||
return new Date(Number(dateTimeSpecification.slice(0, 4)), Number(dateTimeSpecification.slice(5, 7)) - 1, Number(dateTimeSpecification.slice(8, 10)), Number(dateTimeSpecification.slice(11, 13)), // for date strings this will be 0 | ||
if ( | ||
!DateFormats.DATE_TIME_STRING.test(dateTimeSpecification) && | ||
!DateFormats.DATE_STRING.test(dateTimeSpecification) | ||
) | ||
throw new InvalidDateTimeError(dateTimeSpecification) | ||
return new Date( | ||
Number(dateTimeSpecification.slice(0, 4)), | ||
Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
Number(dateTimeSpecification.slice(8, 10)), | ||
Number(dateTimeSpecification.slice(11, 13)), // for date strings this will be 0 | ||
Number(dateTimeSpecification.slice(14, 16)) // for date strings this will be 0 | ||
); | ||
}; | ||
) | ||
} | ||
const toIntegers = (dateTimeSpecification) => { | ||
const hours = dateTimeSpecification.slice(11, 13), minutes = dateTimeSpecification.slice(14, 16); | ||
return { | ||
year: Number(dateTimeSpecification.slice(0, 4)), | ||
month: Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
date: Number(dateTimeSpecification.slice(8, 10)), | ||
hours: hours !== '' ? Number(hours) : undefined, | ||
minutes: minutes !== '' ? Number(minutes) : undefined, | ||
}; | ||
}; | ||
const hours = dateTimeSpecification.slice(11, 13), | ||
minutes = dateTimeSpecification.slice(14, 16) | ||
return { | ||
year: Number(dateTimeSpecification.slice(0, 4)), | ||
month: Number(dateTimeSpecification.slice(5, 7)) - 1, | ||
date: Number(dateTimeSpecification.slice(8, 10)), | ||
hours: hours !== '' ? Number(hours) : undefined, | ||
minutes: minutes !== '' ? Number(minutes) : undefined, | ||
} | ||
} | ||
class NumberRangeError extends Error { | ||
constructor(min, max) { | ||
super(`Number must be between ${min} and ${max}.`); | ||
Object.defineProperty(this, "min", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: min | ||
}); | ||
Object.defineProperty(this, "max", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: max | ||
}); | ||
} | ||
constructor(min, max) { | ||
super(`Number must be between ${min} and ${max}.`) | ||
Object.defineProperty(this, 'min', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: min, | ||
}) | ||
Object.defineProperty(this, 'max', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: max, | ||
}) | ||
} | ||
} | ||
const doubleDigit = (number) => { | ||
if (number < 0 || number > 99) | ||
throw new NumberRangeError(0, 99); | ||
return String(number).padStart(2, '0'); | ||
}; | ||
if (number < 0 || number > 99) throw new NumberRangeError(0, 99) | ||
return String(number).padStart(2, '0') | ||
} | ||
const toDateString = (date) => { | ||
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())}`; | ||
}; | ||
return `${date.getFullYear()}-${doubleDigit(date.getMonth() + 1)}-${doubleDigit(date.getDate())}` | ||
} | ||
const toTimeString = (date) => { | ||
return `${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}`; | ||
}; | ||
return `${doubleDigit(date.getHours())}:${doubleDigit(date.getMinutes())}` | ||
} | ||
const toDateTimeString = (date) => { | ||
return `${toDateString(date)} ${toTimeString(date)}`; | ||
}; | ||
return `${toDateString(date)} ${toTimeString(date)}` | ||
} | ||
const minuteTimePointMultiplier = 1.6666666666666667; // 100 / 60 | ||
const minuteTimePointMultiplier = 1.6666666666666667 // 100 / 60 | ||
const addTimePointsToDateTime = (dateTimeString, pointsToAdd) => { | ||
const minutesToAdd = pointsToAdd / minuteTimePointMultiplier; | ||
const jsDate = toJSDate(dateTimeString); | ||
jsDate.setMinutes(jsDate.getMinutes() + minutesToAdd); | ||
return toDateTimeString(jsDate); | ||
}; | ||
const minutesToAdd = pointsToAdd / minuteTimePointMultiplier | ||
const jsDate = toJSDate(dateTimeString) | ||
jsDate.setMinutes(jsDate.getMinutes() + minutesToAdd) | ||
return toDateTimeString(jsDate) | ||
} | ||
const updateEventsList = ($app, eventCopy, oldEventEnd, newEventEnd) => { | ||
const rrule = eventCopy._getForeignProperties().rrule; | ||
if (rrule && $app.config.plugins.eventRecurrence) { | ||
$app.config.plugins.eventRecurrence.updateRecurrenceOnResize(eventCopy.id, oldEventEnd, newEventEnd); | ||
return; | ||
} | ||
const eventToUpdate = $app.calendarEvents.list.value.find((event) => event.id === eventCopy.id); | ||
if (!eventToUpdate) | ||
return; | ||
eventToUpdate.end = eventCopy.end; | ||
$app.calendarEvents.list.value = [...$app.calendarEvents.list.value]; | ||
}; | ||
const rrule = eventCopy._getForeignProperties().rrule | ||
if (rrule && $app.config.plugins.eventRecurrence) { | ||
$app.config.plugins.eventRecurrence.updateRecurrenceOnResize( | ||
eventCopy.id, | ||
oldEventEnd, | ||
newEventEnd | ||
) | ||
return | ||
} | ||
const eventToUpdate = $app.calendarEvents.list.value.find( | ||
(event) => event.id === eventCopy.id | ||
) | ||
if (!eventToUpdate) return | ||
eventToUpdate.end = eventCopy.end | ||
$app.calendarEvents.list.value = [...$app.calendarEvents.list.value] | ||
} | ||
class TimeGridEventResizer { | ||
constructor($app, eventCopy, updateCopy, initialY, CHANGE_THRESHOLD_IN_TIME_POINTS, dayBoundariesDateTime) { | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app | ||
}); | ||
Object.defineProperty(this, "eventCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy | ||
}); | ||
Object.defineProperty(this, "updateCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy | ||
}); | ||
Object.defineProperty(this, "initialY", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialY | ||
}); | ||
Object.defineProperty(this, "CHANGE_THRESHOLD_IN_TIME_POINTS", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: CHANGE_THRESHOLD_IN_TIME_POINTS | ||
}); | ||
Object.defineProperty(this, "dayBoundariesDateTime", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: dayBoundariesDateTime | ||
}); | ||
Object.defineProperty(this, "originalEventEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "lastIntervalDiff", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "lastValidEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '' | ||
}); | ||
Object.defineProperty(this, "handleMouseMove", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const pixelDiffY = event.clientY - this.initialY; | ||
const timePointsDiffY = pixelDiffY * getTimePointsPerPixel(this.$app); | ||
const currentIntervalDiff = Math.round(timePointsDiffY / this.CHANGE_THRESHOLD_IN_TIME_POINTS); | ||
const timeDidNotChange = currentIntervalDiff === this.lastIntervalDiff; | ||
if (timeDidNotChange) | ||
return; | ||
this.lastIntervalDiff = currentIntervalDiff; | ||
this.setNewTimeForEventEnd(this.CHANGE_THRESHOLD_IN_TIME_POINTS * currentIntervalDiff); | ||
} | ||
}); | ||
Object.defineProperty(this, "handleMouseUp", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.setNewTimeForEventEnd(this.CHANGE_THRESHOLD_IN_TIME_POINTS * this.lastIntervalDiff); | ||
updateEventsList(this.$app, this.eventCopy, this.originalEventEnd, this.lastValidEnd); | ||
this.updateCopy(undefined); | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing'); | ||
this.$app.elements.calendarWrapper.removeEventListener('mousemove', this.handleMouseMove); | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate(this.eventCopy._getExternalEvent()); | ||
} | ||
} | ||
}); | ||
this.originalEventEnd = this.eventCopy.end; | ||
this.lastValidEnd = this.eventCopy.end; | ||
const calendarWrapper = this.$app.elements.calendarWrapper; | ||
if (!calendarWrapper) | ||
return; | ||
calendarWrapper.classList.add('sx__is-resizing'); | ||
this.setupEventListeners(); | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener('mousemove', this.handleMouseMove); | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }); | ||
} | ||
setNewTimeForEventEnd(pointsToAdd) { | ||
const newEnd = addTimePointsToDateTime(this.originalEventEnd, pointsToAdd); | ||
if (newEnd > this.dayBoundariesDateTime.end || | ||
newEnd <= this.eventCopy.start) | ||
return; | ||
this.lastValidEnd = newEnd; | ||
this.eventCopy.end = this.lastValidEnd; | ||
this.updateCopy(this.eventCopy); | ||
} | ||
constructor( | ||
$app, | ||
eventCopy, | ||
updateCopy, | ||
initialY, | ||
CHANGE_THRESHOLD_IN_TIME_POINTS, | ||
dayBoundariesDateTime | ||
) { | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app, | ||
}) | ||
Object.defineProperty(this, 'eventCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy, | ||
}) | ||
Object.defineProperty(this, 'updateCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy, | ||
}) | ||
Object.defineProperty(this, 'initialY', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialY, | ||
}) | ||
Object.defineProperty(this, 'CHANGE_THRESHOLD_IN_TIME_POINTS', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: CHANGE_THRESHOLD_IN_TIME_POINTS, | ||
}) | ||
Object.defineProperty(this, 'dayBoundariesDateTime', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: dayBoundariesDateTime, | ||
}) | ||
Object.defineProperty(this, 'originalEventEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'lastIntervalDiff', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'lastValidEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: '', | ||
}) | ||
Object.defineProperty(this, 'handleMouseMove', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const pixelDiffY = event.clientY - this.initialY | ||
const timePointsDiffY = pixelDiffY * getTimePointsPerPixel(this.$app) | ||
const currentIntervalDiff = Math.round( | ||
timePointsDiffY / this.CHANGE_THRESHOLD_IN_TIME_POINTS | ||
) | ||
const timeDidNotChange = currentIntervalDiff === this.lastIntervalDiff | ||
if (timeDidNotChange) return | ||
this.lastIntervalDiff = currentIntervalDiff | ||
this.setNewTimeForEventEnd( | ||
this.CHANGE_THRESHOLD_IN_TIME_POINTS * currentIntervalDiff | ||
) | ||
}, | ||
}) | ||
Object.defineProperty(this, 'handleMouseUp', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
this.setNewTimeForEventEnd( | ||
this.CHANGE_THRESHOLD_IN_TIME_POINTS * this.lastIntervalDiff | ||
) | ||
updateEventsList( | ||
this.$app, | ||
this.eventCopy, | ||
this.originalEventEnd, | ||
this.lastValidEnd | ||
) | ||
this.updateCopy(undefined) | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing') | ||
this.$app.elements.calendarWrapper.removeEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate( | ||
this.eventCopy._getExternalEvent() | ||
) | ||
} | ||
}, | ||
}) | ||
this.originalEventEnd = this.eventCopy.end | ||
this.lastValidEnd = this.eventCopy.end | ||
const calendarWrapper = this.$app.elements.calendarWrapper | ||
if (!calendarWrapper) return | ||
calendarWrapper.classList.add('sx__is-resizing') | ||
this.setupEventListeners() | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }) | ||
} | ||
setNewTimeForEventEnd(pointsToAdd) { | ||
const newEnd = addTimePointsToDateTime(this.originalEventEnd, pointsToAdd) | ||
if ( | ||
newEnd > this.dayBoundariesDateTime.end || | ||
newEnd <= this.eventCopy.start | ||
) | ||
return | ||
this.lastValidEnd = newEnd | ||
this.eventCopy.end = this.lastValidEnd | ||
this.updateCopy(this.eventCopy) | ||
} | ||
} | ||
var PluginName; | ||
(function (PluginName) { | ||
PluginName["DragAndDrop"] = "dragAndDrop"; | ||
PluginName["EventModal"] = "eventModal"; | ||
PluginName["ScrollController"] = "scrollController"; | ||
PluginName["EventRecurrence"] = "eventRecurrence"; | ||
PluginName["Resize"] = "resize"; | ||
PluginName["CalendarControls"] = "calendarControls"; | ||
})(PluginName || (PluginName = {})); | ||
var PluginName | ||
;(function (PluginName) { | ||
PluginName['DragAndDrop'] = 'dragAndDrop' | ||
PluginName['EventModal'] = 'eventModal' | ||
PluginName['ScrollController'] = 'scrollController' | ||
PluginName['EventRecurrence'] = 'eventRecurrence' | ||
PluginName['Resize'] = 'resize' | ||
PluginName['CalendarControls'] = 'calendarControls' | ||
})(PluginName || (PluginName = {})) | ||
const getTimeGridDayWidth = ($app) => { | ||
return $app.elements.calendarWrapper.querySelector('.sx__time-grid-day').clientWidth; | ||
}; | ||
return $app.elements.calendarWrapper.querySelector('.sx__time-grid-day') | ||
.clientWidth | ||
} | ||
var WeekDay; | ||
(function (WeekDay) { | ||
WeekDay[WeekDay["SUNDAY"] = 0] = "SUNDAY"; | ||
WeekDay[WeekDay["MONDAY"] = 1] = "MONDAY"; | ||
WeekDay[WeekDay["TUESDAY"] = 2] = "TUESDAY"; | ||
WeekDay[WeekDay["WEDNESDAY"] = 3] = "WEDNESDAY"; | ||
WeekDay[WeekDay["THURSDAY"] = 4] = "THURSDAY"; | ||
WeekDay[WeekDay["FRIDAY"] = 5] = "FRIDAY"; | ||
WeekDay[WeekDay["SATURDAY"] = 6] = "SATURDAY"; | ||
})(WeekDay || (WeekDay = {})); | ||
var WeekDay | ||
;(function (WeekDay) { | ||
WeekDay[(WeekDay['SUNDAY'] = 0)] = 'SUNDAY' | ||
WeekDay[(WeekDay['MONDAY'] = 1)] = 'MONDAY' | ||
WeekDay[(WeekDay['TUESDAY'] = 2)] = 'TUESDAY' | ||
WeekDay[(WeekDay['WEDNESDAY'] = 3)] = 'WEDNESDAY' | ||
WeekDay[(WeekDay['THURSDAY'] = 4)] = 'THURSDAY' | ||
WeekDay[(WeekDay['FRIDAY'] = 5)] = 'FRIDAY' | ||
WeekDay[(WeekDay['SATURDAY'] = 6)] = 'SATURDAY' | ||
})(WeekDay || (WeekDay = {})) | ||
WeekDay.MONDAY; | ||
WeekDay.MONDAY | ||
const addDays = (to, nDays) => { | ||
const { year, month, date, hours, minutes } = toIntegers(to); | ||
const isDateTimeString = hours !== undefined && minutes !== undefined; | ||
const jsDate = new Date(year, month, date, hours !== null && hours !== void 0 ? hours : 0, minutes !== null && minutes !== void 0 ? minutes : 0); | ||
jsDate.setDate(jsDate.getDate() + nDays); | ||
if (isDateTimeString) { | ||
return toDateTimeString(jsDate); | ||
} | ||
return toDateString(jsDate); | ||
}; | ||
const { year, month, date, hours, minutes } = toIntegers(to) | ||
const isDateTimeString = hours !== undefined && minutes !== undefined | ||
const jsDate = new Date( | ||
year, | ||
month, | ||
date, | ||
hours !== null && hours !== void 0 ? hours : 0, | ||
minutes !== null && minutes !== void 0 ? minutes : 0 | ||
) | ||
jsDate.setDate(jsDate.getDate() + nDays) | ||
if (isDateTimeString) { | ||
return toDateTimeString(jsDate) | ||
} | ||
return toDateString(jsDate) | ||
} | ||
class DateGridEventResizer { | ||
constructor($app, eventCopy, updateCopy, initialX) { | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app | ||
}); | ||
Object.defineProperty(this, "eventCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy | ||
}); | ||
Object.defineProperty(this, "updateCopy", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy | ||
}); | ||
Object.defineProperty(this, "initialX", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialX | ||
}); | ||
Object.defineProperty(this, "dayWidth", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "originalEventEnd", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "ORIGINAL_NDAYS", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0 | ||
}); | ||
Object.defineProperty(this, "lastNDaysDiff", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0 | ||
}); | ||
Object.defineProperty(this, "handleMouseMove", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const xDifference = event.clientX - this.initialX; | ||
this.lastNDaysDiff = Math.floor(xDifference / this.dayWidth); | ||
this.setNewTimeForEventEnd(); | ||
} | ||
}); | ||
Object.defineProperty(this, "handleMouseUp", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
updateEventsList(this.$app, this.eventCopy, this.originalEventEnd, this.eventCopy.end); | ||
this.updateCopy(undefined); | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing'); | ||
this.$app.elements.calendarWrapper.removeEventListener('mousemove', this.handleMouseMove); | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate(this.eventCopy._getExternalEvent()); | ||
} | ||
} | ||
}); | ||
this.originalEventEnd = eventCopy.end; | ||
this.ORIGINAL_NDAYS = eventCopy._nDaysInGrid || 0; | ||
const calendarWrapper = this.$app.elements.calendarWrapper; | ||
if (!calendarWrapper) | ||
return; | ||
calendarWrapper.classList.add('sx__is-resizing'); | ||
this.dayWidth = getTimeGridDayWidth(this.$app); | ||
this.setupEventListeners(); | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener('mousemove', this.handleMouseMove); | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }); | ||
} | ||
setNewTimeForEventEnd() { | ||
const newEnd = addDays(this.originalEventEnd, this.lastNDaysDiff); | ||
if (newEnd > this.$app.calendarState.range.value.end || | ||
newEnd < this.eventCopy.start || | ||
newEnd < | ||
toDateString(toJSDate(this.$app.calendarState.range.value.start))) | ||
return; | ||
this.eventCopy.end = newEnd; | ||
this.eventCopy._nDaysInGrid = this.ORIGINAL_NDAYS + this.lastNDaysDiff; | ||
this.updateCopy(this.eventCopy); | ||
} | ||
constructor($app, eventCopy, updateCopy, initialX) { | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: $app, | ||
}) | ||
Object.defineProperty(this, 'eventCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: eventCopy, | ||
}) | ||
Object.defineProperty(this, 'updateCopy', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: updateCopy, | ||
}) | ||
Object.defineProperty(this, 'initialX', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: initialX, | ||
}) | ||
Object.defineProperty(this, 'dayWidth', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'originalEventEnd', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'ORIGINAL_NDAYS', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: void 0, | ||
}) | ||
Object.defineProperty(this, 'lastNDaysDiff', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: 0, | ||
}) | ||
Object.defineProperty(this, 'handleMouseMove', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: (event) => { | ||
const xDifference = event.clientX - this.initialX | ||
this.lastNDaysDiff = Math.floor(xDifference / this.dayWidth) | ||
this.setNewTimeForEventEnd() | ||
}, | ||
}) | ||
Object.defineProperty(this, 'handleMouseUp', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: () => { | ||
updateEventsList( | ||
this.$app, | ||
this.eventCopy, | ||
this.originalEventEnd, | ||
this.eventCopy.end | ||
) | ||
this.updateCopy(undefined) | ||
this.$app.elements.calendarWrapper.classList.remove('sx__is-resizing') | ||
this.$app.elements.calendarWrapper.removeEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
if (this.$app.config.callbacks.onEventUpdate) { | ||
this.$app.config.callbacks.onEventUpdate( | ||
this.eventCopy._getExternalEvent() | ||
) | ||
} | ||
}, | ||
}) | ||
this.originalEventEnd = eventCopy.end | ||
this.ORIGINAL_NDAYS = eventCopy._nDaysInGrid || 0 | ||
const calendarWrapper = this.$app.elements.calendarWrapper | ||
if (!calendarWrapper) return | ||
calendarWrapper.classList.add('sx__is-resizing') | ||
this.dayWidth = getTimeGridDayWidth(this.$app) | ||
this.setupEventListeners() | ||
} | ||
setupEventListeners() { | ||
this.$app.elements.calendarWrapper.addEventListener( | ||
'mousemove', | ||
this.handleMouseMove | ||
) | ||
document.addEventListener('mouseup', this.handleMouseUp, { once: true }) | ||
} | ||
setNewTimeForEventEnd() { | ||
const newEnd = addDays(this.originalEventEnd, this.lastNDaysDiff) | ||
if ( | ||
newEnd > this.$app.calendarState.range.value.end || | ||
newEnd < this.eventCopy.start || | ||
newEnd < | ||
toDateString(toJSDate(this.$app.calendarState.range.value.start)) | ||
) | ||
return | ||
this.eventCopy.end = newEnd | ||
this.eventCopy._nDaysInGrid = this.ORIGINAL_NDAYS + this.lastNDaysDiff | ||
this.updateCopy(this.eventCopy) | ||
} | ||
} | ||
class ResizePluginImpl { | ||
constructor(minutesPerInterval) { | ||
Object.defineProperty(this, "minutesPerInterval", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: minutesPerInterval | ||
}); | ||
Object.defineProperty(this, "name", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: PluginName.Resize | ||
}); | ||
Object.defineProperty(this, "$app", { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: null | ||
}); | ||
} | ||
init($app) { | ||
this.$app = $app; | ||
} | ||
createTimeGridEventResizer(calendarEvent, updateCopy, mouseDownEvent, dayBoundariesDateTime) { | ||
if (!this.$app) | ||
return this.logError(); | ||
new TimeGridEventResizer(this.$app, calendarEvent, updateCopy, mouseDownEvent.clientY, this.getTimePointsForIntervalConfig(), dayBoundariesDateTime); | ||
} | ||
createDateGridEventResizer(calendarEvent, updateCopy, mouseDownEvent) { | ||
if (!this.$app) | ||
return this.logError(); | ||
new DateGridEventResizer(this.$app, calendarEvent, updateCopy, mouseDownEvent.clientX); | ||
} | ||
getTimePointsForIntervalConfig() { | ||
if (this.minutesPerInterval === 60) | ||
return 100; | ||
if (this.minutesPerInterval === 30) | ||
return 50; | ||
return 25; | ||
} | ||
logError() { | ||
console.error('The calendar is not yet initialized. Cannot resize events.'); | ||
} | ||
constructor(minutesPerInterval) { | ||
Object.defineProperty(this, 'minutesPerInterval', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: minutesPerInterval, | ||
}) | ||
Object.defineProperty(this, 'name', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: PluginName.Resize, | ||
}) | ||
Object.defineProperty(this, '$app', { | ||
enumerable: true, | ||
configurable: true, | ||
writable: true, | ||
value: null, | ||
}) | ||
} | ||
init($app) { | ||
this.$app = $app | ||
} | ||
createTimeGridEventResizer( | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent, | ||
dayBoundariesDateTime | ||
) { | ||
if (!this.$app) return this.logError() | ||
new TimeGridEventResizer( | ||
this.$app, | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent.clientY, | ||
this.getTimePointsForIntervalConfig(), | ||
dayBoundariesDateTime | ||
) | ||
} | ||
createDateGridEventResizer(calendarEvent, updateCopy, mouseDownEvent) { | ||
if (!this.$app) return this.logError() | ||
new DateGridEventResizer( | ||
this.$app, | ||
calendarEvent, | ||
updateCopy, | ||
mouseDownEvent.clientX | ||
) | ||
} | ||
getTimePointsForIntervalConfig() { | ||
if (this.minutesPerInterval === 60) return 100 | ||
if (this.minutesPerInterval === 30) return 50 | ||
return 25 | ||
} | ||
logError() { | ||
console.error( | ||
'The calendar is not yet initialized. Cannot resize events.' | ||
) | ||
} | ||
} | ||
const createResizePlugin = (minutesPerInterval = 15) => new ResizePluginImpl(minutesPerInterval); | ||
const createResizePlugin = (minutesPerInterval = 15) => | ||
new ResizePluginImpl(minutesPerInterval) | ||
exports.createResizePlugin = createResizePlugin; | ||
})); | ||
exports.createResizePlugin = createResizePlugin | ||
}) |
{ | ||
"name": "@schedule-x/resize", | ||
"version": "1.58.1-alpha.0", | ||
"version": "1.58.1", | ||
"description": "Resize events in the Schedule-X calendar", | ||
@@ -29,3 +29,3 @@ "author": { | ||
"homepage": "https://schedule-x.dev", | ||
"gitHead": "8bf55ae2163bac3d0a66542af554d209627ddc07" | ||
"gitHead": "e107e76362346f2d961b429936f7ee55b25695e7" | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
2582
13.84%0
-100%80278
-7.01%8
-11.11%1
Infinity%