@moontra/moonui-pro 2.17.3 → 2.17.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.17.3",
3
+ "version": "2.17.5",
4
4
  "description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -271,7 +271,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel,
271
271
  import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem } from '../ui/command'
272
272
  import { motion, AnimatePresence, LayoutGroup, useMotionValue, useTransform, animate } from 'framer-motion'
273
273
  import { format, startOfMonth, endOfMonth, startOfWeek, endOfWeek, addDays, addWeeks, addMonths, addYears, subMonths, subYears, isSameMonth, isSameDay, isToday, isBefore, isAfter, differenceInDays, differenceInWeeks, differenceInMonths, parseISO, startOfDay, endOfDay, isWithinInterval, eachDayOfInterval, getDay, setHours, setMinutes, startOfYear, endOfYear, eachMonthOfInterval, getDaysInMonth, getWeek, startOfISOWeek, endOfISOWeek, addHours, subHours, isSameHour, differenceInHours, differenceInMinutes, addMinutes, subMinutes, isSameMinute, setSeconds, setMilliseconds, subDays, subWeeks } from 'date-fns'
274
- import { DragDropContext, Droppable, Draggable, DropResult, DraggableProvided, DraggableStateSnapshot, DroppableProvided } from 'react-beautiful-dnd'
274
+ // Removed react-beautiful-dnd imports - using HTML5 drag & drop instead
275
275
  import { Calendar as CalendarBase } from '../ui/calendar'
276
276
  import { HexColorPicker } from 'react-colorful'
277
277
 
