@open-webapp/calendar 0.8.0 → 0.8.2

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/README.md CHANGED
@@ -201,6 +201,8 @@ import '@open-webapp/calendar/styles.css';
201
201
 
202
202
  ### Theme behavior
203
203
 
204
+ Timed meeting headers keep the time left and `[Join] [RSVP glyph]` right, with a 4px gap; title and organizer follow below. Join retains its text and fits it at an intrinsic width, matching the RSVP glyph's 24px outer height, 1px border, 4px radius and exact status foreground/background/border for accepted, tentative, needsAction and declined in every theme. Hover underlines Join; keyboard focus has a visible theme-colored outline. Without a meeting URL only the right-aligned RSVP glyph appears. The pair stays together when a narrow header wraps. Join keeps its original URL, new-tab attributes and click propagation behavior.
205
+
204
206
  Both components follow the OS/browser `prefers-color-scheme` preference live in `'system'` mode; omitting `theme` preserves this default. Explicit `'light'` and `'dark'` ignore OS changes. Hosts can change the prop on a mounted component (including back to `'system'` or `undefined`) without remounting, closing an open dropdown, losing its search query, focus or keyboard-active option, changing selected calendars, or resetting the pane's current RSVP selection. Theme changes do not trigger selection callbacks or controller refreshes.
205
207
 
206
208
  Each pane forwards its requested mode to its unified grouped footer selector, including both account groups, account-local actions and the shared search. The single-trigger structure and cross-account keyboard navigation are preserved; the approved trigger geometry exception is described above. Standalone selectors choose their own mode: an omitted/system selector follows the OS even inside an explicitly dark or light pane. Adjacent and nested instances can use opposite modes independently; no document/body theme switch is applied.
@@ -1,4 +1,4 @@
1
- import { type JSX, type ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  import type { CalendarEvent, RsvpStatus, Source } from '../core/types.js';
3
3
  import type { CalendarController } from '../core/controller.js';
4
4
  export type RsvpSelection = Set<RsvpStatus>;
@@ -21,4 +21,4 @@ export interface CalendarPaneProps {
21
21
  /** Window name used for the event popup. */
22
22
  popupName?: string;
23
23
  }
24
- export declare function CalendarPane(props: CalendarPaneProps): JSX.Element;
24
+ export declare function CalendarPane(props: CalendarPaneProps): import("react").JSX.Element;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useRef, useState } from 'react';
3
3
  import { filterByRsvp, groupByDay, getOrganizerLabel, formatDayHeader, formatRibbonLabel, isEventCurrent, findNextUpcomingEvent, getCalendarEventKey, DEFAULT_RSVP_STATUSES, } from '../core/events.js';
4
4
  import { GroupedCalendarSelector } from './CalendarSelector.js';
