@morscherlab/mld-sdk 0.7.4 → 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.
@@ -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 = { class: "mld-date-picker__input-wrapper" };
3
- const _hoisted_2 = ["value", "placeholder", "disabled"];
4
- const _hoisted_3 = {
5
- key: 0,
6
- class: "mld-date-picker__dropdown",
7
- role: "dialog",
8
- "aria-modal": "true",
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
- if (containerRef.value && !containerRef.value.contains(event.target)) {
139
- isOpen.value = false;
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 && selectedDate.value) {
144
- currentMonth.value = new Date(
145
- selectedDate.value.getFullYear(),
146
- selectedDate.value.getMonth(),
147
- 1
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", _hoisted_1, [
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, _hoisted_2),
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
- createVNode(Transition, {
181
- "enter-active-class": "mld-date-picker__dropdown-enter-active",
182
- "enter-from-class": "mld-date-picker__dropdown-enter-from",
183
- "enter-to-class": "mld-date-picker__dropdown-enter-to",
184
- "leave-active-class": "mld-date-picker__dropdown-leave-active",
185
- "leave-from-class": "mld-date-picker__dropdown-leave-from",
186
- "leave-to-class": "mld-date-picker__dropdown-leave-to"
187
- }, {
188
- default: withCtx(() => [
189
- isOpen.value ? (openBlock(), createElementBlock("div", _hoisted_3, [
190
- createElementVNode("div", _hoisted_4, [
191
- createElementVNode("button", {
192
- type: "button",
193
- "aria-label": "Previous month",
194
- class: "mld-date-picker__nav-btn",
195
- onClick: prevMonth
196
- }, [..._cache[1] || (_cache[1] = [
197
- createElementVNode("svg", {
198
- viewBox: "0 0 24 24",
199
- fill: "none",
200
- stroke: "currentColor",
201
- "stroke-width": "2",
202
- "stroke-linecap": "round",
203
- "stroke-linejoin": "round"
204
- }, [
205
- createElementVNode("path", { d: "m15 18-6-6 6-6" })
206
- ], -1)
207
- ])]),
208
- createElementVNode("span", _hoisted_5, toDisplayString(monthYear.value), 1),
209
- createElementVNode("button", {
210
- type: "button",
211
- "aria-label": "Next month",
212
- class: "mld-date-picker__nav-btn",
213
- onClick: nextMonth
214
- }, [..._cache[2] || (_cache[2] = [
215
- createElementVNode("svg", {
216
- viewBox: "0 0 24 24",
217
- fill: "none",
218
- stroke: "currentColor",
219
- "stroke-width": "2",
220
- "stroke-linecap": "round",
221
- "stroke-linejoin": "round"
222
- }, [
223
- createElementVNode("path", { d: "m9 18 6-6-6-6" })
224
- ], -1)
225
- ])])
226
- ]),
227
- createElementVNode("div", _hoisted_6, [
228
- (openBlock(), createElementBlock(Fragment, null, renderList(weekDays, (day) => {
229
- return createElementVNode("div", {
230
- key: day,
231
- class: "mld-date-picker__weekday"
232
- }, toDisplayString(day), 1);
233
- }), 64))
234
- ]),
235
- createElementVNode("div", _hoisted_7, [
236
- (openBlock(true), createElementBlock(Fragment, null, renderList(calendarDays.value, (day, index) => {
237
- return openBlock(), createElementBlock("button", {
238
- key: index,
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
- disabled: day.isDisabled,
241
- "aria-label": day.date.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" }),
242
- "aria-selected": isSameDay(day.date, selectedDate.value),
243
- class: normalizeClass([
244
- "mld-date-picker__day",
245
- !day.isCurrentMonth ? "mld-date-picker__day--other-month" : "",
246
- day.isDisabled ? "mld-date-picker__day--disabled" : "",
247
- isSameDay(day.date, selectedDate.value) ? "mld-date-picker__day--selected" : "",
248
- isToday(day.date) && !isSameDay(day.date, selectedDate.value) ? "mld-date-picker__day--today" : ""
249
- ]),
250
- onClick: ($event) => selectDate(day)
251
- }, toDisplayString(day.date.getDate()), 11, _hoisted_8);
252
- }), 128))
253
- ]),
254
- createElementVNode("div", _hoisted_9, [
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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,UAAM,QAAQ;AAOd,UAAM,OAAO;AAIb,UAAM,SAAS,IAAI,KAAK;AACxB,UAAM,eAAe,IAAA;AACrB,UAAM,eAAe,IAAI,oBAAI,MAAM;AAEnC,UAAM,eAAe,SAAS,MAAM;AAClC,UAAI,CAAC,MAAM,WAAY,QAAO;AAC9B,YAAM,OAAO,oBAAI,KAAK,MAAM,aAAa,WAAW;AACpD,aAAO,MAAM,KAAK,QAAA,CAAS,IAAI,OAAO;AAAA,IACxC,CAAC;AAED,UAAM,eAAe,SAAS,MAAM;AAClC,UAAI,CAAC,aAAa,MAAO,QAAO;AAChC,aAAO,aAAa,MAAM,mBAAmB,SAAS;AAAA,QACpD,MAAM;AAAA,QACN,OAAO;AAAA,QACP,KAAK;AAAA,MAAA,CACN;AAAA,IACH,CAAC;AAED,UAAM,YAAY,SAAS,MAAM;AAC/B,aAAO,aAAa,MAAM,mBAAmB,SAAS;AAAA,QACpD,MAAM;AAAA,QACN,OAAO;AAAA,MAAA,CACR;AAAA,IACH,CAAC;AAED,UAAM,WAAW,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,IAAI;AAE1D,UAAM,eAAe,SAAS,MAAM;AAClC,YAAM,OAAO,aAAa,MAAM,YAAA;AAChC,YAAM,QAAQ,aAAa,MAAM,SAAA;AAEjC,YAAM,WAAW,IAAI,KAAK,MAAM,OAAO,CAAC;AACxC,YAAM,UAAU,IAAI,KAAK,MAAM,QAAQ,GAAG,CAAC;AAE3C,YAAM,OAAuE,CAAA;AAG7E,YAAM,eAAe,SAAS,OAAA;AAC9B,eAAS,IAAI,eAAe,GAAG,KAAK,GAAG,KAAK;AAC1C,cAAM,OAAO,IAAI,KAAK,MAAM,OAAO,CAAC,CAAC;AACrC,aAAK,KAAK,EAAE,MAAM,gBAAgB,OAAO,YAAY,eAAe,IAAI,GAAG;AAAA,MAC7E;AAGA,eAAS,IAAI,GAAG,KAAK,QAAQ,QAAA,GAAW,KAAK;AAC3C,cAAM,OAAO,IAAI,KAAK,MAAM,OAAO,CAAC;AACpC,aAAK,KAAK,EAAE,MAAM,gBAAgB,MAAM,YAAY,eAAe,IAAI,GAAG;AAAA,MAC5E;AAGA,YAAM,aAAa,KAAK,KAAK;AAC7B,eAAS,IAAI,GAAG,KAAK,YAAY,KAAK;AACpC,cAAM,OAAO,IAAI,KAAK,MAAM,QAAQ,GAAG,CAAC;AACxC,aAAK,KAAK,EAAE,MAAM,gBAAgB,OAAO,YAAY,eAAe,IAAI,GAAG;AAAA,MAC7E;AAEA,aAAO;AAAA,IACT,CAAC;AAED,aAAS,eAAe,MAAqB;AAC3C,UAAI,MAAM,KAAK;AACb,cAAM,UAAU,oBAAI,KAAK,MAAM,MAAM,WAAW;AAChD,YAAI,OAAO,QAAS,QAAO;AAAA,MAC7B;AACA,UAAI,MAAM,KAAK;AACb,cAAM,UAAU,oBAAI,KAAK,MAAM,MAAM,WAAW;AAChD,YAAI,OAAO,QAAS,QAAO;AAAA,MAC7B;AACA,aAAO;AAAA,IACT;AAEA,aAAS,UAAU,OAAa,OAA6B;AAC3D,UAAI,CAAC,MAAO,QAAO;AACnB,aAAO,MAAM,mBAAmB,MAAM,aAAA;AAAA,IACxC;AAEA,aAAS,QAAQ,MAAqB;AACpC,aAAO,KAAK,aAAA,OAAmB,oBAAI,KAAA,GAAO,aAAA;AAAA,IAC5C;AAEA,aAAS,gBAAgB,MAAoB;AAC3C,YAAM,OAAO,KAAK,YAAA;AAClB,YAAM,QAAQ,OAAO,KAAK,SAAA,IAAa,CAAC,EAAE,SAAS,GAAG,GAAG;AACzD,YAAM,MAAM,OAAO,KAAK,QAAA,CAAS,EAAE,SAAS,GAAG,GAAG;AAClD,aAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA,IAChC;AAEA,aAAS,WAAW,KAA0C;AAC5D,UAAI,IAAI,cAAc,MAAM,SAAU;AACtC,WAAK,qBAAqB,gBAAgB,IAAI,IAAI,CAAC;AACnD,aAAO,QAAQ;AAAA,IACjB;AAEA,aAAS,YAAY;AACnB,mBAAa,QAAQ,IAAI;AAAA,QACvB,aAAa,MAAM,YAAA;AAAA,QACnB,aAAa,MAAM,SAAA,IAAa;AAAA,QAChC;AAAA,MAAA;AAAA,IAEJ;AAEA,aAAS,YAAY;AACnB,mBAAa,QAAQ,IAAI;AAAA,QACvB,aAAa,MAAM,YAAA;AAAA,QACnB,aAAa,MAAM,SAAA,IAAa;AAAA,QAChC;AAAA,MAAA;AAAA,IAEJ;AAEA,aAAS,YAAY;AACnB,YAAM,4BAAY,KAAA;AAClB,mBAAa,QAAQ,IAAI,KAAK,MAAM,eAAe,MAAM,SAAA,GAAY,CAAC;AACtE,UAAI,CAAC,eAAe,KAAK,GAAG;AAC1B,aAAK,qBAAqB,gBAAgB,KAAK,CAAC;AAChD,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAEA,aAAS,QAAQ;AACf,WAAK,qBAAqB,MAAS;AACnC,aAAO,QAAQ;AAAA,IACjB;AAEA,aAAS,iBAAiB;AACxB,UAAI,MAAM,SAAU;AACpB,aAAO,QAAQ,CAAC,OAAO;AAAA,IACzB;AAEA,aAAS,mBAAmB,OAAmB;AAC7C,UAAI,aAAa,SAAS,CAAC,aAAa,MAAM,SAAS,MAAM,MAAc,GAAG;AAC5E,eAAO,QAAQ;AAAA,MACjB;AAAA,IACF;AAEA,UAAM,QAAQ,CAAC,SAAS;AACtB,UAAI,QAAQ,aAAa,OAAO;AAC9B,qBAAa,QAAQ,IAAI;AAAA,UACvB,aAAa,MAAM,YAAA;AAAA,UACnB,aAAa,MAAM,SAAA;AAAA,UACnB;AAAA,QAAA;AAAA,MAEJ;AAAA,IACF,CAAC;AAED,cAAU,MAAM;AACd,eAAS,iBAAiB,SAAS,kBAAkB;AAAA,IACvD,CAAC;AAED,gBAAY,MAAM;AAChB,eAAS,oBAAoB,SAAS,kBAAkB;AAAA,IAC1D,CAAC;;0BAICA,mBAgHM,OAAA;AAAA,iBAhHG;AAAA,QAAJ,KAAI;AAAA,QAAe,OAAM;AAAA,MAAA;QAC5BC,mBAoBM,OApBN,YAoBM;AAAA,UAnBJA,mBAaE,SAAA;AAAA,YAZA,MAAK;AAAA,YACL,UAAA;AAAA,YACC,OAAO,aAAA;AAAA,YACP,aAAa,QAAA,eAAW;AAAA,YACxB,UAAU,QAAA;AAAA,YACV,OAAKC,eAAA;AAAA;yCAA6E,QAAA,IAAI;AAAA,cAAc,QAAA,QAAK,kCAAA;AAAA,cAAmD,QAAA,WAAQ,qCAAA;AAAA,YAAA;YAMpK,SAAO;AAAA,UAAA;;;QASZC,YAwFaC,YAAA;AAAA,UAvFX,sBAAmB;AAAA,UACnB,oBAAiB;AAAA,UACjB,kBAAe;AAAA,UACf,sBAAmB;AAAA,UACnB,oBAAiB;AAAA,UACjB,kBAAe;AAAA,QAAA;2BAEf,MA+EM;AAAA,YA9EE,OAAA,SADRC,UAAA,GAAAL,mBA+EM,OA/EN,YA+EM;AAAA,cAxEJC,mBAsBM,OAtBN,YAsBM;AAAA,gBArBJA,mBASS,UAAA;AAAA,kBARP,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,OAAM;AAAA,kBACL,SAAO;AAAA,gBAAA;kBAERA,mBAEM,OAAA;AAAA,oBAFD,SAAQ;AAAA,oBAAY,MAAK;AAAA,oBAAO,QAAO;AAAA,oBAAe,gBAAa;AAAA,oBAAI,kBAAe;AAAA,oBAAQ,mBAAgB;AAAA,kBAAA;oBACjHA,mBAA2B,QAAA,EAArB,GAAE,kBAAgB;AAAA,kBAAA;;gBAG5BA,mBAAgE,QAAhE,YAAgEK,gBAAnB,UAAA,KAAS,GAAA,CAAA;AAAA,gBACtDL,mBASS,UAAA;AAAA,kBARP,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,OAAM;AAAA,kBACL,SAAO;AAAA,gBAAA;kBAERA,mBAEM,OAAA;AAAA,oBAFD,SAAQ;AAAA,oBAAY,MAAK;AAAA,oBAAO,QAAO;AAAA,oBAAe,gBAAa;AAAA,oBAAI,kBAAe;AAAA,oBAAQ,mBAAgB;AAAA,kBAAA;oBACjHA,mBAA0B,QAAA,EAApB,GAAE,iBAAe;AAAA,kBAAA;;;cAK7BA,mBAQM,OARN,YAQM;AAAA,8BAPJD,mBAMMO,UAAA,MAAAC,WALU,UAAQ,CAAf,QAAG;yBADZP,mBAMM,OAAA;AAAA,oBAJH,KAAK;AAAA,oBACN,OAAM;AAAA,kBAAA,mBAEH,GAAG,GAAA,CAAA;AAAA;;cAIVA,mBAmBM,OAnBN,YAmBM;AAAA,iBAlBJI,UAAA,IAAA,GAAAL,mBAiBSO,UAAA,MAAAC,WAhBgB,aAAA,OAAY,CAA3B,KAAK,UAAK;sCADpBR,mBAiBS,UAAA;AAAA,oBAfN,KAAK;AAAA,oBACN,MAAK;AAAA,oBACJ,UAAU,IAAI;AAAA,oBACd,cAAY,IAAI,KAAK,mBAAkB,SAAA,EAAA,SAAA,QAAA,MAAA,WAAA,OAAA,QAAA,KAAA,WAAA;AAAA,oBACvC,iBAAe,UAAU,IAAI,MAAM,aAAA,KAAY;AAAA,oBAC/C,OAAKE,eAAA;AAAA;sBAAyD,CAAA,IAAI,iBAAc,sCAAA;AAAA,sBAA2D,IAAI,aAAU,mCAAA;AAAA,sBAAwD,UAAU,IAAI,MAAM,aAAA,KAAY,IAAA,mCAAA;AAAA,sBAAyD,QAAQ,IAAI,IAAI,KAAA,CAAM,UAAU,IAAI,MAAM,aAAA,KAAY,IAAA,gCAAA;AAAA,oBAAA;oBAOhW,SAAK,CAAA,WAAE,WAAW,GAAG;AAAA,kBAAA,mBAEnB,IAAI,KAAK,SAAO,GAAA,IAAA,UAAA;AAAA;;cAIvBD,mBAgBM,OAhBN,YAgBM;AAAA,gBAfJA,mBAMS,UAAA;AAAA,kBALP,MAAK;AAAA,kBACL,OAAM;AAAA,kBACL,SAAO;AAAA,gBAAA,GACT,SAED;AAAA,gBAEQ,QAAA,aAAa,QAAA,2BADrBD,mBAOS,UAAA;AAAA;kBALP,MAAK;AAAA,kBACL,OAAM;AAAA,kBACL,SAAO;AAAA,gBAAA,GACT,SAED;;;;;;;;;;"}
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
@@ -1756,12 +1756,6 @@ html.dark .mld-checkbox__native:focus-visible + .mld-checkbox__box {
1756
1756
  overflow: hidden;
1757
1757
  background-color: var(--bg-card);
1758
1758
  }
1759
- /* Allow floating dropdowns (DatePicker, TimePicker, etc.) to escape overflow */
1760
- .mld-collapsible-card:has(.mld-date-picker__dropdown),
1761
- .mld-collapsible-card:has(.mld-time-picker__dropdown),
1762
- .mld-collapsible-card:has(.mld-datetime-picker__dropdown) {
1763
- overflow: visible;
1764
- }
1765
1759
  .mld-collapsible-card__header {
1766
1760
  display: flex;
1767
1761
  align-items: center;
@@ -2070,11 +2064,10 @@ html.dark .mld-checkbox__native:focus-visible + .mld-checkbox__box {
2070
2064
  height: 1rem;
2071
2065
  color: var(--text-muted);
2072
2066
  }
2073
- /* Calendar dropdown */
2067
+ /* Calendar dropdown (teleported to body, positioned via JS) */
2074
2068
  .mld-date-picker__dropdown {
2075
- position: absolute;
2076
- z-index: 50;
2077
- margin-top: 0.25rem;
2069
+ position: fixed;
2070
+ z-index: 9999;
2078
2071
  width: 18rem;
2079
2072
  padding: 0.75rem;
2080
2073
  border-radius: 0.5rem;
@@ -14396,11 +14389,10 @@ to { transform: rotate(360deg);
14396
14389
  color: var(--text-muted);
14397
14390
  }
14398
14391
 
14399
- /* Calendar dropdown */
14392
+ /* Calendar dropdown (teleported to body, positioned via JS) */
14400
14393
  .mld-date-picker__dropdown {
14401
- position: absolute;
14402
- z-index: 50;
14403
- margin-top: 0.25rem;
14394
+ position: fixed;
14395
+ z-index: 9999;
14404
14396
  width: 18rem;
14405
14397
  padding: 0.75rem;
14406
14398
  border-radius: 0.5rem;
@@ -15717,13 +15709,6 @@ to {
15717
15709
  overflow: hidden;
15718
15710
  background-color: var(--bg-card);
15719
15711
  }
15720
-
15721
- /* Allow floating dropdowns (DatePicker, TimePicker, etc.) to escape overflow */
15722
- .mld-collapsible-card:has(.mld-date-picker__dropdown),
15723
- .mld-collapsible-card:has(.mld-time-picker__dropdown),
15724
- .mld-collapsible-card:has(.mld-datetime-picker__dropdown) {
15725
- overflow: visible;
15726
- }
15727
15712
  .mld-collapsible-card__header {
15728
15713
  display: flex;
15729
15714
  align-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@morscherlab/mld-sdk",
3
- "version": "0.7.4",
3
+ "version": "0.7.5",
4
4
  "description": "MLD Platform SDK - Vue 3 components, composables, and types for plugin development",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -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 handleClickOutside(event: MouseEvent) {
156
- if (containerRef.value && !containerRef.value.contains(event.target as Node)) {
157
- isOpen.value = false
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 && selectedDate.value) {
163
- currentMonth.value = new Date(
164
- selectedDate.value.getFullYear(),
165
- selectedDate.value.getMonth(),
166
- 1
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
- <Transition
205
- enter-active-class="mld-date-picker__dropdown-enter-active"
206
- enter-from-class="mld-date-picker__dropdown-enter-from"
207
- enter-to-class="mld-date-picker__dropdown-enter-to"
208
- leave-active-class="mld-date-picker__dropdown-leave-active"
209
- leave-from-class="mld-date-picker__dropdown-leave-from"
210
- leave-to-class="mld-date-picker__dropdown-leave-to"
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
- </div>
292
- </Transition>
321
+ </div>
322
+ </Transition>
323
+ </Teleport>
293
324
  </div>
294
325
  </template>
295
326
 
@@ -7,12 +7,6 @@
7
7
  background-color: var(--bg-card);
8
8
  }
9
9
 
10
- /* Allow floating dropdowns (DatePicker, TimePicker, etc.) to escape overflow */
11
- .mld-collapsible-card:has(.mld-date-picker__dropdown),
12
- .mld-collapsible-card:has(.mld-time-picker__dropdown),
13
- .mld-collapsible-card:has(.mld-datetime-picker__dropdown) {
14
- overflow: visible;
15
- }
16
10
 
17
11
  .mld-collapsible-card__header {
18
12
  display: flex;
@@ -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: absolute;
83
- z-index: 50;
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;