picocrank 1.26.0 → 1.28.0

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/eslint.config.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import js from '@eslint/js'
2
2
  import pluginVue from 'eslint-plugin-vue'
3
3
  import globals from 'globals'
4
- import tseslint from 'typescript-eslint'
5
4
  import vueParser from 'vue-eslint-parser'
6
5
 
7
6
  export default [
@@ -50,15 +49,23 @@ export default [
50
49
  languageOptions: {
51
50
  parser: vueParser,
52
51
  parserOptions: {
53
- parser: {
54
- js: 'espree',
55
- ts: tseslint.parser,
56
- },
57
52
  sourceType: 'module',
58
53
  extraFileExtensions: ['.vue'],
59
54
  },
60
55
  },
61
56
  },
57
+ {
58
+ files: ['**/*.spec.js', 'vue/test/**'],
59
+ languageOptions: {
60
+ globals: {
61
+ ...globals.browser,
62
+ ...globals.node,
63
+ },
64
+ },
65
+ rules: {
66
+ 'vue/one-component-per-file': 'off',
67
+ },
68
+ },
62
69
  {
63
70
  files: ['**/*.vue'],
64
71
  rules: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picocrank",
3
- "version": "1.26.0",
3
+ "version": "1.28.0",
4
4
  "type": "module",
5
5
  "description": "A set of zero dependency Vue components built on the Femtocrank global CSS theme.",
6
6
  "main": "vite.config.js",
@@ -11,7 +11,8 @@
11
11
  "preview": "vite preview",
12
12
  "lint": "eslint .",
13
13
  "lint:fix": "eslint . --fix",
14
- "test": "echo \"Error: no test specified\" && exit 1"
14
+ "test": "vitest run",
15
+ "test:watch": "vitest"
15
16
  },
16
17
  "repository": {
17
18
  "type": "git",
@@ -26,7 +27,7 @@
26
27
  "@hugeicons/core-free-icons": "^4.3.0",
27
28
  "@hugeicons/vue": "^1.0.8",
28
29
  "@vitejs/plugin-vue": "^6.0.8",
29
- "femtocrank": "^2.7.0",
30
+ "femtocrank": "^2.7.1",
30
31
  "unplugin-vue-components": "^32.1.0",
31
32
  "vite": "^8.2.2",
32
33
  "vue": "^3.5.41",
@@ -34,12 +35,14 @@
34
35
  },
35
36
  "devDependencies": {
36
37
  "@eslint/js": "^10.0.1",
38
+ "@vitest/coverage-v8": "^4.1.11",
39
+ "@vue/test-utils": "^2.4.11",
37
40
  "eslint": "^10.9.1",
38
41
  "eslint-plugin-vue": "^10.10.0",
39
42
  "globals": "^17.11.0",
43
+ "happy-dom": "^20.11.8",
40
44
  "semantic-release": "^25.0.9",
41
- "typescript": "^6.0.3",
42
- "typescript-eslint": "^8.68.0",
45
+ "vitest": "^4.1.11",
43
46
  "vue-eslint-parser": "^10.4.1"
44
47
  },
45
48
  "homepage": "https://github.com/jamesread/picocrank#readme"
@@ -35,8 +35,15 @@
35
35
  --login-error-fg: var(--karma-on-bg-fg);
36
36
  --login-muted-fg: var(--muted-text-color);
37
37
 
38
+ --login-spinner-fg: var(--link-color);
39
+ --login-spinner-track: var(--border-color);
40
+
41
+ --form-field-required-fg: var(--karma-bad);
42
+
38
43
  --table-muted-fg: var(--muted-text-color);
39
44
 
45
+ --button-transparent-disabled-fg: color-mix(in srgb, var(--text-color) 45%, var(--section-bg-color));
46
+
40
47
  --table-popover-bg: var(--section-bg-color);
41
48
  --table-popover-border: var(--border-color);
42
49
  --table-popover-shadow: 0 8px 24px color-mix(in srgb, var(--shadow-color) 60%, transparent);
@@ -106,6 +113,45 @@ section .section-header [role="toolbar"] .button {
106
113
  min-width: 0;
107
114
  line-height: normal;
108
115
  }
116
+
117
+ section.narrow {
118
+ max-width: 480px;
119
+ margin-left: auto;
120
+ margin-right: auto;
121
+ border-radius: .8em;
122
+ }
123
+
124
+ section.narrow form {
125
+ grid-template-columns: 1fr;
126
+ }
127
+
128
+ section.narrow fieldset {
129
+ grid-column: span 1;
130
+ }
131
+
132
+ form > .form-field-label-skip {
133
+ grid-column: 1 / -1;
134
+ }
135
+
136
+ /*
137
+ * FormField applies .field-invalid when an error is set programmatically.
138
+ * Mirrors femtocrank :user-invalid (which only applies after user interaction).
139
+ */
140
+ input.field-invalid,
141
+ textarea.field-invalid,
142
+ select.field-invalid {
143
+ border-color: var(--karma-bad-border);
144
+ background-color: var(--karma-bad-wash);
145
+ color: var(--text-color);
146
+ box-shadow: 0 0 0 3px color-mix(in srgb, var(--karma-bad) 35%, transparent);
147
+ }
148
+
149
+ input.field-invalid:focus-visible,
150
+ textarea.field-invalid:focus-visible,
151
+ select.field-invalid:focus-visible {
152
+ outline: 2px solid var(--karma-bad-border);
153
+ outline-offset: 2px;
154
+ }
109
155
  }