@@ -26,24 +26,31 @@ const RSVP_CHIPS = [
26
26
  {
27
27
  status: 'accepted',
28
28
  label: 'Accepted',
29
- icon: (_jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: _jsx("path", { d: "M3 7.7L6 10.7L12 4.3", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })),
29
+ path: 'M5 13l4 4L19 7',
30
30
  },
31
31
  {
32
32
  status: 'tentative',
33
33
  label: 'Maybe',
34
- icon: (_jsxs("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: [_jsx("path", { d: "M5.2 5.6C5.2 4.2 6.2 3.2 7.5 3.2C8.8 3.2 9.8 4.2 9.8 5.4C9.8 6.8 7.6 6.9 7.6 8.8", stroke: "currentColor", strokeWidth: "1.3", strokeLinecap: "round", strokeLinejoin: "round" }), _jsx("circle", { cx: "7.6", cy: "11.2", r: "0.9", fill: "currentColor" })] })),
34
+ path: 'M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z',
35
35
  },
36
36
  {
37
37
  status: 'declined',
38
38
  label: 'Declined',
39
- icon: (_jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: _jsx("path", { d: "M4 4L11 11M11 4L4 11", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) })),
39
+ path: 'M6 18L18 6M6 6l12 12',
40
40
  },
41
41
  {
42
42
  status: 'needsAction',
43
43
  label: 'Unaccepted',
44
- icon: (_jsx("svg", { width: "15", height: "15", viewBox: "0 0 15 15", fill: "none", children: _jsx("circle", { cx: "7.5", cy: "7.5", r: "4.3", stroke: "currentColor", strokeWidth: "1.4" }) })),
44
+ path: 'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z',
45
45
  },
46
46
  ];
47
+ function RsvpGlyph({ path, size = 16, strokeWidth = 2.2 }) {
48
+ return (_jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", focusable: "false", children: _jsx("path", { d: path, stroke: "currentColor", strokeWidth: strokeWidth, strokeLinecap: "round", strokeLinejoin: "round" }) }));
49
+ }
50
+ function RsvpStatusIcon({ status }) {
51
+ const glyph = RSVP_CHIPS.find((chip) => chip.status === status) ?? RSVP_CHIPS[3];
52
+ return (_jsx("span", { className: `calendar-event-rsvp calendar-event-rsvp--${glyph.status}`, role: "img", "aria-label": glyph.status, title: glyph.status, children: _jsx(RsvpGlyph, { path: glyph.path, size: 14, strokeWidth: 2.4 }) }));
53
+ }
47
54
  const DEFAULT_POPUP_NAME = 'notesdiary-cal-event';
48
55
  const POPUP_W = 560;
49
56
  const POPUP_H = 760;
@@ -316,7 +323,7 @@ export function CalendarPane(props) {
316
323
  const loading = ctrlState.loading && filteredEvents.length === 0;
317
324
  const emptyStateText = 'No matching events in the next 30 days';
318
325
  const showCalendarSelector = calendarSources.length > 0;
319
- 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${selectedRsvpStatuses.has(chip.status) ? ' selected' : ''}`, "aria-pressed": selectedRsvpStatuses.has(chip.status), "aria-label": chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, title: chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, onClick: () => 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) => {
326
+ 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("div", { className: "calendar-rsvp-chip-group", role: "group", "aria-label": "RSVP Status Filters", children: RSVP_CHIPS.map((chip) => (_jsxs("button", { type: "button", className: `calendar-rsvp-chip${selectedRsvpStatuses.has(chip.status) ? ' selected' : ''}`, "aria-pressed": selectedRsvpStatuses.has(chip.status), "aria-label": chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, title: chip.status === 'needsAction' ? `${chip.label} (${unacceptedCount})` : chip.label, onClick: () => handleToggle(chip.status), children: [_jsx(RsvpGlyph, { path: chip.path }), chip.status === 'needsAction' && unacceptedCount > 0 && (_jsx("span", { className: "calendar-rsvp-chip-badge", "aria-hidden": "true", children: unacceptedCount > 99 ? '99+' : unacceptedCount }))] }, chip.status))) }), _jsx("button", { type: "button", className: "calendar-today-btn", "aria-label": "Scroll to today", title: "Scroll to today", onClick: () => recenter('smooth'), children: "Today" })] }), 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) => {
320
327
  if (el) {
321
328
  dayHeaderRefs.current.set(group.dateKey, el);
322
329
  }
@@ -340,7 +347,7 @@ export function CalendarPane(props) {
340
347
  ? event.selfResponseStatus
341
348
  : 'needsAction';
342
349
  if (event.isAllDay) {
343
- return (_jsxs("div", { className: `calendar-event-allday calendar-event-row--rsvp-${rsvpStatus}`, children: [_jsxs("span", { className: "calendar-event-title-wrap", children: [_jsx("span", { className: "calendar-event-title", children: event.summary }), props.renderEventAction?.(event)] }), showCalendarLabel && (_jsxs("span", { className: "calendar-event-calendar", children: [_jsx("span", { className: "calendar-event-calendar-dot", style: { backgroundColor: calendar.backgroundColor } }), calendar.summary] })), showOrganizerLabel && (_jsxs("span", { className: "calendar-event-organizer", children: [multi && (_jsx("span", { className: "calendar-event-source-dot", style: { backgroundColor: sourceColor(event.sourceId) } })), organizerText] }))] }, eventKey));
350
+ return (_jsxs("div", { className: `calendar-event-allday calendar-event-row--rsvp-${rsvpStatus}`, children: [_jsxs("div", { className: "calendar-event-header", children: [_jsx("span", { className: "calendar-event-time", children: "All day" }), _jsx(RsvpStatusIcon, { status: event.selfResponseStatus })] }), _jsxs("span", { className: "calendar-event-title-wrap", children: [_jsx("span", { className: "calendar-event-title", children: event.summary }), props.renderEventAction?.(event)] }), showCalendarLabel && (_jsxs("span", { className: "calendar-event-calendar", children: [_jsx("span", { className: "calendar-event-calendar-dot", style: { backgroundColor: calendar.backgroundColor } }), calendar.summary] })), showOrganizerLabel && (_jsxs("span", { className: "calendar-event-organizer", children: [multi && (_jsx("span", { className: "calendar-event-source-dot", style: { backgroundColor: sourceColor(event.sourceId) } })), organizerText] }))] }, eventKey));
344
351
  }
345
352
  const hasLink = usableUrl(event.htmlLink) !== null;
346
353
  return (_jsxs("div", { className: `calendar-event-row${currentEventKeys.has(eventKey) ? ' calendar-event-row--current' : ''}${selectedEventKey === eventKey ? ' calendar-event-row--selected' : ''} calendar-event-row--rsvp-${rsvpStatus}`, ref: (el) => {
@@ -350,7 +357,7 @@ export function CalendarPane(props) {
350
357
  else {
351
358
  timedEventRefs.current.delete(eventKey);
352
359
  }
353
- }, children: [_jsxs("div", { className: "calendar-event-header", children: [_jsx("span", { className: "calendar-event-time", children: formatTimeRange(event) }), event.joinUrl && (_jsx("a", { className: "calendar-event-join", href: event.joinUrl, target: "_blank", rel: "noopener noreferrer", onClick: (e) => e.stopPropagation(), children: "Join" }))] }), _jsxs("div", { className: "calendar-event-title-wrap", children: [hasLink ? (_jsx("a", { className: "calendar-event-title-link", href: event.htmlLink, target: "_blank", rel: "noopener noreferrer", onClick: (e) => {
360
+ }, children: [_jsxs("div", { className: "calendar-event-header", children: [_jsx("span", { className: "calendar-event-time", children: formatTimeRange(event) }), _jsxs("div", { className: "calendar-event-actions", children: [event.joinUrl && (_jsx("a", { className: "calendar-event-join", href: event.joinUrl, target: "_blank", rel: "noopener noreferrer", onClick: (e) => e.stopPropagation(), children: "Join" })), _jsx(RsvpStatusIcon, { status: event.selfResponseStatus })] })] }), _jsxs("div", { className: "calendar-event-title-wrap", children: [hasLink ? (_jsx("a", { className: "calendar-event-title-link", href: event.htmlLink, target: "_blank", rel: "noopener noreferrer", onClick: (e) => {
354
361
  if (isDesktop &&
355
362
  e.button === 0 &&
356
363
  !e.ctrlKey &&
package/dist/styles.css CHANGED
@@ -44,6 +44,39 @@
44
44
  --calendar-empty: #999;
45
45
  --calendar-chip-hover: #00a9ce;
46
46
  --calendar-checkbox: #22a6c0;
47
+ --calendar-chip-group-background: #f1f5f9;
48
+ --calendar-chip-group-border: rgb(226 232 240 / 80%);
49
+ --calendar-chip-active-background: #ffffff;
50
+ --calendar-chip-selected-ring: rgb(99 102 241 / 40%);
51
+ --calendar-chip-icon-accepted: #10b981;
52
+ --calendar-chip-icon-tentative: #f59e0b;
53
+ --calendar-chip-icon-declined: #f43f5e;
54
+ --calendar-chip-icon-needsAction: #0ea5e9;
55
+ --calendar-chip-badge-background: #0ea5e9;
56
+ --calendar-chip-badge-text: #ffffff;
57
+ --calendar-chip-badge-border: #ffffff;
58
+ --calendar-today-background: #f1f5f9;
59
+ --calendar-today-hover: #e2e8f0;
60
+ --calendar-today-text: #334155;
61
+ --calendar-card-background: #f8fafc;
62
+ --calendar-card-border: #e2e8f0;
63
+ --calendar-card-title: #0f172a;
64
+ --calendar-card-time: #64748b;
65
+ --calendar-card-active-background: #eef2ff;
66
+ --calendar-card-active-border: #a5b4fc;
67
+ --calendar-card-active-ring: rgb(99 102 241 / 20%);
68
+ --calendar-status-accepted-text: #059669;
69
+ --calendar-status-accepted-background: #ecfdf5;
70
+ --calendar-status-accepted-border: #a7f3d0;
71
+ --calendar-status-tentative-text: #f59e0b;
72
+ --calendar-status-tentative-background: #fffbeb;
73
+ --calendar-status-tentative-border: #fde68a;
74
+ --calendar-status-declined-text: #f43f5e;
75
+ --calendar-status-declined-background: #fff1f2;
76
+ --calendar-status-declined-border: #fecdd3;
77
+ --calendar-status-needsAction-text: #0ea5e9;
78
+ --calendar-status-needsAction-background: #f0f9ff;
79
+ --calendar-status-needsAction-border: #bae6fd;
47
80
  color-scheme: var(--calendar-scheme);
48
81
  color: var(--calendar-text);
49
82
  }
@@ -112,6 +145,9 @@
112
145
 
113
146
  .calendar-rsvp-chips {
114
147
  display: flex;
148
+ align-items: center;
149
+ box-sizing: border-box;
150
+ min-height: 64px;
115
151
  gap: 8px;
116
152
  padding: 12px 16px;
117
153
  flex-wrap: wrap;
@@ -121,51 +157,101 @@
121
157
  z-index: 2;
122
158
  }
123
159
 
160
+ .calendar-rsvp-chip-group {
161
+ display: flex;
162
+ align-items: center;
163
+ flex-shrink: 0;
164
+ gap: 4px;
165
+ padding: 4px;
166
+ border: 1px solid var(--calendar-chip-group-border);
167
+ border-radius: 12px;
168
+ background: var(--calendar-chip-group-background);
169
+ }
170
+
124
171
  .calendar-rsvp-chip {
125
- width: auto;
126
- min-width: 32px;
127
- height: 32px;
172
+ position: relative;
128
173
  box-sizing: border-box;
129
174
  flex-shrink: 0;
130
175
  display: flex;
131
176
  align-items: center;
132
177
  justify-content: center;
133
- gap: 4px;
134
- padding: 0 8px;
178
+ padding: 6px;
135
179
  background: transparent;
136
- color: var(--calendar-chip-text);
137
- border: 1px solid var(--calendar-chip-border);
138
- border-radius: 999px;
180
+ border: 0;
181
+ border-radius: 8px;
139
182
  cursor: pointer;
140
183
  }
141
184
 
142
- .calendar-scroll-today-btn {
143
- margin-right: 4px;
144
- padding-right: 4px;
145
- border-right: 1px solid var(--calendar-chip-border);
185
+ .calendar-rsvp-chip svg {
186
+ width: 16px;
187
+ height: 16px;
188
+ stroke-width: 2.2;
189
+ }
190
+
191
+ .calendar-rsvp-chip[aria-label='Accepted'] {
192
+ color: var(--calendar-chip-icon-accepted);
193
+ }
194
+
195
+ .calendar-rsvp-chip[aria-label='Maybe'] {
196
+ color: var(--calendar-chip-icon-tentative);
197
+ }
198
+
199
+ .calendar-rsvp-chip[aria-label='Declined'] {
200
+ color: var(--calendar-chip-icon-declined);
201
+ }
202
+
203
+ .calendar-rsvp-chip[aria-label^='Unaccepted'] {
204
+ color: var(--calendar-chip-icon-needsAction);
146
205
  }
147
206
 
148
207
  .calendar-rsvp-chip:hover {
149
- border-color: var(--calendar-chip-hover);
208
+ background: var(--calendar-chip-active-background);
150
209
  }
151
210
 
152
- .calendar-rsvp-chip.selected {
153
- background: var(--calendar-chip-selected);
154
- color: var(--calendar-chip-selected-text);
155
- border-color: var(--calendar-chip-selected);
211
+ .calendar-rsvp-chip-group .calendar-rsvp-chip.selected {
212
+ background: var(--calendar-chip-active-background);
213
+ box-shadow: 0 0 0 1px var(--calendar-chip-selected-ring);
156
214
  }
157
215
 
158
216
  .calendar-rsvp-chip-badge {
159
- min-width: 16px;
160
- padding: 1px 4px;
217
+ position: absolute;
218
+ top: -4px;
219
+ right: -4px;
220
+ box-sizing: border-box;
221
+ display: flex;
222
+ align-items: center;
223
+ justify-content: center;
224
+ min-width: 15px;
225
+ height: 15px;
226
+ padding: 0 2px;
161
227
  border-radius: 999px;
162
- background: var(--calendar-badge);
163
- color: var(--calendar-badge-text);
228
+ border: 1px solid var(--calendar-chip-badge-border);
229
+ background: var(--calendar-chip-badge-background);
230
+ color: var(--calendar-chip-badge-text);
231
+ font-size: 9px;
232
+ font-weight: 700;
233
+ line-height: 1;
234
+ text-align: center;
235
+ white-space: nowrap;
236
+ }
237
+
238
+ .calendar-today-btn {
239
+ margin-left: auto;
240
+ flex-shrink: 0;
241
+ padding: 4px 8px;
242
+ border: 0;
243
+ border-radius: 6px;
244
+ background: var(--calendar-today-background);
245
+ color: var(--calendar-today-text);
246
+ font-family: inherit;
164
247
  font-size: 11px;
165
248
  font-weight: 600;
166
249
  line-height: 16px;
167
- text-align: center;
168
- white-space: nowrap;
250
+ cursor: pointer;
251
+ }
252
+
253
+ .calendar-today-btn:hover {
254
+ background: var(--calendar-today-hover);
169
255
  }
170
256
 
171
257
  .calendar-empty-state {
@@ -202,6 +288,10 @@
202
288
  .calendar-day-events {
203
289
  flex: 1;
204
290
  min-width: 0;
291
+ display: flex;
292
+ flex-direction: column;
293
+ gap: 8px;
294
+ padding: 12px;
205
295
  }
206
296
 
207
297
  .calendar-day-ribbon {
@@ -242,52 +332,76 @@
242
332
  padding: 6px 0;
243
333
  }
244
334
 
245
- .calendar-event-allday {
246
- display: flex;
247
- align-items: center;
248
- gap: 8px;
249
- padding: 10px 16px;
250
- border-right: 3px solid var(--rsvp-bar, transparent);
251
- border-bottom: 1px solid var(--calendar-border);
252
- }
253
-
335
+ .calendar-event-allday,
254
336
  .calendar-event-row {
255
337
  display: flex;
256
338
  flex-direction: column;
257
- gap: 8px;
258
- padding: 10px 16px;
259
- border-right: 3px solid var(--rsvp-bar, transparent);
260
- border-bottom: 1px solid var(--calendar-border);
339
+ gap: 6px;
340
+ padding: 10px;
341
+ border: 1px solid var(--calendar-card-border);
342
+ border-radius: 12px;
343
+ background: var(--calendar-card-background);
261
344
  }
262
345
 
263
- .calendar-event-allday {
264
- background: var(--calendar-allday);
265
- font-style: italic;
346
+ .calendar-event-join,
347
+ .calendar-event-rsvp {
348
+ display: inline-flex;
349
+ flex: none;
350
+ padding: 4px;
351
+ border: 1px solid var(--status-border);
352
+ border-radius: 4px;
353
+ background: var(--status-background);
354
+ color: var(--status-text);
355
+ }
356
+
357
+ .calendar-event-rsvp {
358
+ margin-left: auto;
266
359
  }
267
360
 
268
- .calendar-event-row--rsvp-accepted {
269
- --rsvp-bar: var(--calendar-rsvp-accepted);
361
+ .calendar-event-row--rsvp-accepted,
362
+ .calendar-event-rsvp--accepted {
363
+ --status-text: var(--calendar-status-accepted-text);
364
+ --status-background: var(--calendar-status-accepted-background);
365
+ --status-border: var(--calendar-status-accepted-border);
270
366
  }
271
367
 
272
- .calendar-event-row--rsvp-tentative {
273
- --rsvp-bar: var(--calendar-rsvp-tentative);
368
+ .calendar-event-row--rsvp-tentative,
369
+ .calendar-event-rsvp--tentative {
370
+ --status-text: var(--calendar-status-tentative-text);
371
+ --status-background: var(--calendar-status-tentative-background);
372
+ --status-border: var(--calendar-status-tentative-border);
274
373
  }
275
374
 
276
- .calendar-event-row--rsvp-needsAction {
277
- --rsvp-bar: var(--calendar-rsvp-needsAction);
375
+ .calendar-event-row--rsvp-needsAction,
376
+ .calendar-event-rsvp--needsAction {
377
+ --status-text: var(--calendar-status-needsAction-text);
378
+ --status-background: var(--calendar-status-needsAction-background);
379
+ --status-border: var(--calendar-status-needsAction-border);
278
380
  }
279
381
 
280
- .calendar-event-row--rsvp-declined {
281
- --rsvp-bar: var(--calendar-rsvp-declined);
382
+ .calendar-event-row--rsvp-declined,
383
+ .calendar-event-rsvp--declined {
384
+ --status-text: var(--calendar-status-declined-text);
385
+ --status-background: var(--calendar-status-declined-background);
386
+ --status-border: var(--calendar-status-declined-border);
282
387
  }
283
388
 
284
389
  .calendar-event-header {
285
390
  display: flex;
391
+ flex-wrap: wrap;
286
392
  justify-content: space-between;
287
393
  align-items: center;
288
394
  gap: 8px;
289
395
  }
290
396
 
397
+ .calendar-event-actions {
398
+ display: flex;
399
+ flex: none;
400
+ align-items: center;
401
+ gap: 4px;
402
+ margin-left: auto;
403
+ }
404
+
291
405
  .calendar-event-title-link {
292
406
  align-self: flex-start;
293
407
  text-decoration: none;
@@ -334,15 +448,18 @@
334
448
  }
335
449
 
336
450
  .calendar-event-time {
337
- font-size: 12px;
338
- color: var(--calendar-time);
339
- min-width: 110px;
340
- flex-shrink: 0;
451
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;
452
+ font-size: 10px;
453
+ font-weight: 600;
454
+ color: var(--calendar-card-time);
455
+ min-width: 0;
341
456
  }
342
457
 
343
458
  .calendar-event-title {
344
- font-size: 14px;
345
- color: var(--calendar-text);
459
+ font-size: 12px;
460
+ font-weight: 600;
461
+ line-height: 1.25;
462
+ color: var(--calendar-card-title);
346
463
  }
347
464
 
348
465
  .calendar-event-organizer {
@@ -368,21 +485,27 @@
368
485
  .calendar-event-join {
369
486
  font-size: 12px;
370
487
  font-weight: 500;
371
- color: var(--calendar-accent);
488
+ line-height: 14px;
372
489
  cursor: pointer;
373
490
  text-decoration: none;
374
491
  padding: 4px 8px;
375
- border: 1px solid var(--calendar-accent);
376
- border-radius: 4px;
492
+ white-space: nowrap;
377
493
  }
378
494
 
379
495
  .calendar-event-join:hover {
380
- background: var(--calendar-hover);
496
+ text-decoration: underline;
497
+ }
498
+
499
+ .calendar-event-join:focus-visible {
500
+ outline: 2px solid var(--calendar-focus);
501
+ outline-offset: 2px;
381
502
  }
382
503
 
383
504
  .calendar-event-row--current,
384
505
  .calendar-event-row--selected {
385
- background: var(--calendar-highlight);
506
+ border-color: var(--calendar-card-active-border);
507
+ box-shadow: 0 0 0 1px var(--calendar-card-active-ring);
508
+ background: var(--calendar-card-active-background);
386
509
  }
387
510
 
388
511
  /* Explicit dark and system-dark use exactly the same palette. The media query
@@ -427,6 +550,32 @@
427
550
  --calendar-input-border-style: solid;
428
551
  --calendar-option-hover: #2a2a2a;
429
552
  --calendar-option-active: #10262b;
553
+ --calendar-chip-group-background: rgb(30 41 59 / 90%);
554
+ --calendar-chip-group-border: rgb(51 65 85 / 60%);
555
+ --calendar-chip-active-background: #334155;
556
+ --calendar-chip-badge-border: #1e293b;
557
+ --calendar-today-background: #1e293b;
558
+ --calendar-today-hover: #334155;
559
+ --calendar-today-text: #e2e8f0;
560
+ --calendar-card-background: rgb(30 41 59 / 80%);
561
+ --calendar-card-border: #334155;
562
+ --calendar-card-title: #ffffff;
563
+ --calendar-card-time: #94a3b8;
564
+ --calendar-card-active-background: rgb(30 27 75 / 80%);
565
+ --calendar-card-active-border: #3730a3;
566
+ --calendar-card-active-ring: rgb(129 140 248 / 30%);
567
+ --calendar-status-accepted-text: #34d399;
568
+ --calendar-status-accepted-background: rgb(2 44 34 / 80%);
569
+ --calendar-status-accepted-border: #065f46;
570
+ --calendar-status-tentative-text: #fbbf24;
571
+ --calendar-status-tentative-background: rgb(69 26 3 / 80%);
572
+ --calendar-status-tentative-border: #92400e;
573
+ --calendar-status-declined-text: #fb7185;
574
+ --calendar-status-declined-background: rgb(76 5 25 / 80%);
575
+ --calendar-status-declined-border: #9f1239;
576
+ --calendar-status-needsAction-text: #38bdf8;
577
+ --calendar-status-needsAction-background: rgb(8 47 73 / 80%);
578
+ --calendar-status-needsAction-border: #075985;
430
579
  }
431
580
 
432
581
  @media (prefers-color-scheme: dark) {
@@ -470,6 +619,32 @@
470
619
  --calendar-input-border-style: solid;
471
620
  --calendar-option-hover: #2a2a2a;
472
621
  --calendar-option-active: #10262b;
622
+ --calendar-chip-group-background: rgb(30 41 59 / 90%);
623
+ --calendar-chip-group-border: rgb(51 65 85 / 60%);
624
+ --calendar-chip-active-background: #334155;
625
+ --calendar-chip-badge-border: #1e293b;
626
+ --calendar-today-background: #1e293b;
627
+ --calendar-today-hover: #334155;
628
+ --calendar-today-text: #e2e8f0;
629
+ --calendar-card-background: rgb(30 41 59 / 80%);
630
+ --calendar-card-border: #334155;
631
+ --calendar-card-title: #ffffff;
632
+ --calendar-card-time: #94a3b8;
633
+ --calendar-card-active-background: rgb(30 27 75 / 80%);
634
+ --calendar-card-active-border: #3730a3;
635
+ --calendar-card-active-ring: rgb(129 140 248 / 30%);
636
+ --calendar-status-accepted-text: #34d399;
637
+ --calendar-status-accepted-background: rgb(2 44 34 / 80%);
638
+ --calendar-status-accepted-border: #065f46;
639
+ --calendar-status-tentative-text: #fbbf24;
640
+ --calendar-status-tentative-background: rgb(69 26 3 / 80%);
641
+ --calendar-status-tentative-border: #92400e;
642
+ --calendar-status-declined-text: #fb7185;
643
+ --calendar-status-declined-background: rgb(76 5 25 / 80%);
644
+ --calendar-status-declined-border: #9f1239;
645
+ --calendar-status-needsAction-text: #38bdf8;
646
+ --calendar-status-needsAction-background: rgb(8 47 73 / 80%);
647
+ --calendar-status-needsAction-border: #075985;
473
648
  }
474
649
  }
475
650
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-webapp/calendar",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",