Initial commit: GamePortrait 竖屏版 - 深色豪华主题

This commit is contained in:
li
2026-01-16 17:47:53 +08:00
commit 40976e4b45
26611 changed files with 2843638 additions and 0 deletions
+292
View File
@@ -0,0 +1,292 @@
import { type PropType, type ExtractPropTypes } from 'vue';
import { PopupPosition } from '../popup';
import type { CalendarType, CalendarDayItem } from './types';
export declare const calendarProps: {
show: BooleanConstructor;
type: {
type: PropType<CalendarType>;
default: CalendarType;
};
title: StringConstructor;
color: StringConstructor;
round: {
type: BooleanConstructor;
default: true;
};
readonly: BooleanConstructor;
poppable: {
type: BooleanConstructor;
default: true;
};
maxRange: {
type: (NumberConstructor | StringConstructor)[];
default: null;
};
position: {
type: PropType<PopupPosition>;
default: PopupPosition;
};
teleport: PropType<string | import("vue").RendererElement | null | undefined>;
showMark: {
type: BooleanConstructor;
default: true;
};
showTitle: {
type: BooleanConstructor;
default: true;
};
formatter: PropType<(item: CalendarDayItem) => CalendarDayItem>;
rowHeight: (NumberConstructor | StringConstructor)[];
confirmText: StringConstructor;
rangePrompt: StringConstructor;
lazyRender: {
type: BooleanConstructor;
default: true;
};
showConfirm: {
type: BooleanConstructor;
default: true;
};
defaultDate: PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: {
type: BooleanConstructor;
default: true;
};
closeOnPopstate: {
type: BooleanConstructor;
default: true;
};
showRangePrompt: {
type: BooleanConstructor;
default: true;
};
confirmDisabledText: StringConstructor;
closeOnClickOverlay: {
type: BooleanConstructor;
default: true;
};
safeAreaInsetTop: BooleanConstructor;
safeAreaInsetBottom: {
type: BooleanConstructor;
default: true;
};
minDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
maxDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
firstDayOfWeek: {
type: (NumberConstructor | StringConstructor)[];
default: number;
validator: (val: number) => boolean;
};
};
export type CalendarProps = ExtractPropTypes<typeof calendarProps>;
declare const _default: import("vue").DefineComponent<{
show: BooleanConstructor;
type: {
type: PropType<CalendarType>;
default: CalendarType;
};
title: StringConstructor;
color: StringConstructor;
round: {
type: BooleanConstructor;
default: true;
};
readonly: BooleanConstructor;
poppable: {
type: BooleanConstructor;
default: true;
};
maxRange: {
type: (NumberConstructor | StringConstructor)[];
default: null;
};
position: {
type: PropType<PopupPosition>;
default: PopupPosition;
};
teleport: PropType<string | import("vue").RendererElement | null | undefined>;
showMark: {
type: BooleanConstructor;
default: true;
};
showTitle: {
type: BooleanConstructor;
default: true;
};
formatter: PropType<(item: CalendarDayItem) => CalendarDayItem>;
rowHeight: (NumberConstructor | StringConstructor)[];
confirmText: StringConstructor;
rangePrompt: StringConstructor;
lazyRender: {
type: BooleanConstructor;
default: true;
};
showConfirm: {
type: BooleanConstructor;
default: true;
};
defaultDate: PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: {
type: BooleanConstructor;
default: true;
};
closeOnPopstate: {
type: BooleanConstructor;
default: true;
};
showRangePrompt: {
type: BooleanConstructor;
default: true;
};
confirmDisabledText: StringConstructor;
closeOnClickOverlay: {
type: BooleanConstructor;
default: true;
};
safeAreaInsetTop: BooleanConstructor;
safeAreaInsetBottom: {
type: BooleanConstructor;
default: true;
};
minDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
maxDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
firstDayOfWeek: {
type: (NumberConstructor | StringConstructor)[];
default: number;
validator: (val: number) => boolean;
};
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("select" | "update:show" | "confirm" | "clickSubtitle" | "unselect" | "monthShow" | "overRange")[], "select" | "update:show" | "confirm" | "clickSubtitle" | "unselect" | "monthShow" | "overRange", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<ExtractPropTypes<{
show: BooleanConstructor;
type: {
type: PropType<CalendarType>;
default: CalendarType;
};
title: StringConstructor;
color: StringConstructor;
round: {
type: BooleanConstructor;
default: true;
};
readonly: BooleanConstructor;
poppable: {
type: BooleanConstructor;
default: true;
};
maxRange: {
type: (NumberConstructor | StringConstructor)[];
default: null;
};
position: {
type: PropType<PopupPosition>;
default: PopupPosition;
};
teleport: PropType<string | import("vue").RendererElement | null | undefined>;
showMark: {
type: BooleanConstructor;
default: true;
};
showTitle: {
type: BooleanConstructor;
default: true;
};
formatter: PropType<(item: CalendarDayItem) => CalendarDayItem>;
rowHeight: (NumberConstructor | StringConstructor)[];
confirmText: StringConstructor;
rangePrompt: StringConstructor;
lazyRender: {
type: BooleanConstructor;
default: true;
};
showConfirm: {
type: BooleanConstructor;
default: true;
};
defaultDate: PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: {
type: BooleanConstructor;
default: true;
};
closeOnPopstate: {
type: BooleanConstructor;
default: true;
};
showRangePrompt: {
type: BooleanConstructor;
default: true;
};
confirmDisabledText: StringConstructor;
closeOnClickOverlay: {
type: BooleanConstructor;
default: true;
};
safeAreaInsetTop: BooleanConstructor;
safeAreaInsetBottom: {
type: BooleanConstructor;
default: true;
};
minDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
maxDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
firstDayOfWeek: {
type: (NumberConstructor | StringConstructor)[];
default: number;
validator: (val: number) => boolean;
};
}>> & {
onSelect?: ((...args: any[]) => any) | undefined;
"onUpdate:show"?: ((...args: any[]) => any) | undefined;
onConfirm?: ((...args: any[]) => any) | undefined;
onClickSubtitle?: ((...args: any[]) => any) | undefined;
onUnselect?: ((...args: any[]) => any) | undefined;
onMonthShow?: ((...args: any[]) => any) | undefined;
onOverRange?: ((...args: any[]) => any) | undefined;
}, {
type: CalendarType;
position: PopupPosition;
round: boolean;
readonly: boolean;
safeAreaInsetBottom: boolean;
show: boolean;
lazyRender: boolean;
closeOnClickOverlay: boolean;
closeOnPopstate: boolean;
safeAreaInsetTop: boolean;
poppable: boolean;
maxRange: string | number;
showMark: boolean;
showTitle: boolean;
showConfirm: boolean;
allowSameDay: boolean;
showSubtitle: boolean;
showRangePrompt: boolean;
minDate: Date;
maxDate: Date;
firstDayOfWeek: string | number;
}>;
export default _default;
+414
View File
@@ -0,0 +1,414 @@
import { createVNode as _createVNode, mergeProps as _mergeProps } from "vue";
import { ref, watch, computed, defineComponent } from "vue";
import { pick, isDate, truthProp, numericProp, getScrollTop, makeStringProp, makeNumericProp } from "../utils/index.mjs";
import { t, bem, name, getToday, cloneDate, cloneDates, getPrevDay, getNextDay, compareDay, calcDateNum, compareMonth, getDayByOffset } from "./utils.mjs";
import { raf, useRect, onMountedOrActivated } from "@vant/use";
import { useRefs } from "../composables/use-refs.mjs";
import { useExpose } from "../composables/use-expose.mjs";
import { Popup } from "../popup/index.mjs";
import { Button } from "../button/index.mjs";
import { showToast } from "../toast/index.mjs";
import CalendarMonth from "./CalendarMonth.mjs";
import CalendarHeader from "./CalendarHeader.mjs";
const calendarProps = {
show: Boolean,
type: makeStringProp("single"),
title: String,
color: String,
round: truthProp,
readonly: Boolean,
poppable: truthProp,
maxRange: makeNumericProp(null),
position: makeStringProp("bottom"),
teleport: [String, Object],
showMark: truthProp,
showTitle: truthProp,
formatter: Function,
rowHeight: numericProp,
confirmText: String,
rangePrompt: String,
lazyRender: truthProp,
showConfirm: truthProp,
defaultDate: [Date, Array],
allowSameDay: Boolean,
showSubtitle: truthProp,
closeOnPopstate: truthProp,
showRangePrompt: truthProp,
confirmDisabledText: String,
closeOnClickOverlay: truthProp,
safeAreaInsetTop: Boolean,
safeAreaInsetBottom: truthProp,
minDate: {
type: Date,
validator: isDate,
default: getToday
},
maxDate: {
type: Date,
validator: isDate,
default: () => {
const now = getToday();
return new Date(now.getFullYear(), now.getMonth() + 6, now.getDate());
}
},
firstDayOfWeek: {
type: numericProp,
default: 0,
validator: (val) => val >= 0 && val <= 6
}
};
var stdin_default = defineComponent({
name,
props: calendarProps,
emits: ["select", "confirm", "unselect", "monthShow", "overRange", "update:show", "clickSubtitle"],
setup(props, {
emit,
slots
}) {
const limitDateRange = (date, minDate = props.minDate, maxDate = props.maxDate) => {
if (compareDay(date, minDate) === -1) {
return minDate;
}
if (compareDay(date, maxDate) === 1) {
return maxDate;
}
return date;
};
const getInitialDate = (defaultDate = props.defaultDate) => {
const {
type,
minDate,
maxDate,
allowSameDay
} = props;
if (defaultDate === null) {
return defaultDate;
}
const now = getToday();
if (type === "range") {
if (!Array.isArray(defaultDate)) {
defaultDate = [];
}
const start = limitDateRange(defaultDate[0] || now, minDate, allowSameDay ? maxDate : getPrevDay(maxDate));
const end = limitDateRange(defaultDate[1] || now, allowSameDay ? minDate : getNextDay(minDate));
return [start, end];
}
if (type === "multiple") {
if (Array.isArray(defaultDate)) {
return defaultDate.map((date) => limitDateRange(date));
}
return [limitDateRange(now)];
}
if (!defaultDate || Array.isArray(defaultDate)) {
defaultDate = now;
}
return limitDateRange(defaultDate);
};
let bodyHeight;
const bodyRef = ref();
const subtitle = ref({
text: "",
date: void 0
});
const currentDate = ref(getInitialDate());
const [monthRefs, setMonthRefs] = useRefs();
const dayOffset = computed(() => props.firstDayOfWeek ? +props.firstDayOfWeek % 7 : 0);
const months = computed(() => {
const months2 = [];
const cursor = new Date(props.minDate);
cursor.setDate(1);
do {
months2.push(new Date(cursor));
cursor.setMonth(cursor.getMonth() + 1);
} while (compareMonth(cursor, props.maxDate) !== 1);
return months2;
});
const buttonDisabled = computed(() => {
if (currentDate.value) {
if (props.type === "range") {
return !currentDate.value[0] || !currentDate.value[1];
}
if (props.type === "multiple") {
return !currentDate.value.length;
}
}
return !currentDate.value;
});
const getSelectedDate = () => currentDate.value;
const onScroll = () => {
const top = getScrollTop(bodyRef.value);
const bottom = top + bodyHeight;
const heights = months.value.map((item, index) => monthRefs.value[index].getHeight());
const heightSum = heights.reduce((a, b) => a + b, 0);
if (bottom > heightSum && top > 0) {
return;
}
let height = 0;
let currentMonth;
const visibleRange = [-1, -1];
for (let i = 0; i < months.value.length; i++) {
const month = monthRefs.value[i];
const visible = height <= bottom && height + heights[i] >= top;
if (visible) {
visibleRange[1] = i;
if (!currentMonth) {
currentMonth = month;
visibleRange[0] = i;
}
if (!monthRefs.value[i].showed) {
monthRefs.value[i].showed = true;
emit("monthShow", {
date: month.date,
title: month.getTitle()
});
}
}
height += heights[i];
}
months.value.forEach((month, index) => {
const visible = index >= visibleRange[0] - 1 && index <= visibleRange[1] + 1;
monthRefs.value[index].setVisible(visible);
});
if (currentMonth) {
subtitle.value = {
text: currentMonth.getTitle(),
date: currentMonth.date
};
}
};
const scrollToDate = (targetDate) => {
raf(() => {
months.value.some((month, index) => {
if (compareMonth(month, targetDate) === 0) {
if (bodyRef.value) {
monthRefs.value[index].scrollToDate(bodyRef.value, targetDate);
}
return true;
}
return false;
});
onScroll();
});
};
const scrollToCurrentDate = () => {
if (props.poppable && !props.show) {
return;
}
if (currentDate.value) {
const targetDate = props.type === "single" ? currentDate.value : currentDate.value[0];
if (isDate(targetDate)) {
scrollToDate(targetDate);
}
} else {
raf(onScroll);
}
};
const init = () => {
if (props.poppable && !props.show) {
return;
}
raf(() => {
bodyHeight = Math.floor(useRect(bodyRef).height);
});
scrollToCurrentDate();
};
const reset = (date = getInitialDate()) => {
currentDate.value = date;
scrollToCurrentDate();
};
const checkRange = (date) => {
const {
maxRange,
rangePrompt,
showRangePrompt
} = props;
if (maxRange && calcDateNum(date) > +maxRange) {
if (showRangePrompt) {
showToast(rangePrompt || t("rangePrompt", maxRange));
}
emit("overRange");
return false;
}
return true;
};
const onConfirm = () => {
var _a;
return emit("confirm", (_a = currentDate.value) != null ? _a : cloneDates(currentDate.value));
};
const select = (date, complete) => {
const setCurrentDate = (date2) => {
currentDate.value = date2;
emit("select", cloneDates(date2));
};
if (complete && props.type === "range") {
const valid = checkRange(date);
if (!valid) {
setCurrentDate([date[0], getDayByOffset(date[0], +props.maxRange - 1)]);
return;
}
}
setCurrentDate(date);
if (complete && !props.showConfirm) {
onConfirm();
}
};
const getDisabledDate = (disabledDays2, startDay, date) => {
var _a;
return (_a = disabledDays2.find((day) => compareDay(startDay, day.date) === -1 && compareDay(day.date, date) === -1)) == null ? void 0 : _a.date;
};
const disabledDays = computed(() => monthRefs.value.reduce((arr, ref2) => {
var _a, _b;
arr.push(...(_b = (_a = ref2.disabledDays) == null ? void 0 : _a.value) != null ? _b : []);
return arr;
}, []));
const onClickDay = (item) => {
if (props.readonly || !item.date) {
return;
}
const {
date
} = item;
const {
type
} = props;
if (type === "range") {
if (!currentDate.value) {
select([date]);
return;
}
const [startDay, endDay] = currentDate.value;
if (startDay && !endDay) {
const compareToStart = compareDay(date, startDay);
if (compareToStart === 1) {
const disabledDay = getDisabledDate(disabledDays.value, startDay, date);
if (disabledDay) {
const endDay2 = getPrevDay(disabledDay);
if (compareDay(startDay, endDay2) === -1) {
select([startDay, endDay2]);
} else {
select([date]);
}
} else {
select([startDay, date], true);
}
} else if (compareToStart === -1) {
select([date]);
} else if (props.allowSameDay) {
select([date, date], true);
}
} else {
select([date]);
}
} else if (type === "multiple") {
if (!currentDate.value) {
select([date]);
return;
}
const dates = currentDate.value;
const selectedIndex = dates.findIndex((dateItem) => compareDay(dateItem, date) === 0);
if (selectedIndex !== -1) {
const [unselectedDate] = dates.splice(selectedIndex, 1);
emit("unselect", cloneDate(unselectedDate));
} else if (props.maxRange && dates.length >= +props.maxRange) {
showToast(props.rangePrompt || t("rangePrompt", props.maxRange));
} else {
select([...dates, date]);
}
} else {
select(date, true);
}
};
const updateShow = (value) => emit("update:show", value);
const renderMonth = (date, index) => {
const showMonthTitle = index !== 0 || !props.showSubtitle;
return _createVNode(CalendarMonth, _mergeProps({
"ref": setMonthRefs(index),
"date": date,
"currentDate": currentDate.value,
"showMonthTitle": showMonthTitle,
"firstDayOfWeek": dayOffset.value
}, pick(props, ["type", "color", "minDate", "maxDate", "showMark", "formatter", "rowHeight", "lazyRender", "showSubtitle", "allowSameDay"]), {
"onClick": onClickDay
}), pick(slots, ["top-info", "bottom-info", "month-title"]));
};
const renderFooterButton = () => {
if (slots.footer) {
return slots.footer();
}
if (props.showConfirm) {
const slot = slots["confirm-text"];
const disabled = buttonDisabled.value;
const text = disabled ? props.confirmDisabledText : props.confirmText;
return _createVNode(Button, {
"round": true,
"block": true,
"type": "primary",
"color": props.color,
"class": bem("confirm"),
"disabled": disabled,
"nativeType": "button",
"onClick": onConfirm
}, {
default: () => [slot ? slot({
disabled
}) : text || t("confirm")]
});
}
};
const renderFooter = () => _createVNode("div", {
"class": [bem("footer"), {
"van-safe-area-bottom": props.safeAreaInsetBottom
}]
}, [renderFooterButton()]);
const renderCalendar = () => _createVNode("div", {
"class": bem()
}, [_createVNode(CalendarHeader, {
"date": subtitle.value.date,
"title": props.title,
"subtitle": subtitle.value.text,
"showTitle": props.showTitle,
"showSubtitle": props.showSubtitle,
"firstDayOfWeek": dayOffset.value,
"onClickSubtitle": (event) => emit("clickSubtitle", event)
}, pick(slots, ["title", "subtitle"])), _createVNode("div", {
"ref": bodyRef,
"class": bem("body"),
"onScroll": onScroll
}, [months.value.map(renderMonth)]), renderFooter()]);
watch(() => props.show, init);
watch(() => [props.type, props.minDate, props.maxDate], () => reset(getInitialDate(currentDate.value)));
watch(() => props.defaultDate, (value = null) => {
currentDate.value = value;
scrollToCurrentDate();
});
useExpose({
reset,
scrollToDate,
getSelectedDate
});
onMountedOrActivated(init);
return () => {
if (props.poppable) {
return _createVNode(Popup, {
"show": props.show,
"class": bem("popup"),
"round": props.round,
"position": props.position,
"closeable": props.showTitle || props.showSubtitle,
"teleport": props.teleport,
"closeOnPopstate": props.closeOnPopstate,
"safeAreaInsetTop": props.safeAreaInsetTop,
"closeOnClickOverlay": props.closeOnClickOverlay,
"onUpdate:show": updateShow
}, {
default: renderCalendar
});
}
return renderCalendar();
};
}
});
export {
calendarProps,
stdin_default as default
};
+32
View File
@@ -0,0 +1,32 @@
import { type PropType } from 'vue';
import type { CalendarDayItem } from './types';
declare const _default: import("vue").DefineComponent<{
item: {
type: PropType<CalendarDayItem>;
required: true;
};
color: StringConstructor;
index: NumberConstructor;
offset: {
type: NumberConstructor;
default: number;
};
rowHeight: StringConstructor;
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "click"[], "click", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
item: {
type: PropType<CalendarDayItem>;
required: true;
};
color: StringConstructor;
index: NumberConstructor;
offset: {
type: NumberConstructor;
default: number;
};
rowHeight: StringConstructor;
}>> & {
onClick?: ((...args: any[]) => any) | undefined;
}, {
offset: number;
}>;
export default _default;
+129
View File
@@ -0,0 +1,129 @@
import { createVNode as _createVNode } from "vue";
import { computed, defineComponent } from "vue";
import { makeNumberProp, createNamespace, makeRequiredProp } from "../utils/index.mjs";
import { bem } from "./utils.mjs";
const [name] = createNamespace("calendar-day");
var stdin_default = defineComponent({
name,
props: {
item: makeRequiredProp(Object),
color: String,
index: Number,
offset: makeNumberProp(0),
rowHeight: String
},
emits: ["click"],
setup(props, {
emit,
slots
}) {
const style = computed(() => {
var _a;
const {
item,
index,
color,
offset,
rowHeight
} = props;
const style2 = {
height: rowHeight
};
if (item.type === "placeholder") {
style2.width = "100%";
return style2;
}
if (index === 0) {
style2.marginLeft = `${100 * offset / 7}%`;
}
if (color) {
switch (item.type) {
case "end":
case "start":
case "start-end":
case "multiple-middle":
case "multiple-selected":
style2.background = color;
break;
case "middle":
style2.color = color;
break;
}
}
if (offset + (((_a = item.date) == null ? void 0 : _a.getDate()) || 1) > 28) {
style2.marginBottom = 0;
}
return style2;
});
const onClick = () => {
if (props.item.type !== "disabled") {
emit("click", props.item);
}
};
const renderTopInfo = () => {
const {
topInfo
} = props.item;
if (topInfo || slots["top-info"]) {
return _createVNode("div", {
"class": bem("top-info")
}, [slots["top-info"] ? slots["top-info"](props.item) : topInfo]);
}
};
const renderBottomInfo = () => {
const {
bottomInfo
} = props.item;
if (bottomInfo || slots["bottom-info"]) {
return _createVNode("div", {
"class": bem("bottom-info")
}, [slots["bottom-info"] ? slots["bottom-info"](props.item) : bottomInfo]);
}
};
const renderContent = () => {
const {
item,
color,
rowHeight
} = props;
const {
type,
text
} = item;
const Nodes = [renderTopInfo(), text, renderBottomInfo()];
if (type === "selected") {
return _createVNode("div", {
"class": bem("selected-day"),
"style": {
width: rowHeight,
height: rowHeight,
background: color
}
}, [Nodes]);
}
return Nodes;
};
return () => {
const {
type,
className
} = props.item;
if (type === "placeholder") {
return _createVNode("div", {
"class": bem("day"),
"style": style.value
}, null);
}
return _createVNode("div", {
"role": "gridcell",
"style": style.value,
"class": [bem("day", type), className],
"tabindex": type === "disabled" ? void 0 : -1,
"onClick": onClick
}, [renderContent()]);
};
}
});
export {
stdin_default as default
};
+21
View File
@@ -0,0 +1,21 @@
declare const _default: import("vue").DefineComponent<{
date: DateConstructor;
title: StringConstructor;
subtitle: StringConstructor;
showTitle: BooleanConstructor;
showSubtitle: BooleanConstructor;
firstDayOfWeek: NumberConstructor;
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "clickSubtitle"[], "clickSubtitle", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
date: DateConstructor;
title: StringConstructor;
subtitle: StringConstructor;
showTitle: BooleanConstructor;
showSubtitle: BooleanConstructor;
firstDayOfWeek: NumberConstructor;
}>> & {
onClickSubtitle?: ((...args: any[]) => any) | undefined;
}, {
showTitle: boolean;
showSubtitle: boolean;
}>;
export default _default;
+62
View File
@@ -0,0 +1,62 @@
import { createVNode as _createVNode } from "vue";
import { defineComponent } from "vue";
import { createNamespace } from "../utils/index.mjs";
import { t, bem } from "./utils.mjs";
const [name] = createNamespace("calendar-header");
var stdin_default = defineComponent({
name,
props: {
date: Date,
title: String,
subtitle: String,
showTitle: Boolean,
showSubtitle: Boolean,
firstDayOfWeek: Number
},
emits: ["clickSubtitle"],
setup(props, {
slots,
emit
}) {
const renderTitle = () => {
if (props.showTitle) {
const text = props.title || t("title");
const title = slots.title ? slots.title() : text;
return _createVNode("div", {
"class": bem("header-title")
}, [title]);
}
};
const onClickSubtitle = (event) => emit("clickSubtitle", event);
const renderSubtitle = () => {
if (props.showSubtitle) {
const title = slots.subtitle ? slots.subtitle({
date: props.date,
text: props.subtitle
}) : props.subtitle;
return _createVNode("div", {
"class": bem("header-subtitle"),
"onClick": onClickSubtitle
}, [title]);
}
};
const renderWeekDays = () => {
const {
firstDayOfWeek
} = props;
const weekdays = t("weekdays");
const renderWeekDays2 = [...weekdays.slice(firstDayOfWeek, 7), ...weekdays.slice(0, firstDayOfWeek)];
return _createVNode("div", {
"class": bem("weekdays")
}, [renderWeekDays2.map((text) => _createVNode("span", {
"class": bem("weekday")
}, [text]))]);
};
return () => _createVNode("div", {
"class": bem("header")
}, [renderTitle(), renderSubtitle(), renderWeekDays()]);
}
});
export {
stdin_default as default
};
+86
View File
@@ -0,0 +1,86 @@
import { type PropType, type ExtractPropTypes } from 'vue';
import type { CalendarType, CalendarDayItem } from './types';
declare const calendarMonthProps: {
date: {
type: DateConstructor;
required: true;
};
type: PropType<CalendarType>;
color: StringConstructor;
minDate: {
type: DateConstructor;
required: true;
};
maxDate: {
type: DateConstructor;
required: true;
};
showMark: BooleanConstructor;
rowHeight: (NumberConstructor | StringConstructor)[];
formatter: PropType<(item: CalendarDayItem) => CalendarDayItem>;
lazyRender: BooleanConstructor;
currentDate: PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: BooleanConstructor;
showMonthTitle: BooleanConstructor;
firstDayOfWeek: NumberConstructor;
};
export type CalendarMonthProps = ExtractPropTypes<typeof calendarMonthProps>;
declare const _default: import("vue").DefineComponent<{
date: {
type: DateConstructor;
required: true;
};
type: PropType<CalendarType>;
color: StringConstructor;
minDate: {
type: DateConstructor;
required: true;
};
maxDate: {
type: DateConstructor;
required: true;
};
showMark: BooleanConstructor;
rowHeight: (NumberConstructor | StringConstructor)[];
formatter: PropType<(item: CalendarDayItem) => CalendarDayItem>;
lazyRender: BooleanConstructor;
currentDate: PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: BooleanConstructor;
showMonthTitle: BooleanConstructor;
firstDayOfWeek: NumberConstructor;
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "click"[], "click", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<ExtractPropTypes<{
date: {
type: DateConstructor;
required: true;
};
type: PropType<CalendarType>;
color: StringConstructor;
minDate: {
type: DateConstructor;
required: true;
};
maxDate: {
type: DateConstructor;
required: true;
};
showMark: BooleanConstructor;
rowHeight: (NumberConstructor | StringConstructor)[];
formatter: PropType<(item: CalendarDayItem) => CalendarDayItem>;
lazyRender: BooleanConstructor;
currentDate: PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: BooleanConstructor;
showMonthTitle: BooleanConstructor;
firstDayOfWeek: NumberConstructor;
}>> & {
onClick?: ((...args: any[]) => any) | undefined;
}, {
lazyRender: boolean;
showMark: boolean;
allowSameDay: boolean;
showSubtitle: boolean;
showMonthTitle: boolean;
}>;
export default _default;
+211
View File
@@ -0,0 +1,211 @@
import { createVNode as _createVNode } from "vue";
import { ref, computed, defineComponent } from "vue";
import { pick, addUnit, numericProp, setScrollTop, createNamespace, makeRequiredProp } from "../utils/index.mjs";
import { getMonthEndDay } from "../date-picker/utils.mjs";
import { t, bem, compareDay, getPrevDay, getNextDay, formatMonthTitle } from "./utils.mjs";
import { useRect, useToggle } from "@vant/use";
import { useExpose } from "../composables/use-expose.mjs";
import { useHeight } from "../composables/use-height.mjs";
import CalendarDay from "./CalendarDay.mjs";
const [name] = createNamespace("calendar-month");
const calendarMonthProps = {
date: makeRequiredProp(Date),
type: String,
color: String,
minDate: makeRequiredProp(Date),
maxDate: makeRequiredProp(Date),
showMark: Boolean,
rowHeight: numericProp,
formatter: Function,
lazyRender: Boolean,
currentDate: [Date, Array],
allowSameDay: Boolean,
showSubtitle: Boolean,
showMonthTitle: Boolean,
firstDayOfWeek: Number
};
var stdin_default = defineComponent({
name,
props: calendarMonthProps,
emits: ["click"],
setup(props, {
emit,
slots
}) {
const [visible, setVisible] = useToggle();
const daysRef = ref();
const monthRef = ref();
const height = useHeight(monthRef);
const title = computed(() => formatMonthTitle(props.date));
const rowHeight = computed(() => addUnit(props.rowHeight));
const offset = computed(() => {
const realDay = props.date.getDay();
if (props.firstDayOfWeek) {
return (realDay + 7 - props.firstDayOfWeek) % 7;
}
return realDay;
});
const totalDay = computed(() => getMonthEndDay(props.date.getFullYear(), props.date.getMonth() + 1));
const shouldRender = computed(() => visible.value || !props.lazyRender);
const getTitle = () => title.value;
const getMultipleDayType = (day) => {
const isSelected = (date) => props.currentDate.some((item) => compareDay(item, date) === 0);
if (isSelected(day)) {
const prevDay = getPrevDay(day);
const nextDay = getNextDay(day);
const prevSelected = isSelected(prevDay);
const nextSelected = isSelected(nextDay);
if (prevSelected && nextSelected) {
return "multiple-middle";
}
if (prevSelected) {
return "end";
}
if (nextSelected) {
return "start";
}
return "multiple-selected";
}
return "";
};
const getRangeDayType = (day) => {
const [startDay, endDay] = props.currentDate;
if (!startDay) {
return "";
}
const compareToStart = compareDay(day, startDay);
if (!endDay) {
return compareToStart === 0 ? "start" : "";
}
const compareToEnd = compareDay(day, endDay);
if (props.allowSameDay && compareToStart === 0 && compareToEnd === 0) {
return "start-end";
}
if (compareToStart === 0) {
return "start";
}
if (compareToEnd === 0) {
return "end";
}
if (compareToStart > 0 && compareToEnd < 0) {
return "middle";
}
return "";
};
const getDayType = (day) => {
const {
type,
minDate,
maxDate,
currentDate
} = props;
if (compareDay(day, minDate) < 0 || compareDay(day, maxDate) > 0) {
return "disabled";
}
if (currentDate === null) {
return "";
}
if (Array.isArray(currentDate)) {
if (type === "multiple") {
return getMultipleDayType(day);
}
if (type === "range") {
return getRangeDayType(day);
}
} else if (type === "single") {
return compareDay(day, currentDate) === 0 ? "selected" : "";
}
return "";
};
const getBottomInfo = (dayType) => {
if (props.type === "range") {
if (dayType === "start" || dayType === "end") {
return t(dayType);
}
if (dayType === "start-end") {
return `${t("start")}/${t("end")}`;
}
}
};
const renderTitle = () => {
if (props.showMonthTitle) {
return _createVNode("div", {
"class": bem("month-title")
}, [slots["month-title"] ? slots["month-title"]({
date: props.date,
text: title.value
}) : title.value]);
}
};
const renderMark = () => {
if (props.showMark && shouldRender.value) {
return _createVNode("div", {
"class": bem("month-mark")
}, [props.date.getMonth() + 1]);
}
};
const placeholders = computed(() => {
const count = Math.ceil((totalDay.value + offset.value) / 7);
return Array(count).fill({
type: "placeholder"
});
});
const days = computed(() => {
const days2 = [];
const year = props.date.getFullYear();
const month = props.date.getMonth();
for (let day = 1; day <= totalDay.value; day++) {
const date = new Date(year, month, day);
const type = getDayType(date);
let config = {
date,
type,
text: day,
bottomInfo: getBottomInfo(type)
};
if (props.formatter) {
config = props.formatter(config);
}
days2.push(config);
}
return days2;
});
const disabledDays = computed(() => days.value.filter((day) => day.type === "disabled"));
const scrollToDate = (body, targetDate) => {
if (daysRef.value) {
const daysRect = useRect(daysRef.value);
const totalRows = placeholders.value.length;
const currentRow = Math.ceil((targetDate.getDate() + offset.value) / 7);
const rowOffset = (currentRow - 1) * daysRect.height / totalRows;
setScrollTop(body, daysRect.top + rowOffset + body.scrollTop - useRect(body).top);
}
};
const renderDay = (item, index) => _createVNode(CalendarDay, {
"item": item,
"index": index,
"color": props.color,
"offset": offset.value,
"rowHeight": rowHeight.value,
"onClick": (item2) => emit("click", item2)
}, pick(slots, ["top-info", "bottom-info"]));
const renderDays = () => _createVNode("div", {
"ref": daysRef,
"role": "grid",
"class": bem("days")
}, [renderMark(), (shouldRender.value ? days : placeholders).value.map(renderDay)]);
useExpose({
getTitle,
getHeight: () => height.value,
setVisible,
scrollToDate,
disabledDays
});
return () => _createVNode("div", {
"class": bem("month"),
"ref": monthRef
}, [renderTitle(), renderDays()]);
}
});
export {
stdin_default as default
};
+1
View File
File diff suppressed because one or more lines are too long
+210
View File
@@ -0,0 +1,210 @@
export declare const Calendar: import("../utils").WithInstall<import("vue").DefineComponent<{
show: BooleanConstructor;
type: {
type: import("vue").PropType<import("./types").CalendarType>;
default: import("./types").CalendarType;
};
title: StringConstructor;
color: StringConstructor;
round: {
type: BooleanConstructor;
default: true;
};
readonly: BooleanConstructor;
poppable: {
type: BooleanConstructor;
default: true;
};
maxRange: {
type: (NumberConstructor | StringConstructor)[];
default: null;
};
position: {
type: import("vue").PropType<import("..").PopupPosition>;
default: import("..").PopupPosition;
};
teleport: import("vue").PropType<string | import("vue").RendererElement | null | undefined>;
showMark: {
type: BooleanConstructor;
default: true;
};
showTitle: {
type: BooleanConstructor;
default: true;
};
formatter: import("vue").PropType<(item: import("./types").CalendarDayItem) => import("./types").CalendarDayItem>;
rowHeight: (NumberConstructor | StringConstructor)[];
confirmText: StringConstructor;
rangePrompt: StringConstructor;
lazyRender: {
type: BooleanConstructor;
default: true;
};
showConfirm: {
type: BooleanConstructor;
default: true;
};
defaultDate: import("vue").PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: {
type: BooleanConstructor;
default: true;
};
closeOnPopstate: {
type: BooleanConstructor;
default: true;
};
showRangePrompt: {
type: BooleanConstructor;
default: true;
};
confirmDisabledText: StringConstructor;
closeOnClickOverlay: {
type: BooleanConstructor;
default: true;
};
safeAreaInsetTop: BooleanConstructor;
safeAreaInsetBottom: {
type: BooleanConstructor;
default: true;
};
minDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
maxDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
firstDayOfWeek: {
type: (NumberConstructor | StringConstructor)[];
default: number;
validator: (val: number) => boolean;
};
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("select" | "update:show" | "confirm" | "clickSubtitle" | "unselect" | "monthShow" | "overRange")[], "select" | "update:show" | "confirm" | "clickSubtitle" | "unselect" | "monthShow" | "overRange", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
show: BooleanConstructor;
type: {
type: import("vue").PropType<import("./types").CalendarType>;
default: import("./types").CalendarType;
};
title: StringConstructor;
color: StringConstructor;
round: {
type: BooleanConstructor;
default: true;
};
readonly: BooleanConstructor;
poppable: {
type: BooleanConstructor;
default: true;
};
maxRange: {
type: (NumberConstructor | StringConstructor)[];
default: null;
};
position: {
type: import("vue").PropType<import("..").PopupPosition>;
default: import("..").PopupPosition;
};
teleport: import("vue").PropType<string | import("vue").RendererElement | null | undefined>;
showMark: {
type: BooleanConstructor;
default: true;
};
showTitle: {
type: BooleanConstructor;
default: true;
};
formatter: import("vue").PropType<(item: import("./types").CalendarDayItem) => import("./types").CalendarDayItem>;
rowHeight: (NumberConstructor | StringConstructor)[];
confirmText: StringConstructor;
rangePrompt: StringConstructor;
lazyRender: {
type: BooleanConstructor;
default: true;
};
showConfirm: {
type: BooleanConstructor;
default: true;
};
defaultDate: import("vue").PropType<Date | Date[] | null>;
allowSameDay: BooleanConstructor;
showSubtitle: {
type: BooleanConstructor;
default: true;
};
closeOnPopstate: {
type: BooleanConstructor;
default: true;
};
showRangePrompt: {
type: BooleanConstructor;
default: true;
};
confirmDisabledText: StringConstructor;
closeOnClickOverlay: {
type: BooleanConstructor;
default: true;
};
safeAreaInsetTop: BooleanConstructor;
safeAreaInsetBottom: {
type: BooleanConstructor;
default: true;
};
minDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
maxDate: {
type: DateConstructor;
validator: (val: unknown) => val is Date;
default: () => Date;
};
firstDayOfWeek: {
type: (NumberConstructor | StringConstructor)[];
default: number;
validator: (val: number) => boolean;
};
}>> & {
onSelect?: ((...args: any[]) => any) | undefined;
"onUpdate:show"?: ((...args: any[]) => any) | undefined;
onConfirm?: ((...args: any[]) => any) | undefined;
onClickSubtitle?: ((...args: any[]) => any) | undefined;
onUnselect?: ((...args: any[]) => any) | undefined;
onMonthShow?: ((...args: any[]) => any) | undefined;
onOverRange?: ((...args: any[]) => any) | undefined;
}, {
type: import("./types").CalendarType;
position: import("..").PopupPosition;
round: boolean;
readonly: boolean;
safeAreaInsetBottom: boolean;
show: boolean;
lazyRender: boolean;
closeOnClickOverlay: boolean;
closeOnPopstate: boolean;
safeAreaInsetTop: boolean;
poppable: boolean;
maxRange: string | number;
showMark: boolean;
showTitle: boolean;
showConfirm: boolean;
allowSameDay: boolean;
showSubtitle: boolean;
showRangePrompt: boolean;
minDate: Date;
maxDate: Date;
firstDayOfWeek: string | number;
}>>;
export default Calendar;
export { calendarProps } from './Calendar';
export type { CalendarProps } from './Calendar';
export type { CalendarType, CalendarDayItem, CalendarDayType, CalendarInstance, CalendarThemeVars, } from './types';
declare module 'vue' {
interface GlobalComponents {
VanCalendar: typeof Calendar;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { withInstall } from "../utils/index.mjs";
import _Calendar from "./Calendar.mjs";
const Calendar = withInstall(_Calendar);
var stdin_default = Calendar;
import { calendarProps } from "./Calendar.mjs";
export {
Calendar,
calendarProps,
stdin_default as default
};
+1
View File
@@ -0,0 +1 @@
export {};
+16
View File
@@ -0,0 +1,16 @@
import "../../style/base.css";
import "../../badge/index.css";
import "../../icon/index.css";
import "../../loading/index.css";
import "../../button/index.css";
import "../../overlay/index.css";
import "../../popup/index.css";
import "../../toast/index.css";
import "../../sticky/index.css";
import "../../swipe/index.css";
import "../../swipe-item/index.css";
import "../../tabs/index.css";
import "../../tab/index.css";
import "../../picker/index.css";
import "../../picker-group/index.css";
import "../index.css";
+56
View File
@@ -0,0 +1,56 @@
import type { ComponentPublicInstance, ComputedRef, Ref } from 'vue';
import type { Numeric } from '../utils';
import type { CalendarProps } from './Calendar';
import type { CalendarMonthProps } from './CalendarMonth';
export type CalendarType = 'single' | 'range' | 'multiple';
export type CalendarDayType = '' | 'start' | 'start-end' | 'middle' | 'end' | 'selected' | 'multiple-middle' | 'multiple-selected' | 'disabled' | 'placeholder';
export type CalendarDayItem = {
date?: Date;
text?: Numeric;
type?: CalendarDayType;
topInfo?: string;
className?: unknown;
bottomInfo?: string;
};
export type CalendarExpose = {
reset: (date?: Date | Date[]) => void;
scrollToDate: (targetDate: Date) => void;
getSelectedDate: () => Date | Date[] | null;
};
export type CalendarInstance = ComponentPublicInstance<CalendarProps, CalendarExpose>;
export type CalendarMonthInstance = ComponentPublicInstance<CalendarMonthProps, {
showed?: boolean;
getTitle: () => string;
getHeight: () => number;
setVisible: (value?: boolean | undefined) => void;
scrollToDate: (body: Element, targetDate: Date) => void;
disabledDays: Ref<ComputedRef<CalendarDayItem[]>>;
}>;
export type CalendarThemeVars = {
calendarBackground?: string;
calendarPopupHeight?: string;
calendarHeaderShadow?: string;
calendarHeaderTitleHeight?: string;
calendarHeaderTitleFontSize?: string;
calendarHeaderSubtitleFontSize?: string;
calendarWeekdaysHeight?: string;
calendarWeekdaysFontSize?: string;
calendarMonthTitleFontSize?: string;
calendarMonthMarkColor?: string;
calendarMonthMarkFontSize?: string;
calendarDayHeight?: string;
calendarDayFontSize?: string;
calendarDayMarginBottom?: string;
calendarRangeEdgeColor?: string;
calendarRangeEdgeBackground?: string;
calendarRangeMiddleColor?: string;
calendarRangeMiddleBackgroundOpacity?: number | string;
calendarSelectedDaySize?: string;
calendarSelectedDayColor?: string;
calendarInfoFontSize?: string;
calendarInfoLineHeight?: number | string;
calendarSelectedDayBackground?: string;
calendarDayDisabledColor?: string;
calendarConfirmButtonHeight?: string;
calendarConfirmButtonMargin?: string;
};
View File
+12
View File
@@ -0,0 +1,12 @@
declare const name: string, bem: (el?: import("../utils").Mods | undefined, mods?: import("../utils").Mods | undefined) => import("../utils").Mods, t: (path: string, ...args: unknown[]) => any;
export { name, bem, t };
export declare const formatMonthTitle: (date: Date) => any;
export declare function compareMonth(date1: Date, date2: Date): 0 | 1 | -1;
export declare function compareDay(day1: Date, day2: Date): 0 | 1 | -1;
export declare const cloneDate: (date: Date) => Date;
export declare const cloneDates: (dates: Date | Date[]) => Date | Date[];
export declare function getDayByOffset(date: Date, offset: number): Date;
export declare const getPrevDay: (date: Date) => Date;
export declare const getNextDay: (date: Date) => Date;
export declare const getToday: () => Date;
export declare function calcDateNum(date: [Date, Date]): number;
+56
View File
@@ -0,0 +1,56 @@
import { createNamespace } from "../utils/index.mjs";
const [name, bem, t] = createNamespace("calendar");
const formatMonthTitle = (date) => t("monthTitle", date.getFullYear(), date.getMonth() + 1);
function compareMonth(date1, date2) {
const year1 = date1.getFullYear();
const year2 = date2.getFullYear();
if (year1 === year2) {
const month1 = date1.getMonth();
const month2 = date2.getMonth();
return month1 === month2 ? 0 : month1 > month2 ? 1 : -1;
}
return year1 > year2 ? 1 : -1;
}
function compareDay(day1, day2) {
const compareMonthResult = compareMonth(day1, day2);
if (compareMonthResult === 0) {
const date1 = day1.getDate();
const date2 = day2.getDate();
return date1 === date2 ? 0 : date1 > date2 ? 1 : -1;
}
return compareMonthResult;
}
const cloneDate = (date) => new Date(date);
const cloneDates = (dates) => Array.isArray(dates) ? dates.map(cloneDate) : cloneDate(dates);
function getDayByOffset(date, offset) {
const cloned = cloneDate(date);
cloned.setDate(cloned.getDate() + offset);
return cloned;
}
const getPrevDay = (date) => getDayByOffset(date, -1);
const getNextDay = (date) => getDayByOffset(date, 1);
const getToday = () => {
const today = /* @__PURE__ */ new Date();
today.setHours(0, 0, 0, 0);
return today;
};
function calcDateNum(date) {
const day1 = date[0].getTime();
const day2 = date[1].getTime();
return (day2 - day1) / (1e3 * 60 * 60 * 24) + 1;
}
export {
bem,
calcDateNum,
cloneDate,
cloneDates,
compareDay,
compareMonth,
formatMonthTitle,
getDayByOffset,
getNextDay,
getPrevDay,
getToday,
name,
t
};