design-system-next 2.16.2 → 2.17.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/design-system-next.es.js +7569 -6646
- package/dist/design-system-next.es.js.gz +0 -0
- package/dist/design-system-next.umd.js +14 -14
- package/dist/design-system-next.umd.js.gz +0 -0
- package/dist/main.css +1 -1
- package/dist/main.css.gz +0 -0
- package/dist/package.json.d.ts +1 -1
- package/package.json +1 -1
- package/src/App.vue +43 -1642
- package/src/assets/styles/tailwind.css +20 -0
- package/src/components/attribute-filter/attribute-filter.ts +5 -1
- package/src/components/attribute-filter/attribute-filter.vue +3 -3
- package/src/components/calendar/calendar.ts +1 -1
- package/src/components/calendar/calendar.vue +41 -18
- package/src/components/calendar/use-calendar.ts +13 -6
- package/src/components/calendar-cell/calendar-cell.ts +4 -0
- package/src/components/calendar-cell/use-calendar-cell.ts +21 -2
- package/src/components/card/card.ts +5 -0
- package/src/components/card/use-card.ts +15 -3
- package/src/components/date-picker/date-picker.ts +36 -5
- package/src/components/date-picker/date-picker.vue +2 -1
- package/src/components/date-picker/date-range-picker/date-range-picker.ts +14 -6
- package/src/components/date-picker/date-range-picker/date-range-picker.vue +2 -1
- package/src/components/date-picker/reusable-calendar/reusable-calendar.ts +121 -0
- package/src/components/date-picker/reusable-calendar/reusable-calendar.vue +192 -0
- package/src/components/date-picker/reusable-calendar/use-reusable-calendar.ts +366 -0
- package/src/components/date-picker/tabs/DatePickerCalendarTab.vue +321 -0
- package/src/components/date-picker/tabs/DatePickerMonthTab.vue +60 -0
- package/src/components/date-picker/tabs/DatePickerYearTab.vue +114 -0
- package/src/components/dropdown/dropdown.ts +25 -21
- package/src/components/dropdown/dropdown.vue +1 -1
- package/src/components/icon/icon.ts +36 -0
- package/src/components/icon/icon.vue +12 -0
- package/src/components/icon/use-icon.ts +67 -0
- package/src/components/lozenge/lozenge.ts +1 -1
- package/src/components/popper/popper.ts +12 -0
- package/src/components/popper/popper.vue +36 -0
- package/src/components/popper/use-popper.ts +16 -0
- package/src/components/select/select-ladderized/select-ladderized.ts +16 -12
- package/src/components/select/select-ladderized/select-ladderized.vue +1 -1
- package/src/components/select/select-multiple/select-multiple.ts +8 -4
- package/src/components/select/select-multiple/select-multiple.vue +1 -1
- package/src/components/select/select-multiple/use-select-multiple.ts +15 -4
- package/src/components/select/select.ts +4 -0
- package/src/components/select/select.vue +1 -1
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
ref="reusableCalendarRef"
|
|
4
|
+
:class="reusableCalendarClasses"
|
|
5
|
+
>
|
|
6
|
+
<div
|
|
7
|
+
:class="[
|
|
8
|
+
'spr-flex spr-justify-between spr-gap-2 spr-px-4 spr-py-3',
|
|
9
|
+
'spr-border spr-border-x-0 spr-border-b spr-border-t-0 spr-border-solid spr-border-mushroom-200',
|
|
10
|
+
]"
|
|
11
|
+
>
|
|
12
|
+
<!-- Tabs -->
|
|
13
|
+
<div class="spr-flex spr-gap-1">
|
|
14
|
+
<spr-button
|
|
15
|
+
v-if="showMonthInput"
|
|
16
|
+
:class="getTabClasses('tab-months')"
|
|
17
|
+
variant="secondary"
|
|
18
|
+
size="small"
|
|
19
|
+
@click="handleTabClick('tab-months')"
|
|
20
|
+
>
|
|
21
|
+
{{ getMonthObject('monthValue', calendarTabPageData.selectedMonth)?.fullText }}
|
|
22
|
+
</spr-button>
|
|
23
|
+
<spr-button
|
|
24
|
+
v-if="showYearInput"
|
|
25
|
+
:class="getTabClasses('tab-years')"
|
|
26
|
+
variant="secondary"
|
|
27
|
+
size="small"
|
|
28
|
+
@click="handleTabClick('tab-years')"
|
|
29
|
+
>
|
|
30
|
+
{{ calendarTabPageData.selectedYear }}
|
|
31
|
+
</spr-button>
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<!-- Next & Previous Buttons -->
|
|
35
|
+
<div v-if="currentTab === 'tab-calendar'" class="spr-flex spr-gap-1">
|
|
36
|
+
<spr-button
|
|
37
|
+
class="spr-cursor-pointer"
|
|
38
|
+
variant="secondary"
|
|
39
|
+
size="small"
|
|
40
|
+
:disabled="calendarTabIsMinMonth"
|
|
41
|
+
@click="calendarTabPrevMonth"
|
|
42
|
+
>
|
|
43
|
+
<Icon icon="ph:caret-left" />
|
|
44
|
+
</spr-button>
|
|
45
|
+
<spr-button
|
|
46
|
+
class="spr-cursor-pointer"
|
|
47
|
+
variant="secondary"
|
|
48
|
+
size="small"
|
|
49
|
+
:disabled="calendarTabIsMaxMonth"
|
|
50
|
+
@click="calendarTabNextMonth"
|
|
51
|
+
>
|
|
52
|
+
<Icon icon="ph:caret-right" />
|
|
53
|
+
</spr-button>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div v-if="currentTab === 'tab-years'" class="spr-flex spr-gap-1">
|
|
57
|
+
<spr-button
|
|
58
|
+
class="spr-cursor-pointer"
|
|
59
|
+
variant="secondary"
|
|
60
|
+
size="small"
|
|
61
|
+
:disabled="yearTabIsPreviousButtonDisabled"
|
|
62
|
+
@click="yearTabGoToPreviousPage"
|
|
63
|
+
>
|
|
64
|
+
<Icon icon="ph:caret-left" />
|
|
65
|
+
</spr-button>
|
|
66
|
+
<spr-button
|
|
67
|
+
class="spr-cursor-pointer"
|
|
68
|
+
variant="secondary"
|
|
69
|
+
size="small"
|
|
70
|
+
:disabled="yearTabIsNextButtonDisabled"
|
|
71
|
+
@click="yearTabGoToNextPage"
|
|
72
|
+
>
|
|
73
|
+
<Icon icon="ph:caret-right" />
|
|
74
|
+
</spr-button>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="spr-px-4 spr-pb-4 spr-pt-2">
|
|
79
|
+
<!-- Calendar Tab -->
|
|
80
|
+
<DatePickerCalendarTab
|
|
81
|
+
v-if="currentTab === 'tab-calendar' && showDateInput"
|
|
82
|
+
:calendar-days="calendarDays"
|
|
83
|
+
:selected-month="selectedMonthComputed"
|
|
84
|
+
:selected-year="selectedYearComputed"
|
|
85
|
+
:selected-day="selectedDayComputed"
|
|
86
|
+
:min-max-year="minMaxYear"
|
|
87
|
+
:rest-days="restDays"
|
|
88
|
+
:disabled-dates="disabledDates"
|
|
89
|
+
:disabled="disabled"
|
|
90
|
+
:readonly="readonly"
|
|
91
|
+
@update:date="handleCalendarDateUpdateWrapper as any"
|
|
92
|
+
@update:month="handleCalendarMonthUpdateWrapper as any"
|
|
93
|
+
@update:year="handleCalendarYearUpdateWrapper as any"
|
|
94
|
+
/>
|
|
95
|
+
|
|
96
|
+
<!-- Months Tab -->
|
|
97
|
+
<DatePickerMonthTab
|
|
98
|
+
v-if="currentTab === 'tab-months' && showMonthInput"
|
|
99
|
+
:selected-month="selectedMonthComputed"
|
|
100
|
+
:selected-year="selectedYearComputed"
|
|
101
|
+
:min-max-year="minMaxYear"
|
|
102
|
+
:disabled="disabled"
|
|
103
|
+
:readonly="readonly"
|
|
104
|
+
@update:month="handleMonthTabMonthUpdateWrapper as any"
|
|
105
|
+
/>
|
|
106
|
+
|
|
107
|
+
<!-- Years Tab -->
|
|
108
|
+
<DatePickerYearTab
|
|
109
|
+
v-if="currentTab === 'tab-years' && showYearInput"
|
|
110
|
+
:selected-month="selectedMonthComputed"
|
|
111
|
+
:selected-year="selectedYearComputed"
|
|
112
|
+
:min-max-year="minMaxYear"
|
|
113
|
+
:years-array="yearTabPageData.yearsArray"
|
|
114
|
+
:current-page="yearTabPageData.currentPage"
|
|
115
|
+
:items-per-page="yearTabPageData.itemsPerPage"
|
|
116
|
+
:disabled="disabled"
|
|
117
|
+
:readonly="readonly"
|
|
118
|
+
@update:year="handleYearTabYearUpdateWrapper as any"
|
|
119
|
+
@update:current-page="handleYearTabCurrentPageUpdateWrapper as any"
|
|
120
|
+
/>
|
|
121
|
+
</div>
|
|
122
|
+
</div>
|
|
123
|
+
</template>
|
|
124
|
+
|
|
125
|
+
<script lang="ts" setup>
|
|
126
|
+
import { computed, ref } from 'vue';
|
|
127
|
+
import { Icon } from '@iconify/vue';
|
|
128
|
+
import classNames from 'classnames';
|
|
129
|
+
|
|
130
|
+
import SprButton from '@/components/button/button.vue';
|
|
131
|
+
import DatePickerCalendarTab from '../tabs/DatePickerCalendarTab.vue';
|
|
132
|
+
import DatePickerMonthTab from '../tabs/DatePickerMonthTab.vue';
|
|
133
|
+
import DatePickerYearTab from '../tabs/DatePickerYearTab.vue';
|
|
134
|
+
|
|
135
|
+
import { useReusableCalendar } from './use-reusable-calendar';
|
|
136
|
+
import { reusableCalendarEmitTypes, reusableCalendarPropTypes } from './reusable-calendar';
|
|
137
|
+
|
|
138
|
+
const props = defineProps(reusableCalendarPropTypes);
|
|
139
|
+
const emit = defineEmits(reusableCalendarEmitTypes);
|
|
140
|
+
|
|
141
|
+
const reusableCalendarRef = ref<HTMLElement | null>(null);
|
|
142
|
+
|
|
143
|
+
// Use the composable for all logic
|
|
144
|
+
const {
|
|
145
|
+
// State
|
|
146
|
+
currentTab,
|
|
147
|
+
calendarTabPageData,
|
|
148
|
+
yearTabPageData,
|
|
149
|
+
|
|
150
|
+
// Computed properties
|
|
151
|
+
showMonthInput,
|
|
152
|
+
showDateInput,
|
|
153
|
+
showYearInput,
|
|
154
|
+
calendarDays,
|
|
155
|
+
selectedMonthComputed,
|
|
156
|
+
selectedYearComputed,
|
|
157
|
+
selectedDayComputed,
|
|
158
|
+
calendarTabIsMinMonth,
|
|
159
|
+
calendarTabIsMaxMonth,
|
|
160
|
+
yearTabIsPreviousButtonDisabled,
|
|
161
|
+
yearTabIsNextButtonDisabled,
|
|
162
|
+
|
|
163
|
+
// Functions
|
|
164
|
+
getTabClasses,
|
|
165
|
+
handleTabClick,
|
|
166
|
+
getMonthObject,
|
|
167
|
+
calendarTabPrevMonth,
|
|
168
|
+
calendarTabNextMonth,
|
|
169
|
+
yearTabGoToPreviousPage,
|
|
170
|
+
yearTabGoToNextPage,
|
|
171
|
+
|
|
172
|
+
// Event handlers
|
|
173
|
+
handleCalendarDateUpdateWrapper,
|
|
174
|
+
handleCalendarMonthUpdateWrapper,
|
|
175
|
+
handleCalendarYearUpdateWrapper,
|
|
176
|
+
handleMonthTabMonthUpdateWrapper,
|
|
177
|
+
handleYearTabYearUpdateWrapper,
|
|
178
|
+
handleYearTabCurrentPageUpdateWrapper,
|
|
179
|
+
} = useReusableCalendar(props, emit);
|
|
180
|
+
|
|
181
|
+
// Compute CSS classes using classNames utility
|
|
182
|
+
const reusableCalendarClasses = computed(() => {
|
|
183
|
+
return classNames(
|
|
184
|
+
'reusable-calendar-container spr-bg-white spr-rounded-lg spr-shadow-lg spr-border spr-border-solid spr-border-mushroom-200 min-w-[320px]',
|
|
185
|
+
{
|
|
186
|
+
'spr-disabled': props.disabled,
|
|
187
|
+
'spr-readonly': props.readonly,
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
</script>
|
|
192
|
+
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { computed, ref, watch } from 'vue';
|
|
2
|
+
import { toRefs } from 'vue';
|
|
3
|
+
import dayjs from 'dayjs';
|
|
4
|
+
|
|
5
|
+
import type { SetupContext } from 'vue';
|
|
6
|
+
import type { ReusableCalendarEmitTypes, ReusableCalendarPropTypes } from './reusable-calendar';
|
|
7
|
+
|
|
8
|
+
export const useReusableCalendar = (
|
|
9
|
+
props: ReusableCalendarPropTypes,
|
|
10
|
+
emit: SetupContext<ReusableCalendarEmitTypes>['emit']
|
|
11
|
+
) => {
|
|
12
|
+
// Extract reactive props
|
|
13
|
+
const {
|
|
14
|
+
mode,
|
|
15
|
+
} = toRefs(props);
|
|
16
|
+
|
|
17
|
+
// Internal state
|
|
18
|
+
const currentTab = ref<string>('tab-calendar');
|
|
19
|
+
const calendarTabPageData = ref({
|
|
20
|
+
selectedMonth: props.selectedMonth ?? dayjs().month(),
|
|
21
|
+
selectedYear: props.selectedYear ?? dayjs().year(),
|
|
22
|
+
calendarDays: [] as Array<{ date: Date; inactive: boolean }>,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const yearTabPageData = ref({
|
|
26
|
+
currentPage: 0,
|
|
27
|
+
itemsPerPage: 12,
|
|
28
|
+
yearsArray: Array.from(
|
|
29
|
+
{ length: props.minMaxYear.max - props.minMaxYear.min + 1 },
|
|
30
|
+
(_, index) => props.minMaxYear.min + index,
|
|
31
|
+
).filter((year) => year <= props.minMaxYear.max && year >= props.minMaxYear.min),
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Computed properties
|
|
35
|
+
const showMonthInput = computed(() => mode.value === 'full' || mode.value === 'month-year');
|
|
36
|
+
const showDateInput = computed(() => mode.value === 'full');
|
|
37
|
+
const showYearInput = computed(() => mode.value === 'full' || mode.value === 'month-year' || mode.value === 'year-only');
|
|
38
|
+
|
|
39
|
+
const calendarDays = computed(() => calendarTabPageData.value.calendarDays);
|
|
40
|
+
const selectedMonthComputed = computed(() => calendarTabPageData.value.selectedMonth);
|
|
41
|
+
const selectedYearComputed = computed(() => calendarTabPageData.value.selectedYear);
|
|
42
|
+
const selectedDayComputed = computed(() => props.modelValue ? dayjs(props.modelValue, props.format).date() : 0);
|
|
43
|
+
|
|
44
|
+
// Calendar navigation computed properties
|
|
45
|
+
const calendarTabIsMinMonth = computed(() =>
|
|
46
|
+
dayjs()
|
|
47
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
48
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
49
|
+
.isSame(dayjs().year(props.minMaxYear.min).month(0), 'month'),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const calendarTabIsMaxMonth = computed(() =>
|
|
53
|
+
dayjs()
|
|
54
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
55
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
56
|
+
.isSame(dayjs().year(props.minMaxYear.max).month(11), 'month'),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const yearTabIsPreviousButtonDisabled = computed(() => {
|
|
60
|
+
return yearTabPageData.value.currentPage === 0;
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const yearTabIsNextButtonDisabled = computed(() => {
|
|
64
|
+
return (
|
|
65
|
+
(yearTabPageData.value.currentPage + 1) * yearTabPageData.value.itemsPerPage >=
|
|
66
|
+
yearTabPageData.value.yearsArray.length
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Calendar update function
|
|
71
|
+
const calendarTabUpdateCalendar = () => {
|
|
72
|
+
const firstDay = dayjs()
|
|
73
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
74
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
75
|
+
.startOf('month')
|
|
76
|
+
.day();
|
|
77
|
+
|
|
78
|
+
const lastDate = dayjs()
|
|
79
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
80
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
81
|
+
.endOf('month')
|
|
82
|
+
.date();
|
|
83
|
+
|
|
84
|
+
const prevMonthDays = firstDay;
|
|
85
|
+
const totalDays = prevMonthDays + lastDate;
|
|
86
|
+
const nextMonthDays = totalDays % 7 === 0 ? 0 : 7 - (totalDays % 7);
|
|
87
|
+
|
|
88
|
+
const calendar = [];
|
|
89
|
+
|
|
90
|
+
// Previous month days
|
|
91
|
+
for (let index = prevMonthDays; index > 0; index--) {
|
|
92
|
+
const date = dayjs()
|
|
93
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
94
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
95
|
+
.date(-index + 1);
|
|
96
|
+
|
|
97
|
+
calendar.push({ date, inactive: true });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Current month days
|
|
101
|
+
for (let index = 1; index <= lastDate; index++) {
|
|
102
|
+
const date = dayjs()
|
|
103
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
104
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
105
|
+
.date(index);
|
|
106
|
+
|
|
107
|
+
calendar.push({ date, inactive: false });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Next month days
|
|
111
|
+
for (let index = 1; index <= nextMonthDays; index++) {
|
|
112
|
+
const date = dayjs()
|
|
113
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
114
|
+
.month(calendarTabPageData.value.selectedMonth + 1)
|
|
115
|
+
.date(index);
|
|
116
|
+
|
|
117
|
+
calendar.push({ date, inactive: true });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
calendarTabPageData.value.calendarDays = calendar.map((day) => ({ ...day, date: day.date.toDate() }));
|
|
121
|
+
goBackToCalendarTab();
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const goBackToCalendarTab = () => {
|
|
125
|
+
if(props.mode === 'full' && currentTab.value !== 'tab-calendar') {
|
|
126
|
+
currentTab.value = 'tab-calendar';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Navigation functions
|
|
131
|
+
const calendarTabPrevMonth = () => {
|
|
132
|
+
if (calendarTabIsMinMonth.value) return;
|
|
133
|
+
|
|
134
|
+
const newDate = dayjs()
|
|
135
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
136
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
137
|
+
.subtract(1, 'month');
|
|
138
|
+
|
|
139
|
+
calendarTabPageData.value.selectedMonth = newDate.month();
|
|
140
|
+
calendarTabPageData.value.selectedYear = newDate.year();
|
|
141
|
+
|
|
142
|
+
calendarTabUpdateCalendar();
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const calendarTabNextMonth = () => {
|
|
146
|
+
if (calendarTabIsMaxMonth.value) return;
|
|
147
|
+
|
|
148
|
+
const newDate = dayjs()
|
|
149
|
+
.year(calendarTabPageData.value.selectedYear)
|
|
150
|
+
.month(calendarTabPageData.value.selectedMonth)
|
|
151
|
+
.add(1, 'month');
|
|
152
|
+
|
|
153
|
+
calendarTabPageData.value.selectedMonth = newDate.month();
|
|
154
|
+
calendarTabPageData.value.selectedYear = newDate.year();
|
|
155
|
+
|
|
156
|
+
calendarTabUpdateCalendar();
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const yearTabGoToPreviousPage = () => {
|
|
160
|
+
if (yearTabPageData.value.currentPage > 0) {
|
|
161
|
+
yearTabPageData.value.currentPage--;
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const yearTabGoToNextPage = () => {
|
|
166
|
+
if (
|
|
167
|
+
(yearTabPageData.value.currentPage + 1) * yearTabPageData.value.itemsPerPage <
|
|
168
|
+
yearTabPageData.value.yearsArray.length
|
|
169
|
+
) {
|
|
170
|
+
yearTabPageData.value.currentPage++;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// Tab functions
|
|
175
|
+
const getTabClasses = (tab: string) => {
|
|
176
|
+
return {
|
|
177
|
+
'spr-cursor-pointer': true,
|
|
178
|
+
'spr-background-color-pressed !spr-shadow-button': currentTab.value === tab,
|
|
179
|
+
};
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const handleTabClick = (tab: string) => {
|
|
183
|
+
if (currentTab.value === tab && props.mode === 'full') {
|
|
184
|
+
currentTab.value = 'tab-calendar';
|
|
185
|
+
} else {
|
|
186
|
+
currentTab.value = tab;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// Month list for display
|
|
191
|
+
const monthsList = ref(
|
|
192
|
+
Array.from({ length: 12 }, (_, i) => ({
|
|
193
|
+
text: dayjs().month(i).format('MMM'),
|
|
194
|
+
fullText: dayjs().month(i).format('MMMM'),
|
|
195
|
+
monthValue: i,
|
|
196
|
+
})),
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
const getMonthObject = (field: string, value: string | number) => {
|
|
200
|
+
return monthsList.value.find(
|
|
201
|
+
(_month: { text: string; fullText: string; monthValue: number }) =>
|
|
202
|
+
_month[field as keyof typeof _month].toString().toLowerCase() === value.toString().toLowerCase(),
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Event handlers
|
|
207
|
+
const handleCalendarDateUpdate = (day: { date: Date; inactive: boolean }) => {
|
|
208
|
+
const selectedDate = dayjs(day.date);
|
|
209
|
+
|
|
210
|
+
// Update internal state
|
|
211
|
+
calendarTabPageData.value.selectedMonth = day.date.getMonth();
|
|
212
|
+
calendarTabPageData.value.selectedYear = day.date.getFullYear();
|
|
213
|
+
|
|
214
|
+
// Update calendar display
|
|
215
|
+
calendarTabUpdateCalendar();
|
|
216
|
+
|
|
217
|
+
// Emit events
|
|
218
|
+
emit('update:month', day.date.getMonth());
|
|
219
|
+
emit('update:year', day.date.getFullYear());
|
|
220
|
+
emit('update:day', day.date.getDate());
|
|
221
|
+
emit('update:modelValue', selectedDate.format(props.format));
|
|
222
|
+
};
|
|
223
|
+
|
|
224
|
+
const handleCalendarMonthUpdate = (month: number) => {
|
|
225
|
+
calendarTabPageData.value.selectedMonth = month;
|
|
226
|
+
emit('update:month', month);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const handleCalendarYearUpdate = (year: number) => {
|
|
230
|
+
calendarTabPageData.value.selectedYear = year;
|
|
231
|
+
emit('update:year', year);
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
const handleMonthTabMonthUpdate = (month: number) => {
|
|
235
|
+
calendarTabPageData.value.selectedMonth = month;
|
|
236
|
+
calendarTabUpdateCalendar();
|
|
237
|
+
emit('update:month', month);
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const handleYearTabYearUpdate = (year: number) => {
|
|
241
|
+
calendarTabPageData.value.selectedYear = year;
|
|
242
|
+
calendarTabUpdateCalendar();
|
|
243
|
+
emit('update:year', year);
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const handleYearTabCurrentPageUpdate = (page: number) => {
|
|
247
|
+
yearTabPageData.value.currentPage = page;
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
// Wrapper functions for event handlers
|
|
251
|
+
const handleCalendarDateUpdateWrapper = (day: { date: Date; inactive: boolean }) => {
|
|
252
|
+
handleCalendarDateUpdate(day);
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
const handleCalendarMonthUpdateWrapper = (month: number) => {
|
|
256
|
+
handleCalendarMonthUpdate(month);
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
const handleCalendarYearUpdateWrapper = (year: number) => {
|
|
260
|
+
handleCalendarYearUpdate(year);
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
const handleMonthTabMonthUpdateWrapper = (month: number) => {
|
|
264
|
+
handleMonthTabMonthUpdate(month);
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const handleYearTabYearUpdateWrapper = (year: number) => {
|
|
268
|
+
handleYearTabYearUpdate(year);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const handleYearTabCurrentPageUpdateWrapper = (page: number) => {
|
|
272
|
+
handleYearTabCurrentPageUpdate(page);
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Initialize based on mode
|
|
276
|
+
const getInitialTab = () => {
|
|
277
|
+
switch (props.mode) {
|
|
278
|
+
case 'month-year':
|
|
279
|
+
return 'tab-months';
|
|
280
|
+
case 'year-only':
|
|
281
|
+
return 'tab-years';
|
|
282
|
+
default:
|
|
283
|
+
return 'tab-calendar';
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// Initialize component
|
|
288
|
+
currentTab.value = getInitialTab();
|
|
289
|
+
calendarTabUpdateCalendar();
|
|
290
|
+
|
|
291
|
+
// Watch for prop changes
|
|
292
|
+
watch(() => props.modelValue, (newValue) => {
|
|
293
|
+
if (newValue) {
|
|
294
|
+
const parsedDate = dayjs(newValue, props.format);
|
|
295
|
+
if (parsedDate.isValid()) {
|
|
296
|
+
calendarTabPageData.value.selectedMonth = parsedDate.month();
|
|
297
|
+
calendarTabPageData.value.selectedYear = parsedDate.year();
|
|
298
|
+
calendarTabUpdateCalendar();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
watch(() => props.selectedMonth, (newMonth) => {
|
|
304
|
+
if (newMonth !== undefined) {
|
|
305
|
+
calendarTabPageData.value.selectedMonth = newMonth;
|
|
306
|
+
calendarTabUpdateCalendar();
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
watch(() => props.selectedYear, (newYear) => {
|
|
311
|
+
if (newYear !== undefined) {
|
|
312
|
+
calendarTabPageData.value.selectedYear = newYear;
|
|
313
|
+
calendarTabUpdateCalendar();
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
watch(() => props.mode, () => {
|
|
318
|
+
currentTab.value = getInitialTab();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
watch(() => props.minMaxYear, () => {
|
|
322
|
+
yearTabPageData.value.yearsArray = Array.from(
|
|
323
|
+
{ length: props.minMaxYear.max - props.minMaxYear.min + 1 },
|
|
324
|
+
(_, index) => props.minMaxYear.min + index,
|
|
325
|
+
).filter((year) => year <= props.minMaxYear.max && year >= props.minMaxYear.min);
|
|
326
|
+
|
|
327
|
+
yearTabPageData.value.currentPage = 0;
|
|
328
|
+
}, { deep: true });
|
|
329
|
+
|
|
330
|
+
return {
|
|
331
|
+
// State
|
|
332
|
+
currentTab,
|
|
333
|
+
calendarTabPageData,
|
|
334
|
+
yearTabPageData,
|
|
335
|
+
|
|
336
|
+
// Computed properties
|
|
337
|
+
showMonthInput,
|
|
338
|
+
showDateInput,
|
|
339
|
+
showYearInput,
|
|
340
|
+
calendarDays,
|
|
341
|
+
selectedMonthComputed,
|
|
342
|
+
selectedYearComputed,
|
|
343
|
+
selectedDayComputed,
|
|
344
|
+
calendarTabIsMinMonth,
|
|
345
|
+
calendarTabIsMaxMonth,
|
|
346
|
+
yearTabIsPreviousButtonDisabled,
|
|
347
|
+
yearTabIsNextButtonDisabled,
|
|
348
|
+
|
|
349
|
+
// Functions
|
|
350
|
+
getTabClasses,
|
|
351
|
+
handleTabClick,
|
|
352
|
+
getMonthObject,
|
|
353
|
+
calendarTabPrevMonth,
|
|
354
|
+
calendarTabNextMonth,
|
|
355
|
+
yearTabGoToPreviousPage,
|
|
356
|
+
yearTabGoToNextPage,
|
|
357
|
+
|
|
358
|
+
// Event handlers
|
|
359
|
+
handleCalendarDateUpdateWrapper,
|
|
360
|
+
handleCalendarMonthUpdateWrapper,
|
|
361
|
+
handleCalendarYearUpdateWrapper,
|
|
362
|
+
handleMonthTabMonthUpdateWrapper,
|
|
363
|
+
handleYearTabYearUpdateWrapper,
|
|
364
|
+
handleYearTabCurrentPageUpdateWrapper,
|
|
365
|
+
};
|
|
366
|
+
};
|