diff --git a/frontend/src/components/calendar/EventDetailPanel.tsx b/frontend/src/components/calendar/EventDetailPanel.tsx index 33adc6d..541c7ed 100644 --- a/frontend/src/components/calendar/EventDetailPanel.tsx +++ b/frontend/src/components/calendar/EventDetailPanel.tsx @@ -290,8 +290,10 @@ export default function EventDetailPanel({ useEffect(() => { const el = descRef.current; if (!el) return; - el.style.height = 'auto'; - el.style.height = `${el.scrollHeight}px`; + requestAnimationFrame(() => { + el.style.height = 'auto'; + el.style.height = `${el.scrollHeight}px`; + }); }, [editState.description, isEditing]); // Poll lock status in view mode for shared events (Stream A: real-time lock awareness) @@ -376,11 +378,11 @@ export default function EventDetailPanel({ end_datetime: endDt, all_day: data.all_day, location_id: data.location_id ? parseInt(data.location_id) : null, - is_starred: data.is_starred, - recurrence_rule: rule, }; - // Invited editors cannot change calendars — omit calendar_id from payload + // Invited editors are restricted to the backend allowlist — omit fields they cannot modify if (!canModifyAsInvitee) { + payload.is_starred = data.is_starred; + payload.recurrence_rule = rule; payload.calendar_id = data.calendar_id ? parseInt(data.calendar_id) : null; } @@ -548,6 +550,7 @@ export default function EventDetailPanel({ : event?.title || ''; return ( + // onWheel stopPropagation: defence-in-depth with CalendarPage's panelOpen guard to prevent month-scroll bleed
e.stopPropagation()}> {/* Header */}
@@ -866,18 +869,6 @@ export default function EventDetailPanel({
)} - {/* Star for invited editors (no recurrence row shown) */} - {canModifyAsInvitee && ( -
- updateField('is_starred', (e.target as HTMLInputElement).checked)} - /> - -
- )} - {editState.recurrence_type === 'every_n_days' && (
@@ -955,7 +946,7 @@ export default function EventDetailPanel({ value={editState.description} onChange={(e) => updateField('description', e.target.value)} placeholder="Add a description..." - className="text-sm resize-y flex-1 min-h-[80px]" + className="text-sm flex-1 min-h-[80px]" />
diff --git a/frontend/src/components/calendar/EventForm.tsx b/frontend/src/components/calendar/EventForm.tsx index b24f770..2884b88 100644 --- a/frontend/src/components/calendar/EventForm.tsx +++ b/frontend/src/components/calendar/EventForm.tsx @@ -146,8 +146,10 @@ export default function EventForm({ event, templateData, templateName, initialSt useEffect(() => { const el = descRef.current; if (!el) return; - el.style.height = 'auto'; - el.style.height = `${el.scrollHeight}px`; + requestAnimationFrame(() => { + el.style.height = 'auto'; + el.style.height = `${el.scrollHeight}px`; + }); }, [formData.description]); const selectableCalendars = calendars.filter((c) => !c.is_system); @@ -269,7 +271,7 @@ export default function EventForm({ event, templateData, templateName, initialSt value={formData.description} onChange={(e) => setFormData({ ...formData, description: e.target.value })} placeholder="Add a description..." - className="min-h-[80px] resize-y text-sm" + className="min-h-[80px] text-sm" />