routie dev init since i didn't adhere to any proper guidance up until now

This commit is contained in:
2026-04-29 22:27:29 -06:00
commit e1dabb71e2
15301 changed files with 3562618 additions and 0 deletions
@@ -0,0 +1,193 @@
import { validateTimestamp, validateWeekdays } from '../util/timestamp.js';
import type { PropType } from 'vue';
import type { CalendarFormatter, CalendarTimestamp } from '../types.js';
import type { ColorValue } from '../../../composables/color.js';
export declare const makeCalendarBaseProps: <Defaults extends {
start?: unknown;
end?: unknown;
weekdays?: unknown;
firstDayOfWeek?: unknown;
firstDayOfYear?: unknown;
weekdayFormat?: unknown;
dayFormat?: unknown;
locale?: unknown;
now?: unknown;
type?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
start: unknown extends Defaults["start"] ? {
type: (DateConstructor | NumberConstructor | StringConstructor)[];
validate: typeof validateTimestamp;
default: () => string;
} : Omit<{
type: (DateConstructor | NumberConstructor | StringConstructor)[];
validate: typeof validateTimestamp;
default: () => string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["start"] ? string | number | Date : string | number | Date | Defaults["start"]>;
default: unknown extends Defaults["start"] ? string | number | Date : Defaults["start"] | NonNullable<string | number | Date>;
};
end: unknown extends Defaults["end"] ? {
type: (DateConstructor | NumberConstructor | StringConstructor)[];
validate: typeof validateTimestamp;
} : Omit<{
type: (DateConstructor | NumberConstructor | StringConstructor)[];
validate: typeof validateTimestamp;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["end"] ? string | number | Date : string | number | Date | Defaults["end"]>;
default: unknown extends Defaults["end"] ? string | number | Date : Defaults["end"] | NonNullable<string | number | Date>;
};
weekdays: unknown extends Defaults["weekdays"] ? {
type: PropType<number[] | string>;
default: () => number[];
validate: typeof validateWeekdays;
} : Omit<{
type: PropType<number[] | string>;
default: () => number[];
validate: typeof validateWeekdays;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["weekdays"] ? string | number[] : string | number[] | Defaults["weekdays"]>;
default: unknown extends Defaults["weekdays"] ? string | number[] : Defaults["weekdays"] | NonNullable<string | number[]>;
};
firstDayOfWeek: unknown extends Defaults["firstDayOfWeek"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["firstDayOfWeek"] ? string | number : string | number | Defaults["firstDayOfWeek"]>;
default: unknown extends Defaults["firstDayOfWeek"] ? string | number : Defaults["firstDayOfWeek"] | NonNullable<string | number>;
};
firstDayOfYear: unknown extends Defaults["firstDayOfYear"] ? (NumberConstructor | StringConstructor)[] : {
type: PropType<unknown extends Defaults["firstDayOfYear"] ? string | number : string | number | Defaults["firstDayOfYear"]>;
default: unknown extends Defaults["firstDayOfYear"] ? string | number : Defaults["firstDayOfYear"] | NonNullable<string | number>;
};
weekdayFormat: unknown extends Defaults["weekdayFormat"] ? {
type: PropType<CalendarFormatter>;
default: null;
} : Omit<{
type: PropType<CalendarFormatter>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["weekdayFormat"] ? CalendarFormatter : CalendarFormatter | Defaults["weekdayFormat"]>;
default: unknown extends Defaults["weekdayFormat"] ? CalendarFormatter : CalendarFormatter | Defaults["weekdayFormat"];
};
dayFormat: unknown extends Defaults["dayFormat"] ? {
type: PropType<CalendarFormatter>;
default: null;
} : Omit<{
type: PropType<CalendarFormatter>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["dayFormat"] ? CalendarFormatter : CalendarFormatter | Defaults["dayFormat"]>;
default: unknown extends Defaults["dayFormat"] ? CalendarFormatter : CalendarFormatter | Defaults["dayFormat"];
};
locale: unknown extends Defaults["locale"] ? StringConstructor : {
type: PropType<unknown extends Defaults["locale"] ? string : string | Defaults["locale"]>;
default: unknown extends Defaults["locale"] ? string : string | Defaults["locale"];
};
now: unknown extends Defaults["now"] ? {
type: StringConstructor;
validator: typeof validateTimestamp;
} : Omit<{
type: StringConstructor;
validator: typeof validateTimestamp;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["now"] ? string : string | Defaults["now"]>;
default: unknown extends Defaults["now"] ? string : string | Defaults["now"];
};
type: unknown extends Defaults["type"] ? {
type: PropType<'month' | 'week' | 'day' | '4day' | 'custom-weekly' | 'custom-daily' | 'category'>;
default: string;
} : Omit<{
type: PropType<'month' | 'week' | 'day' | '4day' | 'custom-weekly' | 'custom-daily' | 'category'>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["type"] ? "4day" | "category" | "custom-daily" | "custom-weekly" | "day" | "month" | "week" : "4day" | "category" | "custom-daily" | "custom-weekly" | "day" | "month" | "week" | Defaults["type"]>;
default: unknown extends Defaults["type"] ? "4day" | "category" | "custom-daily" | "custom-weekly" | "day" | "month" | "week" : Defaults["type"] | NonNullable<"4day" | "category" | "custom-daily" | "custom-weekly" | "day" | "month" | "week">;
};
};
export interface CalendarBaseProps {
modelValue?: string | number | Date;
categoryDays?: string | number;
start: string | number | Date;
end: string | number | Date | undefined;
weekdays: string | number[];
firstDayOfWeek: number | string | undefined;
firstDayOfYear: number | string | undefined;
weekdayFormat: CalendarFormatter | string | undefined;
dayFormat: CalendarFormatter | string | undefined;
locale: string | undefined;
now: string | undefined;
type: 'month' | 'week' | 'day' | '4day' | 'custom-weekly' | 'custom-daily' | 'category';
}
export declare function useCalendarBase(props: CalendarBaseProps): {
times: {
now: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: import("../types.js").CalendarCategory;
};
today: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: import("../types.js").CalendarCategory;
};
};
locale: {
name: string;
decimalSeparator: import("vue").ShallowRef<string>;
messages: import("vue").Ref<import("../../../types.js").LocaleMessages, import("../../../types.js").LocaleMessages>;
current: import("vue").Ref<string, string>;
fallback: import("vue").Ref<string, string>;
t: (key: string, ...params: unknown[]) => string;
n: (value: number) => string;
provide: (props: import("../../../types.js").LocaleOptions) => import("../../../types.js").LocaleInstance;
isRtl: import("vue").Ref<boolean, boolean>;
rtl: import("vue").Ref<Record<string, boolean>, Record<string, boolean>>;
rtlClasses: import("vue").Ref<string, string>;
};
parsedValue: import("vue").ComputedRef<CalendarTimestamp>;
parsedWeekdays: import("vue").ComputedRef<number[]>;
effectiveWeekdays: import("vue").ComputedRef<number[]>;
weekdaySkips: import("vue").ComputedRef<number[]>;
parsedStart: import("vue").ComputedRef<CalendarTimestamp>;
parsedEnd: import("vue").ComputedRef<CalendarTimestamp>;
days: import("vue").ComputedRef<CalendarTimestamp[]>;
dayFormatter: import("vue").ComputedRef<CalendarFormatter>;
weekdayFormatter: import("vue").ComputedRef<CalendarFormatter>;
getColorProps: (colors: {
background?: ColorValue;
text?: ColorValue;
}) => {
class: string[];
style: import("vue").CSSProperties;
};
getRelativeClasses: (timestamp: CalendarTimestamp, outside?: boolean) => {
'v-present': boolean;
'v-past': boolean;
'v-future': boolean;
'v-outside': boolean;
};
getWeekNumber: (timestamp: CalendarTimestamp) => number;
getStartOfWeek: (timestamp: CalendarTimestamp) => CalendarTimestamp;
getEndOfWeek: (timestamp: CalendarTimestamp) => CalendarTimestamp;
getFormatter: (options: Intl.DateTimeFormatOptions) => CalendarFormatter;
updateTimes: () => void;
};
@@ -0,0 +1,160 @@
// Composables
import { useTimes } from "./times.js";
import { computeColor } from "../../../composables/color.js";
import { useDate } from "../../../composables/date/index.js";
import { provideLocale } from "../../../composables/locale.js"; // Utilities
import { computed } from 'vue';
import { createDayList, createNativeLocaleFormatter, getEndOfMonth, getEndOfWeek, getStartOfMonth, getStartOfWeek, getTimestampIdentifier, getWeekdaySkips, parseDate, parseTimestamp, validateTimestamp, validateWeekdays } from "../util/timestamp.js";
import { propsFactory } from "../../../util/index.js"; // Types
export const makeCalendarBaseProps = propsFactory({
start: {
type: [String, Number, Date],
validate: validateTimestamp,
default: () => parseDate(new Date()).date
},
end: {
type: [String, Number, Date],
validate: validateTimestamp
},
weekdays: {
type: [Array, String],
default: () => [0, 1, 2, 3, 4, 5, 6],
validate: validateWeekdays
},
firstDayOfWeek: [Number, String],
firstDayOfYear: [Number, String],
weekdayFormat: {
type: Function,
default: null
},
dayFormat: {
type: Function,
default: null
},
locale: String,
now: {
type: String,
validator: validateTimestamp
},
type: {
type: String,
default: 'month'
}
}, 'VCalendar-base');
export function useCalendarBase(props) {
const {
times,
updateTimes
} = useTimes({
now: props.now
});
const locale = provideLocale(props);
const adapter = useDate();
const parsedStart = computed(() => {
if (props.type === 'month') {
return getStartOfMonth(parseTimestamp(props.start, true));
}
return parseTimestamp(props.start, true);
});
const parsedEnd = computed(() => {
const start = parsedStart.value;
const end = props.end ? parseTimestamp(props.end) || start : start;
const value = getTimestampIdentifier(end) < getTimestampIdentifier(start) ? start : end;
if (props.type === 'month') {
return getEndOfMonth(value);
}
return value;
});
const parsedValue = computed(() => {
return validateTimestamp(props.modelValue) ? parseTimestamp(props.modelValue, true) : parsedStart.value || times.today;
});
const parsedWeekdays = computed(() => {
const weekdays = Array.isArray(props.weekdays) ? props.weekdays : (props.weekdays || '').split(',').map(x => parseInt(x, 10));
const first = adapter.toJsDate(adapter.startOfWeek(adapter.date(), props.firstDayOfWeek)).getDay();
return [...weekdays.toSorted().filter(v => v >= first), ...weekdays.toSorted().filter(v => v < first)];
});
const effectiveWeekdays = computed(() => {
const start = parsedValue.value;
const days = parseInt(String(props.categoryDays)) || 1;
switch (props.type) {
case 'day':
return [start.weekday];
case '4day':
return [start.weekday, (start.weekday + 1) % 7, (start.weekday + 2) % 7, (start.weekday + 3) % 7];
case 'category':
return Array.from({
length: days
}, (_, i) => (start.weekday + i) % 7);
default:
return parsedWeekdays.value;
}
});
const weekdaySkips = computed(() => {
return getWeekdaySkips(parsedWeekdays.value);
});
const days = computed(() => {
return createDayList(parsedStart.value, parsedEnd.value, times.today, weekdaySkips.value);
});
const dayFormatter = computed(() => {
if (props.dayFormat) {
return props.dayFormat;
}
return createNativeLocaleFormatter(locale.current.value, () => ({
timeZone: 'UTC',
day: 'numeric'
}));
});
const weekdayFormatter = computed(() => {
if (props.weekdayFormat) {
return props.weekdayFormat;
}
return createNativeLocaleFormatter(locale.current.value, (_tms, short) => ({
timeZone: 'UTC',
weekday: short ? 'short' : 'long'
}));
});
function getColorProps(colors) {
return computeColor(colors);
}
function getRelativeClasses(timestamp, outside = false) {
return {
'v-present': timestamp.present,
'v-past': timestamp.past,
'v-future': timestamp.future,
'v-outside': outside
};
}
function getWeekNumber(timestamp) {
return adapter.getWeek(adapter.date(timestamp.date), props.firstDayOfWeek, props.firstDayOfYear);
}
function _getStartOfWeek(timestamp) {
return getStartOfWeek(timestamp, parsedWeekdays.value, times.today);
}
function _getEndOfWeek(timestamp) {
return getEndOfWeek(timestamp, parsedWeekdays.value, times.today);
}
function getFormatter(options) {
return createNativeLocaleFormatter(locale.current.value, () => options);
}
return {
times,
locale,
parsedValue,
parsedWeekdays,
effectiveWeekdays,
weekdaySkips,
parsedStart,
parsedEnd,
days,
dayFormatter,
weekdayFormatter,
getColorProps,
getRelativeClasses,
getWeekNumber,
getStartOfWeek: _getStartOfWeek,
getEndOfWeek: _getEndOfWeek,
getFormatter,
updateTimes
};
}
//# sourceMappingURL=calendarBase.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,65 @@
@layer vuetify-components {
.v-calendar-events .v-event-more {
background-color: rgb(var(--v-theme-surface));
color: rgb(var(--v-theme-on-surface));
}
.v-calendar-events .v-event-more.v-outside {
background-color: rgb(var(--v-theme-surface-light));
color: rgb(var(--v-theme-on-surface-light));
}
.v-calendar .v-event {
position: relative;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
cursor: pointer;
line-height: 20px;
margin-right: -1px;
z-index: 1;
border-radius: 4px;
}
.v-calendar .v-event-more {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 12px;
cursor: pointer;
font-weight: bold;
z-index: 1;
position: relative;
}
.v-calendar .v-event-timed-container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin-right: 10px;
pointer-events: none;
}
.v-calendar .v-event-timed {
position: absolute;
white-space: nowrap;
text-overflow: ellipsis;
font-size: 12px;
cursor: pointer;
border: 1px solid rgb(var(--v-theme-surface));
border-radius: 4px;
pointer-events: all;
}
.v-calendar .v-event-summary {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
white-space: nowrap;
}
.v-calendar.v-calendar-events .v-calendar-weekly__head-weekday {
margin-right: -1px;
}
.v-calendar.v-calendar-events .v-calendar-weekly__day {
overflow: visible;
margin-right: -1px;
}
}
@@ -0,0 +1,307 @@
import type { PropType, VNode } from 'vue';
import type { CalendarBaseProps } from './calendarBase.js';
import type { CalendarCategory, CalendarDayBodySlotScope, CalendarDaySlotScope, CalendarEvent, CalendarEventCategoryFunction, CalendarEventColorFunction, CalendarEventNameFunction, CalendarEventOverlapMode, CalendarEventParsed, CalendarEventTimedFunction, CalendarEventVisual, CalendarTimestamp } from '../types.js';
type VDailyEventsMap = {
[date: string]: {
parent: HTMLElement;
more: HTMLElement | null;
events: HTMLElement[];
};
};
export interface VEventScopeInput {
eventParsed: CalendarEventParsed;
day: CalendarDaySlotScope;
start: boolean;
end: boolean;
timed: boolean;
}
export declare const makeCalendarWithEventsProps: <Defaults extends {
events?: unknown;
eventStart?: unknown;
eventEnd?: unknown;
eventTimed?: unknown;
eventCategory?: unknown;
eventHeight?: unknown;
eventColor?: unknown;
eventTextColor?: unknown;
eventName?: unknown;
eventOverlapThreshold?: unknown;
eventOverlapMode?: unknown;
eventMore?: unknown;
eventMoreText?: unknown;
eventRipple?: unknown;
eventMarginBottom?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
events: unknown extends Defaults["events"] ? {
type: PropType<CalendarEvent[]>;
default: () => never[];
} : Omit<{
type: PropType<CalendarEvent[]>;
default: () => never[];
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["events"] ? CalendarEvent[] : CalendarEvent[] | Defaults["events"]>;
default: unknown extends Defaults["events"] ? CalendarEvent[] : CalendarEvent[] | Defaults["events"];
};
eventStart: unknown extends Defaults["eventStart"] ? {
type: StringConstructor;
default: string;
} : Omit<{
type: StringConstructor;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventStart"] ? string : string | Defaults["eventStart"]>;
default: unknown extends Defaults["eventStart"] ? string : string | Defaults["eventStart"];
};
eventEnd: unknown extends Defaults["eventEnd"] ? {
type: StringConstructor;
default: string;
} : Omit<{
type: StringConstructor;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventEnd"] ? string : string | Defaults["eventEnd"]>;
default: unknown extends Defaults["eventEnd"] ? string : string | Defaults["eventEnd"];
};
eventTimed: unknown extends Defaults["eventTimed"] ? {
type: PropType<string | CalendarEventTimedFunction>;
default: string;
} : Omit<{
type: PropType<string | CalendarEventTimedFunction>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventTimed"] ? string | CalendarEventTimedFunction : string | CalendarEventTimedFunction | Defaults["eventTimed"]>;
default: unknown extends Defaults["eventTimed"] ? string | CalendarEventTimedFunction : Defaults["eventTimed"] | NonNullable<string | CalendarEventTimedFunction>;
};
eventCategory: unknown extends Defaults["eventCategory"] ? {
type: PropType<string | CalendarEventCategoryFunction>;
default: string;
} : Omit<{
type: PropType<string | CalendarEventCategoryFunction>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventCategory"] ? string | CalendarEventCategoryFunction : string | CalendarEventCategoryFunction | Defaults["eventCategory"]>;
default: unknown extends Defaults["eventCategory"] ? string | CalendarEventCategoryFunction : Defaults["eventCategory"] | NonNullable<string | CalendarEventCategoryFunction>;
};
eventHeight: unknown extends Defaults["eventHeight"] ? {
type: NumberConstructor;
default: number;
} : Omit<{
type: NumberConstructor;
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventHeight"] ? number : number | Defaults["eventHeight"]>;
default: unknown extends Defaults["eventHeight"] ? number : number | Defaults["eventHeight"];
};
eventColor: unknown extends Defaults["eventColor"] ? {
type: PropType<string | CalendarEventColorFunction>;
default: string;
} : Omit<{
type: PropType<string | CalendarEventColorFunction>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventColor"] ? string | CalendarEventColorFunction : string | CalendarEventColorFunction | Defaults["eventColor"]>;
default: unknown extends Defaults["eventColor"] ? string | CalendarEventColorFunction : Defaults["eventColor"] | NonNullable<string | CalendarEventColorFunction>;
};
eventTextColor: unknown extends Defaults["eventTextColor"] ? {
type: PropType<string | CalendarEventColorFunction>;
} : Omit<{
type: PropType<string | CalendarEventColorFunction>;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventTextColor"] ? string | CalendarEventColorFunction : string | CalendarEventColorFunction | Defaults["eventTextColor"]>;
default: unknown extends Defaults["eventTextColor"] ? string | CalendarEventColorFunction : Defaults["eventTextColor"] | NonNullable<string | CalendarEventColorFunction>;
};
eventName: unknown extends Defaults["eventName"] ? {
type: PropType<string | CalendarEventNameFunction>;
default: string;
} : Omit<{
type: PropType<string | CalendarEventNameFunction>;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventName"] ? string | CalendarEventNameFunction : string | CalendarEventNameFunction | Defaults["eventName"]>;
default: unknown extends Defaults["eventName"] ? string | CalendarEventNameFunction : Defaults["eventName"] | NonNullable<string | CalendarEventNameFunction>;
};
eventOverlapThreshold: unknown extends Defaults["eventOverlapThreshold"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventOverlapThreshold"] ? string | number : string | number | Defaults["eventOverlapThreshold"]>;
default: unknown extends Defaults["eventOverlapThreshold"] ? string | number : Defaults["eventOverlapThreshold"] | NonNullable<string | number>;
};
eventOverlapMode: unknown extends Defaults["eventOverlapMode"] ? {
type: PropType<'stack' | 'column' | CalendarEventOverlapMode>;
default: string;
validate: (mode: any) => boolean;
} : Omit<{
type: PropType<'stack' | 'column' | CalendarEventOverlapMode>;
default: string;
validate: (mode: any) => boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventOverlapMode"] ? "column" | "stack" | CalendarEventOverlapMode : "column" | "stack" | CalendarEventOverlapMode | Defaults["eventOverlapMode"]>;
default: unknown extends Defaults["eventOverlapMode"] ? "column" | "stack" | CalendarEventOverlapMode : Defaults["eventOverlapMode"] | NonNullable<"column" | "stack" | CalendarEventOverlapMode>;
};
eventMore: unknown extends Defaults["eventMore"] ? {
type: BooleanConstructor;
default: boolean;
} : Omit<{
type: BooleanConstructor;
default: boolean;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventMore"] ? boolean : boolean | Defaults["eventMore"]>;
default: unknown extends Defaults["eventMore"] ? boolean : boolean | Defaults["eventMore"];
};
eventMoreText: unknown extends Defaults["eventMoreText"] ? {
type: StringConstructor;
default: string;
} : Omit<{
type: StringConstructor;
default: string;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventMoreText"] ? string : string | Defaults["eventMoreText"]>;
default: unknown extends Defaults["eventMoreText"] ? string : string | Defaults["eventMoreText"];
};
eventRipple: unknown extends Defaults["eventRipple"] ? {
type: (BooleanConstructor | ObjectConstructor)[];
default: null;
} : Omit<{
type: (BooleanConstructor | ObjectConstructor)[];
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventRipple"] ? boolean | Record<string, any> : boolean | Record<string, any> | Defaults["eventRipple"]>;
default: unknown extends Defaults["eventRipple"] ? boolean | Record<string, any> : Defaults["eventRipple"] | NonNullable<boolean | Record<string, any>>;
};
eventMarginBottom: unknown extends Defaults["eventMarginBottom"] ? {
type: NumberConstructor;
default: number;
} : Omit<{
type: NumberConstructor;
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["eventMarginBottom"] ? number : number | Defaults["eventMarginBottom"]>;
default: unknown extends Defaults["eventMarginBottom"] ? number : number | Defaults["eventMarginBottom"];
};
};
interface CalendarWithEventsProps extends CalendarBaseProps {
events: CalendarEvent[];
eventStart: string;
eventEnd: string;
eventTimed: string | CalendarEventTimedFunction;
eventCategory: string | CalendarEventCategoryFunction;
eventHeight: number;
eventColor: string | CalendarEventColorFunction;
eventTextColor: string | CalendarEventColorFunction | undefined;
eventName: string | CalendarEventNameFunction;
eventOverlapThreshold: string | number;
eventOverlapMode: string | CalendarEventOverlapMode;
eventMore: boolean;
eventMoreText: string;
eventRipple: boolean | object | null | undefined;
eventMarginBottom: number;
type: 'month' | 'week' | 'day' | '4day' | 'custom-weekly' | 'custom-daily' | 'category';
}
export declare function useCalendarWithEvents(props: CalendarWithEventsProps, slots: any, attrs: any): {
times: {
now: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: CalendarCategory;
};
today: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: CalendarCategory;
};
};
locale: {
name: string;
decimalSeparator: import("vue").ShallowRef<string>;
messages: import("vue").Ref<import("../../../types.js").LocaleMessages, import("../../../types.js").LocaleMessages>;
current: import("vue").Ref<string, string>;
fallback: import("vue").Ref<string, string>;
t: (key: string, ...params: unknown[]) => string;
n: (value: number) => string;
provide: (props: import("../../../types.js").LocaleOptions) => import("../../../types.js").LocaleInstance;
isRtl: import("vue").Ref<boolean, boolean>;
rtl: import("vue").Ref<Record<string, boolean>, Record<string, boolean>>;
rtlClasses: import("vue").Ref<string, string>;
};
parsedValue: import("vue").ComputedRef<CalendarTimestamp>;
parsedWeekdays: import("vue").ComputedRef<number[]>;
effectiveWeekdays: import("vue").ComputedRef<number[]>;
weekdaySkips: import("vue").ComputedRef<number[]>;
parsedStart: import("vue").ComputedRef<CalendarTimestamp>;
parsedEnd: import("vue").ComputedRef<CalendarTimestamp>;
days: import("vue").ComputedRef<CalendarTimestamp[]>;
dayFormatter: import("vue").ComputedRef<import("../types.js").CalendarFormatter>;
weekdayFormatter: import("vue").ComputedRef<import("../types.js").CalendarFormatter>;
getColorProps: (colors: {
background?: import("../../../composables/color.js").ColorValue;
text?: import("../../../composables/color.js").ColorValue;
}) => {
class: string[];
style: import("vue").CSSProperties;
};
getRelativeClasses: (timestamp: CalendarTimestamp, outside?: boolean) => {
'v-present': boolean;
'v-past': boolean;
'v-future': boolean;
'v-outside': boolean;
};
getWeekNumber: (timestamp: CalendarTimestamp) => number;
getStartOfWeek: (timestamp: CalendarTimestamp) => CalendarTimestamp;
getEndOfWeek: (timestamp: CalendarTimestamp) => CalendarTimestamp;
getFormatter: (options: Intl.DateTimeFormatOptions) => import("../types.js").CalendarFormatter;
updateTimes: () => void;
noEvents: import("vue").ComputedRef<boolean>;
parsedEvents: import("vue").ComputedRef<CalendarEventParsed[]>;
parsedEventOverlapThreshold: import("vue").ComputedRef<number>;
eventTimedFunction: import("vue").ComputedRef<CalendarEventTimedFunction>;
eventCategoryFunction: import("vue").ComputedRef<CalendarEventCategoryFunction>;
eventTextColorFunction: import("vue").ComputedRef<CalendarEventColorFunction>;
eventNameFunction: import("vue").ComputedRef<CalendarEventNameFunction>;
eventModeFunction: import("vue").ComputedRef<CalendarEventOverlapMode>;
eventWeekdays: import("vue").ComputedRef<number[]>;
categoryMode: import("vue").ComputedRef<boolean>;
eventColorFunction: (e: CalendarEvent) => string | undefined;
eventsRef: import("vue").Ref<HTMLElement[], HTMLElement[]>;
updateEventVisibility: () => void;
getEventsMap: () => VDailyEventsMap;
genDayEvent: ({ event }: CalendarEventVisual, day: CalendarDaySlotScope) => VNode;
genTimedEvent: ({ event, left, width }: CalendarEventVisual, day: CalendarDayBodySlotScope) => VNode | false;
genEvent: (event: CalendarEventParsed, scopeInput: VEventScopeInput, timedEvent: boolean, data: Record<string, unknown>) => VNode;
genName: (eventSummary: () => string | VNode) => VNode;
genPlaceholder: (day: CalendarTimestamp) => VNode;
genMore: (day: CalendarDaySlotScope) => VNode;
getVisibleEvents: () => CalendarEventParsed[];
isEventForCategory: (event: CalendarEventParsed, category: CalendarCategory) => boolean;
getEventsForDay: (day: CalendarDaySlotScope) => CalendarEventParsed[];
getEventsForDayAll: (day: CalendarDaySlotScope) => CalendarEventParsed[];
getEventsForDayTimed: (day: CalendarDaySlotScope) => CalendarEventParsed[];
getScopedSlots: () => any;
};
@@ -0,0 +1,473 @@
import { createElementVNode as _createElementVNode, createTextVNode as _createTextVNode, mergeProps as _mergeProps, withDirectives as _withDirectives } from "vue";
// Styles
import "./calendarWithEvents.css";
// Composables
import { useCalendarBase } from "./calendarBase.js"; // Directives
import vRipple from "../../../directives/ripple/index.js"; // Utilities
import { computed, ref } from 'vue';
import { CalendarEventOverlapModes } from "../modes/index.js";
import { isEventHiddenOn, isEventOn, isEventOnDay, isEventOverlapping, isEventStart, parseEvent } from "../util/events.js";
import { diffMinutes, getDayIdentifier } from "../util/timestamp.js";
import { getPrefixedEventHandlers, propsFactory } from "../../../util/index.js"; // Types
// Constants
const WIDTH_FULL = 100;
const WIDTH_START = 95;
// const MINUTES_IN_DAY = 1440
// Prevent import from being erased
void vRipple;
export const makeCalendarWithEventsProps = propsFactory({
events: {
type: Array,
default: () => []
},
eventStart: {
type: String,
default: 'start'
},
eventEnd: {
type: String,
default: 'end'
},
eventTimed: {
type: [String, Function],
default: 'timed'
},
eventCategory: {
type: [String, Function],
default: 'category'
},
eventHeight: {
type: Number,
default: 20
},
eventColor: {
type: [String, Function],
default: 'primary'
},
eventTextColor: {
type: [String, Function]
},
eventName: {
type: [String, Function],
default: 'name'
},
eventOverlapThreshold: {
type: [String, Number],
default: 60
},
eventOverlapMode: {
type: [String, Function],
default: 'stack',
validate: mode => mode in CalendarEventOverlapModes || typeof mode === 'function'
},
eventMore: {
type: Boolean,
default: true
},
eventMoreText: {
type: String,
default: '$vuetify.calendar.moreEvents'
},
eventRipple: {
type: [Boolean, Object],
default: null
},
eventMarginBottom: {
type: Number,
default: 1
}
}, 'VCalendar-events');
export function useCalendarWithEvents(props, slots, attrs) {
const base = useCalendarBase(props);
const noEvents = computed(() => {
return !Array.isArray(props.events) || props.events.length === 0;
});
const categoryMode = computed(() => {
return props.type === 'category';
});
const eventTimedFunction = computed(() => {
return typeof props.eventTimed === 'function' ? props.eventTimed : event => !!event[props.eventTimed];
});
const eventCategoryFunction = computed(() => {
return typeof props.eventCategory === 'function' ? props.eventCategory : event => event[props.eventCategory];
});
const parsedEvents = computed(() => {
if (!props.events) return [];
return props.events.map((event, index) => parseEvent(event, index, props.eventStart || '', props.eventEnd || '', eventTimedFunction.value(event), categoryMode.value ? eventCategoryFunction.value(event) : false));
});
const parsedEventOverlapThreshold = computed(() => {
return parseInt(String(props.eventOverlapThreshold || 0));
});
const eventTextColorFunction = computed(() => {
return typeof props.eventTextColor === 'function' ? props.eventTextColor : () => props.eventTextColor;
});
const eventNameFunction = computed(() => {
return typeof props.eventName === 'function' ? props.eventName : (event, timedEvent) => event.input[props.eventName] || '';
});
const eventModeFunction = computed(() => {
return typeof props.eventOverlapMode === 'function' ? props.eventOverlapMode : CalendarEventOverlapModes[props.eventOverlapMode];
});
const eventWeekdays = computed(() => {
return base.effectiveWeekdays.value;
});
function eventColorFunction(e) {
return typeof props.eventColor === 'function' ? props.eventColor(e) : e.color || props.eventColor;
}
const eventsRef = ref([]);
function updateEventVisibility() {
if (noEvents.value || !props.eventMore) {
return;
}
const eventHeight = props.eventHeight || 0;
const eventsMap = getEventsMap();
for (const date in eventsMap) {
const {
parent,
events,
more
} = eventsMap[date];
if (!more) {
break;
}
const parentBounds = parent.getBoundingClientRect();
const last = events.length - 1;
const eventsSorted = events.map(event => ({
event,
bottom: event.getBoundingClientRect().bottom
})).sort((a, b) => a.bottom - b.bottom);
let hidden = 0;
for (let i = 0; i <= last; i++) {
const bottom = eventsSorted[i].bottom;
const hide = i === last ? bottom > parentBounds.bottom : bottom + eventHeight > parentBounds.bottom;
if (hide) {
eventsSorted[i].event.style.display = 'none';
hidden++;
}
}
// TODO: avoid direct DOM manipulation
if (hidden) {
more.style.display = '';
more.innerHTML = base.locale.t(props.eventMoreText, hidden);
} else {
more.style.display = 'none';
}
}
}
function getEventsMap() {
const eventsMap = {};
const elements = eventsRef.value;
if (!elements || !elements.length) {
return eventsMap;
}
elements.forEach(el => {
const date = el.getAttribute('data-date');
if (el.parentElement && date) {
if (!(date in eventsMap)) {
eventsMap[date] = {
parent: el.parentElement,
more: null,
events: []
};
}
if (el.getAttribute('data-more')) {
eventsMap[date].more = el;
} else {
eventsMap[date].events.push(el);
el.style.display = '';
}
}
});
return eventsMap;
}
function genDayEvent({
event
}, day) {
const eventHeight = props.eventHeight || 0;
const eventMarginBottom = props.eventMarginBottom || 0;
const dayIdentifier = getDayIdentifier(day);
const week = day.week;
const start = dayIdentifier === event.startIdentifier;
let end = dayIdentifier === event.endIdentifier;
let width = WIDTH_START;
if (!categoryMode.value) {
for (let i = day.index + 1; i < week.length; i++) {
const weekdayIdentifier = getDayIdentifier(week[i]);
if (event.endIdentifier >= weekdayIdentifier) {
width += WIDTH_FULL;
end = end || weekdayIdentifier === event.endIdentifier;
} else {
end = true;
break;
}
}
}
const scope = {
eventParsed: event,
day,
start,
end,
timed: false
};
return genEvent(event, scope, false, {
class: ['v-event', {
'v-event-start': start,
'v-event-end': end
}],
style: {
height: `${eventHeight}px`,
width: `${width}%`,
marginBottom: `${eventMarginBottom}px`
},
'data-date': day.date
});
}
function genTimedEvent({
event,
left,
width
}, day) {
const startDelta = day.timeDelta(event.start, day);
const endDelta = day.timeDelta(event.end, day);
if (endDelta === false || startDelta === false || endDelta < 0 || startDelta >= 1 || isEventHiddenOn(event, day)) {
return false;
}
const dayIdentifier = getDayIdentifier(day);
const start = event.startIdentifier >= dayIdentifier;
const end = event.endIdentifier > dayIdentifier;
const top = day.timeToY(event.start, day);
const bottom = day.timeToY(event.end, day);
const height = Math.max(props.eventHeight || 0, bottom - top);
const scope = {
eventParsed: event,
day,
start,
end,
timed: true
};
return genEvent(event, scope, true, {
class: 'v-event-timed',
style: {
top: `${top}px`,
height: `${height}px`,
left: `${left}%`,
width: `${width}%`
}
});
}
function genEvent(event, scopeInput, timedEvent, data) {
const slot = slots.event;
const text = eventTextColorFunction.value(event.input);
const background = eventColorFunction(event.input);
const overlapsNoon = event.start.hour < 12 && event.end.hour >= 12;
const singline = diffMinutes(event.start, event.end) <= parsedEventOverlapThreshold.value;
const formatTime = (withTime, ampm) => {
const formatter = base.getFormatter({
timeZone: 'UTC',
hour: 'numeric',
minute: withTime.minute > 0 ? 'numeric' : undefined
});
return formatter(withTime, true);
};
const timeSummary = () => formatTime(event.start, overlapsNoon) + ' - ' + formatTime(event.end, true);
const eventSummary = () => {
const name = eventNameFunction.value(event, timedEvent);
if (event.start.hasTime) {
if (timedEvent) {
const time = timeSummary();
const delimiter = singline ? ', ' : _createElementVNode("br", null, null);
return _createElementVNode("span", {
"class": "v-event-summary"
}, [_createElementVNode("strong", null, [name]), delimiter, time]);
} else {
const time = formatTime(event.start, true);
return _createElementVNode("span", {
"class": "v-event-summary"
}, [_createElementVNode("strong", null, [time]), _createTextVNode(" "), name]);
}
}
return _createElementVNode("span", {
"class": "v-event-summary"
}, [name]);
};
const scope = {
...scopeInput,
event: event.input,
outside: scopeInput.day.outside,
singline,
overlapsNoon,
formatTime,
timeSummary,
eventSummary
};
const events = getPrefixedEventHandlers(attrs, ':event', nativeEvent => ({
...scope,
nativeEvent
}));
return _withDirectives(_createElementVNode("div", _mergeProps(base.getColorProps({
text,
background
}), events, data, {
"ref_for": true,
"ref": eventsRef
}), [slot?.(scope) ?? genName(eventSummary)]), [[vRipple, props.eventRipple ?? true]]);
}
function genName(eventSummary) {
return _createElementVNode("div", {
"class": "pl-1"
}, [eventSummary()]);
}
function genPlaceholder(day) {
const height = (props.eventHeight || 0) + (props.eventMarginBottom || 0);
return _createElementVNode("div", {
"style": {
height: `${height}px`
},
"data-date": day.date,
"ref_for": true,
"ref": eventsRef
}, null);
}
function genMore(day) {
const eventHeight = props.eventHeight || 0;
const eventMarginBottom = props.eventMarginBottom || 0;
const events = getPrefixedEventHandlers(attrs, ':more', nativeEvent => ({
nativeEvent,
...day
}));
return _withDirectives(_createElementVNode("div", _mergeProps({
"class": ['v-event-more pl-1', {
'v-outside': day.outside
}],
"data-date": day.date,
"data-more": "1",
"style": {
display: 'none',
height: `${eventHeight}px`,
marginBottom: `${eventMarginBottom}px`
},
"ref_for": true,
"ref": eventsRef
}, events), null), [[vRipple, props.eventRipple ?? true]]);
}
function getVisibleEvents() {
const days = base.days.value;
const start = getDayIdentifier(days[0]);
const end = getDayIdentifier(days[days.length - 1]);
return parsedEvents.value.filter(event => isEventOverlapping(event, start, end));
}
function isEventForCategory(event, category) {
return !categoryMode.value || typeof category === 'object' && category.categoryName && category.categoryName === event.category || typeof event.category === 'string' && category === event.category || typeof event.category !== 'string' && category === null;
}
function getEventsForDay(day) {
const identifier = getDayIdentifier(day);
const firstWeekday = eventWeekdays.value[0];
return parsedEvents.value.filter(event => isEventStart(event, day, identifier, firstWeekday));
}
function getEventsForDayAll(day) {
const identifier = getDayIdentifier(day);
const firstWeekday = eventWeekdays.value[0];
return parsedEvents.value.filter(event => event.allDay && (categoryMode.value ? isEventOn(event, identifier) : isEventStart(event, day, identifier, firstWeekday)) && isEventForCategory(event, day.category));
}
function getEventsForDayTimed(day) {
return parsedEvents.value.filter(event => !event.allDay && isEventOnDay(event, day, day.intervalRange) && isEventForCategory(event, day.category));
}
function getScopedSlots() {
if (noEvents.value) {
return {
...slots
};
}
const mode = eventModeFunction.value(parsedEvents.value, eventWeekdays.value[0], parsedEventOverlapThreshold.value);
const isNode = input => !!input;
const getSlotChildren = (day, getter, mapper, timed) => {
const events = getter(day);
const visuals = mode(day, events, timed, categoryMode.value);
if (timed) {
return visuals.map(visual => mapper(visual, day)).filter(isNode);
}
const children = [];
visuals.forEach((visual, index) => {
while (children.length < visual.column) {
children.push(genPlaceholder(day));
}
const mapped = mapper(visual, day);
if (mapped) {
children.push(mapped);
}
});
return children;
};
return {
...slots,
day: day => {
let children = getSlotChildren(day, getEventsForDay, genDayEvent, false);
if (children && children.length > 0 && props.eventMore) {
children.push(genMore(day));
}
if (slots.day) {
const slot = slots.day(day);
if (slot) {
children = children ? children.concat(slot) : slot;
}
}
return children;
},
'day-header': day => {
let children = getSlotChildren(day, getEventsForDayAll, genDayEvent, false);
if (slots['day-header']) {
const slot = slots['day-header'](day);
if (slot) {
children = children ? children.concat(slot) : slot;
}
}
return children;
},
'day-body': day => {
const events = getSlotChildren(day, getEventsForDayTimed, genTimedEvent, true);
let children = [_createElementVNode("div", {
"class": "v-event-timed-container"
}, [events])];
if (slots['day-body']) {
const slot = slots['day-body'](day);
if (slot) {
children = children.concat(slot);
}
}
return children;
}
};
}
return {
...base,
noEvents,
parsedEvents,
parsedEventOverlapThreshold,
eventTimedFunction,
eventCategoryFunction,
eventTextColorFunction,
eventNameFunction,
eventModeFunction,
eventWeekdays,
categoryMode,
eventColorFunction,
eventsRef,
updateEventVisibility,
getEventsMap,
genDayEvent,
genTimedEvent,
genEvent,
genName,
genPlaceholder,
genMore,
getVisibleEvents,
isEventForCategory,
getEventsForDay,
getEventsForDayAll,
getEventsForDayTimed,
getScopedSlots
};
}
//# sourceMappingURL=calendarWithEvents.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,69 @@
@use '../../../styles/tools'
@use '../../../styles/settings'
@use '../variables' as *
@include tools.layer('components')
.v-calendar-events
.v-event-more
background-color: $calendar-background
color: $calendar-on-background
&.v-outside
background-color: $calendar-outside-background
color: $calendar-on-outside-background
.v-calendar
.v-event
position: relative
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
font-size: $calendar-event-font-size
cursor: pointer
line-height: $calendar-event-line-height
margin-right: -$calendar-line-width
z-index: 1
border-radius: $calendar-event-border-radius
.v-event-more
overflow: hidden
text-overflow: ellipsis
white-space: nowrap
font-size: $calendar-event-font-size
cursor: pointer
font-weight: bold
z-index: 1
position: relative
.v-event-timed-container
position: absolute
top: 0
bottom: 0
left: 0
right: 0
margin-right: $calendar-event-right-empty
pointer-events: none
.v-event-timed
position: absolute
white-space: nowrap
text-overflow: ellipsis
font-size: $calendar-event-font-size
cursor: pointer
border: $calendar-event-border-width solid $calendar-background
border-radius: $calendar-event-border-radius
pointer-events: all
.v-event-summary
display: inline-block
overflow: hidden
text-overflow: ellipsis
width: 100%
white-space: nowrap
&.v-calendar-events
.v-calendar-weekly__head-weekday
margin-right: -$calendar-line-width
.v-calendar-weekly__day
overflow: visible
margin-right: -$calendar-line-width
@@ -0,0 +1,232 @@
import { validateNumber, validateTime } from '../util/timestamp.js';
import type { PropType, StyleValue } from 'vue';
import type { CalendarBaseProps } from './calendarBase.js';
import type { CalendarDayBodySlotScope, CalendarFormatter, CalendarTimestamp } from '../types.js';
import type { VTime } from '../util/timestamp.js';
export declare const makeCalendarWithIntervalsProps: <Defaults extends {
maxDays?: unknown;
intervalHeight?: unknown;
intervalWidth?: unknown;
intervalMinutes?: unknown;
firstInterval?: unknown;
firstTime?: unknown;
intervalCount?: unknown;
intervalFormat?: unknown;
intervalStyle?: unknown;
showIntervalLabel?: unknown;
} = {}>(defaults?: Defaults | undefined) => {
maxDays: unknown extends Defaults["maxDays"] ? {
type: NumberConstructor;
default: number;
} : Omit<{
type: NumberConstructor;
default: number;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["maxDays"] ? number : number | Defaults["maxDays"]>;
default: unknown extends Defaults["maxDays"] ? number : number | Defaults["maxDays"];
};
intervalHeight: unknown extends Defaults["intervalHeight"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["intervalHeight"] ? string | number : string | number | Defaults["intervalHeight"]>;
default: unknown extends Defaults["intervalHeight"] ? string | number : Defaults["intervalHeight"] | NonNullable<string | number>;
};
intervalWidth: unknown extends Defaults["intervalWidth"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["intervalWidth"] ? string | number : string | number | Defaults["intervalWidth"]>;
default: unknown extends Defaults["intervalWidth"] ? string | number : Defaults["intervalWidth"] | NonNullable<string | number>;
};
intervalMinutes: unknown extends Defaults["intervalMinutes"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["intervalMinutes"] ? string | number : string | number | Defaults["intervalMinutes"]>;
default: unknown extends Defaults["intervalMinutes"] ? string | number : Defaults["intervalMinutes"] | NonNullable<string | number>;
};
firstInterval: unknown extends Defaults["firstInterval"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["firstInterval"] ? string | number : string | number | Defaults["firstInterval"]>;
default: unknown extends Defaults["firstInterval"] ? string | number : Defaults["firstInterval"] | NonNullable<string | number>;
};
firstTime: unknown extends Defaults["firstTime"] ? {
type: PropType<VTime>;
validate: typeof validateTime;
} : Omit<{
type: PropType<VTime>;
validate: typeof validateTime;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["firstTime"] ? VTime : Defaults["firstTime"] | VTime>;
default: unknown extends Defaults["firstTime"] ? VTime : Defaults["firstTime"] | NonNullable<VTime>;
};
intervalCount: unknown extends Defaults["intervalCount"] ? {
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
} : Omit<{
type: (NumberConstructor | StringConstructor)[];
default: number;
validate: typeof validateNumber;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["intervalCount"] ? string | number : string | number | Defaults["intervalCount"]>;
default: unknown extends Defaults["intervalCount"] ? string | number : Defaults["intervalCount"] | NonNullable<string | number>;
};
intervalFormat: unknown extends Defaults["intervalFormat"] ? {
type: PropType<CalendarFormatter>;
default: null;
} : Omit<{
type: PropType<CalendarFormatter>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["intervalFormat"] ? CalendarFormatter : CalendarFormatter | Defaults["intervalFormat"]>;
default: unknown extends Defaults["intervalFormat"] ? CalendarFormatter : CalendarFormatter | Defaults["intervalFormat"];
};
intervalStyle: unknown extends Defaults["intervalStyle"] ? {
type: PropType<(interval: CalendarTimestamp) => StyleValue>;
default: null;
} : Omit<{
type: PropType<(interval: CalendarTimestamp) => StyleValue>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["intervalStyle"] ? (interval: CalendarTimestamp) => StyleValue : ((interval: CalendarTimestamp) => StyleValue) | Defaults["intervalStyle"]>;
default: unknown extends Defaults["intervalStyle"] ? (interval: CalendarTimestamp) => StyleValue : ((interval: CalendarTimestamp) => StyleValue) | Defaults["intervalStyle"];
};
showIntervalLabel: unknown extends Defaults["showIntervalLabel"] ? {
type: PropType<(interval: CalendarTimestamp) => boolean>;
default: null;
} : Omit<{
type: PropType<(interval: CalendarTimestamp) => boolean>;
default: null;
}, "default" | "type"> & {
type: PropType<unknown extends Defaults["showIntervalLabel"] ? (interval: CalendarTimestamp) => boolean : ((interval: CalendarTimestamp) => boolean) | Defaults["showIntervalLabel"]>;
default: unknown extends Defaults["showIntervalLabel"] ? (interval: CalendarTimestamp) => boolean : ((interval: CalendarTimestamp) => boolean) | Defaults["showIntervalLabel"];
};
};
interface CalendarWithIntervalsProps extends CalendarBaseProps {
maxDays: number;
intervalHeight: string | number;
intervalMinutes: string | number;
firstInterval: string | number;
firstTime: VTime | undefined;
intervalCount: string | number;
intervalFormat: CalendarFormatter | string | undefined;
}
export declare function useCalendarWithIntervals(props: CalendarWithIntervalsProps): {
times: {
now: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: import("../types.js").CalendarCategory;
};
today: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: import("../types.js").CalendarCategory;
};
};
locale: {
name: string;
decimalSeparator: import("vue").ShallowRef<string>;
messages: import("vue").Ref<import("../../../types.js").LocaleMessages, import("../../../types.js").LocaleMessages>;
current: import("vue").Ref<string, string>;
fallback: import("vue").Ref<string, string>;
t: (key: string, ...params: unknown[]) => string;
n: (value: number) => string;
provide: (props: import("../../../types.js").LocaleOptions) => import("../../../types.js").LocaleInstance;
isRtl: import("vue").Ref<boolean, boolean>;
rtl: import("vue").Ref<Record<string, boolean>, Record<string, boolean>>;
rtlClasses: import("vue").Ref<string, string>;
};
parsedValue: import("vue").ComputedRef<CalendarTimestamp>;
parsedWeekdays: import("vue").ComputedRef<number[]>;
effectiveWeekdays: import("vue").ComputedRef<number[]>;
weekdaySkips: import("vue").ComputedRef<number[]>;
parsedStart: import("vue").ComputedRef<CalendarTimestamp>;
parsedEnd: import("vue").ComputedRef<CalendarTimestamp>;
dayFormatter: import("vue").ComputedRef<CalendarFormatter>;
weekdayFormatter: import("vue").ComputedRef<CalendarFormatter>;
getColorProps: (colors: {
background?: import("../../../composables/color.js").ColorValue;
text?: import("../../../composables/color.js").ColorValue;
}) => {
class: string[];
style: import("vue").CSSProperties;
};
getRelativeClasses: (timestamp: CalendarTimestamp, outside?: boolean) => {
'v-present': boolean;
'v-past': boolean;
'v-future': boolean;
'v-outside': boolean;
};
getWeekNumber: (timestamp: CalendarTimestamp) => number;
getStartOfWeek: (timestamp: CalendarTimestamp) => CalendarTimestamp;
getEndOfWeek: (timestamp: CalendarTimestamp) => CalendarTimestamp;
getFormatter: (options: Intl.DateTimeFormatOptions) => CalendarFormatter;
updateTimes: () => void;
scrollAreaRef: import("vue").ShallowRef<HTMLElement | undefined, HTMLElement | undefined>;
parsedFirstInterval: import("vue").ComputedRef<number>;
parsedIntervalMinutes: import("vue").ComputedRef<number>;
parsedIntervalCount: import("vue").ComputedRef<number>;
parsedIntervalHeight: import("vue").ComputedRef<number>;
parsedFirstTime: import("vue").ComputedRef<number | false>;
firstMinute: import("vue").ComputedRef<number>;
bodyHeight: import("vue").ComputedRef<number>;
days: import("vue").ComputedRef<CalendarTimestamp[]>;
intervals: import("vue").ComputedRef<CalendarTimestamp[][]>;
intervalFormatter: import("vue").ComputedRef<CalendarFormatter>;
showIntervalLabelDefault: (interval: CalendarTimestamp) => boolean;
intervalStyleDefault: (_interval: CalendarTimestamp) => StyleValue;
getTimestampAtEvent: (e: Event, day: CalendarTimestamp) => CalendarTimestamp;
getSlotScope: (timestamp: CalendarTimestamp) => CalendarDayBodySlotScope;
scrollToTime: (time: VTime) => boolean;
minutesToPixels: (minutes: number) => number;
timeToY: (time: VTime | CalendarTimestamp, targetDateOrClamp?: CalendarTimestamp | boolean) => number | false;
timeDelta: (time: VTime | CalendarTimestamp, targetDate?: CalendarTimestamp) => number | false;
};
@@ -0,0 +1,208 @@
// Composables
import { useCalendarBase } from "./calendarBase.js"; // Utilities
import { computed, shallowRef } from 'vue';
import { copyTimestamp, createDayList, createIntervalList, createNativeLocaleFormatter, getDayIdentifier, MINUTES_IN_DAY, parseTime, updateMinutes, validateNumber, validateTime } from "../util/timestamp.js";
import { propsFactory } from "../../../util/index.js";
import { Box, getTargetBox } from "../../../util/box.js"; // Types
export const makeCalendarWithIntervalsProps = propsFactory({
maxDays: {
type: Number,
default: 7
},
intervalHeight: {
type: [Number, String],
default: 48,
validate: validateNumber
},
intervalWidth: {
type: [Number, String],
default: 60,
validate: validateNumber
},
intervalMinutes: {
type: [Number, String],
default: 60,
validate: validateNumber
},
firstInterval: {
type: [Number, String],
default: 0,
validate: validateNumber
},
firstTime: {
type: [Number, String, Object],
validate: validateTime
},
intervalCount: {
type: [Number, String],
default: 24,
validate: validateNumber
},
intervalFormat: {
type: Function,
default: null
},
intervalStyle: {
type: Function,
default: null
},
showIntervalLabel: {
type: Function,
default: null
}
}, 'VCalendar-intervals');
export function useCalendarWithIntervals(props) {
const base = useCalendarBase(props);
const scrollAreaRef = shallowRef();
const parsedFirstInterval = computed(() => {
return parseInt(String(props.firstInterval || 0));
});
const parsedIntervalMinutes = computed(() => {
return parseInt(String(props.intervalMinutes || 60));
});
const parsedIntervalCount = computed(() => {
return parseInt(String(props.intervalCount || 24));
});
const parsedIntervalHeight = computed(() => {
return parseFloat(String(props.intervalHeight || 48));
});
const parsedFirstTime = computed(() => {
return parseTime(props.firstTime);
});
const firstMinute = computed(() => {
const time = parsedFirstTime.value;
return time !== false && time >= 0 && time <= MINUTES_IN_DAY ? time : parsedFirstInterval.value * parsedIntervalMinutes.value;
});
const bodyHeight = computed(() => {
return parsedIntervalCount.value * parsedIntervalHeight.value;
});
const days = computed(() => {
return createDayList(base.parsedStart.value, base.parsedEnd.value, base.times.today, base.weekdaySkips.value, props.maxDays);
});
const intervals = computed(() => {
const daysValue = days.value;
const first = firstMinute.value;
const minutes = parsedIntervalMinutes.value;
const count = parsedIntervalCount.value;
const now = base.times.now;
return daysValue.map(d => createIntervalList(d, first, minutes, count, now));
});
const intervalFormatter = computed(() => {
if (props.intervalFormat) {
return props.intervalFormat;
}
return createNativeLocaleFormatter(base.locale.current.value, (tms, short) => !short ? {
timeZone: 'UTC',
hour: '2-digit',
minute: '2-digit'
} : tms.minute === 0 ? {
timeZone: 'UTC',
hour: 'numeric'
} : {
timeZone: 'UTC',
hour: 'numeric',
minute: '2-digit'
});
});
function showIntervalLabelDefault(interval) {
const first = intervals.value[0][0];
const isFirst = first.hour === interval.hour && first.minute === interval.minute;
return !isFirst;
}
function intervalStyleDefault(_interval) {
return undefined;
}
function getTimestampAtEvent(e, day) {
const timestamp = copyTimestamp(day);
const bounds = new Box(e.currentTarget);
const baseMinutes = firstMinute.value;
const touchEvent = e;
const mouseEvent = e;
const touches = touchEvent.changedTouches || touchEvent.touches;
const target = touches && touches[0] ? touches[0] : mouseEvent;
const point = getTargetBox([target.clientX, target.clientY]);
const addIntervals = (point.y - bounds.top) / parsedIntervalHeight.value;
const addMinutes = Math.floor(addIntervals * parsedIntervalMinutes.value);
const minutes = baseMinutes + addMinutes;
return updateMinutes(timestamp, minutes, base.times.now);
}
function getSlotScope(timestamp) {
const scope = copyTimestamp(timestamp);
scope.timeToY = timeToY;
scope.timeDelta = timeDelta;
scope.minutesToPixels = minutesToPixels;
scope.week = days.value;
scope.intervalRange = [firstMinute.value, firstMinute.value + parsedIntervalCount.value * parsedIntervalMinutes.value];
return scope;
}
function scrollToTime(time) {
const y = timeToY(time);
const pane = scrollAreaRef.value;
if (y === false || !pane) {
return false;
}
pane.scrollTop = y;
return true;
}
function minutesToPixels(minutes) {
return minutes / parsedIntervalMinutes.value * parsedIntervalHeight.value;
}
function timeToY(time, targetDateOrClamp = false) {
const clamp = targetDateOrClamp !== false;
const targetDate = typeof targetDateOrClamp !== 'boolean' ? targetDateOrClamp : undefined;
let y = timeDelta(time, targetDate);
if (y === false) return y;
y *= bodyHeight.value;
if (clamp) {
if (y < 0) {
y = 0;
} else if (y > bodyHeight.value) {
y = bodyHeight.value;
}
} else {
if (y < 0) {
y = y + bodyHeight.value;
} else if (y > bodyHeight.value) {
y = y - bodyHeight.value;
}
}
return y;
}
function timeDelta(time, targetDate) {
let minutes = parseTime(time);
if (minutes === false) {
return false;
}
const gap = parsedIntervalCount.value * parsedIntervalMinutes.value;
if (targetDate && typeof time === 'object' && 'day' in time) {
const a = getDayIdentifier(time);
const b = getDayIdentifier(targetDate);
minutes += (a - b) * gap;
}
const min = firstMinute.value;
return (minutes - min) / gap;
}
return {
...base,
scrollAreaRef,
parsedFirstInterval,
parsedIntervalMinutes,
parsedIntervalCount,
parsedIntervalHeight,
parsedFirstTime,
firstMinute,
bodyHeight,
days,
intervals,
intervalFormatter,
showIntervalLabelDefault,
intervalStyleDefault,
getTimestampAtEvent,
getSlotScope,
scrollToTime,
minutesToPixels,
timeToY,
timeDelta
};
}
//# sourceMappingURL=calendarWithIntervals.js.map
File diff suppressed because one or more lines are too long
@@ -0,0 +1,45 @@
import type { CalendarTimestamp } from '../types.js';
export declare function useTimes(props: {
now: string | undefined;
}): {
times: {
now: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: import("../types.js").CalendarCategory;
};
today: {
date: string;
time: string;
year: number;
month: number;
day: number;
weekday: number;
hour: number;
minute: number;
hasDay: boolean;
hasTime: boolean;
past: boolean;
present: boolean;
future: boolean;
category?: import("../types.js").CalendarCategory;
};
};
parsedNow: import("vue").ComputedRef<CalendarTimestamp | null>;
updateTimes: () => void;
setPresent: () => void;
getNow: () => CalendarTimestamp;
updateDay: (now: CalendarTimestamp, target: CalendarTimestamp) => void;
updateTime: (now: CalendarTimestamp, target: CalendarTimestamp) => void;
};
@@ -0,0 +1,55 @@
// Utilities
import { computed, reactive, watch } from 'vue';
import { parseDate, parseTimestamp, validateTimestamp } from "../util/timestamp.js"; // Types
export function useTimes(props) {
const times = reactive({
now: parseTimestamp('0000-00-00 00:00', true),
today: parseTimestamp('0000-00-00', true)
});
const parsedNow = computed(() => {
return props.now && validateTimestamp(props.now) ? parseTimestamp(props.now, true) : null;
});
function setPresent() {
times.now.present = times.today.present = true;
times.now.past = times.today.past = false;
times.now.future = times.today.future = false;
}
function getNow() {
return parseDate(new Date());
}
function updateDay(now, target) {
if (now.date !== target.date) {
target.year = now.year;
target.month = now.month;
target.day = now.day;
target.weekday = now.weekday;
target.date = now.date;
}
}
function updateTime(now, target) {
if (now.time !== target.time) {
target.hour = now.hour;
target.minute = now.minute;
target.time = now.time;
}
}
function updateTimes() {
const now = parsedNow.value || getNow();
updateDay(now, times.now);
updateTime(now, times.now);
updateDay(now, times.today);
}
watch(parsedNow, updateTimes);
updateTimes();
setPresent();
return {
times,
parsedNow,
updateTimes,
setPresent,
getNow,
updateDay,
updateTime
};
}
//# sourceMappingURL=times.js.map
@@ -0,0 +1 @@
{"version":3,"file":"times.js","names":["computed","reactive","watch","parseDate","parseTimestamp","validateTimestamp","useTimes","props","times","now","today","parsedNow","setPresent","present","past","future","getNow","Date","updateDay","target","date","year","month","day","weekday","updateTime","time","hour","minute","updateTimes","value"],"sources":["../../../../src/components/VCalendar/composables/times.ts"],"sourcesContent":["// Utilities\nimport { computed, reactive, watch } from 'vue'\nimport {\n parseDate,\n parseTimestamp,\n validateTimestamp,\n} from '../util/timestamp'\n\n// Types\nimport type { CalendarTimestamp } from '../types'\n\nexport function useTimes (props: { now: string | undefined }) {\n const times = reactive({\n now: parseTimestamp('0000-00-00 00:00', true),\n today: parseTimestamp('0000-00-00', true),\n })\n\n const parsedNow = computed((): CalendarTimestamp | null => {\n return props.now && validateTimestamp(props.now) ? parseTimestamp(props.now, true) : null\n })\n\n function setPresent (): void {\n times.now.present = times.today.present = true\n times.now.past = times.today.past = false\n times.now.future = times.today.future = false\n }\n\n function getNow (): CalendarTimestamp {\n return parseDate(new Date())\n }\n\n function updateDay (now: CalendarTimestamp, target: CalendarTimestamp): void {\n if (now.date !== target.date) {\n target.year = now.year\n target.month = now.month\n target.day = now.day\n target.weekday = now.weekday\n target.date = now.date\n }\n }\n\n function updateTime (now: CalendarTimestamp, target: CalendarTimestamp): void {\n if (now.time !== target.time) {\n target.hour = now.hour\n target.minute = now.minute\n target.time = now.time\n }\n }\n\n function updateTimes (): void {\n const now: CalendarTimestamp = parsedNow.value || getNow()\n updateDay(now, times.now)\n updateTime(now, times.now)\n updateDay(now, times.today)\n }\n\n watch(parsedNow, updateTimes)\n\n updateTimes()\n setPresent()\n\n return {\n times,\n parsedNow,\n updateTimes,\n setPresent,\n getNow,\n updateDay,\n updateTime,\n }\n}\n"],"mappings":"AAAA;AACA,SAASA,QAAQ,EAAEC,QAAQ,EAAEC,KAAK,QAAQ,KAAK;AAAA,SAE7CC,SAAS,EACTC,cAAc,EACdC,iBAAiB,gCAGnB;AAGA,OAAO,SAASC,QAAQA,CAAEC,KAAkC,EAAE;EAC5D,MAAMC,KAAK,GAAGP,QAAQ,CAAC;IACrBQ,GAAG,EAAEL,cAAc,CAAC,kBAAkB,EAAE,IAAI,CAAC;IAC7CM,KAAK,EAAEN,cAAc,CAAC,YAAY,EAAE,IAAI;EAC1C,CAAC,CAAC;EAEF,MAAMO,SAAS,GAAGX,QAAQ,CAAC,MAAgC;IACzD,OAAOO,KAAK,CAACE,GAAG,IAAIJ,iBAAiB,CAACE,KAAK,CAACE,GAAG,CAAC,GAAGL,cAAc,CAACG,KAAK,CAACE,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI;EAC3F,CAAC,CAAC;EAEF,SAASG,UAAUA,CAAA,EAAU;IAC3BJ,KAAK,CAACC,GAAG,CAACI,OAAO,GAAGL,KAAK,CAACE,KAAK,CAACG,OAAO,GAAG,IAAI;IAC9CL,KAAK,CAACC,GAAG,CAACK,IAAI,GAAGN,KAAK,CAACE,KAAK,CAACI,IAAI,GAAG,KAAK;IACzCN,KAAK,CAACC,GAAG,CAACM,MAAM,GAAGP,KAAK,CAACE,KAAK,CAACK,MAAM,GAAG,KAAK;EAC/C;EAEA,SAASC,MAAMA,CAAA,EAAuB;IACpC,OAAOb,SAAS,CAAC,IAAIc,IAAI,CAAC,CAAC,CAAC;EAC9B;EAEA,SAASC,SAASA,CAAET,GAAsB,EAAEU,MAAyB,EAAQ;IAC3E,IAAIV,GAAG,CAACW,IAAI,KAAKD,MAAM,CAACC,IAAI,EAAE;MAC5BD,MAAM,CAACE,IAAI,GAAGZ,GAAG,CAACY,IAAI;MACtBF,MAAM,CAACG,KAAK,GAAGb,GAAG,CAACa,KAAK;MACxBH,MAAM,CAACI,GAAG,GAAGd,GAAG,CAACc,GAAG;MACpBJ,MAAM,CAACK,OAAO,GAAGf,GAAG,CAACe,OAAO;MAC5BL,MAAM,CAACC,IAAI,GAAGX,GAAG,CAACW,IAAI;IACxB;EACF;EAEA,SAASK,UAAUA,CAAEhB,GAAsB,EAAEU,MAAyB,EAAQ;IAC5E,IAAIV,GAAG,CAACiB,IAAI,KAAKP,MAAM,CAACO,IAAI,EAAE;MAC5BP,MAAM,CAACQ,IAAI,GAAGlB,GAAG,CAACkB,IAAI;MACtBR,MAAM,CAACS,MAAM,GAAGnB,GAAG,CAACmB,MAAM;MAC1BT,MAAM,CAACO,IAAI,GAAGjB,GAAG,CAACiB,IAAI;IACxB;EACF;EAEA,SAASG,WAAWA,CAAA,EAAU;IAC5B,MAAMpB,GAAsB,GAAGE,SAAS,CAACmB,KAAK,IAAId,MAAM,CAAC,CAAC;IAC1DE,SAAS,CAACT,GAAG,EAAED,KAAK,CAACC,GAAG,CAAC;IACzBgB,UAAU,CAAChB,GAAG,EAAED,KAAK,CAACC,GAAG,CAAC;IAC1BS,SAAS,CAACT,GAAG,EAAED,KAAK,CAACE,KAAK,CAAC;EAC7B;EAEAR,KAAK,CAACS,SAAS,EAAEkB,WAAW,CAAC;EAE7BA,WAAW,CAAC,CAAC;EACbjB,UAAU,CAAC,CAAC;EAEZ,OAAO;IACLJ,KAAK;IACLG,SAAS;IACTkB,WAAW;IACXjB,UAAU;IACVI,MAAM;IACNE,SAAS;IACTO;EACF,CAAC;AACH","ignoreList":[]}