nuxt-ui-elements-pro 0.1.4 → 0.1.6

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.
Files changed (39) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +50 -15
  3. package/dist/runtime/components/EventCalendar.d.vue.ts +48 -42
  4. package/dist/runtime/components/EventCalendar.vue +116 -606
  5. package/dist/runtime/components/EventCalendar.vue.d.ts +48 -42
  6. package/dist/runtime/components/EventCalendarHeader.d.vue.ts +26 -0
  7. package/dist/runtime/components/EventCalendarHeader.vue +48 -0
  8. package/dist/runtime/components/EventCalendarHeader.vue.d.ts +26 -0
  9. package/dist/runtime/components/EventCalendarListView.d.vue.ts +25 -0
  10. package/dist/runtime/components/EventCalendarListView.vue +95 -0
  11. package/dist/runtime/components/EventCalendarListView.vue.d.ts +25 -0
  12. package/dist/runtime/components/EventCalendarMonthView.d.vue.ts +34 -0
  13. package/dist/runtime/components/EventCalendarMonthView.vue +336 -0
  14. package/dist/runtime/components/EventCalendarMonthView.vue.d.ts +34 -0
  15. package/dist/runtime/components/EventCalendarTimeGrid.d.vue.ts +31 -0
  16. package/dist/runtime/components/EventCalendarTimeGrid.vue +306 -0
  17. package/dist/runtime/components/EventCalendarTimeGrid.vue.d.ts +31 -0
  18. package/dist/runtime/composables/useEventCalendar.d.ts +52 -0
  19. package/dist/runtime/composables/useEventCalendar.js +362 -0
  20. package/dist/runtime/composables/useEventCalendarContext.d.ts +8 -0
  21. package/dist/runtime/composables/useEventCalendarContext.js +11 -0
  22. package/dist/runtime/composables/useEventCalendarDragDrop.d.ts +1 -1
  23. package/dist/runtime/composables/useEventCalendarDragDrop.js +11 -9
  24. package/dist/runtime/composables/useEventCalendarKeyboard.d.ts +20 -0
  25. package/dist/runtime/composables/useEventCalendarKeyboard.js +128 -0
  26. package/dist/runtime/composables/useEventCalendarResize.d.ts +31 -0
  27. package/dist/runtime/composables/useEventCalendarResize.js +87 -0
  28. package/dist/runtime/composables/useEventCalendarSelect.d.ts +21 -0
  29. package/dist/runtime/composables/useEventCalendarSelect.js +119 -0
  30. package/dist/runtime/index.d.ts +2 -0
  31. package/dist/runtime/index.js +1 -0
  32. package/dist/runtime/types/event-calendar.d.ts +169 -0
  33. package/dist/runtime/types/index.d.ts +4 -0
  34. package/dist/runtime/types/index.js +4 -0
  35. package/dist/runtime/utils/event-calendar.d.ts +22 -1
  36. package/dist/runtime/utils/event-calendar.js +199 -1
  37. package/dist/runtime/utils/recurrence.d.ts +30 -0
  38. package/dist/runtime/utils/recurrence.js +150 -0
  39. package/package.json +15 -6
