@umbra.ui/core 0.1.18 → 0.1.20

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 (147) hide show
  1. package/dist/components/controls/Button/Button.vue +417 -0
  2. package/dist/components/controls/Button/README.md +348 -0
  3. package/dist/components/controls/Button/theme.css +200 -0
  4. package/dist/components/controls/Checkbox/Checkbox.vue +164 -0
  5. package/dist/components/controls/Checkbox/README.md +441 -0
  6. package/dist/components/controls/Checkbox/theme.css +36 -0
  7. package/dist/components/controls/Dropdown/Dropdown.vue +476 -0
  8. package/dist/components/controls/Dropdown/README.md +370 -0
  9. package/dist/components/controls/Dropdown/theme.css +50 -0
  10. package/dist/components/controls/Dropdown/types.ts +6 -0
  11. package/dist/components/controls/IconButton/IconButton.vue +267 -0
  12. package/dist/components/controls/IconButton/README.md +502 -0
  13. package/dist/components/controls/IconButton/theme.css +89 -0
  14. package/dist/components/controls/Radio/README.md +591 -0
  15. package/dist/components/controls/Radio/Radio.vue +89 -0
  16. package/dist/components/controls/Radio/theme.css +14 -0
  17. package/dist/components/controls/RangeSlider/README.md +608 -0
  18. package/dist/components/controls/RangeSlider/RangeSlider.vue +535 -0
  19. package/dist/components/controls/RangeSlider/theme.css +80 -0
  20. package/dist/components/controls/SegmentedControl/README.md +587 -0
  21. package/dist/components/controls/SegmentedControl/SegmentedControl.vue +284 -0
  22. package/dist/components/controls/SegmentedControl/theme.css +60 -0
  23. package/dist/components/controls/SegmentedControl/types.ts +5 -0
  24. package/dist/components/controls/Slider/README.md +627 -0
  25. package/dist/components/controls/Slider/Slider.vue +260 -0
  26. package/dist/components/controls/Slider/theme.css +74 -0
  27. package/dist/components/controls/Stepper/README.md +601 -0
  28. package/dist/components/controls/Stepper/Stepper.vue +103 -0
  29. package/dist/components/controls/Stepper/theme.css +53 -0
  30. package/dist/components/controls/Switch/README.md +667 -0
  31. package/dist/components/controls/Switch/Switch.vue +127 -0
  32. package/dist/components/controls/Switch/theme.css +42 -0
  33. package/dist/components/dialogs/Alert/Alert.vue +218 -0
  34. package/dist/components/dialogs/Alert/README.md +450 -0
  35. package/dist/components/dialogs/Alert/theme.css +44 -0
  36. package/dist/components/dialogs/Alert/types.ts +11 -0
  37. package/dist/components/dialogs/Toast/README.md +522 -0
  38. package/dist/components/dialogs/Toast/Toast.vue +296 -0
  39. package/dist/components/dialogs/Toast/ToastContainer.vue +330 -0
  40. package/dist/components/dialogs/Toast/theme.css +44 -0
  41. package/dist/components/dialogs/Toast/types.ts +46 -0
  42. package/dist/components/dialogs/Toast/useToast.ts +127 -0
  43. package/dist/components/indicators/ProgressBar/ProgressBar.vue +98 -0
  44. package/dist/components/indicators/ProgressBar/README.md +744 -0
  45. package/dist/components/indicators/ProgressBar/theme.css +36 -0
  46. package/dist/components/indicators/Tooltip/README.md +723 -0
  47. package/dist/components/indicators/Tooltip/TooltipProvider.vue +142 -0
  48. package/dist/components/indicators/Tooltip/theme.css +18 -0
  49. package/dist/components/indicators/Tooltip/tooltip.ts +48 -0
  50. package/dist/components/indicators/Tooltip/types.ts +15 -0
  51. package/dist/components/indicators/Tooltip/useTooltip.ts +71 -0
  52. package/dist/components/inputs/AutogrowTextView/AutogrowTextView.vue +110 -0
  53. package/dist/components/inputs/AutogrowTextView/README.md +643 -0
  54. package/dist/components/inputs/AutogrowTextView/theme.css +28 -0
  55. package/dist/components/inputs/InputCard/InputCard.vue +600 -0
  56. package/dist/components/inputs/InputCard/README.md +636 -0
  57. package/dist/components/inputs/InputEmail/InputEmail.vue +698 -0
  58. package/dist/components/inputs/InputEmail/README.md +764 -0
  59. package/dist/components/inputs/InputNumber/InputNumber.vue +300 -0
  60. package/dist/components/inputs/InputNumber/README.md +749 -0
  61. package/dist/components/inputs/InputPhone/InputPhone.vue +645 -0
  62. package/dist/components/inputs/InputPhone/README.md +636 -0
  63. package/dist/components/inputs/InputSecure/InputSecure.vue +646 -0
  64. package/dist/components/inputs/InputSecure/README.md +771 -0
  65. package/dist/components/inputs/InputText/InputText.vue +225 -0
  66. package/dist/components/inputs/InputText/README.md +844 -0
  67. package/dist/components/inputs/OTP/OTP.vue +349 -0
  68. package/dist/components/inputs/OTP/README.md +736 -0
  69. package/dist/components/inputs/OTP/theme.css +50 -0
  70. package/dist/components/inputs/StringCapture/README.md +718 -0
  71. package/dist/components/inputs/StringCapture/StringCapture.vue +315 -0
  72. package/dist/components/inputs/StringCapture/theme.css +86 -0
  73. package/dist/components/inputs/Tags/README.md +897 -0
  74. package/dist/components/inputs/Tags/TagBar.vue +793 -0
  75. package/dist/components/inputs/Tags/TagCreation.vue +219 -0
  76. package/dist/components/inputs/Tags/TagPicker.vue +380 -0
  77. package/dist/components/inputs/Tags/tag-bar-styles.ts +354 -0
  78. package/dist/components/inputs/Tags/theme.css +121 -0
  79. package/dist/components/inputs/Tags/types.ts +346 -0
  80. package/dist/components/inputs/search/README.md +759 -0
  81. package/dist/components/inputs/search/SearchBar.vue +394 -0
  82. package/dist/components/inputs/search/SearchResults.vue +310 -0
  83. package/dist/components/inputs/search/theme.css +187 -0
  84. package/dist/components/inputs/search/types.ts +8 -0
  85. package/dist/components/inputs/theme.css +102 -0
  86. package/dist/components/menus/ActionMenu/ActionMenu.vue +383 -0
  87. package/dist/components/menus/ActionMenu/README.md +825 -0
  88. package/dist/components/menus/ActionMenu/theme.css +93 -0
  89. package/dist/components/models/Popover/Popover.vue +551 -0
  90. package/dist/components/models/Popover/README.md +885 -0
  91. package/dist/components/models/Popover/theme.css +52 -0
  92. package/dist/components/models/Sheet/README.md +1159 -0
  93. package/dist/components/models/Sheet/Sheet.vue +465 -0
  94. package/dist/components/models/Sheet/theme.css +72 -0
  95. package/dist/components/models/Sidebar/README.md +1228 -0
  96. package/dist/components/models/Sidebar/Sidebar.vue +480 -0
  97. package/dist/components/models/Sidebar/theme.css +90 -0
  98. package/dist/components/navigation/adaptive/AdaptiveLayout.vue +779 -0
  99. package/dist/components/navigation/adaptive/AdaptiveLayoutBreadcrumbs.vue +192 -0
  100. package/dist/components/navigation/adaptive/AdaptiveLayoutMenuButton.vue +149 -0
  101. package/dist/components/navigation/adaptive/README.md +768 -0
  102. package/dist/components/navigation/adaptive/types.ts +19 -0
  103. package/dist/components/navigation/adaptive/useAdaptiveLayout.ts +89 -0
  104. package/dist/components/navigation/adaptive/useBreakpoints.ts +41 -0
  105. package/dist/components/navigation/adaptive/useContainerMonitor.ts +214 -0
  106. package/dist/components/navigation/adaptive/useViewAnimation.ts +721 -0
  107. package/dist/components/navigation/adaptive/useViewResize.ts +211 -0
  108. package/dist/components/navigation/navstack/NavigationStack.vue +180 -0
  109. package/dist/components/navigation/navstack/README.md +994 -0
  110. package/dist/components/navigation/navstack/useNavigationStack.ts +164 -0
  111. package/dist/components/navigation/slideover/README.md +1275 -0
  112. package/dist/components/navigation/slideover/SlideoverController.vue +287 -0
  113. package/dist/components/navigation/slideover/useSlideoverController.ts +320 -0
  114. package/dist/components/navigation/splitview/README.md +1115 -0
  115. package/dist/components/navigation/splitview/SplitViewController.vue +176 -0
  116. package/dist/components/navigation/splitview/useSplitViewController.ts +388 -0
  117. package/dist/components/navigation/tabcontroller/README.md +919 -0
  118. package/dist/components/navigation/tabcontroller/TabController.vue +307 -0
  119. package/dist/components/navigation/tabcontroller/TabItem.vue +57 -0
  120. package/dist/components/navigation/tabcontroller/types.ts +24 -0
  121. package/dist/components/navigation/tabcontroller/useTabController.ts +18 -0
  122. package/dist/components/navigation/theme.css +91 -0
  123. package/dist/components/navigation/types.ts +7 -0
  124. package/dist/components/pickers/CollectionPicker/CollectionPicker.vue +398 -0
  125. package/dist/components/pickers/CollectionPicker/README.md +1115 -0
  126. package/dist/components/pickers/CollectionPicker/theme.css +14 -0
  127. package/dist/components/pickers/CollectionPicker/types.ts +11 -0
  128. package/dist/components/pickers/ColorPicker/ColorPicker.vue +376 -0
  129. package/dist/components/pickers/ColorPicker/README.md +1439 -0
  130. package/dist/components/pickers/ColorPicker/colors.ts +299 -0
  131. package/dist/components/pickers/ColorPicker/theme.css +32 -0
  132. package/dist/components/pickers/DatePicker/DatePicker.vue +660 -0
  133. package/dist/components/pickers/DatePicker/README.md +1195 -0
  134. package/dist/components/pickers/DatePicker/theme.css +22 -0
  135. package/dist/components/pickers/FilePicker/FilePicker.vue +534 -0
  136. package/dist/components/pickers/FilePicker/README.md +1542 -0
  137. package/dist/components/pickers/FilePicker/theme.css +48 -0
  138. package/dist/components/pickers/FilePicker/types.ts +10 -0
  139. package/dist/components/pickers/IconPicker/IconPicker.vue +327 -0
  140. package/dist/components/pickers/IconPicker/README.md +1161 -0
  141. package/dist/components/pickers/IconPicker/theme.css +28 -0
  142. package/dist/components/pickers/theme.css +82 -0
  143. package/dist/components/views/MarkdownViewer/MarkdownViewer.vue +442 -0
  144. package/dist/components/views/MarkdownViewer/README.md +833 -0
  145. package/dist/components/views/MarkdownViewer/theme.css +130 -0
  146. package/dist/css/umbra-ui.css +42 -0
  147. package/package.json +6 -3
