@morscherlab/mld-sdk 0.7.3 → 0.7.5
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/components/DatePicker.vue.d.ts +2 -0
- package/dist/components/DatePicker.vue.js +151 -118
- package/dist/components/DatePicker.vue.js.map +1 -1
- package/dist/styles.css +6 -8
- package/package.json +1 -1
- package/src/components/DatePicker.vue +57 -26
- package/src/styles/components/collapsible-card.css +1 -0
- package/src/styles/components/date-picker.css +3 -4
|
@@ -19,5 +19,7 @@ declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, imp
|
|
|
19
19
|
clearable: boolean;
|
|
20
20
|
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {
|
|
21
21
|
containerRef: HTMLDivElement;
|
|
22
|
+
inputRef: HTMLDivElement;
|
|
23
|
+
dropdownRef: HTMLDivElement;
|
|
22
24
|
}, HTMLDivElement>;
|
|
23
25
|
export default _default;
|
|
@@ -1,19 +1,11 @@
|
|
|
1
|
-
import { defineComponent, ref, computed, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode, normalizeClass, createStaticVNode, createVNode, Transition, withCtx, toDisplayString, Fragment, renderList, createCommentVNode } from "vue";
|
|
2
|
-
const _hoisted_1 =
|
|
3
|
-
const _hoisted_2 =
|
|
4
|
-
const _hoisted_3 = {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"aria-label": "Date picker"
|
|
10
|
-
};
|
|
11
|
-
const _hoisted_4 = { class: "mld-date-picker__header" };
|
|
12
|
-
const _hoisted_5 = { class: "mld-date-picker__month-year" };
|
|
13
|
-
const _hoisted_6 = { class: "mld-date-picker__weekdays" };
|
|
14
|
-
const _hoisted_7 = { class: "mld-date-picker__grid" };
|
|
15
|
-
const _hoisted_8 = ["disabled", "aria-label", "aria-selected", "onClick"];
|
|
16
|
-
const _hoisted_9 = { class: "mld-date-picker__footer" };
|
|
1
|
+
import { defineComponent, ref, computed, watch, onMounted, onUnmounted, openBlock, createElementBlock, createElementVNode, normalizeClass, createStaticVNode, createBlock, Teleport, createVNode, Transition, withCtx, normalizeStyle, toDisplayString, Fragment, renderList, createCommentVNode } from "vue";
|
|
2
|
+
const _hoisted_1 = ["value", "placeholder", "disabled"];
|
|
3
|
+
const _hoisted_2 = { class: "mld-date-picker__header" };
|
|
4
|
+
const _hoisted_3 = { class: "mld-date-picker__month-year" };
|
|
5
|
+
const _hoisted_4 = { class: "mld-date-picker__weekdays" };
|
|
6
|
+
const _hoisted_5 = { class: "mld-date-picker__grid" };
|
|
7
|
+
const _hoisted_6 = ["disabled", "aria-label", "aria-selected", "onClick"];
|
|
8
|
+
const _hoisted_7 = { class: "mld-date-picker__footer" };
|
|
17
9
|
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
18
10
|
__name: "DatePicker",
|
|
19
11
|
props: {
|
|
@@ -32,6 +24,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
32
24
|
const emit = __emit;
|
|
33
25
|
const isOpen = ref(false);
|
|
34
26
|
const containerRef = ref();
|
|
27
|
+
const inputRef = ref();
|
|
28
|
+
const dropdownRef = ref();
|
|
29
|
+
const dropdownStyle = ref({});
|
|
35
30
|
const currentMonth = ref(/* @__PURE__ */ new Date());
|
|
36
31
|
const selectedDate = computed(() => {
|
|
37
32
|
if (!props.modelValue) return null;
|
|
@@ -134,25 +129,48 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
134
129
|
if (props.disabled) return;
|
|
135
130
|
isOpen.value = !isOpen.value;
|
|
136
131
|
}
|
|
132
|
+
function updateDropdownPosition() {
|
|
133
|
+
if (!inputRef.value) return;
|
|
134
|
+
const rect = inputRef.value.getBoundingClientRect();
|
|
135
|
+
dropdownStyle.value = {
|
|
136
|
+
position: "fixed",
|
|
137
|
+
top: `${rect.bottom + 4}px`,
|
|
138
|
+
left: `${rect.left}px`,
|
|
139
|
+
width: `${Math.max(rect.width, 288)}px`,
|
|
140
|
+
zIndex: "9999"
|
|
141
|
+
};
|
|
142
|
+
}
|
|
137
143
|
function handleClickOutside(event) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
144
|
+
var _a, _b;
|
|
145
|
+
const target = event.target;
|
|
146
|
+
if ((_a = containerRef.value) == null ? void 0 : _a.contains(target)) return;
|
|
147
|
+
if ((_b = dropdownRef.value) == null ? void 0 : _b.contains(target)) return;
|
|
148
|
+
isOpen.value = false;
|
|
149
|
+
}
|
|
150
|
+
function handleScrollOrResize() {
|
|
151
|
+
if (isOpen.value) isOpen.value = false;
|
|
141
152
|
}
|
|
142
153
|
watch(isOpen, (open) => {
|
|
143
|
-
if (open
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
154
|
+
if (open) {
|
|
155
|
+
updateDropdownPosition();
|
|
156
|
+
if (selectedDate.value) {
|
|
157
|
+
currentMonth.value = new Date(
|
|
158
|
+
selectedDate.value.getFullYear(),
|
|
159
|
+
selectedDate.value.getMonth(),
|
|
160
|
+
1
|
|
161
|
+
);
|
|
162
|
+
}
|
|
149
163
|
}
|
|
150
164
|
});
|
|
151
165
|
onMounted(() => {
|
|
152
166
|
document.addEventListener("click", handleClickOutside);
|
|
167
|
+
window.addEventListener("scroll", handleScrollOrResize, true);
|
|
168
|
+
window.addEventListener("resize", handleScrollOrResize);
|
|
153
169
|
});
|
|
154
170
|
onUnmounted(() => {
|
|
155
171
|
document.removeEventListener("click", handleClickOutside);
|
|
172
|
+
window.removeEventListener("scroll", handleScrollOrResize, true);
|
|
173
|
+
window.removeEventListener("resize", handleScrollOrResize);
|
|
156
174
|
});
|
|
157
175
|
return (_ctx, _cache) => {
|
|
158
176
|
return openBlock(), createElementBlock("div", {
|
|
@@ -160,7 +178,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
160
178
|
ref: containerRef,
|
|
161
179
|
class: "mld-date-picker"
|
|
162
180
|
}, [
|
|
163
|
-
createElementVNode("div",
|
|
181
|
+
createElementVNode("div", {
|
|
182
|
+
ref_key: "inputRef",
|
|
183
|
+
ref: inputRef,
|
|
184
|
+
class: "mld-date-picker__input-wrapper"
|
|
185
|
+
}, [
|
|
164
186
|
createElementVNode("input", {
|
|
165
187
|
type: "text",
|
|
166
188
|
readonly: "",
|
|
@@ -174,100 +196,111 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
174
196
|
__props.disabled ? "mld-date-picker__input--disabled" : ""
|
|
175
197
|
]),
|
|
176
198
|
onClick: toggleCalendar
|
|
177
|
-
}, null, 10,
|
|
199
|
+
}, null, 10, _hoisted_1),
|
|
178
200
|
_cache[0] || (_cache[0] = createStaticVNode('<div class="mld-date-picker__icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"></path><path d="M16 2v4"></path><rect width="18" height="18" x="3" y="4" rx="2"></rect><path d="M3 10h18"></path></svg></div>', 1))
|
|
179
|
-
]),
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
"
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
"
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
201
|
+
], 512),
|
|
202
|
+
(openBlock(), createBlock(Teleport, { to: "body" }, [
|
|
203
|
+
createVNode(Transition, {
|
|
204
|
+
"enter-active-class": "mld-date-picker__dropdown-enter-active",
|
|
205
|
+
"enter-from-class": "mld-date-picker__dropdown-enter-from",
|
|
206
|
+
"enter-to-class": "mld-date-picker__dropdown-enter-to",
|
|
207
|
+
"leave-active-class": "mld-date-picker__dropdown-leave-active",
|
|
208
|
+
"leave-from-class": "mld-date-picker__dropdown-leave-from",
|
|
209
|
+
"leave-to-class": "mld-date-picker__dropdown-leave-to"
|
|
210
|
+
}, {
|
|
211
|
+
default: withCtx(() => [
|
|
212
|
+
isOpen.value ? (openBlock(), createElementBlock("div", {
|
|
213
|
+
key: 0,
|
|
214
|
+
ref_key: "dropdownRef",
|
|
215
|
+
ref: dropdownRef,
|
|
216
|
+
class: "mld-date-picker__dropdown",
|
|
217
|
+
style: normalizeStyle(dropdownStyle.value),
|
|
218
|
+
role: "dialog",
|
|
219
|
+
"aria-modal": "true",
|
|
220
|
+
"aria-label": "Date picker"
|
|
221
|
+
}, [
|
|
222
|
+
createElementVNode("div", _hoisted_2, [
|
|
223
|
+
createElementVNode("button", {
|
|
224
|
+
type: "button",
|
|
225
|
+
"aria-label": "Previous month",
|
|
226
|
+
class: "mld-date-picker__nav-btn",
|
|
227
|
+
onClick: prevMonth
|
|
228
|
+
}, [..._cache[1] || (_cache[1] = [
|
|
229
|
+
createElementVNode("svg", {
|
|
230
|
+
viewBox: "0 0 24 24",
|
|
231
|
+
fill: "none",
|
|
232
|
+
stroke: "currentColor",
|
|
233
|
+
"stroke-width": "2",
|
|
234
|
+
"stroke-linecap": "round",
|
|
235
|
+
"stroke-linejoin": "round"
|
|
236
|
+
}, [
|
|
237
|
+
createElementVNode("path", { d: "m15 18-6-6 6-6" })
|
|
238
|
+
], -1)
|
|
239
|
+
])]),
|
|
240
|
+
createElementVNode("span", _hoisted_3, toDisplayString(monthYear.value), 1),
|
|
241
|
+
createElementVNode("button", {
|
|
242
|
+
type: "button",
|
|
243
|
+
"aria-label": "Next month",
|
|
244
|
+
class: "mld-date-picker__nav-btn",
|
|
245
|
+
onClick: nextMonth
|
|
246
|
+
}, [..._cache[2] || (_cache[2] = [
|
|
247
|
+
createElementVNode("svg", {
|
|
248
|
+
viewBox: "0 0 24 24",
|
|
249
|
+
fill: "none",
|
|
250
|
+
stroke: "currentColor",
|
|
251
|
+
"stroke-width": "2",
|
|
252
|
+
"stroke-linecap": "round",
|
|
253
|
+
"stroke-linejoin": "round"
|
|
254
|
+
}, [
|
|
255
|
+
createElementVNode("path", { d: "m9 18 6-6-6-6" })
|
|
256
|
+
], -1)
|
|
257
|
+
])])
|
|
258
|
+
]),
|
|
259
|
+
createElementVNode("div", _hoisted_4, [
|
|
260
|
+
(openBlock(), createElementBlock(Fragment, null, renderList(weekDays, (day) => {
|
|
261
|
+
return createElementVNode("div", {
|
|
262
|
+
key: day,
|
|
263
|
+
class: "mld-date-picker__weekday"
|
|
264
|
+
}, toDisplayString(day), 1);
|
|
265
|
+
}), 64))
|
|
266
|
+
]),
|
|
267
|
+
createElementVNode("div", _hoisted_5, [
|
|
268
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(calendarDays.value, (day, index) => {
|
|
269
|
+
return openBlock(), createElementBlock("button", {
|
|
270
|
+
key: index,
|
|
271
|
+
type: "button",
|
|
272
|
+
disabled: day.isDisabled,
|
|
273
|
+
"aria-label": day.date.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" }),
|
|
274
|
+
"aria-selected": isSameDay(day.date, selectedDate.value),
|
|
275
|
+
class: normalizeClass([
|
|
276
|
+
"mld-date-picker__day",
|
|
277
|
+
!day.isCurrentMonth ? "mld-date-picker__day--other-month" : "",
|
|
278
|
+
day.isDisabled ? "mld-date-picker__day--disabled" : "",
|
|
279
|
+
isSameDay(day.date, selectedDate.value) ? "mld-date-picker__day--selected" : "",
|
|
280
|
+
isToday(day.date) && !isSameDay(day.date, selectedDate.value) ? "mld-date-picker__day--today" : ""
|
|
281
|
+
]),
|
|
282
|
+
onClick: ($event) => selectDate(day)
|
|
283
|
+
}, toDisplayString(day.date.getDate()), 11, _hoisted_6);
|
|
284
|
+
}), 128))
|
|
285
|
+
]),
|
|
286
|
+
createElementVNode("div", _hoisted_7, [
|
|
287
|
+
createElementVNode("button", {
|
|
239
288
|
type: "button",
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
createElementVNode("button", {
|
|
256
|
-
type: "button",
|
|
257
|
-
class: "mld-date-picker__footer-btn mld-date-picker__today-btn",
|
|
258
|
-
onClick: goToToday
|
|
259
|
-
}, " Today "),
|
|
260
|
-
__props.clearable && __props.modelValue ? (openBlock(), createElementBlock("button", {
|
|
261
|
-
key: 0,
|
|
262
|
-
type: "button",
|
|
263
|
-
class: "mld-date-picker__footer-btn mld-date-picker__clear-btn",
|
|
264
|
-
onClick: clear
|
|
265
|
-
}, " Clear ")) : createCommentVNode("", true)
|
|
266
|
-
])
|
|
267
|
-
])) : createCommentVNode("", true)
|
|
268
|
-
]),
|
|
269
|
-
_: 1
|
|
270
|
-
})
|
|
289
|
+
class: "mld-date-picker__footer-btn mld-date-picker__today-btn",
|
|
290
|
+
onClick: goToToday
|
|
291
|
+
}, " Today "),
|
|
292
|
+
__props.clearable && __props.modelValue ? (openBlock(), createElementBlock("button", {
|
|
293
|
+
key: 0,
|
|
294
|
+
type: "button",
|
|
295
|
+
class: "mld-date-picker__footer-btn mld-date-picker__clear-btn",
|
|
296
|
+
onClick: clear
|
|
297
|
+
}, " Clear ")) : createCommentVNode("", true)
|
|
298
|
+
])
|
|
299
|
+
], 4)) : createCommentVNode("", true)
|
|
300
|
+
]),
|
|
301
|
+
_: 1
|
|
302
|
+
})
|
|
303
|
+
]))
|
|
271
304
|
], 512);
|
|
272
305
|
};
|
|
273
306
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DatePicker.vue.js","sources":["../../src/components/DatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch, onMounted, onUnmounted } from 'vue'\n\ninterface Props {\n modelValue?: string\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n min?: string\n max?: string\n clearable?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n disabled: false,\n error: false,\n size: 'md',\n clearable: true,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | undefined]\n}>()\n\nconst isOpen = ref(false)\nconst containerRef = ref<HTMLDivElement>()\nconst currentMonth = ref(new Date())\n\nconst selectedDate = computed(() => {\n if (!props.modelValue) return null\n const date = new Date(props.modelValue + 'T00:00:00')\n return isNaN(date.getTime()) ? null : date\n})\n\nconst displayValue = computed(() => {\n if (!selectedDate.value) return ''\n return selectedDate.value.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n})\n\nconst monthYear = computed(() => {\n return currentMonth.value.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n })\n})\n\nconst weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']\n\nconst calendarDays = computed(() => {\n const year = currentMonth.value.getFullYear()\n const month = currentMonth.value.getMonth()\n\n const firstDay = new Date(year, month, 1)\n const lastDay = new Date(year, month + 1, 0)\n\n const days: { date: Date; isCurrentMonth: boolean; isDisabled: boolean }[] = []\n\n // Previous month days\n const startPadding = firstDay.getDay()\n for (let i = startPadding - 1; i >= 0; i--) {\n const date = new Date(year, month, -i)\n days.push({ date, isCurrentMonth: false, isDisabled: isDateDisabled(date) })\n }\n\n // Current month days\n for (let i = 1; i <= lastDay.getDate(); i++) {\n const date = new Date(year, month, i)\n days.push({ date, isCurrentMonth: true, isDisabled: isDateDisabled(date) })\n }\n\n // Next month days\n const endPadding = 42 - days.length\n for (let i = 1; i <= endPadding; i++) {\n const date = new Date(year, month + 1, i)\n days.push({ date, isCurrentMonth: false, isDisabled: isDateDisabled(date) })\n }\n\n return days\n})\n\nfunction isDateDisabled(date: Date): boolean {\n if (props.min) {\n const minDate = new Date(props.min + 'T00:00:00')\n if (date < minDate) return true\n }\n if (props.max) {\n const maxDate = new Date(props.max + 'T00:00:00')\n if (date > maxDate) return true\n }\n return false\n}\n\nfunction isSameDay(date1: Date, date2: Date | null): boolean {\n if (!date2) return false\n return date1.toDateString() === date2.toDateString()\n}\n\nfunction isToday(date: Date): boolean {\n return date.toDateString() === new Date().toDateString()\n}\n\nfunction formatDateValue(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nfunction selectDate(day: { date: Date; isDisabled: boolean }) {\n if (day.isDisabled || props.disabled) return\n emit('update:modelValue', formatDateValue(day.date))\n isOpen.value = false\n}\n\nfunction prevMonth() {\n currentMonth.value = new Date(\n currentMonth.value.getFullYear(),\n currentMonth.value.getMonth() - 1,\n 1\n )\n}\n\nfunction nextMonth() {\n currentMonth.value = new Date(\n currentMonth.value.getFullYear(),\n currentMonth.value.getMonth() + 1,\n 1\n )\n}\n\nfunction goToToday() {\n const today = new Date()\n currentMonth.value = new Date(today.getFullYear(), today.getMonth(), 1)\n if (!isDateDisabled(today)) {\n emit('update:modelValue', formatDateValue(today))\n isOpen.value = false\n }\n}\n\nfunction clear() {\n emit('update:modelValue', undefined)\n isOpen.value = false\n}\n\nfunction toggleCalendar() {\n if (props.disabled) return\n isOpen.value = !isOpen.value\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n if (containerRef.value && !containerRef.value.contains(event.target as Node)) {\n isOpen.value = false\n }\n}\n\nwatch(isOpen, (open) => {\n if (open && selectedDate.value) {\n currentMonth.value = new Date(\n selectedDate.value.getFullYear(),\n selectedDate.value.getMonth(),\n 1\n )\n }\n})\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n})\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"mld-date-picker\">\n <div class=\"mld-date-picker__input-wrapper\">\n <input\n type=\"text\"\n readonly\n :value=\"displayValue\"\n :placeholder=\"placeholder || 'Select date'\"\n :disabled=\"disabled\"\n :class=\"[\n 'mld-date-picker__input',\n `mld-date-picker__input--${size}`,\n error ? 'mld-date-picker__input--error' : '',\n disabled ? 'mld-date-picker__input--disabled' : '',\n ]\"\n @click=\"toggleCalendar\"\n />\n <div class=\"mld-date-picker__icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M8 2v4\" /><path d=\"M16 2v4\" /><rect width=\"18\" height=\"18\" x=\"3\" y=\"4\" rx=\"2\" /><path d=\"M3 10h18\" />\n </svg>\n </div>\n </div>\n\n <Transition\n enter-active-class=\"mld-date-picker__dropdown-enter-active\"\n enter-from-class=\"mld-date-picker__dropdown-enter-from\"\n enter-to-class=\"mld-date-picker__dropdown-enter-to\"\n leave-active-class=\"mld-date-picker__dropdown-leave-active\"\n leave-from-class=\"mld-date-picker__dropdown-leave-from\"\n leave-to-class=\"mld-date-picker__dropdown-leave-to\"\n >\n <div\n v-if=\"isOpen\"\n class=\"mld-date-picker__dropdown\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Date picker\"\n >\n <div class=\"mld-date-picker__header\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n class=\"mld-date-picker__nav-btn\"\n @click=\"prevMonth\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <span class=\"mld-date-picker__month-year\">{{ monthYear }}</span>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n class=\"mld-date-picker__nav-btn\"\n @click=\"nextMonth\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n </div>\n\n <div class=\"mld-date-picker__weekdays\">\n <div\n v-for=\"day in weekDays\"\n :key=\"day\"\n class=\"mld-date-picker__weekday\"\n >\n {{ day }}\n </div>\n </div>\n\n <div class=\"mld-date-picker__grid\">\n <button\n v-for=\"(day, index) in calendarDays\"\n :key=\"index\"\n type=\"button\"\n :disabled=\"day.isDisabled\"\n :aria-label=\"day.date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })\"\n :aria-selected=\"isSameDay(day.date, selectedDate)\"\n :class=\"[\n 'mld-date-picker__day',\n !day.isCurrentMonth ? 'mld-date-picker__day--other-month' : '',\n day.isDisabled ? 'mld-date-picker__day--disabled' : '',\n isSameDay(day.date, selectedDate) ? 'mld-date-picker__day--selected' : '',\n isToday(day.date) && !isSameDay(day.date, selectedDate) ? 'mld-date-picker__day--today' : '',\n ]\"\n @click=\"selectDate(day)\"\n >\n {{ day.date.getDate() }}\n </button>\n </div>\n\n <div class=\"mld-date-picker__footer\">\n <button\n type=\"button\"\n class=\"mld-date-picker__footer-btn mld-date-picker__today-btn\"\n @click=\"goToToday\"\n >\n Today\n </button>\n <button\n v-if=\"clearable && modelValue\"\n type=\"button\"\n class=\"mld-date-picker__footer-btn mld-date-picker__clear-btn\"\n @click=\"clear\"\n >\n Clear\n </button>\n </div>\n </div>\n </Transition>\n </div>\n</template>\n\n<style>\n@import '../styles/components/date-picker.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_normalizeClass","_createVNode","_Transition","_openBlock","_toDisplayString","_Fragment","_renderList"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DatePicker.vue.js","sources":["../../src/components/DatePicker.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { ref, computed, watch, onMounted, onUnmounted } from 'vue'\n\ninterface Props {\n modelValue?: string\n placeholder?: string\n disabled?: boolean\n error?: boolean\n size?: 'sm' | 'md' | 'lg'\n min?: string\n max?: string\n clearable?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n disabled: false,\n error: false,\n size: 'md',\n clearable: true,\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | undefined]\n}>()\n\nconst isOpen = ref(false)\nconst containerRef = ref<HTMLDivElement>()\nconst inputRef = ref<HTMLDivElement>()\nconst dropdownRef = ref<HTMLDivElement>()\nconst dropdownStyle = ref<Record<string, string>>({})\nconst currentMonth = ref(new Date())\n\nconst selectedDate = computed(() => {\n if (!props.modelValue) return null\n const date = new Date(props.modelValue + 'T00:00:00')\n return isNaN(date.getTime()) ? null : date\n})\n\nconst displayValue = computed(() => {\n if (!selectedDate.value) return ''\n return selectedDate.value.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n})\n\nconst monthYear = computed(() => {\n return currentMonth.value.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n })\n})\n\nconst weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']\n\nconst calendarDays = computed(() => {\n const year = currentMonth.value.getFullYear()\n const month = currentMonth.value.getMonth()\n\n const firstDay = new Date(year, month, 1)\n const lastDay = new Date(year, month + 1, 0)\n\n const days: { date: Date; isCurrentMonth: boolean; isDisabled: boolean }[] = []\n\n // Previous month days\n const startPadding = firstDay.getDay()\n for (let i = startPadding - 1; i >= 0; i--) {\n const date = new Date(year, month, -i)\n days.push({ date, isCurrentMonth: false, isDisabled: isDateDisabled(date) })\n }\n\n // Current month days\n for (let i = 1; i <= lastDay.getDate(); i++) {\n const date = new Date(year, month, i)\n days.push({ date, isCurrentMonth: true, isDisabled: isDateDisabled(date) })\n }\n\n // Next month days\n const endPadding = 42 - days.length\n for (let i = 1; i <= endPadding; i++) {\n const date = new Date(year, month + 1, i)\n days.push({ date, isCurrentMonth: false, isDisabled: isDateDisabled(date) })\n }\n\n return days\n})\n\nfunction isDateDisabled(date: Date): boolean {\n if (props.min) {\n const minDate = new Date(props.min + 'T00:00:00')\n if (date < minDate) return true\n }\n if (props.max) {\n const maxDate = new Date(props.max + 'T00:00:00')\n if (date > maxDate) return true\n }\n return false\n}\n\nfunction isSameDay(date1: Date, date2: Date | null): boolean {\n if (!date2) return false\n return date1.toDateString() === date2.toDateString()\n}\n\nfunction isToday(date: Date): boolean {\n return date.toDateString() === new Date().toDateString()\n}\n\nfunction formatDateValue(date: Date): string {\n const year = date.getFullYear()\n const month = String(date.getMonth() + 1).padStart(2, '0')\n const day = String(date.getDate()).padStart(2, '0')\n return `${year}-${month}-${day}`\n}\n\nfunction selectDate(day: { date: Date; isDisabled: boolean }) {\n if (day.isDisabled || props.disabled) return\n emit('update:modelValue', formatDateValue(day.date))\n isOpen.value = false\n}\n\nfunction prevMonth() {\n currentMonth.value = new Date(\n currentMonth.value.getFullYear(),\n currentMonth.value.getMonth() - 1,\n 1\n )\n}\n\nfunction nextMonth() {\n currentMonth.value = new Date(\n currentMonth.value.getFullYear(),\n currentMonth.value.getMonth() + 1,\n 1\n )\n}\n\nfunction goToToday() {\n const today = new Date()\n currentMonth.value = new Date(today.getFullYear(), today.getMonth(), 1)\n if (!isDateDisabled(today)) {\n emit('update:modelValue', formatDateValue(today))\n isOpen.value = false\n }\n}\n\nfunction clear() {\n emit('update:modelValue', undefined)\n isOpen.value = false\n}\n\nfunction toggleCalendar() {\n if (props.disabled) return\n isOpen.value = !isOpen.value\n}\n\nfunction updateDropdownPosition() {\n if (!inputRef.value) return\n const rect = inputRef.value.getBoundingClientRect()\n dropdownStyle.value = {\n position: 'fixed',\n top: `${rect.bottom + 4}px`,\n left: `${rect.left}px`,\n width: `${Math.max(rect.width, 288)}px`,\n zIndex: '9999',\n }\n}\n\nfunction handleClickOutside(event: MouseEvent) {\n const target = event.target as Node\n if (containerRef.value?.contains(target)) return\n if (dropdownRef.value?.contains(target)) return\n isOpen.value = false\n}\n\nfunction handleScrollOrResize() {\n if (isOpen.value) isOpen.value = false\n}\n\nwatch(isOpen, (open) => {\n if (open) {\n updateDropdownPosition()\n if (selectedDate.value) {\n currentMonth.value = new Date(\n selectedDate.value.getFullYear(),\n selectedDate.value.getMonth(),\n 1\n )\n }\n }\n})\n\nonMounted(() => {\n document.addEventListener('click', handleClickOutside)\n window.addEventListener('scroll', handleScrollOrResize, true)\n window.addEventListener('resize', handleScrollOrResize)\n})\n\nonUnmounted(() => {\n document.removeEventListener('click', handleClickOutside)\n window.removeEventListener('scroll', handleScrollOrResize, true)\n window.removeEventListener('resize', handleScrollOrResize)\n})\n</script>\n\n<template>\n <div ref=\"containerRef\" class=\"mld-date-picker\">\n <div ref=\"inputRef\" class=\"mld-date-picker__input-wrapper\">\n <input\n type=\"text\"\n readonly\n :value=\"displayValue\"\n :placeholder=\"placeholder || 'Select date'\"\n :disabled=\"disabled\"\n :class=\"[\n 'mld-date-picker__input',\n `mld-date-picker__input--${size}`,\n error ? 'mld-date-picker__input--error' : '',\n disabled ? 'mld-date-picker__input--disabled' : '',\n ]\"\n @click=\"toggleCalendar\"\n />\n <div class=\"mld-date-picker__icon\">\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M8 2v4\" /><path d=\"M16 2v4\" /><rect width=\"18\" height=\"18\" x=\"3\" y=\"4\" rx=\"2\" /><path d=\"M3 10h18\" />\n </svg>\n </div>\n </div>\n\n <Teleport to=\"body\">\n <Transition\n enter-active-class=\"mld-date-picker__dropdown-enter-active\"\n enter-from-class=\"mld-date-picker__dropdown-enter-from\"\n enter-to-class=\"mld-date-picker__dropdown-enter-to\"\n leave-active-class=\"mld-date-picker__dropdown-leave-active\"\n leave-from-class=\"mld-date-picker__dropdown-leave-from\"\n leave-to-class=\"mld-date-picker__dropdown-leave-to\"\n >\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"mld-date-picker__dropdown\"\n :style=\"dropdownStyle\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Date picker\"\n >\n <div class=\"mld-date-picker__header\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n class=\"mld-date-picker__nav-btn\"\n @click=\"prevMonth\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m15 18-6-6 6-6\" />\n </svg>\n </button>\n <span class=\"mld-date-picker__month-year\">{{ monthYear }}</span>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n class=\"mld-date-picker__nav-btn\"\n @click=\"nextMonth\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"m9 18 6-6-6-6\" />\n </svg>\n </button>\n </div>\n\n <div class=\"mld-date-picker__weekdays\">\n <div\n v-for=\"day in weekDays\"\n :key=\"day\"\n class=\"mld-date-picker__weekday\"\n >\n {{ day }}\n </div>\n </div>\n\n <div class=\"mld-date-picker__grid\">\n <button\n v-for=\"(day, index) in calendarDays\"\n :key=\"index\"\n type=\"button\"\n :disabled=\"day.isDisabled\"\n :aria-label=\"day.date.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })\"\n :aria-selected=\"isSameDay(day.date, selectedDate)\"\n :class=\"[\n 'mld-date-picker__day',\n !day.isCurrentMonth ? 'mld-date-picker__day--other-month' : '',\n day.isDisabled ? 'mld-date-picker__day--disabled' : '',\n isSameDay(day.date, selectedDate) ? 'mld-date-picker__day--selected' : '',\n isToday(day.date) && !isSameDay(day.date, selectedDate) ? 'mld-date-picker__day--today' : '',\n ]\"\n @click=\"selectDate(day)\"\n >\n {{ day.date.getDate() }}\n </button>\n </div>\n\n <div class=\"mld-date-picker__footer\">\n <button\n type=\"button\"\n class=\"mld-date-picker__footer-btn mld-date-picker__today-btn\"\n @click=\"goToToday\"\n >\n Today\n </button>\n <button\n v-if=\"clearable && modelValue\"\n type=\"button\"\n class=\"mld-date-picker__footer-btn mld-date-picker__clear-btn\"\n @click=\"clear\"\n >\n Clear\n </button>\n </div>\n </div>\n </Transition>\n </Teleport>\n </div>\n</template>\n\n<style>\n@import '../styles/components/date-picker.css';\n</style>\n"],"names":["_createElementBlock","_createElementVNode","_normalizeClass","_createBlock","_Teleport","_createVNode","_Transition","_toDisplayString","_Fragment","_renderList","_openBlock"],"mappings":"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"}
|
package/dist/styles.css
CHANGED
|
@@ -2064,11 +2064,10 @@ html.dark .mld-checkbox__native:focus-visible + .mld-checkbox__box {
|
|
|
2064
2064
|
height: 1rem;
|
|
2065
2065
|
color: var(--text-muted);
|
|
2066
2066
|
}
|
|
2067
|
-
/* Calendar dropdown */
|
|
2067
|
+
/* Calendar dropdown (teleported to body, positioned via JS) */
|
|
2068
2068
|
.mld-date-picker__dropdown {
|
|
2069
|
-
position:
|
|
2070
|
-
z-index:
|
|
2071
|
-
margin-top: 0.25rem;
|
|
2069
|
+
position: fixed;
|
|
2070
|
+
z-index: 9999;
|
|
2072
2071
|
width: 18rem;
|
|
2073
2072
|
padding: 0.75rem;
|
|
2074
2073
|
border-radius: 0.5rem;
|
|
@@ -14390,11 +14389,10 @@ to { transform: rotate(360deg);
|
|
|
14390
14389
|
color: var(--text-muted);
|
|
14391
14390
|
}
|
|
14392
14391
|
|
|
14393
|
-
/* Calendar dropdown */
|
|
14392
|
+
/* Calendar dropdown (teleported to body, positioned via JS) */
|
|
14394
14393
|
.mld-date-picker__dropdown {
|
|
14395
|
-
position:
|
|
14396
|
-
z-index:
|
|
14397
|
-
margin-top: 0.25rem;
|
|
14394
|
+
position: fixed;
|
|
14395
|
+
z-index: 9999;
|
|
14398
14396
|
width: 18rem;
|
|
14399
14397
|
padding: 0.75rem;
|
|
14400
14398
|
border-radius: 0.5rem;
|
package/package.json
CHANGED
|
@@ -25,6 +25,9 @@ const emit = defineEmits<{
|
|
|
25
25
|
|
|
26
26
|
const isOpen = ref(false)
|
|
27
27
|
const containerRef = ref<HTMLDivElement>()
|
|
28
|
+
const inputRef = ref<HTMLDivElement>()
|
|
29
|
+
const dropdownRef = ref<HTMLDivElement>()
|
|
30
|
+
const dropdownStyle = ref<Record<string, string>>({})
|
|
28
31
|
const currentMonth = ref(new Date())
|
|
29
32
|
|
|
30
33
|
const selectedDate = computed(() => {
|
|
@@ -152,34 +155,58 @@ function toggleCalendar() {
|
|
|
152
155
|
isOpen.value = !isOpen.value
|
|
153
156
|
}
|
|
154
157
|
|
|
155
|
-
function
|
|
156
|
-
if (
|
|
157
|
-
|
|
158
|
+
function updateDropdownPosition() {
|
|
159
|
+
if (!inputRef.value) return
|
|
160
|
+
const rect = inputRef.value.getBoundingClientRect()
|
|
161
|
+
dropdownStyle.value = {
|
|
162
|
+
position: 'fixed',
|
|
163
|
+
top: `${rect.bottom + 4}px`,
|
|
164
|
+
left: `${rect.left}px`,
|
|
165
|
+
width: `${Math.max(rect.width, 288)}px`,
|
|
166
|
+
zIndex: '9999',
|
|
158
167
|
}
|
|
159
168
|
}
|
|
160
169
|
|
|
170
|
+
function handleClickOutside(event: MouseEvent) {
|
|
171
|
+
const target = event.target as Node
|
|
172
|
+
if (containerRef.value?.contains(target)) return
|
|
173
|
+
if (dropdownRef.value?.contains(target)) return
|
|
174
|
+
isOpen.value = false
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function handleScrollOrResize() {
|
|
178
|
+
if (isOpen.value) isOpen.value = false
|
|
179
|
+
}
|
|
180
|
+
|
|
161
181
|
watch(isOpen, (open) => {
|
|
162
|
-
if (open
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
182
|
+
if (open) {
|
|
183
|
+
updateDropdownPosition()
|
|
184
|
+
if (selectedDate.value) {
|
|
185
|
+
currentMonth.value = new Date(
|
|
186
|
+
selectedDate.value.getFullYear(),
|
|
187
|
+
selectedDate.value.getMonth(),
|
|
188
|
+
1
|
|
189
|
+
)
|
|
190
|
+
}
|
|
168
191
|
}
|
|
169
192
|
})
|
|
170
193
|
|
|
171
194
|
onMounted(() => {
|
|
172
195
|
document.addEventListener('click', handleClickOutside)
|
|
196
|
+
window.addEventListener('scroll', handleScrollOrResize, true)
|
|
197
|
+
window.addEventListener('resize', handleScrollOrResize)
|
|
173
198
|
})
|
|
174
199
|
|
|
175
200
|
onUnmounted(() => {
|
|
176
201
|
document.removeEventListener('click', handleClickOutside)
|
|
202
|
+
window.removeEventListener('scroll', handleScrollOrResize, true)
|
|
203
|
+
window.removeEventListener('resize', handleScrollOrResize)
|
|
177
204
|
})
|
|
178
205
|
</script>
|
|
179
206
|
|
|
180
207
|
<template>
|
|
181
208
|
<div ref="containerRef" class="mld-date-picker">
|
|
182
|
-
<div class="mld-date-picker__input-wrapper">
|
|
209
|
+
<div ref="inputRef" class="mld-date-picker__input-wrapper">
|
|
183
210
|
<input
|
|
184
211
|
type="text"
|
|
185
212
|
readonly
|
|
@@ -201,21 +228,24 @@ onUnmounted(() => {
|
|
|
201
228
|
</div>
|
|
202
229
|
</div>
|
|
203
230
|
|
|
204
|
-
<
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
<div
|
|
213
|
-
v-if="isOpen"
|
|
214
|
-
class="mld-date-picker__dropdown"
|
|
215
|
-
role="dialog"
|
|
216
|
-
aria-modal="true"
|
|
217
|
-
aria-label="Date picker"
|
|
231
|
+
<Teleport to="body">
|
|
232
|
+
<Transition
|
|
233
|
+
enter-active-class="mld-date-picker__dropdown-enter-active"
|
|
234
|
+
enter-from-class="mld-date-picker__dropdown-enter-from"
|
|
235
|
+
enter-to-class="mld-date-picker__dropdown-enter-to"
|
|
236
|
+
leave-active-class="mld-date-picker__dropdown-leave-active"
|
|
237
|
+
leave-from-class="mld-date-picker__dropdown-leave-from"
|
|
238
|
+
leave-to-class="mld-date-picker__dropdown-leave-to"
|
|
218
239
|
>
|
|
240
|
+
<div
|
|
241
|
+
v-if="isOpen"
|
|
242
|
+
ref="dropdownRef"
|
|
243
|
+
class="mld-date-picker__dropdown"
|
|
244
|
+
:style="dropdownStyle"
|
|
245
|
+
role="dialog"
|
|
246
|
+
aria-modal="true"
|
|
247
|
+
aria-label="Date picker"
|
|
248
|
+
>
|
|
219
249
|
<div class="mld-date-picker__header">
|
|
220
250
|
<button
|
|
221
251
|
type="button"
|
|
@@ -288,8 +318,9 @@ onUnmounted(() => {
|
|
|
288
318
|
Clear
|
|
289
319
|
</button>
|
|
290
320
|
</div>
|
|
291
|
-
|
|
292
|
-
|
|
321
|
+
</div>
|
|
322
|
+
</Transition>
|
|
323
|
+
</Teleport>
|
|
293
324
|
</div>
|
|
294
325
|
</template>
|
|
295
326
|
|
|
@@ -77,11 +77,10 @@
|
|
|
77
77
|
color: var(--text-muted);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
|
-
/* Calendar dropdown */
|
|
80
|
+
/* Calendar dropdown (teleported to body, positioned via JS) */
|
|
81
81
|
.mld-date-picker__dropdown {
|
|
82
|
-
position:
|
|
83
|
-
z-index:
|
|
84
|
-
margin-top: 0.25rem;
|
|
82
|
+
position: fixed;
|
|
83
|
+
z-index: 9999;
|
|
85
84
|
width: 18rem;
|
|
86
85
|
padding: 0.75rem;
|
|
87
86
|
border-radius: 0.5rem;
|