@@ -0,0 +1,336 @@
1
+ <script>
2
+ import { Primitive } from "reka-ui";
3
+ import { computed, ref } from "vue";
4
+ import { useEventListener, onKeyStroke } from "@vueuse/core";
5
+ import { useEventCalendarContext } from "../composables/useEventCalendarContext";
6
+ </script>
7
+
8
+ <script setup>
9
+ const props = defineProps({
10
+ as: { type: null, required: false }
11
+ });
12
+ defineSlots();
13
+ const ctx = useEventCalendarContext();
14
+ const isEmpty = computed(
15
+ () => !ctx.loading.value && ctx.monthWeekLayouts.value.every(
16
+ (layout) => layout.spanning.length === 0 && layout.singleDay.length === 0
17
+ )
18
+ );
19
+ const expandedDay = ref(null);
20
+ function openExpandDay(dateKey, e) {
21
+ e.stopPropagation();
22
+ expandedDay.value = dateKey;
23
+ }
24
+ function closeExpandDay() {
25
+ expandedDay.value = null;
26
+ }
27
+ function isExpanded(dateKey) {
28
+ return expandedDay.value === dateKey;
29
+ }
30
+ useEventListener(document, "click", closeExpandDay);
31
+ onKeyStroke("Escape", () => {
32
+ if (expandedDay.value) closeExpandDay();
33
+ });
34
+ </script>
35
+
36
+ <template>
37
+ <Primitive v-if="ctx.view.value === 'month'" :as="props.as ?? 'div'" data-slot="monthView">
38
+ <!-- Weekday headers -->
39
+ <div data-slot="weekdayRow" role="row" :class="ctx.ui.value.weekdayRow({ class: ctx.propUi.value?.weekdayRow })">
40
+ <div
41
+ v-for="(day, index) in ctx.weekdayLabels.value"
42
+ :key="day"
43
+ data-slot="weekdayCell"
44
+ role="columnheader"
45
+ :class="ctx.ui.value.weekdayCell({ class: ctx.propUi.value?.weekdayCell })">
46
+ <slot name="day-header" :day="day" :index="index">
47
+ {{ day }}
48
+ </slot>
49
+ </div>
50
+ </div>
51
+
52
+ <!-- Month grid body -->
53
+ <div class="relative">
54
+ <div
55
+ data-slot="monthBody"
56
+ role="grid"
57
+ :aria-label="ctx.headerTitle.value"
58
+ :class="ctx.ui.value.monthBody({ class: ctx.propUi.value?.monthBody })"
59
+ @keydown="ctx.onGridKeydown"
60
+ @selectstart.prevent>
61
+ <div
62
+ v-for="layout in ctx.monthWeekLayouts.value"
63
+ :key="layout.week.days[0].date.toString()"
64
+ data-slot="monthWeekRow"
65
+ role="row"
66
+ :class="ctx.ui.value.monthWeekRow({ class: ctx.propUi.value?.monthWeekRow })"
67
+ :style="{
68
+ display: 'grid',
69
+ gridTemplateColumns: 'repeat(7, minmax(0, 1fr))',
70
+ gridTemplateRows: layout.totalEventRows > 0 ? `auto repeat(${layout.totalEventRows}, 24px)${layout.overflow.length > 0 ? ' auto' : ''} 1fr` : 'auto 1fr',
71
+ rowGap: '2px',
72
+ minHeight: '96px'
73
+ }">
74
+
75
+ <!-- Layer 1: Day cell backgrounds (borders, hover, click/drop targets) -->
76
+ <div
77
+ v-for="(day, colIdx) in layout.week.days"
78
+ :key="'bg-' + day.date.toString()"
79
+ data-slot="dayCell"
80
+ role="gridcell"
81
+ :tabindex="ctx.isFocusedDate(day.date) ? 0 : -1"
82
+ :aria-label="ctx.formatDateAriaLabel(day.date)"
83
+ :aria-current="day.isToday ? 'date' : void 0"
84
+ :data-date="day.date.toString()"
85
+ :class="[
86
+ ctx.ui.value.dayCell({ class: ctx.propUi.value?.dayCell }),
87
+ !day.isCurrentMonth && ctx.ui.value.dayCellOutside({ class: ctx.propUi.value?.dayCellOutside }),
88
+ ctx.dropTargetKey.value === `month-${day.date.toString()}` && ctx.ui.value.dropTarget({ class: ctx.propUi.value?.dropTarget }),
89
+ colIdx === 6 && 'border-r-0!',
90
+ ctx.isDateInSelection(day.date) && ctx.ui.value.selectionOverlay({ class: ctx.propUi.value?.selectionOverlay }),
91
+ isExpanded(day.date.toString()) && 'relative z-10'
92
+ ]"
93
+ :style="{
94
+ gridColumn: `${colIdx + 1}`,
95
+ gridRow: '1 / -1'
96
+ }"
97
+ @click="ctx.handleDateClick(day)"
98
+ @pointerdown="ctx.onDayCellPointerDown(day.date, $event)"
99
+ @pointermove="ctx.onDayCellPointerMove(day.date)"
100
+ @pointerup="ctx.onSelectionPointerUp()"
101
+ @dragover="ctx.onDragOver(`month-${day.date.toString()}`, $event)"
102
+ @dragleave="ctx.onDragLeave"
103
+ @drop="ctx.onDropMonthCell(day.date, $event)">
104
+ </div>
105
+
106
+ <!-- Layer 2: Day numbers (row 1) -->
107
+ <div
108
+ v-for="(day, colIdx) in layout.week.days"
109
+ :key="'num-' + day.date.toString()"
110
+ data-slot="dayNumber"
111
+ :class="ctx.ui.value.monthDayNumber({ class: ctx.propUi.value?.monthDayNumber })"
112
+ :style="{
113
+ gridColumn: `${colIdx + 1}`,
114
+ gridRow: '1',
115
+ pointerEvents: 'none'
116
+ }">
117
+ <slot name="day" :day="day">
118
+ <div
119
+ :class="[
120
+ !day.isToday && ctx.ui.value.dayNumber({ class: ctx.propUi.value?.dayNumber }),
121
+ day.isToday && ctx.ui.value.dayNumberToday({ class: ctx.propUi.value?.dayNumberToday }),
122
+ !day.isCurrentMonth && !day.isToday && ctx.ui.value.dayNumberOutside({ class: ctx.propUi.value?.dayNumberOutside })
123
+ ]">
124
+ {{ day.date.day }}
125
+ </div>
126
+ </slot>
127
+ </div>
128
+
129
+ <!-- Layer 3: Spanning event bars -->
130
+ <template v-for="spanEvent in layout.spanning" :key="'span-' + spanEvent.event.id + '-' + spanEvent.startCol">
131
+ <div
132
+ v-if="spanEvent.lane < ctx.monthConfig.value.maxEvents"
133
+ data-slot="spanningEventChip"
134
+ role="button"
135
+ :aria-label="ctx.formatEventAriaLabel(spanEvent.event)"
136
+ tabindex="0"
137
+ :draggable="ctx.editable.value && spanEvent.event.draggable && spanEvent.isStart"
138
+ :class="[
139
+ ctx.ui.value.spanningEventChip({ class: ctx.propUi.value?.spanningEventChip }),
140
+ spanEvent.isStart && 'rounded-l border-l-2 border-[var(--event-color)] ml-0.5',
141
+ spanEvent.isEnd && 'rounded-r mr-0.5',
142
+ !spanEvent.isStart && 'pl-1',
143
+ !spanEvent.isEnd && 'pr-1',
144
+ ctx.draggedEventId.value === spanEvent.event.id && 'opacity-50'
145
+ ]"
146
+ :style="{
147
+ ...ctx.getEventStyle(spanEvent.event, 15),
148
+ gridColumn: `${spanEvent.startCol + 1} / span ${spanEvent.span}`,
149
+ gridRow: `${spanEvent.lane + 2}`
150
+ }"
151
+ @click="ctx.handleEventClick(spanEvent.event, $event)"
152
+ @keydown.enter.stop="ctx.handleEventClick(spanEvent.event, $event)"
153
+ @keydown.space.prevent.stop="ctx.handleEventClick(spanEvent.event, $event)"
154
+ @dragstart="ctx.onDragStart(spanEvent.event, $event)"
155
+ @dragend="ctx.onDragEnd">
156
+ <slot name="event" :event="spanEvent.event.original" :view="ctx.view.value">
157
+ <template v-if="spanEvent.isStart">
158
+ <UIcon
159
+ v-if="spanEvent.event.recurringEventId"
160
+ name="i-lucide-repeat"
161
+ data-slot="recurringIcon"
162
+ :class="ctx.ui.value.recurringIcon({ class: ctx.propUi.value?.recurringIcon })"
163
+ aria-hidden="true" />
164
+ <span
165
+ v-if="!spanEvent.event.allDay"
166
+ data-slot="eventTime"
167
+ :class="ctx.ui.value.eventTime({ class: ctx.propUi.value?.eventTime })">
168
+ {{ ctx.formatTime(spanEvent.event.start) }}
169
+ </span>
170
+ {{ spanEvent.event.title }}
171
+ </template>
172
+ <span v-else class="sr-only">{{ spanEvent.event.title }} (continued)</span>
173
+ </slot>
174
+ </div>
175
+ </template>
176
+
177
+ <!-- Layer 4: Single-day events -->
178
+ <template v-for="singleEvent in layout.singleDay" :key="'single-' + singleEvent.event.id">
179
+ <div
180
+ data-slot="eventChip"
181
+ role="button"
182
+ :aria-label="ctx.formatEventAriaLabel(singleEvent.event)"
183
+ tabindex="0"
184
+ :draggable="ctx.editable.value && singleEvent.event.draggable"
185
+ :class="[
186
+ ctx.ui.value.eventChip({ class: ctx.propUi.value?.eventChip }),
187
+ ctx.draggedEventId.value === singleEvent.event.id && 'opacity-50'
188
+ ]"
189
+ :style="{
190
+ ...ctx.getEventStyle(singleEvent.event),
191
+ gridColumn: `${singleEvent.col + 1}`,
192
+ gridRow: `${singleEvent.gridRow}`
193
+ }"
194
+ @click="ctx.handleEventClick(singleEvent.event, $event)"
195
+ @keydown.enter.stop="ctx.handleEventClick(singleEvent.event, $event)"
196
+ @keydown.space.prevent.stop="ctx.handleEventClick(singleEvent.event, $event)"
197
+ @dragstart="ctx.onDragStart(singleEvent.event, $event)"
198
+ @dragend="ctx.onDragEnd">
199
+ <slot name="event" :event="singleEvent.event.original" :view="ctx.view.value">
200
+ <UIcon
201
+ v-if="singleEvent.event.recurringEventId"
202
+ name="i-lucide-repeat"
203
+ data-slot="recurringIcon"
204
+ :class="ctx.ui.value.recurringIcon({ class: ctx.propUi.value?.recurringIcon })"
205
+ aria-hidden="true" />
206
+ <span
207
+ v-if="!singleEvent.event.allDay"
208
+ data-slot="eventTime"
209
+ :class="ctx.ui.value.eventTime({ class: ctx.propUi.value?.eventTime })">
210
+ {{ ctx.formatTime(singleEvent.event.start) }}
211
+ </span>
212
+ {{ singleEvent.event.title }}
213
+ </slot>
214
+ </div>
215
+ </template>
216
+
217
+ <!-- Layer 5: "+N more" indicators -->
218
+ <template v-for="overflowItem in layout.overflow" :key="'more-' + overflowItem.col">
219
+ <div
220
+ data-slot="moreEvents"
221
+ role="button"
222
+ tabindex="0"
223
+ :aria-label="`${overflowItem.hiddenCount} more events`"
224
+ :class="ctx.ui.value.moreEvents({ class: ctx.propUi.value?.moreEvents })"
225
+ :style="{
226
+ gridColumn: `${overflowItem.col + 1}`,
227
+ gridRow: `${overflowItem.gridRow}`
228
+ }"
229
+ @click="openExpandDay(layout.week.days[overflowItem.col].date.toString(), $event)"
230
+ @keydown.enter.stop="openExpandDay(layout.week.days[overflowItem.col].date.toString(), $event)"
231
+ @keydown.space.prevent.stop="openExpandDay(layout.week.days[overflowItem.col].date.toString(), $event)">
232
+ <slot
233
+ name="more-events"
234
+ :events="overflowItem.hiddenEvents.map((e) => e.original)"
235
+ :count="overflowItem.hiddenCount"
236
+ :day="layout.week.days[overflowItem.col]">
237
+ +{{ overflowItem.hiddenCount }} more
238
+ </slot>
239
+ </div>
240
+ </template>
241
+
242
+ <!-- Layer 6: Expanded overlay -->
243
+ <template v-for="(day, colIdx) in layout.week.days" :key="'expand-' + day.date.toString()">
244
+ <div
245
+ v-if="isExpanded(day.date.toString()) && day.events.length > ctx.monthConfig.value.maxEvents"
246
+ data-slot="expandedOverlay"
247
+ role="dialog"
248
+ :aria-label="`Events for ${ctx.formatDateAriaLabel(day.date)}`"
249
+ :class="ctx.ui.value.expandedOverlay({ class: ctx.propUi.value?.expandedOverlay })"
250
+ :style="{
251
+ gridColumn: `${colIdx + 1}`,
252
+ gridRow: '1 / -1',
253
+ zIndex: 20
254
+ }"
255
+ @click.stop>
256
+ <div
257
+ data-slot="dayNumber"
258
+ :class="[
259
+ !day.isToday && ctx.ui.value.dayNumber({ class: ctx.propUi.value?.dayNumber }),
260
+ day.isToday && ctx.ui.value.dayNumberToday({ class: ctx.propUi.value?.dayNumberToday })
261
+ ]">
262
+ {{ day.date.day }}
263
+ </div>
264
+ <div data-slot="eventList" :class="ctx.ui.value.eventList({ class: ctx.propUi.value?.eventList })">
265
+ <div
266
+ v-for="event in day.events"
267
+ :key="`expanded-${event.id}`"
268
+ data-slot="eventChip"
269
+ role="button"
270
+ :aria-label="ctx.formatEventAriaLabel(event)"
271
+ tabindex="0"
272
+ :draggable="ctx.editable.value && event.draggable"
273
+ :class="ctx.ui.value.eventChip({ class: ctx.propUi.value?.eventChip })"
274
+ :style="ctx.getEventStyle(event)"
275
+ @click="ctx.handleEventClick(event, $event)"
276
+ @keydown.enter.stop="ctx.handleEventClick(event, $event)"
277
+ @keydown.space.prevent.stop="ctx.handleEventClick(event, $event)"
278
+ @dragstart="ctx.onDragStart(event, $event)"
279
+ @dragend="ctx.onDragEnd">
280
+ <slot name="event" :event="event.original" :view="ctx.view.value">
281
+ <UIcon
282
+ v-if="event.recurringEventId"
283
+ name="i-lucide-repeat"
284
+ data-slot="recurringIcon"
285
+ :class="ctx.ui.value.recurringIcon({ class: ctx.propUi.value?.recurringIcon })"
286
+ aria-hidden="true" />
287
+ <span
288
+ v-if="!event.allDay"
289
+ data-slot="eventTime"
290
+ :class="ctx.ui.value.eventTime({ class: ctx.propUi.value?.eventTime })">
291
+ {{ ctx.formatTime(event.start) }}
292
+ </span>
293
+ {{ event.title }}
294
+ </slot>
295
+ </div>
296
+ </div>
297
+ </div>
298
+ </template>
299
+ </div>
300
+ </div>
301
+
302
+ <!-- Loading overlay -->
303
+ <div
304
+ v-if="ctx.loading.value"
305
+ data-slot="loadingOverlay"
306
+ role="status"
307
+ :class="ctx.ui.value.loadingOverlay({ class: ctx.propUi.value?.loadingOverlay })">
308
+ <slot name="loading">
309
+ <UIcon
310
+ name="i-lucide-loader-circle"
311
+ data-slot="loadingIcon"
312
+ :class="ctx.ui.value.loadingIcon({ class: ctx.propUi.value?.loadingIcon })"
313
+ aria-hidden="true" />
314
+ <span class="sr-only">Loading events</span>
315
+ </slot>
316
+ </div>
317
+
318
+ <!-- Empty state -->
319
+ <div
320
+ v-else-if="isEmpty"
321
+ data-slot="emptyState"
322
+ :class="ctx.ui.value.emptyState({ class: ctx.propUi.value?.emptyState })">
323
+ <slot name="empty">
324
+ <UIcon
325
+ name="i-lucide-calendar-x2"
326
+ data-slot="emptyStateIcon"
327
+ :class="ctx.ui.value.emptyStateIcon({ class: ctx.propUi.value?.emptyStateIcon })"
328
+ aria-hidden="true" />
329
+ <p data-slot="emptyStateText" :class="ctx.ui.value.emptyStateText({ class: ctx.propUi.value?.emptyStateText })">
330
+ No events
331
+ </p>
332
+ </slot>
333
+ </div>
334
+ </div>
335
+ </Primitive>
336
+ </template>
@@ -0,0 +1,34 @@
1
+ import type { CalendarEvent, CalendarView, CalendarDay } from "../types/event-calendar.js";
2
+ import { type Component } from "vue";
3
+ export interface EventCalendarMonthViewProps {
4
+ /** Rendered element type @defaultValue 'div' */
5
+ as?: string | Component;
6
+ }
7
+ export interface EventCalendarMonthViewSlots {
8
+ "day-header": (props: {
9
+ day: string;
10
+ index: number;
11
+ }) => any;
12
+ day: (props: {
13
+ day: CalendarDay;
14
+ }) => any;
15
+ event: (props: {
16
+ event: CalendarEvent;
17
+ view: CalendarView;
18
+ }) => any;
19
+ "more-events": (props: {
20
+ events: CalendarEvent[];
21
+ count: number;
22
+ day: CalendarDay;
23
+ }) => any;
24
+ loading: () => any;
25
+ empty: () => any;
26
+ }
27
+ declare const _default: typeof __VLS_export;
28
+ export default _default;
29
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<EventCalendarMonthViewProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<EventCalendarMonthViewProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, EventCalendarMonthViewSlots>;
30
+ type __VLS_WithSlots<T, S> = T & {
31
+ new (): {
32
+ $slots: S;
33
+ };
34
+ };
@@ -0,0 +1,31 @@
1
+ import type { CalendarDate } from "@internationalized/date";
2
+ import type { CalendarEvent, CalendarView } from "../types/event-calendar.js";
3
+ import { type Component } from "vue";
4
+ export interface EventCalendarTimeGridProps {
5
+ /** Rendered element type @defaultValue 'div' */
6
+ as?: string | Component;
7
+ }
8
+ export interface EventCalendarTimeGridSlots {
9
+ event: (props: {
10
+ event: CalendarEvent;
11
+ view: CalendarView;
12
+ }) => any;
13
+ "time-label": (props: {
14
+ hour: number;
15
+ label: string;
16
+ }) => any;
17
+ "all-day": (props: {
18
+ events: CalendarEvent[];
19
+ date: CalendarDate;
20
+ }) => any;
21
+ loading: () => any;
22
+ empty: () => any;
23
+ }
24
+ declare const _default: typeof __VLS_export;
25
+ export default _default;
26
+ declare const __VLS_export: __VLS_WithSlots<import("vue").DefineComponent<EventCalendarTimeGridProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<EventCalendarTimeGridProps> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>, EventCalendarTimeGridSlots>;
27
+ type __VLS_WithSlots<T, S> = T & {
28
+ new (): {
29
+ $slots: S;
30
+ };
31
+ };