@@ -0,0 +1,660 @@
1
+ <script setup lang="ts">
2
+ import { ChevronRightIcon, CalendarDaysIcon } from "@umbra.ui/icons";
3
+ // - Imports
4
+ import { ref, watch, onMounted, nextTick, computed, onUnmounted } from "vue";
5
+ import {
6
+ offset,
7
+ flip,
8
+ shift,
9
+ size,
10
+ computePosition,
11
+ hide,
12
+ autoUpdate,
13
+ } from "@floating-ui/vue";
14
+ import "./theme.css";
15
+ // - Interfaces
16
+ interface Month {
17
+ title: string;
18
+ days: Day[];
19
+ }
20
+ interface Day {
21
+ key: number;
22
+ day: number;
23
+ inCurrentMonth: boolean;
24
+ year: number;
25
+ month: number;
26
+ date: Date;
27
+ }
28
+ // - Props
29
+ export interface Props {
30
+ date: Date;
31
+ }
32
+ const props = withDefaults(defineProps<Props>(), {
33
+ date: () => new Date(),
34
+ });
35
+ // - Emits
36
+ const emits = defineEmits(["update:date"]);
37
+ // - State Management
38
+ const weekdays = ["MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"];
39
+ const days = ref<Day[]>([]);
40
+ const showAlldays = ref<boolean>(false);
41
+ const months = ref<Month[]>([]);
42
+ const selectedDate = ref<Date>(props.date);
43
+ // - Computed Properties
44
+ watch(
45
+ () => props.date,
46
+ (newValue) => {
47
+ selectedDate.value = newValue;
48
+ }
49
+ );
50
+ const dateString = computed(() => {
51
+ return new Intl.DateTimeFormat("en-US", {
52
+ weekday: "long",
53
+ month: "long",
54
+ day: "numeric",
55
+ }).format(selectedDate.value);
56
+ });
57
+
58
+ const yearString = computed(() => {
59
+ return new Intl.DateTimeFormat("en-US", {
60
+ year: "numeric",
61
+ }).format(selectedDate.value);
62
+ });
63
+ // - Element References
64
+ const showPopover = ref<boolean>(false);
65
+ const button = ref<HTMLElement | null>(null);
66
+ const picker = ref<HTMLElement | null>(null);
67
+ const container = ref<HTMLElement | null>(null);
68
+ const overlay = ref<HTMLElement | null>(null);
69
+
70
+ // - Position tracking
71
+ let cleanupAutoUpdate: (() => void) | null = null;
72
+
73
+ // - Lifecycle
74
+ onMounted(async () => {
75
+ setupCompactCalendar();
76
+ });
77
+
78
+ onUnmounted(() => {
79
+ if (cleanupAutoUpdate) {
80
+ cleanupAutoUpdate();
81
+ }
82
+ });
83
+
84
+ // - Calendar Setup Toggling
85
+ const setupCompactCalendar = () => {
86
+ months.value = [];
87
+ // set up days for compact calendar
88
+ days.value = generateMonth(new Date(props.date)).days;
89
+ };
90
+ const setupFullCalendar = async () => {
91
+ allowScroll.value = false;
92
+ days.value = [];
93
+
94
+ // set up months with the next 5 months
95
+ for (let i = 0; i < 4; i++) {
96
+ months.value.push(
97
+ generateMonth(
98
+ new Date(props.date.getFullYear(), props.date.getMonth() + i, 1)
99
+ )
100
+ );
101
+ }
102
+
103
+ // set up months with the previous five months
104
+ for (let i = 0; i < 4; i++) {
105
+ fetchPreviousMonth();
106
+ }
107
+
108
+ // scroll back to the month in the compact calendar
109
+ await nextTick();
110
+ if (scrollview.value) {
111
+ scrollview.value.scrollTop = 470;
112
+ }
113
+
114
+ // allow the month labels to show when the user scrolls
115
+ setTimeout(() => {
116
+ allowScroll.value = true;
117
+ }, 200);
118
+ };
119
+ const toggleCalendar = async () => {
120
+ showAlldays.value = !showAlldays.value;
121
+
122
+ if (showAlldays.value) {
123
+ setupFullCalendar();
124
+ } else {
125
+ setupCompactCalendar();
126
+ }
127
+ };
128
+ // - Date Calculations
129
+ const fetchNextMonth = () => {
130
+ const month = months.value[months.value.length - 1];
131
+ const day = month.days[Math.floor(month.days.length / 2)];
132
+ const date = new Date(day.year, day.month, day.day);
133
+ date.setMonth(date.getMonth() + 1);
134
+ months.value.push(generateMonth(date));
135
+ };
136
+ const fetchPreviousMonth = () => {
137
+ const month = months.value[0];
138
+ const day = month.days[Math.floor(month.days.length / 2)];
139
+ const date = new Date(day.year, day.month, day.day);
140
+ date.setMonth(date.getMonth() - 1);
141
+ months.value.unshift(generateMonth(date));
142
+ };
143
+ function generateMonth(date: Date): Month {
144
+ const firstDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1);
145
+ const daysInMonth = new Date(
146
+ date.getFullYear(),
147
+ date.getMonth() + 1,
148
+ 0
149
+ ).getDate();
150
+
151
+ // Calculate the offset based on the day of the week (0 = Sunday, 1 = Monday, ..., 6 = Saturday)
152
+ let startDay = firstDayOfMonth.getDay(); // Adjusted startDay calculation
153
+
154
+ // If the startDay is 0 (Sunday), set it to 7 for consistency
155
+ startDay = startDay === 0 ? 7 : startDay;
156
+
157
+ const generatedDays: Day[] = [];
158
+
159
+ const year = date.getFullYear();
160
+ const month = date.getMonth();
161
+
162
+ for (let i = 1; i <= daysInMonth; i++) {
163
+ const currentDate = new Date(year, month, i);
164
+
165
+ let inCurrentMonth = true;
166
+ generatedDays.push({
167
+ key: i, // Key starts from 1
168
+ day: i,
169
+ inCurrentMonth,
170
+ year,
171
+ month,
172
+ date: currentDate, // Set the newly added date field
173
+ });
174
+ }
175
+
176
+ // Fill in days from the previous month if needed to complete the week
177
+ const previousMonthLastDay = new Date(year, month, 0).getDate();
178
+ const previousMonthDaysNeeded = startDay - 1;
179
+ for (
180
+ let i = previousMonthLastDay - previousMonthDaysNeeded + 1;
181
+ i <= previousMonthLastDay;
182
+ i++
183
+ ) {
184
+ const currentDate = new Date(year, month - 1, i); // Calculate date for the previous month
185
+ generatedDays.unshift({
186
+ key: i,
187
+ day: i,
188
+ inCurrentMonth: false,
189
+ year: month === 0 ? year - 1 : year,
190
+ month: month === 0 ? 11 : month - 1,
191
+ date: currentDate, // Set the newly added date field
192
+ });
193
+ }
194
+
195
+ // Fill in days from the next month if needed to complete the grid
196
+ const remainingDays = 35 - generatedDays.length;
197
+ for (let i = 1; i <= remainingDays; i++) {
198
+ const nextMonthDate = new Date(year, month + 1, i); // Calculate date for the next month
199
+ generatedDays.push({
200
+ key: i,
201
+ day: i,
202
+ inCurrentMonth: false,
203
+ year: month === 11 ? year + 1 : year,
204
+ month: month === 11 ? 0 : month + 1,
205
+ date: nextMonthDate, // Set the newly added date field
206
+ });
207
+ }
208
+
209
+ const monthTitle = new Intl.DateTimeFormat("en-US", {
210
+ month: "long",
211
+ year: "numeric",
212
+ }).format(date);
213
+ return {
214
+ title: monthTitle,
215
+ days: generatedDays,
216
+ };
217
+ }
218
+
219
+ // - Handle Day Cell Appearance
220
+ function drawBorderTop(day: Day): boolean {
221
+ if (day.inCurrentMonth && day.day <= 7) {
222
+ return true;
223
+ }
224
+ return false;
225
+ }
226
+ function drawBorderLeft(day: Day, index: number): boolean {
227
+ if (index === 0) {
228
+ return false;
229
+ }
230
+ if (day.inCurrentMonth && day.day === 1) {
231
+ return true;
232
+ }
233
+ return false;
234
+ }
235
+ function setMarginTopOffset(month: Month, index: number): boolean {
236
+ if (index === 0) {
237
+ return false;
238
+ }
239
+ if (month.days[0].inCurrentMonth) {
240
+ return false;
241
+ }
242
+ return true;
243
+ }
244
+
245
+ // - Date Selection
246
+ function isDaySelected(day: Day): boolean {
247
+ return selectedDate.value.getTime() === day.date.getTime();
248
+ }
249
+
250
+ function select(date: Date) {
251
+ selectedDate.value = date;
252
+ emits("update:date", date);
253
+ }
254
+
255
+ // - Handle Scrolling
256
+ const scrollview = ref<HTMLElement | null>(null);
257
+ const fetchInProgress = ref<boolean>(false);
258
+ const allowScroll = ref<boolean>(false);
259
+ const isScrolling = ref<boolean>(false);
260
+ let scrollTimeout: NodeJS.Timeout | undefined;
261
+ const handleScroll = () => {
262
+ // Set isScrolling to true when scrolling starts
263
+ if (allowScroll.value) {
264
+ isScrolling.value = true;
265
+ }
266
+
267
+ // Clear the timeout if it exists
268
+ if (scrollTimeout !== undefined) {
269
+ clearTimeout(scrollTimeout);
270
+ }
271
+
272
+ // Set a timeout to reset isScrolling after a short delay (e.g., 200ms)
273
+ scrollTimeout = setTimeout(() => {
274
+ isScrolling.value = false;
275
+ }, 400); // Adjust the delay as needed
276
+
277
+ if (!scrollview.value) return;
278
+
279
+ const percentage =
280
+ (scrollview.value.scrollTop /
281
+ (scrollview.value.scrollHeight - scrollview.value.clientHeight)) *
282
+ 100;
283
+ if (percentage <= 25 && !fetchInProgress.value) {
284
+ fetchInProgress.value = true;
285
+ fetchPreviousMonth();
286
+ fetchInProgress.value = false;
287
+ }
288
+ // fetch more data to show if the user has scrolled more than 75% down
289
+ else if (percentage > 75 && !fetchInProgress.value) {
290
+ fetchInProgress.value = true;
291
+ fetchNextMonth();
292
+ fetchInProgress.value = false;
293
+ }
294
+ };
295
+
296
+ // - Popover Management
297
+ const togglePopover = () => {
298
+ showPopover.value = !showPopover.value;
299
+ if (showPopover.value) {
300
+ nextTick(() => {
301
+ updatePopoverPosition();
302
+ });
303
+ } else {
304
+ // revert back to the small calendar
305
+ showAlldays.value = false;
306
+ setupCompactCalendar();
307
+
308
+ // Clean up auto-update
309
+ if (cleanupAutoUpdate) {
310
+ cleanupAutoUpdate();
311
+ cleanupAutoUpdate = null;
312
+ }
313
+ }
314
+ };
315
+
316
+ const updatePopoverPosition = async () => {
317
+ if (!button.value || !picker.value) return;
318
+
319
+ // Wait for the DOM to be updated
320
+ await nextTick();
321
+
322
+ // Clean up any existing auto-update
323
+ if (cleanupAutoUpdate) {
324
+ cleanupAutoUpdate();
325
+ }
326
+
327
+ // Set up auto-update to track position changes
328
+ cleanupAutoUpdate = autoUpdate(button.value, picker.value, () => {
329
+ computePosition(button.value!, picker.value!, {
330
+ placement: "bottom-start",
331
+ middleware: [
332
+ offset(4), // px between anchor and popover
333
+ flip(), // switch side of space becomes too narrow
334
+ shift(),
335
+ size({
336
+ padding: 20,
337
+ apply({
338
+ availableWidth,
339
+ availableHeight,
340
+ elements,
341
+ }: {
342
+ availableWidth: number;
343
+ availableHeight: number;
344
+ elements: {
345
+ floating: {
346
+ style: {
347
+ maxWidth: string;
348
+ maxHeight: string;
349
+ };
350
+ };
351
+ };
352
+ }) {
353
+ // Change styles, e.g.
354
+ Object.assign(elements.floating.style, {
355
+ maxWidth: `${availableWidth}px`,
356
+ maxHeight: `${availableHeight}px`,
357
+ });
358
+ },
359
+ }),
360
+ ],
361
+ }).then(({ x, y }) => {
362
+ if (picker.value) {
363
+ Object.assign(picker.value.style, {
364
+ left: `${x}px`,
365
+ top: `${y}px`,
366
+ });
367
+ }
368
+ });
369
+ });
370
+ };
371
+
372
+ const handleOverlayClick = () => {
373
+ togglePopover();
374
+ };
375
+ </script>
376
+
377
+ <template>
378
+ <div :class="$style.container" ref="container">
379
+ <div
380
+ :class="[
381
+ $style.button,
382
+ showPopover ? $style.button_selected : $style.button_normal,
383
+ ]"
384
+ @click="togglePopover"
385
+ ref="button"
386
+ >
387
+ <CalendarDaysIcon :size="16" />
388
+ <p :class="['callout', $style.button_label]">{{ dateString }}</p>
389
+ <p :class="['callout', $style.button_sublabel]">{{ yearString }}</p>
390
+ </div>
391
+
392
+ <!-- Teleport the overlay and picker to body -->
393
+ <Teleport to="body">
394
+ <div
395
+ v-if="showPopover"
396
+ :class="$style.overlay"
397
+ ref="overlay"
398
+ @click="handleOverlayClick"
399
+ ></div>
400
+ <div v-if="showPopover" :class="$style.picker" ref="picker">
401
+ <div :class="$style.weekdays">
402
+ <p v-for="weekday in weekdays" :key="weekday">{{ weekday }}</p>
403
+ </div>
404
+ <div v-if="!showAlldays" :class="[$style.days]">
405
+ <p
406
+ v-for="day in days"
407
+ :key="`compact-${day.year}-${day.month}-${day.day}`"
408
+ :class="[
409
+ 'callout',
410
+ $style.day,
411
+ isDaySelected(day) ? $style.day_selected : '',
412
+ ]"
413
+ :style="{ opacity: day.inCurrentMonth ? 1 : 0.5 }"
414
+ @click="select(day.date)"
415
+ >
416
+ {{ day.day }}
417
+ </p>
418
+ <ChevronRightIcon
419
+ :class="[$style.day, $style.more_dates_button]"
420
+ @click="toggleCalendar"
421
+ />
422
+ </div>
423
+ <div
424
+ v-else
425
+ :class="$style.months"
426
+ ref="scrollview"
427
+ @scroll="handleScroll"
428
+ >
429
+ <div
430
+ v-for="(month, index) in months"
431
+ :key="month.title"
432
+ :class="[
433
+ $style.month,
434
+ setMarginTopOffset(month, index) ? $style.margin_top_offset : '',
435
+ ]"
436
+ >
437
+ <div
438
+ :class="$style.month_days"
439
+ :style="{ opacity: isScrolling ? 0.15 : 1 }"
440
+ >
441
+ <p
442
+ v-for="(day, index) in month.days"
443
+ :key="`full-${day.year}-${day.month}-${day.day}`"
444
+ :class="[
445
+ 'callout',
446
+ $style.day,
447
+ drawBorderTop(day) ? $style.border_top : '',
448
+ drawBorderLeft(day, index) ? $style.border_left : '',
449
+ isDaySelected(day) ? $style.day_selected : '',
450
+ ]"
451
+ :style="{
452
+ opacity: day.inCurrentMonth ? 1 : 0,
453
+ pointerEvents: day.inCurrentMonth ? 'auto' : 'none',
454
+ zIndex: day.inCurrentMonth ? 1 : 0,
455
+ }"
456
+ @click="select(day.date)"
457
+ >
458
+ {{ day.day }}
459
+ </p>
460
+ </div>
461
+ <div
462
+ :class="$style.month_header"
463
+ :style="{ opacity: isScrolling ? 1 : 0 }"
464
+ >
465
+ <p class="headline">{{ month.title }}</p>
466
+ </div>
467
+ </div>
468
+ </div>
469
+ </div>
470
+ </Teleport>
471
+ </div>
472
+ </template>
473
+
474
+ <style module>
475
+ .container {
476
+ display: flex;
477
+ flex-direction: column;
478
+ gap: 0.235rem;
479
+ align-items: start;
480
+ }
481
+ .button {
482
+ padding-top: 0.588rem;
483
+ padding-bottom: 0.588rem;
484
+ border-radius: 0.353rem;
485
+ cursor: default;
486
+ user-select: none;
487
+ display: flex;
488
+ align-items: center;
489
+ gap: 0.588rem;
490
+ transition: padding-left 0.3s, padding-right 0.3s, background-color 0.3s,
491
+ box-shadow 0.3s;
492
+ }
493
+ .button_normal {
494
+ background-color: var(--picker-button-bg);
495
+ border: var(--picker-button-border);
496
+ }
497
+ .button_normal:hover {
498
+ background-color: var(--picker-button-hover-bg);
499
+ padding-left: 0.588rem;
500
+ padding-right: 0.588rem;
501
+ box-shadow: 0px 1px 0px 0px var(--picker-button-hover-shadow),
502
+ inset 0px 1px 0px 0px var(--picker-button-hover-inset-shadow);
503
+ border: var(--picker-button-hover-border);
504
+ }
505
+ .button_selected {
506
+ background-color: var(--picker-button-selected-bg);
507
+ padding-left: 0.588rem;
508
+ padding-right: 0.588rem;
509
+ border: var(--picker-button-hover-border);
510
+ }
511
+ .button_label {
512
+ font-weight: 700 !important;
513
+ font-variation-settings: "wght" 700 !important;
514
+ }
515
+ .button_sublabel {
516
+ opacity: 0.5;
517
+ }
518
+ .picker {
519
+ position: absolute;
520
+ top: 0;
521
+ left: 0;
522
+ background-color: var(--picker-picker-bg);
523
+ border-radius: 0.353rem;
524
+ overflow: hidden;
525
+ box-shadow: 0px 1px 0px 0px var(--picker-picker-shadow),
526
+ inset 0px 1px 0px 0px var(--picker-picker-inset-shadow);
527
+ border: var(--picker-picker-border);
528
+ z-index: 1000;
529
+ }
530
+ .weekdays {
531
+ display: grid;
532
+ grid-template-columns: repeat(7, 1fr);
533
+ align-items: center;
534
+ padding-left: 0.294rem;
535
+ padding-right: 0.294rem;
536
+ min-height: 2rem;
537
+ background-color: var(--picker-bg-subtle);
538
+ border-bottom: 1px solid var(--picker-border-light);
539
+ }
540
+ .weekdays p {
541
+ opacity: var(--datepicker-weekdays-opacity);
542
+ font-size: 0.765rem;
543
+ min-width: 2.588rem;
544
+ text-align: center;
545
+ color: var(--picker-text-secondary);
546
+ }
547
+ .days {
548
+ display: grid;
549
+ grid-template-columns: repeat(7, 1fr);
550
+ gap: 0;
551
+ align-items: center;
552
+ max-height: 32rem;
553
+ overflow: auto;
554
+ color: var(--picker-text-primary);
555
+ }
556
+
557
+ .days :nth-last-child(2) {
558
+ display: none;
559
+ }
560
+
561
+ .months {
562
+ display: flex;
563
+ flex-direction: column;
564
+ max-height: 32rem;
565
+ overflow: auto;
566
+ }
567
+ .months::-webkit-scrollbar {
568
+ display: none;
569
+ }
570
+ .month {
571
+ display: grid;
572
+ grid-template-columns: 1fr;
573
+ grid-template-rows: 1fr;
574
+ grid-template-areas: "content";
575
+ }
576
+ .month_header {
577
+ padding-left: 0.706rem;
578
+ padding-right: 0.706rem;
579
+ padding-top: 0.5rem;
580
+ padding-bottom: 0.5rem;
581
+ grid-area: content;
582
+ display: flex;
583
+ align-items: center;
584
+ justify-content: center;
585
+ transition: opacity 0.3s ease;
586
+ user-select: none;
587
+ cursor: default;
588
+ pointer-events: none;
589
+ color: var(--picker-text-primary);
590
+ }
591
+
592
+ .month_days {
593
+ display: grid;
594
+ grid-template-columns: repeat(7, 1fr);
595
+ gap: 0;
596
+ align-items: center;
597
+ max-height: 32rem;
598
+ overflow: auto;
599
+ grid-area: content;
600
+ transition: opacity 0.3s ease;
601
+ color: var(--picker-text-primary);
602
+ }
603
+
604
+ .day {
605
+ min-width: 2.588rem;
606
+ height: 2rem;
607
+ text-align: center;
608
+ display: flex;
609
+ align-items: center;
610
+ justify-content: center;
611
+ user-select: none;
612
+ cursor: default;
613
+ border-radius: 0.235rem;
614
+ padding: 0.294rem;
615
+ }
616
+ .day:hover {
617
+ background-color: var(--picker-bg-hover);
618
+ }
619
+ .day_selected {
620
+ background-color: var(--datepicker-day-selected-bg);
621
+ border-radius: 999px;
622
+ border: 1px solid var(--datepicker-day-selected-border);
623
+ }
624
+ .day_selected:hover {
625
+ background-color: var(--datepicker-day-selected-bg);
626
+ }
627
+ .border_top {
628
+ border-top: 1px solid var(--picker-border-light);
629
+ border-top-right-radius: 0;
630
+ border-top-left-radius: 0;
631
+ }
632
+ .border_left {
633
+ border-left: 1px solid var(--picker-border-light);
634
+ border-bottom-left-radius: 0;
635
+ }
636
+ .margin_top_offset {
637
+ margin-top: -2rem;
638
+ }
639
+
640
+ .more_dates_button {
641
+ width: 2.588rem;
642
+ height: 2rem;
643
+ padding: 0.471rem;
644
+ background-color: var(--picker-selection-bar-bg);
645
+ }
646
+ .more_dates_button:hover {
647
+ background-color: var(--picker-bg-hover);
648
+ }
649
+
650
+ .overlay {
651
+ position: fixed;
652
+ top: 0;
653
+ left: 0;
654
+ width: 100%;
655
+ height: 100%;
656
+ background-color: var(--picker-overlay-bg);
657
+ opacity: 0;
658
+ z-index: 999;
659
+ }
660
+ </style>