Skip to content

Commit 144d940

Browse files
feat: event resize
1 parent d8e6c6d commit 144d940

1 file changed

Lines changed: 103 additions & 71 deletions

File tree

examples/react/basic/src/index.tsx

Lines changed: 103 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -507,13 +507,11 @@ function ScheduleView({
507507

508508
// Check if this segment's day is within the preview range
509509
const previewAffectsThisDay =
510-
previewStartDateStr === dayDate ||
511-
previewEndDateStr === dayDate ||
512-
(previewStartDateStr < dayDate && previewEndDateStr > dayDate)
510+
dayDate >= previewStartDateStr && dayDate <= previewEndDateStr
513511

514-
// Check if this segment is being shrunk away (not in preview range anymore)
515-
const isBeingShrunkAway =
516-
isThisSegmentBeingResized && !previewAffectsThisDay
512+
// Check if this segment should be hidden (not in preview range anymore)
513+
// This applies to ANY segment of the event being resized, not just the edge being resized
514+
const isBeingShrunkAway = !previewAffectsThisDay
517515

518516
// Check if the preview has actually changed from the original event bounds
519517
const hasPreviewChanged =
@@ -523,48 +521,46 @@ function ScheduleView({
523521
if (isBeingShrunkAway) {
524522
// This segment is being removed by the resize, hide it
525523
shouldHideSegment = true
526-
} else if (isThisSegmentBeingResized && isSpanningMultipleDays && previewAffectsThisDay) {
527-
// Extending to another day - use multi-day style with SEGMENT bounds
528-
previewStyle = calculateOriginalSegmentStyleForMultiDay(
529-
segmentStart,
530-
segmentEnd,
531-
resizeState.edge,
532-
true,
533-
)
534-
} else if (isThisSegmentBeingResized && !isSpanningMultipleDays && hasPreviewChanged) {
535-
// Normal resize within same day - only apply if preview actually changed
536-
// For multi-day events, the segment always starts at midnight (for non-first segments)
537-
// and ends at end of day (for non-last segments), except for the actual boundaries
538-
const effectivePreviewStart = resizeState.edge === 'top' && previewStartDateStr === dayDate
539-
? resizeState.previewStart
540-
: segmentStart
541-
const effectivePreviewEnd = resizeState.edge === 'bottom' && previewEndDateStr === dayDate
542-
? resizeState.previewEnd
543-
: segmentEnd
544-
545-
previewStyle = calculatePreviewStyleForSegment(
546-
effectivePreviewStart,
547-
effectivePreviewEnd,
548-
segmentStart,
549-
segmentEnd,
550-
resizeState.edge,
551-
)
552-
} else if (!isThisSegmentBeingResized && previewAffectsThisDay && hasPreviewChanged) {
553-
// This segment is newly affected by the resize (e.g., shrinking to this day)
554-
// Check if this is the new "last segment" for bottom resize
555-
const isNewLastSegment =
556-
resizeState.edge === 'bottom' && previewEndDateStr === dayDate
557-
const isNewFirstSegment =
558-
resizeState.edge === 'top' && previewStartDateStr === dayDate
559-
560-
if (isNewLastSegment || isNewFirstSegment) {
561-
previewStyle = calculatePreviewStyleForSegment(
562-
resizeState.previewStart,
563-
resizeState.previewEnd,
564-
segmentStart,
565-
segmentEnd,
566-
resizeState.edge,
567-
)
524+
} else if (previewAffectsThisDay && hasPreviewChanged) {
525+
// This segment is within the preview range - calculate its new bounds
526+
const isPreviewFirstDay = previewStartDateStr === dayDate
527+
const isPreviewLastDay = previewEndDateStr === dayDate
528+
529+
// Calculate the effective start and end for this segment in the preview
530+
let effectiveStart: string
531+
let effectiveEnd: string
532+
533+
if (isPreviewFirstDay && isPreviewLastDay) {
534+
// Single day event - use exact preview times
535+
effectiveStart = resizeState.previewStart
536+
effectiveEnd = resizeState.previewEnd
537+
} else if (isPreviewFirstDay) {
538+
// First day of multi-day - start at preview start, end at end of day
539+
effectiveStart = resizeState.previewStart
540+
effectiveEnd = `${dayDate}T23:59:59`
541+
} else if (isPreviewLastDay) {
542+
// Last day of multi-day - start at beginning of day, end at preview end
543+
effectiveStart = `${dayDate}T00:00:00`
544+
effectiveEnd = resizeState.previewEnd
545+
} else {
546+
// Middle day - full day
547+
effectiveStart = `${dayDate}T00:00:00`
548+
effectiveEnd = `${dayDate}T23:59:59`
549+
}
550+
551+
// Calculate preview style from effective times
552+
const startDate = new Date(effectiveStart)
553+
const endDate = new Date(effectiveEnd)
554+
const startMinutes = startDate.getHours() * 60 + startDate.getMinutes()
555+
const endMinutes = endDate.getHours() * 60 + endDate.getMinutes() || MINUTES_IN_DAY
556+
const topPercent = (startMinutes / MINUTES_IN_DAY) * 100
557+
const heightPercent = ((endMinutes - startMinutes) / MINUTES_IN_DAY) * 100
558+
559+
if (heightPercent > 0) {
560+
previewStyle = {
561+
top: `${topPercent}%`,
562+
height: `${Math.max(heightPercent, (30 / MINUTES_IN_DAY) * 100)}%`,
563+
}
568564
}
569565
}
570566
}
@@ -585,19 +581,23 @@ function ScheduleView({
585581
if (isBeingResized && resizeState.previewStart && resizeState.previewEnd) {
586582
const previewEndDateStr = resizeState.previewEnd.split('T')[0]
587583
const previewStartDateStr = resizeState.previewStart.split('T')[0]
584+
const previewAffectsThisDay = dayDate >= previewStartDateStr && dayDate <= previewEndDateStr
585+
586+
if (previewAffectsThisDay) {
587+
const isPreviewFirstDay = previewStartDateStr === dayDate
588+
const isPreviewLastDay = previewEndDateStr === dayDate
588589

589-
if (resizeState.edge === 'top') {
590-
// For top edge resize, update start if this is the new first segment
591-
if (previewStartDateStr === dayDate) {
590+
// Update display times based on position in preview range
591+
if (isPreviewFirstDay) {
592592
displayStart = resizeState.previewStart
593+
} else {
594+
displayStart = `${dayDate}T00:00:00`
593595
}
594-
} else if (resizeState.edge === 'bottom') {
595-
// For bottom edge resize, update end if this is the new last segment
596-
if (previewEndDateStr === dayDate) {
596+
597+
if (isPreviewLastDay) {
597598
displayEnd = resizeState.previewEnd
598-
} else if (isThisSegmentBeingResized && previewEndDateStr !== segmentStartDate) {
599-
// Extending to next day - show end of day for current segment
600-
displayEnd = `${segmentStartDate}T23:59:00`
599+
} else {
600+
displayEnd = `${dayDate}T23:59:00`
601601
}
602602
}
603603
}
@@ -673,43 +673,75 @@ function ScheduleView({
673673
</div>
674674
)
675675
})}
676-
{/* Ghost preview on target day when resizing across days */}
676+
{/* Ghost preview on ALL days in preview range when resizing across days */}
677677
{resizeState.isResizing &&
678-
resizeState.targetDayDate === dayDate &&
679678
resizeState.previewStart &&
680679
resizeState.previewEnd &&
681680
(() => {
682681
const previewStartDate = resizeState.previewStart.split('T')[0]
683682
const previewEndDate = resizeState.previewEnd.split('T')[0]
684683

684+
// Check if this day already has a segment of the event being resized
685685
const eventOnThisDay = day.events.some(
686686
(e) => e.id === resizeState.eventId,
687687
)
688+
689+
// Check if this day is within the new preview range
688690
const isDayInPreviewRange =
689691
dayDate >= previewStartDate && dayDate <= previewEndDate
690692

693+
// Show ghost on days that are in the preview range but don't have an existing segment
691694
if (!eventOnThisDay && isDayInPreviewRange) {
692-
const ghostStyle = calculateGhostPreviewStyle(
693-
resizeState.previewStart,
694-
resizeState.previewEnd,
695-
resizeState.edge,
696-
)
695+
// Calculate ghost style based on position in the range
696+
const isFirstDay = dayDate === previewStartDate
697+
const isLastDay = dayDate === previewEndDate
698+
699+
let ghostTop: number
700+
let ghostBottom: number
701+
702+
if (isFirstDay && isLastDay) {
703+
// Single day - use actual times
704+
const startDate = new Date(resizeState.previewStart)
705+
const endDate = new Date(resizeState.previewEnd)
706+
ghostTop = (startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY * 100
707+
ghostBottom = (endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY * 100
708+
} else if (isFirstDay) {
709+
// First day of multi-day range
710+
const startDate = new Date(resizeState.previewStart)
711+
ghostTop = (startDate.getHours() * 60 + startDate.getMinutes()) / MINUTES_IN_DAY * 100
712+
ghostBottom = 100 // End of day
713+
} else if (isLastDay) {
714+
// Last day of multi-day range
715+
const endDate = new Date(resizeState.previewEnd)
716+
ghostTop = 0 // Start of day
717+
ghostBottom = (endDate.getHours() * 60 + endDate.getMinutes()) / MINUTES_IN_DAY * 100
718+
} else {
719+
// Middle day - full day
720+
ghostTop = 0
721+
ghostBottom = 100
722+
}
723+
724+
const ghostHeight = ghostBottom - ghostTop
725+
if (ghostHeight <= 0) return null
697726

698-
if (!ghostStyle) return null
727+
const ghostStyle = {
728+
top: `${ghostTop}%`,
729+
height: `${Math.max(ghostHeight, (30 / MINUTES_IN_DAY) * 100)}%`,
730+
}
699731

700732
// Calculate display times for the ghost
701-
const ghostStartTime = resizeState.edge === 'bottom'
702-
? '00:00'
703-
: new Date(resizeState.previewStart).toLocaleTimeString('en-US', {
733+
const ghostStartTime = isFirstDay
734+
? new Date(resizeState.previewStart).toLocaleTimeString('en-US', {
704735
hour: 'numeric',
705736
minute: '2-digit',
706737
})
707-
const ghostEndTime = resizeState.edge === 'top'
708-
? '11:59 PM'
709-
: new Date(resizeState.previewEnd).toLocaleTimeString('en-US', {
738+
: '12:00 AM'
739+
const ghostEndTime = isLastDay
740+
? new Date(resizeState.previewEnd).toLocaleTimeString('en-US', {
710741
hour: 'numeric',
711742
minute: '2-digit',
712743
})
744+
: '11:59 PM'
713745

714746
return (
715747
<div

0 commit comments

Comments
 (0)