110
156
 
111
157
  /*
package/vite.config.js CHANGED
@@ -192,4 +192,9 @@ export default defineConfig({
192
192
  }),
193
193
  vue(),
194
194
  ],
195
+ test: {
196
+ environment: 'happy-dom',
197
+ include: ['vue/**/*.spec.js'],
198
+ setupFiles: ['./vue/test/setup.js'],
199
+ },
195
200
  })
@@ -1,84 +1,79 @@
1
- <script setup lang="ts">
1
+ <script setup>
2
2
  import { ref, computed, watch, onUnmounted } from 'vue'
3
3
  import { HugeiconsIcon } from '@hugeicons/vue'
4
4
 
5
- export interface CalendarEvent {
6
- id: string | number
7
- title: string
8
- startDate?: Date | string | null
9
- endDate?: Date | string | null
10
- date?: Date | string | null
11
- /** Optional Hugeicons icon (from @hugeicons/core-free-icons). */
12
- icon?: unknown
13
- /** Optional CSS color overriding the default event background. */
14
- color?: string
15
- /** Optional CSS color for event title/time when using a custom background. */
16
- foregroundColor?: string
17
- [key: string]: any
18
- }
19
-
20
- /** Payload for `event-move-request`: call `respond(true)` after a successful commit, or `respond(false)` to decline (e.g. failed server update). */
21
- export interface CalendarEventMoveRequest {
22
- event: CalendarEvent
23
- /** Calendar cell where the drag started (for multi-day events, the visible segment day). */
24
- sourceDate: Date
25
- /** Calendar cell where the event was dropped. */
26
- targetDate: Date
27
- /** Invoke exactly once with the outcome. If omitted until timeout, the move is treated as rejected. */
28
- respond: (_accepted: boolean) => void
29
- }
30
-
31
- export interface CalendarProps {
32
- events: CalendarEvent[]
33
- monthNames?: string[]
34
- dayNames?: string[]
35
- loading?: boolean
36
- error?: string | null
37
- /** When true, events can be dragged to another day. */
38
- eventDragEnabled?: boolean
39
- /**
40
- * Max time (ms) to wait for `respond()` on `event-move-request`.
41
- * If `respond` is not called in time, the move is rejected and a warning is logged.
42
- * Set to `0` to disable the timeout (not recommended if listeners may omit `respond`).
43
- */
44
- eventMoveResponseTimeoutMs?: number
45
- // Formatter functions
46
- getEventDate?: (_event: CalendarEvent) => Date | null
47
- getEventDateRange?: (_event: CalendarEvent) => { start: Date | null; end: Date | null }
48
- formatEventTime?: (_event: CalendarEvent, _date: Date) => string
49
- // Customization
50
- showNavigation?: boolean
51
- /** When true, day titles show ordinal + full month name (e.g. "21st July") instead of the day number alone. */
52
- shortMonthSuffix?: boolean
53
- currentMonth?: number
54
- currentYear?: number
55
- }
56
-
57
- const props = withDefaults(defineProps<CalendarProps>(), {
58
- section: false,
59
- monthNames: () => [
60
- 'January', 'February', 'March', 'April', 'May', 'June',
61
- 'July', 'August', 'September', 'October', 'November', 'December'
62
- ],
63
- dayNames: () => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
64
- loading: false,
65
- error: null,
66
- eventDragEnabled: true,
67
- eventMoveResponseTimeoutMs: 15000,
68
- showNavigation: true,
69
- shortMonthSuffix: false,
5
+ const props = defineProps({
6
+ events: {
7
+ type: Array,
8
+ required: true,
9
+ },
10
+ monthNames: {
11
+ type: Array,
12
+ default: () => [
13
+ 'January', 'February', 'March', 'April', 'May', 'June',
14
+ 'July', 'August', 'September', 'October', 'November', 'December',
15
+ ],
16
+ },
17
+ dayNames: {
18
+ type: Array,
19
+ default: () => ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
20
+ },
21
+ loading: {
22
+ type: Boolean,
23
+ default: false,
24
+ },
25
+ error: {
26
+ type: String,
27
+ default: null,
28
+ },
29
+ eventDragEnabled: {
30
+ type: Boolean,
31
+ default: true,
32
+ },
33
+ eventMoveResponseTimeoutMs: {
34
+ type: Number,
35
+ default: 15000,
36
+ },
37
+ getEventDate: {
38
+ type: Function,
39
+ default: null,
40
+ },
41
+ getEventDateRange: {
42
+ type: Function,
43
+ default: null,
44
+ },
45
+ formatEventTime: {
46
+ type: Function,
47
+ default: null,
48
+ },
49
+ showNavigation: {
50
+ type: Boolean,
51
+ default: true,
52
+ },
53
+ shortMonthSuffix: {
54
+ type: Boolean,
55
+ default: false,
56
+ },
57
+ currentMonth: {
58
+ type: Number,
59
+ default: undefined,
60
+ },
61
+ currentYear: {
62
+ type: Number,
63
+ default: undefined,
64
+ },
70
65
  })
71
66
 
72
- const emit = defineEmits<{
73
- 'event-click': [event: CalendarEvent]
74
- 'date-click': [date: Date]
75
- 'date-range-select': [start: Date, end: Date]
76
- 'month-change': [month: number, year: number]
77
- 'event-context-menu': [event: CalendarEvent, mouseEvent: MouseEvent]
78
- 'event-move-request': [payload: CalendarEventMoveRequest]
79
- 'event-moved': [payload: { event: CalendarEvent; sourceDate: Date; targetDate: Date }]
80
- 'event-move-rejected': [payload: { event: CalendarEvent; sourceDate: Date; targetDate: Date }]
81
- }>()
67
+ const emit = defineEmits([
68
+ 'event-click',
69
+ 'date-click',
70
+ 'date-range-select',
71
+ 'month-change',
72
+ 'event-context-menu',
73
+ 'event-move-request',
74
+ 'event-moved',
75
+ 'event-move-rejected',
76
+ ])
82
77
 
83
78
  // Internal calendar state
84
79
  const internalCurrentDate = ref(new Date())
@@ -93,7 +88,7 @@ const viewMonth = computed(() => currentDate.value.getMonth())
93
88
  const viewYear = computed(() => currentDate.value.getFullYear())
94
89
 
95
90
  // Compute the first visible day (Monday) for the current month view
96
- function getStartOfGrid(date: Date): Date {
91
+ function getStartOfGrid(date) {
97
92
  const firstOfMonth = new Date(date.getFullYear(), date.getMonth(), 1)
98
93
  const dayOfWeek = (firstOfMonth.getDay() + 6) % 7 // Monday=0
99
94
  const start = new Date(firstOfMonth)
@@ -103,19 +98,19 @@ function getStartOfGrid(date: Date): Date {
103
98
  }
104
99
 
105
100
  // Anchor date for the 6x7 grid; we will shift this by weeks without re-rendering the grid structure
106
- const gridStartDate = ref<Date>(getStartOfGrid(currentDate.value))
101
+ const gridStartDate = ref(getStartOfGrid(currentDate.value))
107
102
  // Track if we're actively scrolling to prevent watcher from resetting grid anchor
108
103
  const isScrolling = ref(false)
109
104
 
110
105
  // Helper function to check if a time is midnight (00:00)
111
- function isMidnight(dateValue: any): boolean {
106
+ function isMidnight(dateValue) {
112
107
  if (!dateValue) return false
113
108
  const date = new Date(dateValue)
114
109
  return date.getHours() === 0 && date.getMinutes() === 0
115
110
  }
116
111
 
117
112
  // Helper function to format time, returning "No time" if midnight
118
- function formatTimeOrNoTime(dateValue: any): string {
113
+ function formatTimeOrNoTime(dateValue) {
119
114
  if (!dateValue) return 'No time'
120
115
  if (isMidnight(dateValue)) return 'No time'
121
116
  const date = new Date(dateValue)
@@ -123,7 +118,7 @@ function formatTimeOrNoTime(dateValue: any): string {
123
118
  }
124
119
 
125
120
  // Determine if a date is in the past (before today)
126
- function isPastDay(date: Date): boolean {
121
+ function isPastDay(date) {
127
122
  const day = new Date(date)
128
123
  day.setHours(0, 0, 0, 0)
129
124
  const today = new Date()
@@ -132,14 +127,14 @@ function isPastDay(date: Date): boolean {
132
127
  }
133
128
 
134
129
  // Get event date range
135
- function resolveEventDateRange(event: CalendarEvent): { start: Date | null; end: Date | null } {
130
+ function resolveEventDateRange(event) {
136
131
  if (props.getEventDateRange) {
137
132
  return props.getEventDateRange(event)
138
133
  }
139
134
 
140
135
  // Default implementation
141
- let start: Date | null = null
142
- let end: Date | null = null
136
+ let start = null
137
+ let end = null
143
138
 
144
139
  if (event.startDate) {
145
140
  start = new Date(event.startDate)
@@ -155,7 +150,7 @@ function resolveEventDateRange(event: CalendarEvent): { start: Date | null; end:
155
150
  }
156
151
 
157
152
  // Get events for a specific date
158
- function getEventsForDate(date: Date): CalendarEvent[] {
153
+ function getEventsForDate(date) {
159
154
  const targetDate = new Date(date)
160
155
  targetDate.setHours(0, 0, 0, 0)
161
156
 
@@ -178,7 +173,7 @@ function getEventsForDate(date: Date): CalendarEvent[] {
178
173
  }
179
174
 
180
175
  // Check if an event is a multi-day event
181
- function isMultiDayEvent(event: CalendarEvent): boolean {
176
+ function isMultiDayEvent(event) {
182
177
  const { start, end } = resolveEventDateRange(event)
183
178
 
184
179
  if (!start || !end) return false
@@ -193,7 +188,7 @@ function isMultiDayEvent(event: CalendarEvent): boolean {
193
188
  }
194
189
 
195
190
  // Get the position of an event within a multi-day range for a specific date
196
- function getMultiDayPosition(event: CalendarEvent, date: Date): 'start' | 'middle' | 'end' | 'single' {
191
+ function getMultiDayPosition(event, date) {
197
192
  const { start, end } = resolveEventDateRange(event)
198
193
 
199
194
  if (!start || !end) return 'single'
@@ -215,7 +210,7 @@ function getMultiDayPosition(event: CalendarEvent, date: Date): 'start' | 'middl
215
210
  }
216
211
 
217
212
  // Format event time based on position in multi-day event
218
- function formatEventTimeDefault(event: CalendarEvent, date: Date): string {
213
+ function formatEventTimeDefault(event, date) {
219
214
  if (props.formatEventTime) {
220
215
  return props.formatEventTime(event, date)
221
216
  }
@@ -238,8 +233,8 @@ function formatEventTimeDefault(event: CalendarEvent, date: Date): string {
238
233
  return 'All day'
239
234
  }
240
235
 
241
- function getEventStyle(event: CalendarEvent): Record<string, string> | undefined {
242
- const style: Record<string, string> = {}
236
+ function getEventStyle(event) {
237
+ const style = {}
243
238
  if (event.color) {
244
239
  style['--event-color'] = event.color
245
240
  }
@@ -250,7 +245,7 @@ function getEventStyle(event: CalendarEvent): Record<string, string> | undefined
250
245
  }
251
246
 
252
247
  // Get ordinal suffix for a number (1st, 2nd, 3rd, 4th, etc.)
253
- function getOrdinalSuffix(day: number): string {
248
+ function getOrdinalSuffix(day) {
254
249
  const j = day % 10
255
250
  const k = day % 100
256
251
  if (j === 1 && k !== 11) {
@@ -267,7 +262,7 @@ function getOrdinalSuffix(day: number): string {
267
262
 
268
263
  // Calendar generation from persistent grid start
269
264
  const calendarDays = computed(() => {
270
- const days = [] as { date: Date; events: CalendarEvent[] }[]
265
+ const days = []
271
266
  const start = gridStartDate.value
272
267
  for (let i = 0; i < 42; i++) {
273
268
  const date = new Date(start)
@@ -320,13 +315,13 @@ function goToToday() {
320
315
  // Week navigation (mouse wheel)
321
316
  const lastWheelAt = ref(0)
322
317
  const wheelThrottleMs = 180
323
- function getVisibleMonthYear(start: Date): { month: number; year: number } {
318
+ function getVisibleMonthYear(start) {
324
319
  const mid = new Date(start)
325
320
  mid.setDate(start.getDate() + 21) // middle of 6x7 grid
326
321
  return { month: mid.getMonth(), year: mid.getFullYear() }
327
322
  }
328
323
 
329
- function adjustByWeeks(weeks: number): void {
324
+ function adjustByWeeks(weeks) {
330
325
  const newStart = new Date(gridStartDate.value)
331
326
  newStart.setDate(newStart.getDate() + weeks * 7)
332
327
  gridStartDate.value = newStart
@@ -347,7 +342,7 @@ function adjustByWeeks(weeks: number): void {
347
342
  }
348
343
  }
349
344
 
350
- function handleWheel(event: WheelEvent): void {
345
+ function handleWheel(event) {
351
346
  // Prevent page scrolling while using calendar scroll
352
347
  event.preventDefault()
353
348
  const now = (typeof performance !== 'undefined' && performance.now) ? performance.now() : Date.now()
@@ -358,11 +353,11 @@ function handleWheel(event: WheelEvent): void {
358
353
  }
359
354
 
360
355
  // Event handlers
361
- function handleEventClick(event: CalendarEvent) {
356
+ function handleEventClick(event) {
362
357
  emit('event-click', event)
363
358
  }
364
359
 
365
- function handleContextMenu(event: CalendarEvent, mouseEvent: MouseEvent) {
360
+ function handleContextMenu(event, mouseEvent) {
366
361
  mouseEvent.preventDefault()
367
362
  mouseEvent.stopPropagation()
368
363
  emit('event-context-menu', event, mouseEvent)
@@ -370,34 +365,34 @@ function handleContextMenu(event: CalendarEvent, mouseEvent: MouseEvent) {
370
365
 
371
366
  // --- Date range selection (click / drag) ---
372
367
 
373
- function startOfDay(d: Date): Date {
368
+ function startOfDay(d) {
374
369
  const x = new Date(d)
375
370
  x.setHours(0, 0, 0, 0)
376
371
  return x
377
372
  }
378
373
 
379
- function toDateKey(d: Date): string {
374
+ function toDateKey(d) {
380
375
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
381
376
  }
382
377
 
383
- function dateFromKey(key: string): Date {
378
+ function dateFromKey(key) {
384
379
  const [y, m, day] = key.split('-').map(Number)
385
380
  return startOfDay(new Date(y, m - 1, day))
386
381
  }
387
382
 
388
383
  const isDraggingRange = ref(false)
389
- const rangeDragAnchor = ref<Date | null>(null)
390
- const rangeDragEnd = ref<Date | null>(null)
391
- const selectedRangeStart = ref<Date | null>(null)
392
- const selectedRangeEnd = ref<Date | null>(null)
384
+ const rangeDragAnchor = ref(null)
385
+ const rangeDragEnd = ref(null)
386
+ const selectedRangeStart = ref(null)
387
+ const selectedRangeEnd = ref(null)
393
388
 
394
- function isEventTarget(ev: Event): boolean {
389
+ function isEventTarget(ev) {
395
390
  const t = ev.target
396
391
  if (!(t instanceof Node)) return false
397
- return Boolean((t as HTMLElement).closest?.('.calendar-event'))
392
+ return Boolean(t.closest?.('.calendar-event'))
398
393
  }
399
394
 
400
- function getRangeBounds(): { lo: Date; hi: Date } | null {
395
+ function getRangeBounds() {
401
396
  const a = rangeDragAnchor.value
402
397
  const b = rangeDragEnd.value
403
398
  if (!a || !b) return null
@@ -407,15 +402,17 @@ function getRangeBounds(): { lo: Date; hi: Date } | null {
407
402
  return { lo: startOfDay(b), hi: startOfDay(a) }
408
403
  }
409
404
 
410
- function rangeHighlightForDate(date: Date): 'none' | 'single' | 'start' | 'end' | 'middle' {
405
+ function rangeHighlightForDate(date) {
411
406
  const bounds = isDraggingRange.value
412
407
  ? getRangeBounds()
413
408
  : selectedRangeStart.value && selectedRangeEnd.value
414
409
  ? (() => {
415
- const sa = startOfDay(selectedRangeStart.value!).getTime()
416
- const sb = startOfDay(selectedRangeEnd.value!).getTime()
417
- const lo = sa <= sb ? startOfDay(selectedRangeStart.value!) : startOfDay(selectedRangeEnd.value!)
418
- const hi = sa <= sb ? startOfDay(selectedRangeEnd.value!) : startOfDay(selectedRangeStart.value!)
410
+ const rangeStart = selectedRangeStart.value
411
+ const rangeEnd = selectedRangeEnd.value
412
+ const sa = startOfDay(rangeStart).getTime()
413
+ const sb = startOfDay(rangeEnd).getTime()
414
+ const lo = sa <= sb ? startOfDay(rangeStart) : startOfDay(rangeEnd)
415
+ const hi = sa <= sb ? startOfDay(rangeEnd) : startOfDay(rangeStart)
419
416
  return { lo, hi }
420
417
  })()
421
418
  : null
@@ -428,18 +425,18 @@ function rangeHighlightForDate(date: Date): 'none' | 'single' | 'start' | 'end'
428
425
  return 'middle'
429
426
  }
430
427
 
431
- function onWindowTouchMove(ev: TouchEvent): void {
428
+ function onWindowTouchMove(ev) {
432
429
  if (!isDraggingRange.value || ev.touches.length === 0) return
433
430
  const { clientX, clientY } = ev.touches[0]
434
431
  const el = document.elementFromPoint(clientX, clientY)
435
432
  if (!el) return
436
- const cell = (el as HTMLElement).closest?.('[data-calendar-date]')
433
+ const cell = el.closest?.('[data-calendar-date]')
437
434
  const key = cell?.dataset?.calendarDate
438
435
  if (!key) return
439
436
  rangeDragEnd.value = dateFromKey(key)
440
437
  }
441
438
 
442
- function detachRangePointerListeners(): void {
439
+ function detachRangePointerListeners() {
443
440
  window.removeEventListener('mouseup', endRangeSelectionFromPointer)
444
441
  window.removeEventListener('blur', endRangeSelectionFromPointer)
445
442
  window.removeEventListener('touchmove', onWindowTouchMove)
@@ -447,7 +444,7 @@ function detachRangePointerListeners(): void {
447
444
  window.removeEventListener('touchcancel', endRangeSelectionFromPointer)
448
445
  }
449
446
 
450
- function endRangeSelectionFromPointer(): void {
447
+ function endRangeSelectionFromPointer() {
451
448
  if (!isDraggingRange.value) return
452
449
  const bounds = getRangeBounds()
453
450
  isDraggingRange.value = false
@@ -466,7 +463,7 @@ function endRangeSelectionFromPointer(): void {
466
463
  }
467
464
  }
468
465
 
469
- function onDayPointerDown(date: Date, ev: MouseEvent | TouchEvent): void {
466
+ function onDayPointerDown(date, ev) {
470
467
  if (isEventTarget(ev)) return
471
468
  if (ev instanceof MouseEvent && ev.button !== 0) return
472
469
 
@@ -484,7 +481,7 @@ function onDayPointerDown(date: Date, ev: MouseEvent | TouchEvent): void {
484
481
  }
485
482
  }
486
483
 
487
- function onDayPointerEnter(date: Date): void {
484
+ function onDayPointerEnter(date) {
488
485
  if (!isDraggingRange.value) return
489
486
  rangeDragEnd.value = startOfDay(date)
490
487
  }
@@ -497,17 +494,17 @@ onUnmounted(() => {
497
494
 
498
495
  const CALENDAR_EVENT_DRAG_MIME = 'application/x-picocrank-calendar-event-id'
499
496
 
500
- const draggingEventId = ref<string | number | null>(null)
501
- const draggingSourceDate = ref<Date | null>(null)
502
- const dragOverTargetDate = ref<Date | null>(null)
497
+ const draggingEventId = ref(null)
498
+ const draggingSourceDate = ref(null)
499
+ const dragOverTargetDate = ref(null)
503
500
  const eventMoveLocked = ref(false)
504
501
 
505
- function sameCalendarDay(a: Date | null, b: Date | null): boolean {
502
+ function sameCalendarDay(a, b) {
506
503
  if (!a || !b) return false
507
504
  return startOfDay(a).getTime() === startOfDay(b).getTime()
508
505
  }
509
506
 
510
- function onEventDragStart(event: CalendarEvent, sourceCellDate: Date, dragEvent: DragEvent): void {
507
+ function onEventDragStart(event, sourceCellDate, dragEvent) {
511
508
  if (!props.eventDragEnabled) {
512
509
  dragEvent.preventDefault()
513
510
  return
@@ -521,13 +518,13 @@ function onEventDragStart(event: CalendarEvent, sourceCellDate: Date, dragEvent:
521
518
  }
522
519
  }
523
520
 
524
- function onEventDragEnd(): void {
521
+ function onEventDragEnd() {
525
522
  draggingEventId.value = null
526
523
  draggingSourceDate.value = null
527
524
  dragOverTargetDate.value = null
528
525
  }
529
526
 
530
- function onDayDragOver(dayDate: Date, ev: DragEvent): void {
527
+ function onDayDragOver(dayDate, ev) {
531
528
  if (!props.eventDragEnabled || draggingEventId.value === null) return
532
529
  ev.preventDefault()
533
530
  if (ev.dataTransfer) {
@@ -536,7 +533,7 @@ function onDayDragOver(dayDate: Date, ev: DragEvent): void {
536
533
  dragOverTargetDate.value = startOfDay(dayDate)
537
534
  }
538
535
 
539
- function onDayDrop(dayDate: Date, ev: DragEvent): void {
536
+ function onDayDrop(dayDate, ev) {
540
537
  ev.preventDefault()
541
538
  dragOverTargetDate.value = null
542
539
  if (!props.eventDragEnabled) return
@@ -560,9 +557,9 @@ function onDayDrop(dayDate: Date, ev: DragEvent): void {
560
557
  const targetClone = new Date(targetDate)
561
558
 
562
559
  let settled = false
563
- let watchdog: ReturnType<typeof setTimeout> | undefined
560
+ let watchdog
564
561
 
565
- function respond(accepted: boolean): void {
562
+ function respond(accepted) {
566
563
  if (settled) return
567
564
  settled = true
568
565
  if (watchdog !== undefined) {