@open-webapp/calendar 0.6.0 → 0.6.1
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/dist/react/CalendarPane.js +16 -9
- package/dist/styles.css +9 -2
- package/package.json +1 -1
|
@@ -130,6 +130,7 @@ export function CalendarPane(props) {
|
|
|
130
130
|
const hasScrolledForEventsRef = useRef(false);
|
|
131
131
|
const paneRef = useRef(null);
|
|
132
132
|
const chipsRef = useRef(null);
|
|
133
|
+
const scrollRef = useRef(null);
|
|
133
134
|
const popupRef = useRef(null);
|
|
134
135
|
const [now, setNow] = useState(() => new Date());
|
|
135
136
|
const [savedSelection, setSavedSelection] = useState(null);
|
|
@@ -274,15 +275,21 @@ export function CalendarPane(props) {
|
|
|
274
275
|
if (!chipsEl || !paneEl)
|
|
275
276
|
return;
|
|
276
277
|
const observer = new ResizeObserver((entries) => {
|
|
277
|
-
const entry
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
278
|
+
for (const entry of entries) {
|
|
279
|
+
if (entry.target === scrollRef.current) {
|
|
280
|
+
// The day ribbon centers its label in the visible scroll area, so it needs that height.
|
|
281
|
+
paneEl.style.setProperty('--calendar-scroll-height', `${entry.target.getBoundingClientRect().height}px`);
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
// contentRect excludes padding; the sticky day-header offset needs the
|
|
285
|
+
// chip row's full border-box height (chips have vertical padding).
|
|
286
|
+
const height = entry.borderBoxSize?.[0]?.blockSize ?? entry.target.getBoundingClientRect().height;
|
|
287
|
+
paneEl.style.setProperty('--chip-row-height', `${height}px`);
|
|
288
|
+
}
|
|
284
289
|
});
|
|
285
290
|
observer.observe(chipsEl);
|
|
291
|
+
if (scrollRef.current)
|
|
292
|
+
observer.observe(scrollRef.current);
|
|
286
293
|
return () => observer.disconnect();
|
|
287
294
|
}, [connected, needsReauth]);
|
|
288
295
|
if (!connected) {
|
|
@@ -298,14 +305,14 @@ export function CalendarPane(props) {
|
|
|
298
305
|
const loading = ctrlState.loading && filteredEvents.length === 0;
|
|
299
306
|
const emptyStateText = 'No matching events in the next 30 days';
|
|
300
307
|
const showCalendarSelector = calendarSources.length > 0;
|
|
301
|
-
return (_jsxs("div", { className: "calendar-pane", "data-calendar-theme": theme, ref: paneRef, children: [_jsxs("div", { className: "calendar-pane-scroll", children: [_jsxs("div", { className: "calendar-rsvp-chips", ref: chipsRef, children: [_jsx("button", { type: "button", className: "calendar-rsvp-chip calendar-scroll-today-btn", "aria-label": "Scroll to today", title: "Scroll to today", onClick: () => recenter('smooth'), children: _jsxs("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [_jsx("rect", { x: "2", y: "3", width: "11", height: "10", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }), _jsx("path", { d: "M2 6H13", stroke: "currentColor", strokeWidth: "1.2" }), _jsx("path", { d: "M5 2V4M10 2V4", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }), _jsx("circle", { cx: "7.5", cy: "9.5", r: "1.3", fill: "currentColor" })] }) }), RSVP_CHIPS.map((chip) => (_jsxs("button", { type: "button", className: `calendar-rsvp-chip${(chip.status === 'needsAction' ? isExclusive : selectedRsvpStatuses.has(chip.status)) ? ' selected' : ''}`, "aria-pressed": chip.status === 'needsAction' ? isExclusive : selectedRsvpStatuses.has(chip.status), "aria-label": chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, title: chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, onClick: () => chip.status === 'needsAction' ? handleUnaccepted() : handleToggle(chip.status), children: [chip.icon, chip.status === 'needsAction' && (_jsx("span", { className: "calendar-rsvp-chip-badge", "aria-hidden": "true", children: unacceptedCount > 99 ? '99+' : unacceptedCount }))] }, chip.status)))] }), needsScopeSources.map((s) => (_jsx("div", { children: props.sourceNotice?.(s) }, s.id))), error && (_jsx("div", { className: "empty-state calendar-empty-state", role: "alert", children: _jsx("p", { children: "Couldn't load calendar events. Try again shortly." }) })), !(error && filteredEvents.length === 0) && (_jsxs("div", { className: "calendar-day-groups", children: [dayGroups.map((group) => (_jsxs("div", { className: "calendar-day-group", children: [_jsx("div", { className: "calendar-day-header", ref: (el) => {
|
|
308
|
+
return (_jsxs("div", { className: "calendar-pane", "data-calendar-theme": theme, ref: paneRef, children: [_jsxs("div", { className: "calendar-pane-scroll", ref: scrollRef, children: [_jsxs("div", { className: "calendar-rsvp-chips", ref: chipsRef, children: [_jsx("button", { type: "button", className: "calendar-rsvp-chip calendar-scroll-today-btn", "aria-label": "Scroll to today", title: "Scroll to today", onClick: () => recenter('smooth'), children: _jsxs("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [_jsx("rect", { x: "2", y: "3", width: "11", height: "10", rx: "1.5", stroke: "currentColor", strokeWidth: "1.2" }), _jsx("path", { d: "M2 6H13", stroke: "currentColor", strokeWidth: "1.2" }), _jsx("path", { d: "M5 2V4M10 2V4", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round" }), _jsx("circle", { cx: "7.5", cy: "9.5", r: "1.3", fill: "currentColor" })] }) }), RSVP_CHIPS.map((chip) => (_jsxs("button", { type: "button", className: `calendar-rsvp-chip${(chip.status === 'needsAction' ? isExclusive : selectedRsvpStatuses.has(chip.status)) ? ' selected' : ''}`, "aria-pressed": chip.status === 'needsAction' ? isExclusive : selectedRsvpStatuses.has(chip.status), "aria-label": chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, title: chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, onClick: () => chip.status === 'needsAction' ? handleUnaccepted() : handleToggle(chip.status), children: [chip.icon, chip.status === 'needsAction' && (_jsx("span", { className: "calendar-rsvp-chip-badge", "aria-hidden": "true", children: unacceptedCount > 99 ? '99+' : unacceptedCount }))] }, chip.status)))] }), needsScopeSources.map((s) => (_jsx("div", { children: props.sourceNotice?.(s) }, s.id))), error && (_jsx("div", { className: "empty-state calendar-empty-state", role: "alert", children: _jsx("p", { children: "Couldn't load calendar events. Try again shortly." }) })), !(error && filteredEvents.length === 0) && (_jsxs("div", { className: "calendar-day-groups", children: [dayGroups.map((group) => (_jsxs("div", { className: "calendar-day-group", children: [_jsx("div", { className: "calendar-day-header", ref: (el) => {
|
|
302
309
|
if (el) {
|
|
303
310
|
dayHeaderRefs.current.set(group.dateKey, el);
|
|
304
311
|
}
|
|
305
312
|
else {
|
|
306
313
|
dayHeaderRefs.current.delete(group.dateKey);
|
|
307
314
|
}
|
|
308
|
-
}, children: formatDayHeader(group.dateKey, todayIso) }), group.events.length > 0 && (_jsxs("div", { className: "calendar-day-body", children: [_jsx("div", { className: "calendar-day-ribbon", "aria-hidden": "true", "data-today": group.dateKey === todayIso ? 'true' : undefined, children: _jsx("span", { className: "calendar-day-ribbon-label", children: formatRibbonLabel(group.dateKey) }) }), _jsx("div", { className: "calendar-day-events", children: group.events.map((event) => {
|
|
315
|
+
}, children: formatDayHeader(group.dateKey, todayIso) }), group.events.length > 0 && (_jsxs("div", { className: "calendar-day-body", children: [_jsx("div", { className: "calendar-day-ribbon", "aria-hidden": "true", "data-today": group.dateKey === todayIso ? 'true' : undefined, children: _jsx("div", { className: "calendar-day-ribbon-window", children: _jsx("span", { className: "calendar-day-ribbon-label", children: formatRibbonLabel(group.dateKey) }) }) }), _jsx("div", { className: "calendar-day-events", children: group.events.map((event) => {
|
|
309
316
|
const eventKey = getCalendarEventKey(event);
|
|
310
317
|
const calendar = calendarsByKey.get(`${event.sourceId}\u0000${event.calendarId}`);
|
|
311
318
|
const showCalendarLabel = calendar && !calendar.primary;
|
package/dist/styles.css
CHANGED
|
@@ -222,11 +222,18 @@
|
|
|
222
222
|
color: var(--calendar-chip-selected-text);
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
+
.calendar-day-ribbon-window {
|
|
226
|
+
position: sticky;
|
|
227
|
+
top: calc(var(--chip-row-height, 44px) + var(--calendar-day-header-height, 33px));
|
|
228
|
+
/* Visible part of the ribbon: as tall as the scroll area below the sticky headers, capped at the ribbon. */
|
|
229
|
+
height: min(100%, calc(var(--calendar-scroll-height, 100vh) - var(--chip-row-height, 44px) - var(--calendar-day-header-height, 33px)));
|
|
230
|
+
display: flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
}
|
|
233
|
+
|
|
225
234
|
.calendar-day-ribbon-label {
|
|
226
235
|
writing-mode: vertical-rl;
|
|
227
236
|
transform: rotate(180deg);
|
|
228
|
-
position: sticky;
|
|
229
|
-
top: calc(var(--chip-row-height, 44px) + var(--calendar-day-header-height, 33px));
|
|
230
237
|
white-space: nowrap;
|
|
231
238
|
padding: 6px 0;
|
|
232
239
|
}
|