@@ -441,6 +441,9 @@ export const CalendarPro = React.forwardRef<HTMLDivElement, CalendarProProps>(({
441
441
  theme = 'system',
442
442
  ...props
443
443
  }, ref) => {
444
+ // Drag state
445
+ const [draggedEventId, setDraggedEventId] = useState<string | null>(null)
446
+ const [dragOverInfo, setDragOverInfo] = useState<{ date: Date; hour?: number } | null>(null)
444
447
  const [internalSidebarCollapsed, setInternalSidebarCollapsed] = useState(false)
445
448
  const sidebarCollapsed = controlledSidebarCollapsed ?? internalSidebarCollapsed
446
449
 
@@ -617,29 +620,91 @@ export const CalendarPro = React.forwardRef<HTMLDivElement, CalendarProProps>(({
617
620
  }, [selectedEvent, onEventDelete])
618
621
 
619
622
  // Handle drag start
620
- const handleDragStart = useCallback((event: CalendarEvent) => {
623
+ const handleDragStart = useCallback((e: React.DragEvent, event: CalendarEvent) => {
621
624
  if (!allowEventDragging) return
625
+
626
+ setDraggedEventId(event.id)
622
627
  setIsDragging(true)
623
- setDraggedEvent(event)
628
+
629
+ // Store event data in dataTransfer
630
+ e.dataTransfer.effectAllowed = 'move'
631
+ e.dataTransfer.setData('text/plain', event.id)
632
+
633
+ // Create drag image with preserved dimensions
634
+ const dragImage = e.currentTarget.cloneNode(true) as HTMLElement
635
+ const originalRect = e.currentTarget.getBoundingClientRect()
636
+ dragImage.style.opacity = '0.8'
637
+ dragImage.style.position = 'absolute'
638
+ dragImage.style.top = '-1000px'
639
+ dragImage.style.width = `${originalRect.width}px`
640
+ dragImage.style.height = `${originalRect.height}px`
641
+ dragImage.style.boxSizing = 'border-box'
642
+ document.body.appendChild(dragImage)
643
+ e.dataTransfer.setDragImage(dragImage, e.nativeEvent.offsetX, e.nativeEvent.offsetY)
644
+ setTimeout(() => document.body.removeChild(dragImage), 0)
624
645
  }, [allowEventDragging])
625
646
 
626
- // Handle drag end
627
- const handleDragEnd = useCallback((result: DropResult) => {
628
- setIsDragging(false)
629
- setDraggedEvent(null)
630
- setDropTarget(null)
647
+ // Handle drag over
648
+ const handleDragOver = useCallback((e: React.DragEvent, date: Date, hour?: number) => {
649
+ e.preventDefault()
650
+ e.dataTransfer.dropEffect = 'move'
651
+ setDragOverInfo({ date, hour })
652
+ }, [])
653
+
654
+ // Handle drag leave
655
+ const handleDragLeave = useCallback((e: React.DragEvent) => {
656
+ // Only clear if we're leaving the drop zone entirely
657
+ const rect = e.currentTarget.getBoundingClientRect()
658
+ const x = e.clientX
659
+ const y = e.clientY
660
+
661
+ if (x < rect.left || x >= rect.right || y < rect.top || y >= rect.bottom) {
662
+ setDragOverInfo(null)
663
+ }
664
+ }, [])
665
+
666
+ // Handle drop
667
+ const handleDrop = useCallback((e: React.DragEvent, date: Date, hour?: number) => {
668
+ e.preventDefault()
669
+
670
+ const eventId = e.dataTransfer.getData('text/plain')
671
+ const draggedEvent = events.find(ev => ev.id === eventId)
672
+
673
+ if (!draggedEvent || !onEventDrop) return
674
+
675
+ // Calculate new start and end times
676
+ let newStart: Date
677
+ let newEnd: Date
631
678
 
632
- if (!result.destination || !draggedEvent || !onEventDrop) return
679
+ if (hour !== undefined) {
680
+ // Dropped on a specific hour slot
681
+ newStart = setHours(setMinutes(date, 0), hour)
682
+ } else {
683
+ // Dropped on a day (keep original time)
684
+ const originalHours = draggedEvent.start.getHours()
685
+ const originalMinutes = draggedEvent.start.getMinutes()
686
+ newStart = setHours(setMinutes(date, originalMinutes), originalHours)
687
+ }
633
688
 
634
- // Calculate new start and end dates based on drop position
635
- // This is a simplified version - you'd need to implement proper date calculation
636
- // based on the view and drop position
637
- const newStart = new Date(result.destination.droppableId)
689
+ // Keep the same duration
638
690
  const duration = differenceInMinutes(draggedEvent.end, draggedEvent.start)
639
- const newEnd = addMinutes(newStart, duration)
691
+ newEnd = addMinutes(newStart, duration)
640
692
 
693
+ // Update event
641
694
  onEventDrop(draggedEvent.id, newStart, newEnd)
642
- }, [draggedEvent, onEventDrop])
695
+
696
+ // Reset drag state
697
+ setDraggedEventId(null)
698
+ setDragOverInfo(null)
699
+ setIsDragging(false)
700
+ }, [events, onEventDrop])
701
+
702
+ // Handle drag end (cleanup)
703
+ const handleDragEnd = useCallback(() => {
704
+ setDraggedEventId(null)
705
+ setDragOverInfo(null)
706
+ setIsDragging(false)
707
+ }, [])
643
708
 
644
709
  // Export calendar
645
710
  const exportCalendar = useCallback((format: 'ics' | 'csv' | 'json') => {
@@ -721,7 +786,15 @@ END:VCALENDAR`
721
786
  <div className="flex-1 overflow-auto">
722
787
  <div className="min-h-full">
723
788
  {/* All day events */}
724
- <div className="border-b p-2">
789
+ <div
790
+ className={cn(
791
+ "border-b p-2",
792
+ dragOverInfo?.date && !dragOverInfo?.hour && isSameDay(dragOverInfo.date, currentDate) && "bg-primary/10"
793
+ )}
794
+ onDragOver={(e) => handleDragOver(e, currentDate)}
795
+ onDragLeave={handleDragLeave}
796
+ onDrop={(e) => handleDrop(e, currentDate)}
797
+ >
725
798
  <div className="text-xs text-muted-foreground mb-1">All Day</div>
726
799
  <div className="space-y-1">
727
800
  {dayEvents
@@ -729,10 +802,14 @@ END:VCALENDAR`
729
802
  .map(event => (
730
803
  <div
731
804
  key={event.id}
805
+ draggable={allowEventDragging}
806
+ onDragStart={(e) => handleDragStart(e, event)}
807
+ onDragEnd={handleDragEnd}
732
808
  className="p-2 rounded text-xs cursor-pointer hover:opacity-80"
733
809
  style={{
734
810
  backgroundColor: event.color || eventColors[event.category || ''] || '#3b82f6',
735
- color: '#ffffff'
811
+ color: '#ffffff',
812
+ opacity: draggedEventId === event.id ? 0.5 : 1
736
813
  }}
737
814
  onClick={(e) => handleEventClick(event, e)}
738
815
  >
@@ -750,7 +827,13 @@ END:VCALENDAR`
750
827
  {format(setHours(new Date(), hour), timeFormat === '12h' ? 'h a' : 'HH:00')}
751
828
  </div>
752
829
  <div
753
- className="flex-1 relative border-l cursor-pointer hover:bg-muted/20"
830
+ className={cn(
831
+ "flex-1 relative border-l cursor-pointer hover:bg-muted/20",
832
+ dragOverInfo?.date && dragOverInfo?.hour === hour && isSameDay(dragOverInfo.date, currentDate) && "bg-primary/10"
833
+ )}
834
+ onDragOver={(e) => handleDragOver(e, currentDate, hour)}
835
+ onDragLeave={handleDragLeave}
836
+ onDrop={(e) => handleDrop(e, currentDate, hour)}
754
837
  onClick={() => {
755
838
  if (allowEventCreation) {
756
839
  const clickedTime = setHours(setMinutes(currentDate, 0), hour)
@@ -783,13 +866,18 @@ END:VCALENDAR`
783
866
  return (
784
867
  <div
785
868
  key={event.id}
869
+ draggable={allowEventDragging}
870
+ onDragStart={(e) => handleDragStart(e, event)}
871
+ onDragEnd={handleDragEnd}
786
872
  className="absolute left-0 right-0 mx-1 p-1 rounded text-xs cursor-pointer hover:opacity-80 overflow-hidden"
787
873
  style={{
788
874
  top: `${top}px`,
789
875
  height: `${height}px`,
790
876
  backgroundColor: event.color || eventColors[event.category || ''] || '#3b82f6',
791
877
  color: '#ffffff',
792
- zIndex: 10
878
+ zIndex: 10,
879
+ opacity: draggedEventId === event.id ? 0.5 : 1,
880
+ cursor: allowEventDragging ? 'move' : 'pointer'
793
881
  }}
794
882
  onClick={(e) => {
795
883
  e.stopPropagation()
@@ -860,14 +948,17 @@ END:VCALENDAR`
860
948
  const dayEvents = eventsInView.filter(event =>
861
949
  isSameDay(new Date(event.start), day) && !event.allDay
862
950
  )
863
-
864
951
  return (
865
952
  <div
866
953
  key={day.toISOString()}
867
954
  className={cn(
868
955
  "flex-1 relative border-l border-b cursor-pointer hover:bg-muted/20",
869
- isToday(day) && "bg-primary/5"
956
+ isToday(day) && "bg-primary/5",
957
+ dragOverInfo?.date && dragOverInfo?.hour === hour && isSameDay(dragOverInfo.date, day) && "bg-primary/10"
870
958
  )}
959
+ onDragOver={(e) => handleDragOver(e, day, hour)}
960
+ onDragLeave={handleDragLeave}
961
+ onDrop={(e) => handleDrop(e, day, hour)}
871
962
  onClick={() => {
872
963
  if (allowEventCreation) {
873
964
  const clickedTime = setHours(setMinutes(day, 0), hour)
@@ -898,13 +989,18 @@ END:VCALENDAR`
898
989
  return (
899
990
  <div
900
991
  key={event.id}
992
+ draggable={allowEventDragging}
993
+ onDragStart={(e) => handleDragStart(e, event)}
994
+ onDragEnd={handleDragEnd}
901
995
  className="absolute left-0 right-0 mx-1 p-1 rounded text-xs cursor-pointer hover:opacity-80 overflow-hidden"
902
996
  style={{
903
997
  top: `${top}px`,
904
998
  height: `${height}px`,
905
999
  backgroundColor: event.color || eventColors[event.category || ''] || '#3b82f6',
906
1000
  color: '#ffffff',
907
- zIndex: 10
1001
+ zIndex: 10,
1002
+ opacity: draggedEventId === event.id ? 0.5 : 1,
1003
+ cursor: allowEventDragging ? 'move' : 'pointer'
908
1004
  }}
909
1005
  onClick={(e) => {
910
1006
  e.stopPropagation()
@@ -971,8 +1067,12 @@ END:VCALENDAR`
971
1067
  "min-h-[100px] p-2 border rounded-lg cursor-pointer transition-colors",
972
1068
  !isCurrentMonth && "opacity-50",
973
1069
  isToday(day) && "bg-primary/10 border-primary",
974
- "hover:bg-muted/50"
1070
+ "hover:bg-muted/50",
1071
+ dragOverInfo?.date && !dragOverInfo?.hour && isSameDay(dragOverInfo.date, day) && "bg-primary/20 border-primary"
975
1072
  )}
1073
+ onDragOver={(e) => handleDragOver(e, day)}
1074
+ onDragLeave={handleDragLeave}
1075
+ onDrop={(e) => handleDrop(e, day)}
976
1076
  onClick={() => handleDateSelect(day)}
977
1077
  >
978
1078
  <div className={cn(
@@ -986,10 +1086,15 @@ END:VCALENDAR`
986
1086
  return (
987
1087
  <motion.div
988
1088
  key={event.id}
1089
+ draggable={allowEventDragging}
1090
+ onDragStart={(e) => handleDragStart(e, event)}
1091
+ onDragEnd={handleDragEnd}
989
1092
  className="text-xs p-1 rounded cursor-pointer truncate"
990
1093
  style={{
991
1094
  backgroundColor: event.color || eventColors[event.category || ''] || '#3b82f6',
992
- color: '#ffffff'
1095
+ color: '#ffffff',
1096
+ opacity: draggedEventId === event.id ? 0.5 : 1,
1097
+ cursor: allowEventDragging ? 'move' : 'pointer'
993
1098
  }}
994
1099
  whileHover={{ scale: 1.02 }}
995
1100
  whileTap={{ scale: 0.98 }}
@@ -1057,8 +1162,8 @@ END:VCALENDAR`
1057
1162
  </CardHeader>
1058
1163
  <CardContent>
1059
1164
  <div className="grid grid-cols-7 gap-1 text-xs">
1060
- {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map(day => (
1061
- <div key={day} className="text-center text-muted-foreground p-1">
1165
+ {['S', 'M', 'T', 'W', 'T', 'F', 'S'].map((day, index) => (
1166
+ <div key={`${day}-${index}`} className="text-center text-muted-foreground p-1">
1062
1167
  {day}
1063
1168
  </div>
1064
1169
  ))}