@nomideusz/svelte-calendar 1.2.0 → 1.4.0
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 +143 -93
- package/dist/adapters/mapped.d.ts +7 -7
- package/dist/adapters/mapped.js +5 -2
- package/dist/adapters/memory.d.ts +7 -6
- package/dist/adapters/memory.js +3 -4
- package/dist/adapters/recurring.d.ts +6 -6
- package/dist/adapters/recurring.js +12 -14
- package/dist/calendar/Calendar.svelte +226 -304
- package/dist/calendar/Calendar.svelte.d.ts +1 -1
- package/dist/primitives/DayHeader.svelte +7 -7
- package/dist/primitives/EmptySlot.svelte +6 -6
- package/dist/primitives/EventBlock.svelte +19 -19
- package/dist/primitives/FloatingPanel.svelte +4 -4
- package/dist/primitives/NowIndicator.svelte +5 -5
- package/dist/primitives/TimeGutter.svelte +4 -4
- package/dist/theme/auto.d.ts +5 -0
- package/dist/theme/auto.js +16 -3
- package/dist/theme/presets.d.ts +2 -2
- package/dist/theme/presets.js +2 -2
- package/dist/views/agenda/AgendaDay.svelte +207 -323
- package/dist/views/agenda/AgendaWeek.svelte +145 -222
- package/dist/views/mobile/MobileDay.svelte +79 -60
- package/dist/views/mobile/MobileWeek.svelte +48 -38
- package/dist/views/month/MonthGrid.svelte +92 -36
- package/dist/views/planner/PlannerScroll.svelte +78 -72
- package/dist/views/planner/PlannerWeek.svelte +145 -90
- package/dist/views/shared/context.svelte.d.ts +2 -0
- package/dist/views/shared/context.svelte.js +1 -0
- package/dist/views/shared/format.d.ts +3 -0
- package/dist/views/shared/format.js +10 -1
- package/package.json +1 -1
- package/widget/widget.js +816 -725
|
@@ -21,7 +21,8 @@ import { createClock } from "../../core/clock.svelte.js";
|
|
|
21
21
|
import { fitParts } from "../../text-fit.js";
|
|
22
22
|
import { HOUR_MS, sod, addDaysMs, diffDays } from "../../core/time.js";
|
|
23
23
|
import { startOfWeek as sowFn, isAllDay, segmentForDay } from "../../core/time.js";
|
|
24
|
-
import { fmtHParts, fmtTime, fmtDuration, weekdayShort, weekdayLong } from "../../core/locale.js";
|
|
24
|
+
import { fmtHParts, fmtTime, fmtDuration, fmtWeekRange, weekdayShort, weekdayLong } from "../../core/locale.js";
|
|
25
|
+
import { dateLong } from "../shared/format.js";
|
|
25
26
|
let { mode = "week", mondayStart = true, locale, height = 520, events = [], style = "", focusDate, oneventclick, oneventcreate, onexternaldrop, selectedEventId = null, readOnly = false, visibleHours } = $props();
|
|
26
27
|
// ── Context ────────────────────────────────────────
|
|
27
28
|
const ctx = useCalendarContext();
|
|
@@ -122,6 +123,7 @@ const dayCols = $derived.by(() => {
|
|
|
122
123
|
cols.push({
|
|
123
124
|
ms,
|
|
124
125
|
isToday: ms === todayMs,
|
|
126
|
+
markToday: showDates && ms === todayMs,
|
|
125
127
|
isPast: equalDays ? false : ms < todayMs,
|
|
126
128
|
isWeekend: dow === 0 || dow === 6,
|
|
127
129
|
isDisabled: disabledSet.has(ms),
|
|
@@ -301,8 +303,12 @@ const weekIsEmpty = $derived(!events.some((ev) => ev.start.getTime() < weekEndMs
|
|
|
301
303
|
// Week with today → current time minus ~1h of context; otherwise the
|
|
302
304
|
// visibleHours start or 08:00, whichever is later. Lands on a whole hour,
|
|
303
305
|
// with room for its label (centred on the line) below the sticky top.
|
|
306
|
+
// An event running across that hour line would be sliced under the sticky
|
|
307
|
+
// top, so the scroll starts at that event's hour instead.
|
|
304
308
|
$effect(() => {
|
|
305
309
|
void weekStartMs;
|
|
310
|
+
void startHour;
|
|
311
|
+
void endHour;
|
|
306
312
|
const el = scrollEl;
|
|
307
313
|
if (!el) return;
|
|
308
314
|
untrack(() => {
|
|
@@ -313,7 +319,26 @@ $effect(() => {
|
|
|
313
319
|
} else {
|
|
314
320
|
targetHour = Math.max(startHour, Math.min(8, endHour - 1));
|
|
315
321
|
}
|
|
316
|
-
|
|
322
|
+
let hour = Math.floor(targetHour);
|
|
323
|
+
// Moving up can slice an earlier event on another day, so repeat
|
|
324
|
+
// until no block crosses the line.
|
|
325
|
+
// ponytail: looks back at most 2 h, so a long block can't drag the view to dawn.
|
|
326
|
+
const floorY = (hour - 2 - startHour) * HOUR_H;
|
|
327
|
+
for (let moved = true; moved;) {
|
|
328
|
+
moved = false;
|
|
329
|
+
const line = (hour - startHour) * HOUR_H;
|
|
330
|
+
for (const day of layoutByDay.values()) {
|
|
331
|
+
for (const p of day) {
|
|
332
|
+
if (p.top < line && p.top + p.height > line && p.top >= floorY) {
|
|
333
|
+
hour = Math.floor(startHour + p.top / HOUR_H);
|
|
334
|
+
moved = true;
|
|
335
|
+
break;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (moved) break;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
el.scrollTop = Math.max(0, (hour - startHour) * HOUR_H - LABEL_ROOM);
|
|
317
342
|
});
|
|
318
343
|
});
|
|
319
344
|
// ── Pointer coalescing ─────────────────────────────
|
|
@@ -389,11 +414,12 @@ function clampToDayBand(ms, dayMs) {
|
|
|
389
414
|
return Math.max(atHour(dayMs, startHour), Math.min(atHour(dayMs, endHour), ms));
|
|
390
415
|
}
|
|
391
416
|
// ── Blocked slot helpers ───────────────────────────
|
|
417
|
+
/** The blocked slot covering `hour` on the day, if any (truthy = blocked). */
|
|
392
418
|
function isBlockedAt(dayMs, hour) {
|
|
393
|
-
if (!blockedSlots?.length) return
|
|
419
|
+
if (!blockedSlots?.length) return undefined;
|
|
394
420
|
const jsDay = new Date(dayMs).getDay();
|
|
395
421
|
const isoDay = jsDay === 0 ? 7 : jsDay;
|
|
396
|
-
return blockedSlots.
|
|
422
|
+
return blockedSlots.find((slot) => {
|
|
397
423
|
if (slot.day && slot.day !== isoDay) return false;
|
|
398
424
|
return hour >= slot.start && hour < slot.end;
|
|
399
425
|
});
|
|
@@ -640,11 +666,14 @@ function onColKeydown(e, i) {
|
|
|
640
666
|
const day = dayCols[i];
|
|
641
667
|
if (e.key === "Enter" || e.key === " ") {
|
|
642
668
|
e.preventDefault();
|
|
643
|
-
if (!oneventcreate || readOnly
|
|
669
|
+
if (!oneventcreate || readOnly) return;
|
|
670
|
+
// Say why nothing was created, through the calendar's status line.
|
|
671
|
+
if (day.isDisabled) return ctx.announce(`${dateLong(day.ms, locale)}, ${L.unavailable}`);
|
|
644
672
|
const step = Math.max(1, ctx.snapInterval) / 60;
|
|
645
673
|
const want = day.isToday ? snapHour(nowFracHour, "floor") + step : 9;
|
|
646
674
|
const hour = Math.min(Math.max(want, startHour), endHour - step);
|
|
647
|
-
|
|
675
|
+
const slot = isBlockedAt(day.ms, hour);
|
|
676
|
+
if (slot) return ctx.announce(`${slot.label || L.unavailable}, ${blockedRangeLabel(day.ms, slot.start, slot.end)}`);
|
|
648
677
|
const startMs = atHour(day.ms, hour);
|
|
649
678
|
oneventcreate({
|
|
650
679
|
start: new Date(startMs),
|
|
@@ -899,7 +928,9 @@ function onWindowKeydown(e) {
|
|
|
899
928
|
style:--tw-col-min="{MIN_COL_W}px"
|
|
900
929
|
style:height={autoHeight ? undefined : (height ? `${height}px` : '100%')}
|
|
901
930
|
role="region"
|
|
902
|
-
aria-label={L.weekAhead}
|
|
931
|
+
aria-label="{singleDay ? L.dayPlanner : L.weekAhead}{dayCols.length
|
|
932
|
+
? `, ${singleDay ? dateLong(dayCols[0].ms, locale) : fmtWeekRange(dayCols[0].ms, locale, dayCols[dayCols.length - 1].ms)}`
|
|
933
|
+
: ''}"
|
|
903
934
|
>
|
|
904
935
|
<div class="tw-scroll" bind:this={scrollEl}>
|
|
905
936
|
<div class="tw-inner" style:min-width="{innerMinWidth}px">
|
|
@@ -912,12 +943,12 @@ function onWindowKeydown(e) {
|
|
|
912
943
|
{#each dayCols as day (day.ms)}
|
|
913
944
|
<div
|
|
914
945
|
class="tw-hd"
|
|
915
|
-
class:tw-hd--today={day.
|
|
916
|
-
aria-current={day.
|
|
946
|
+
class:tw-hd--today={day.markToday}
|
|
947
|
+
aria-current={day.markToday ? 'date' : undefined}
|
|
917
948
|
>
|
|
918
949
|
<span class="tw-hd-wd">{singleDay ? weekdayLong(day.ms, locale) : weekdayShort(day.ms, locale)}</span>
|
|
919
950
|
{#if showDates}
|
|
920
|
-
<span class="tw-hd-num" class:tw-hd-num--today={day.
|
|
951
|
+
<span class="tw-hd-num" class:tw-hd-num--today={day.markToday}>{day.dayNum}</span>
|
|
921
952
|
{/if}
|
|
922
953
|
{#if dayHeaderSnippet}
|
|
923
954
|
<div class="tw-hd-custom">
|
|
@@ -938,7 +969,7 @@ function onWindowKeydown(e) {
|
|
|
938
969
|
{@const segs = allDayByDay.get(day.ms) ?? []}
|
|
939
970
|
{@const isExpanded = adExpanded[day.ms] ?? false}
|
|
940
971
|
{@const shown = isExpanded ? segs : segs.slice(0, ALLDAY_MAX)}
|
|
941
|
-
<div class="tw-ad-cell" class:tw-ad-cell--today={day.
|
|
972
|
+
<div class="tw-ad-cell" class:tw-ad-cell--today={day.markToday}>
|
|
942
973
|
{#each shown as seg (seg.ev.id)}
|
|
943
974
|
{@render allDayChip(seg)}
|
|
944
975
|
{/each}
|
|
@@ -1011,14 +1042,14 @@ function onWindowKeydown(e) {
|
|
|
1011
1042
|
<!-- svelte-ignore a11y_no_noninteractive_tabindex -->
|
|
1012
1043
|
<div
|
|
1013
1044
|
class="tw-col"
|
|
1014
|
-
class:tw-col--today={day.
|
|
1045
|
+
class:tw-col--today={day.markToday}
|
|
1015
1046
|
class:tw-col--past={day.isPast}
|
|
1016
1047
|
class:tw-col--weekend={day.isWeekend}
|
|
1017
1048
|
class:tw-col--disabled={day.isDisabled}
|
|
1018
1049
|
data-day={day.ms}
|
|
1019
1050
|
role={colsCreate ? 'group' : undefined}
|
|
1020
|
-
aria-label={colsCreate ? `${
|
|
1021
|
-
aria-keyshortcuts={colsCreate ? 'Enter' : undefined}
|
|
1051
|
+
aria-label={colsCreate ? `${dateLong(day.ms, locale)}, ${day.isDisabled ? L.unavailable : L.createEvent}` : undefined}
|
|
1052
|
+
aria-keyshortcuts={colsCreate && !day.isDisabled ? 'Enter' : undefined}
|
|
1022
1053
|
tabindex={colsCreate ? (day.ms === tabbableColMs ? 0 : -1) : undefined}
|
|
1023
1054
|
onfocusin={() => (focusedColMs = day.ms)}
|
|
1024
1055
|
onkeydown={colsCreate ? (e) => onColKeydown(e, di) : undefined}
|
|
@@ -1064,6 +1095,7 @@ function onWindowKeydown(e) {
|
|
|
1064
1095
|
class:tw-ev--past={p.ev.end.getTime() < clock.tick}
|
|
1065
1096
|
class:tw-ev--short={p.height < 44}
|
|
1066
1097
|
class:tw-ev--compact={p.height < 34}
|
|
1098
|
+
class:tw-ev--on-now={weekHasToday && nowY !== null && p.top < nowY && p.top + p.height > nowY}
|
|
1067
1099
|
style:top="{p.top}px"
|
|
1068
1100
|
style:height="{p.height}px"
|
|
1069
1101
|
style:left="calc({(p.col / p.totalCols) * 100}% + 1px)"
|
|
@@ -1121,8 +1153,8 @@ function onWindowKeydown(e) {
|
|
|
1121
1153
|
style:top="{ghost.top}px"
|
|
1122
1154
|
style:height="{ghost.height}px"
|
|
1123
1155
|
style:--ev-color={ghost.create
|
|
1124
|
-
? 'var(--dt-accent, #
|
|
1125
|
-
: (movingEvent?.color ?? 'var(--dt-
|
|
1156
|
+
? 'var(--dt-accent, #1d4fd7)'
|
|
1157
|
+
: (movingEvent?.color ?? 'var(--dt-event, var(--dt-accent))')}
|
|
1126
1158
|
aria-hidden="true"
|
|
1127
1159
|
>
|
|
1128
1160
|
{#if ghost.showTime}
|
|
@@ -1138,9 +1170,8 @@ function onWindowKeydown(e) {
|
|
|
1138
1170
|
|
|
1139
1171
|
<!-- Now line (today's column only) -->
|
|
1140
1172
|
{#if day.isToday && nowY !== null}
|
|
1141
|
-
<div class="tw-now" style:top="{nowY}px" aria-label={L.currentTime}>
|
|
1142
|
-
|
|
1143
|
-
</div>
|
|
1173
|
+
<div class="tw-now" style:top="{nowY}px" aria-label={L.currentTime}></div>
|
|
1174
|
+
<span class="tw-now-dot" style:top="{nowY}px" aria-hidden="true"></span>
|
|
1144
1175
|
{/if}
|
|
1145
1176
|
</div>
|
|
1146
1177
|
{/each}
|
|
@@ -1166,7 +1197,7 @@ function onWindowKeydown(e) {
|
|
|
1166
1197
|
overflow: hidden;
|
|
1167
1198
|
user-select: none;
|
|
1168
1199
|
font-variant-numeric: tabular-nums;
|
|
1169
|
-
background: var(--dt-paper, none), var(--dt-bg, #
|
|
1200
|
+
background: var(--dt-paper, none), var(--dt-bg, #efebe9);
|
|
1170
1201
|
-webkit-tap-highlight-color: transparent;
|
|
1171
1202
|
}
|
|
1172
1203
|
.tw--auto { overflow: visible; }
|
|
@@ -1183,12 +1214,12 @@ function onWindowKeydown(e) {
|
|
|
1183
1214
|
overscroll-behavior-x: contain;
|
|
1184
1215
|
overscroll-behavior-y: auto;
|
|
1185
1216
|
scrollbar-width: thin;
|
|
1186
|
-
scrollbar-color: var(--dt-scrollbar, rgba(
|
|
1217
|
+
scrollbar-color: var(--dt-scrollbar, rgba(15, 15, 15, 0.1)) transparent;
|
|
1187
1218
|
}
|
|
1188
1219
|
.tw--auto .tw-scroll { overflow-y: visible; }
|
|
1189
1220
|
.tw-scroll::-webkit-scrollbar { width: 5px; height: 5px; }
|
|
1190
1221
|
.tw-scroll::-webkit-scrollbar-thumb {
|
|
1191
|
-
background: var(--dt-scrollbar, rgba(
|
|
1222
|
+
background: var(--dt-scrollbar, rgba(15, 15, 15, 0.1));
|
|
1192
1223
|
border-radius: 4px;
|
|
1193
1224
|
}
|
|
1194
1225
|
.tw-scroll::-webkit-scrollbar-track { background: transparent; }
|
|
@@ -1204,8 +1235,8 @@ function onWindowKeydown(e) {
|
|
|
1204
1235
|
position: sticky;
|
|
1205
1236
|
top: 0;
|
|
1206
1237
|
z-index: 30;
|
|
1207
|
-
background: var(--dt-paper, none), var(--dt-bg, #
|
|
1208
|
-
border-bottom: 1px solid var(--dt-border, rgba(
|
|
1238
|
+
background: var(--dt-paper, none), var(--dt-bg, #efebe9);
|
|
1239
|
+
border-bottom: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1209
1240
|
}
|
|
1210
1241
|
|
|
1211
1242
|
/* ─── Day header row ─────────────────────────────── */
|
|
@@ -1218,7 +1249,7 @@ function onWindowKeydown(e) {
|
|
|
1218
1249
|
position: sticky;
|
|
1219
1250
|
left: 0;
|
|
1220
1251
|
z-index: 2;
|
|
1221
|
-
background: var(--dt-paper, none), var(--dt-bg, #
|
|
1252
|
+
background: var(--dt-paper, none), var(--dt-bg, #efebe9);
|
|
1222
1253
|
}
|
|
1223
1254
|
|
|
1224
1255
|
.tw-hd {
|
|
@@ -1229,17 +1260,17 @@ function onWindowKeydown(e) {
|
|
|
1229
1260
|
align-items: center;
|
|
1230
1261
|
gap: 4px;
|
|
1231
1262
|
padding: 14px 4px 12px;
|
|
1232
|
-
border-left: 1px solid var(--dt-border, rgba(
|
|
1263
|
+
border-left: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1233
1264
|
}
|
|
1234
1265
|
|
|
1235
1266
|
.tw-hd-wd {
|
|
1236
1267
|
font: 500 12px/1 var(--dt-sans, system-ui, sans-serif);
|
|
1237
1268
|
letter-spacing: 0.08em;
|
|
1238
1269
|
text-transform: uppercase;
|
|
1239
|
-
color: var(--dt-text-2, rgba(
|
|
1270
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
|
|
1240
1271
|
}
|
|
1241
1272
|
.tw-hd--today .tw-hd-wd {
|
|
1242
|
-
color: var(--dt-accent, #
|
|
1273
|
+
color: var(--dt-accent, #1d4fd7);
|
|
1243
1274
|
}
|
|
1244
1275
|
|
|
1245
1276
|
/* The day number is the typography of the grid: large, regular weight. */
|
|
@@ -1250,11 +1281,11 @@ function onWindowKeydown(e) {
|
|
|
1250
1281
|
font: 400 40px/1 var(--dt-sans, system-ui, sans-serif);
|
|
1251
1282
|
font-stretch: 90%;
|
|
1252
1283
|
letter-spacing: -0.02em;
|
|
1253
|
-
color: var(--dt-text, rgba(
|
|
1284
|
+
color: var(--dt-text, rgba(15, 15, 15, 0.87));
|
|
1254
1285
|
}
|
|
1255
1286
|
/* Today: the numeral in the accent, nothing else. */
|
|
1256
1287
|
.tw-hd-num--today {
|
|
1257
|
-
color: var(--dt-accent, #
|
|
1288
|
+
color: var(--dt-accent, #1d4fd7);
|
|
1258
1289
|
}
|
|
1259
1290
|
|
|
1260
1291
|
.tw-hd-custom {
|
|
@@ -1265,7 +1296,7 @@ function onWindowKeydown(e) {
|
|
|
1265
1296
|
/* ─── All-day strip ──────────────────────────────── */
|
|
1266
1297
|
.tw-allday {
|
|
1267
1298
|
display: flex;
|
|
1268
|
-
border-top: 1px solid var(--dt-border, rgba(
|
|
1299
|
+
border-top: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1269
1300
|
}
|
|
1270
1301
|
|
|
1271
1302
|
.tw-ad-gutter {
|
|
@@ -1276,15 +1307,16 @@ function onWindowKeydown(e) {
|
|
|
1276
1307
|
position: sticky;
|
|
1277
1308
|
left: 0;
|
|
1278
1309
|
z-index: 2;
|
|
1279
|
-
background: var(--dt-paper, none), var(--dt-bg, #
|
|
1310
|
+
background: var(--dt-paper, none), var(--dt-bg, #efebe9);
|
|
1280
1311
|
display: flex;
|
|
1281
1312
|
align-items: flex-start;
|
|
1282
1313
|
justify-content: flex-end;
|
|
1283
1314
|
padding: 6px 8px 6px 0;
|
|
1284
1315
|
}
|
|
1285
1316
|
.tw-ad-gutter-lb {
|
|
1286
|
-
font: 500
|
|
1287
|
-
|
|
1317
|
+
font: 500 12px/1.2 var(--dt-sans, system-ui, sans-serif);
|
|
1318
|
+
letter-spacing: 0.08em;
|
|
1319
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.66));
|
|
1288
1320
|
text-align: right;
|
|
1289
1321
|
}
|
|
1290
1322
|
|
|
@@ -1295,9 +1327,9 @@ function onWindowKeydown(e) {
|
|
|
1295
1327
|
flex-direction: column;
|
|
1296
1328
|
gap: 2px;
|
|
1297
1329
|
padding: 4px 0 5px;
|
|
1298
|
-
border-left: 1px solid var(--dt-border, rgba(
|
|
1330
|
+
border-left: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1299
1331
|
}
|
|
1300
|
-
.tw-ad-cell--today { background: var(--dt-today-bg, rgba(
|
|
1332
|
+
.tw-ad-cell--today { background: var(--dt-today-bg, rgba(29, 79, 215, 0.04)); }
|
|
1301
1333
|
|
|
1302
1334
|
.tw-ad {
|
|
1303
1335
|
appearance: none;
|
|
@@ -1333,11 +1365,11 @@ function onWindowKeydown(e) {
|
|
|
1333
1365
|
text-decoration: line-through;
|
|
1334
1366
|
}
|
|
1335
1367
|
.tw-ad--cancelled {
|
|
1336
|
-
background: color-mix(in srgb, var(--ev-color) 55%, var(--dt-bg, #
|
|
1368
|
+
background: color-mix(in srgb, var(--ev-color) 55%, var(--dt-bg, #efebe9));
|
|
1337
1369
|
}
|
|
1338
1370
|
.tw-ad:focus-visible {
|
|
1339
1371
|
outline: none;
|
|
1340
|
-
box-shadow: inset 0 0 0 2px var(--dt-btn-text, #fff), 0 0 0 2px var(--dt-accent, #
|
|
1372
|
+
box-shadow: inset 0 0 0 2px var(--dt-btn-text, #fff), 0 0 0 2px var(--dt-accent, #1d4fd7);
|
|
1341
1373
|
}
|
|
1342
1374
|
|
|
1343
1375
|
.tw-ad-title {
|
|
@@ -1350,7 +1382,7 @@ function onWindowKeydown(e) {
|
|
|
1350
1382
|
min-width: 0;
|
|
1351
1383
|
}
|
|
1352
1384
|
.tw-ad-span {
|
|
1353
|
-
font: 400
|
|
1385
|
+
font: 400 12.5px/1 var(--dt-sans, system-ui, sans-serif);
|
|
1354
1386
|
font-variant-numeric: tabular-nums;
|
|
1355
1387
|
color: inherit;
|
|
1356
1388
|
opacity: 0.75;
|
|
@@ -1380,19 +1412,19 @@ function onWindowKeydown(e) {
|
|
|
1380
1412
|
appearance: none;
|
|
1381
1413
|
background: none;
|
|
1382
1414
|
border: none;
|
|
1383
|
-
border-radius:
|
|
1415
|
+
border-radius: 0;
|
|
1384
1416
|
text-align: left;
|
|
1385
1417
|
align-self: flex-start;
|
|
1386
|
-
font:
|
|
1387
|
-
color: var(--dt-text-2, rgba(
|
|
1418
|
+
font: 400 12.5px/1 var(--dt-sans, system-ui, sans-serif);
|
|
1419
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
|
|
1388
1420
|
padding: 2px 6px;
|
|
1389
1421
|
cursor: pointer;
|
|
1390
1422
|
-webkit-tap-highlight-color: transparent;
|
|
1391
1423
|
}
|
|
1392
|
-
.tw-ad-more:hover { color: var(--dt-text, rgba(
|
|
1424
|
+
.tw-ad-more:hover { color: var(--dt-text, rgba(15, 15, 15, 0.87)); }
|
|
1393
1425
|
.tw-ad-more:focus-visible {
|
|
1394
1426
|
outline: none;
|
|
1395
|
-
box-shadow: 0 0 0 2px var(--dt-accent, #
|
|
1427
|
+
box-shadow: 0 0 0 2px var(--dt-accent, #1d4fd7);
|
|
1396
1428
|
}
|
|
1397
1429
|
|
|
1398
1430
|
/* ─── Grid body ──────────────────────────────────── */
|
|
@@ -1407,8 +1439,8 @@ function onWindowKeydown(e) {
|
|
|
1407
1439
|
position: sticky;
|
|
1408
1440
|
left: 0;
|
|
1409
1441
|
z-index: 20;
|
|
1410
|
-
background: var(--dt-paper, none), var(--dt-bg, #
|
|
1411
|
-
border-right: 1px solid var(--dt-border, rgba(
|
|
1442
|
+
background: var(--dt-paper, none), var(--dt-bg, #efebe9);
|
|
1443
|
+
border-right: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1412
1444
|
}
|
|
1413
1445
|
|
|
1414
1446
|
/* Timetable hour: the numeral carries the rank, the suffix sits raised
|
|
@@ -1425,7 +1457,7 @@ function onWindowKeydown(e) {
|
|
|
1425
1457
|
font-stretch: 85%;
|
|
1426
1458
|
font-variant-numeric: tabular-nums;
|
|
1427
1459
|
letter-spacing: -0.02em;
|
|
1428
|
-
color: var(--dt-text, rgba(
|
|
1460
|
+
color: var(--dt-text, rgba(15, 15, 15, 0.87));
|
|
1429
1461
|
white-space: nowrap;
|
|
1430
1462
|
}
|
|
1431
1463
|
.tw-gutter-lb::after {
|
|
@@ -1435,7 +1467,7 @@ function onWindowKeydown(e) {
|
|
|
1435
1467
|
height: 1px;
|
|
1436
1468
|
margin-left: 5px;
|
|
1437
1469
|
align-self: center;
|
|
1438
|
-
background: var(--dt-border-day, rgba(
|
|
1470
|
+
background: var(--dt-border-day, rgba(15, 15, 15, 0.3));
|
|
1439
1471
|
}
|
|
1440
1472
|
.tw-gutter-lb--under {
|
|
1441
1473
|
visibility: hidden;
|
|
@@ -1445,7 +1477,7 @@ function onWindowKeydown(e) {
|
|
|
1445
1477
|
font-weight: 500;
|
|
1446
1478
|
line-height: 1;
|
|
1447
1479
|
letter-spacing: 0;
|
|
1448
|
-
color: var(--dt-text-2, rgba(
|
|
1480
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
|
|
1449
1481
|
}
|
|
1450
1482
|
|
|
1451
1483
|
/* The clock beside the now line, and the drag's edges while it lasts —
|
|
@@ -1457,16 +1489,16 @@ function onWindowKeydown(e) {
|
|
|
1457
1489
|
transform: translateY(-50%);
|
|
1458
1490
|
padding: 2px 4px;
|
|
1459
1491
|
border-radius: 0;
|
|
1460
|
-
background: var(--dt-surface, var(--dt-bg, #
|
|
1492
|
+
background: var(--dt-surface, var(--dt-bg, #efebe9));
|
|
1461
1493
|
font: 500 11px/1.2 var(--dt-sans, system-ui, sans-serif);
|
|
1462
1494
|
font-variant-numeric: tabular-nums;
|
|
1463
|
-
color: var(--dt-accent, #
|
|
1495
|
+
color: var(--dt-accent, #1d4fd7);
|
|
1464
1496
|
white-space: nowrap;
|
|
1465
1497
|
z-index: 2;
|
|
1466
1498
|
}
|
|
1467
1499
|
/* The clock is a reversed plate on the accent, like a board's live time. */
|
|
1468
1500
|
.tw-gutter-now {
|
|
1469
|
-
background: var(--dt-accent, #
|
|
1501
|
+
background: var(--dt-accent, #1d4fd7);
|
|
1470
1502
|
color: var(--dt-btn-text, #ffffff);
|
|
1471
1503
|
}
|
|
1472
1504
|
|
|
@@ -1491,7 +1523,7 @@ function onWindowKeydown(e) {
|
|
|
1491
1523
|
left: 0;
|
|
1492
1524
|
right: 0;
|
|
1493
1525
|
height: 1px;
|
|
1494
|
-
background: var(--dt-border, rgba(
|
|
1526
|
+
background: var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1495
1527
|
}
|
|
1496
1528
|
.tw-line--half { opacity: 0.4; }
|
|
1497
1529
|
.tw-now-week {
|
|
@@ -1499,7 +1531,7 @@ function onWindowKeydown(e) {
|
|
|
1499
1531
|
left: 0;
|
|
1500
1532
|
right: 0;
|
|
1501
1533
|
height: 0;
|
|
1502
|
-
border-top: 2px solid var(--dt-accent, #
|
|
1534
|
+
border-top: 2px solid var(--dt-accent, #1d4fd7);
|
|
1503
1535
|
opacity: 0.85;
|
|
1504
1536
|
transform: translateY(-1px);
|
|
1505
1537
|
}
|
|
@@ -1509,35 +1541,38 @@ function onWindowKeydown(e) {
|
|
|
1509
1541
|
flex: 1 1 0;
|
|
1510
1542
|
min-width: var(--tw-col-min, 110px);
|
|
1511
1543
|
position: relative;
|
|
1512
|
-
border-left: 1px solid var(--dt-border, rgba(
|
|
1544
|
+
border-left: 1px solid var(--dt-border, rgba(15, 15, 15, 0.08));
|
|
1513
1545
|
box-sizing: border-box;
|
|
1514
1546
|
}
|
|
1515
1547
|
.tw-col:focus-visible {
|
|
1516
|
-
outline: 2px solid var(--dt-accent, #
|
|
1548
|
+
outline: 2px solid var(--dt-accent, #1d4fd7);
|
|
1517
1549
|
outline-offset: -2px;
|
|
1518
1550
|
}
|
|
1519
1551
|
/* The gutter's right border already bounds the first column */
|
|
1520
1552
|
.tw-lines + .tw-col { border-left: none; }
|
|
1521
1553
|
|
|
1522
|
-
|
|
1554
|
+
/* --tw-col-wash: the column's ground, repeated under an event that the
|
|
1555
|
+
now line crosses (that event is opaque, so the line runs beneath it). */
|
|
1556
|
+
.tw-col { background: var(--tw-col-wash, transparent); }
|
|
1557
|
+
.tw-col--today { --tw-col-wash: var(--dt-today-bg, rgba(29, 79, 215, 0.04)); }
|
|
1523
1558
|
/* Dim past days with a wash, never a subtree opacity (event contrast) */
|
|
1524
1559
|
.tw-col--past {
|
|
1525
|
-
|
|
1560
|
+
--tw-col-wash: color-mix(in srgb, var(--dt-text, rgba(15, 15, 15, 0.87)) 4%, transparent);
|
|
1526
1561
|
}
|
|
1527
1562
|
/* What has already happened steps back; a cancelled block keeps its own look. */
|
|
1528
1563
|
.tw-ev--past:not(.tw-ev--cancelled) {
|
|
1529
1564
|
opacity: 0.78;
|
|
1530
1565
|
}
|
|
1531
1566
|
.tw-col--weekend:not(.tw-col--today):not(.tw-col--past) {
|
|
1532
|
-
|
|
1567
|
+
--tw-col-wash: var(--dt-weekend-bg, rgba(15, 15, 15, 0.012));
|
|
1533
1568
|
}
|
|
1534
1569
|
.tw-col--disabled {
|
|
1535
1570
|
background: repeating-linear-gradient(
|
|
1536
1571
|
45deg,
|
|
1537
1572
|
transparent,
|
|
1538
1573
|
transparent 6px,
|
|
1539
|
-
var(--dt-border, rgba(
|
|
1540
|
-
var(--dt-border, rgba(
|
|
1574
|
+
var(--dt-border, rgba(15, 15, 15, 0.08)) 6px,
|
|
1575
|
+
var(--dt-border, rgba(15, 15, 15, 0.08)) 7px
|
|
1541
1576
|
) !important;
|
|
1542
1577
|
}
|
|
1543
1578
|
|
|
@@ -1549,8 +1584,8 @@ function onWindowKeydown(e) {
|
|
|
1549
1584
|
z-index: 2;
|
|
1550
1585
|
background: repeating-linear-gradient(
|
|
1551
1586
|
-45deg,
|
|
1552
|
-
color-mix(in srgb, var(--dt-text, rgba(
|
|
1553
|
-
color-mix(in srgb, var(--dt-text, rgba(
|
|
1587
|
+
color-mix(in srgb, var(--dt-text, rgba(15, 15, 15, 0.87)) 4%, transparent),
|
|
1588
|
+
color-mix(in srgb, var(--dt-text, rgba(15, 15, 15, 0.87)) 4%, transparent) 4px,
|
|
1554
1589
|
transparent 4px,
|
|
1555
1590
|
transparent 8px
|
|
1556
1591
|
);
|
|
@@ -1561,8 +1596,8 @@ function onWindowKeydown(e) {
|
|
|
1561
1596
|
overflow: hidden;
|
|
1562
1597
|
}
|
|
1563
1598
|
.tw-blocked-lb {
|
|
1564
|
-
font: 500
|
|
1565
|
-
color: var(--dt-text-2, rgba(
|
|
1599
|
+
font: 500 11px/1 var(--dt-sans, system-ui, sans-serif);
|
|
1600
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
|
|
1566
1601
|
text-transform: uppercase;
|
|
1567
1602
|
letter-spacing: 0.04em;
|
|
1568
1603
|
white-space: nowrap;
|
|
@@ -1570,24 +1605,28 @@ function onWindowKeydown(e) {
|
|
|
1570
1605
|
}
|
|
1571
1606
|
|
|
1572
1607
|
/* ─── Now line ───────────────────────────────────── */
|
|
1608
|
+
/* Under the events (z 6): the one it crosses is opaque (.tw-ev--on-now),
|
|
1609
|
+
so the line never strikes through a title. The dot stays on top. */
|
|
1573
1610
|
.tw-now {
|
|
1574
1611
|
position: absolute;
|
|
1575
1612
|
left: 0;
|
|
1576
1613
|
right: 0;
|
|
1577
1614
|
height: 0;
|
|
1578
|
-
border-top: 2px solid var(--dt-accent, #
|
|
1579
|
-
z-index:
|
|
1615
|
+
border-top: 2px solid var(--dt-accent, #1d4fd7);
|
|
1616
|
+
z-index: 5;
|
|
1580
1617
|
pointer-events: none;
|
|
1581
1618
|
transform: translateY(-1px);
|
|
1582
1619
|
}
|
|
1583
1620
|
.tw-now-dot {
|
|
1584
1621
|
position: absolute;
|
|
1585
1622
|
left: -4px;
|
|
1586
|
-
top: -5px;
|
|
1587
1623
|
width: 8px;
|
|
1588
1624
|
height: 8px;
|
|
1625
|
+
margin-top: -4px;
|
|
1589
1626
|
border-radius: 50%;
|
|
1590
|
-
background: var(--dt-accent, #
|
|
1627
|
+
background: var(--dt-accent, #1d4fd7);
|
|
1628
|
+
z-index: 12;
|
|
1629
|
+
pointer-events: none;
|
|
1591
1630
|
}
|
|
1592
1631
|
|
|
1593
1632
|
/* ─── Events ─────────────────────────────────────── */
|
|
@@ -1608,7 +1647,7 @@ function onWindowKeydown(e) {
|
|
|
1608
1647
|
-webkit-tap-highlight-color: transparent;
|
|
1609
1648
|
}
|
|
1610
1649
|
.tw-ev:hover {
|
|
1611
|
-
background: var(--dt-hover, rgba(
|
|
1650
|
+
background: var(--dt-hover, rgba(15, 15, 15, 0.04));
|
|
1612
1651
|
z-index: 8;
|
|
1613
1652
|
}
|
|
1614
1653
|
/* Short blocks keep duration-proportional height, but get a 44px
|
|
@@ -1628,8 +1667,19 @@ function onWindowKeydown(e) {
|
|
|
1628
1667
|
z-index: 9;
|
|
1629
1668
|
}
|
|
1630
1669
|
.tw-ev--current {
|
|
1631
|
-
background: var(--dt-accent-dim, rgba(
|
|
1632
|
-
}
|
|
1670
|
+
background: var(--dt-accent-dim, rgba(29, 79, 215, 0.12));
|
|
1671
|
+
}
|
|
1672
|
+
/* An event the now line crosses lays its column's ground (and its own
|
|
1673
|
+
wash) over the paper, so the line passes beneath its text. */
|
|
1674
|
+
.tw-ev.tw-ev--on-now {
|
|
1675
|
+
background:
|
|
1676
|
+
linear-gradient(var(--tw-ev-wash, transparent), var(--tw-ev-wash, transparent)),
|
|
1677
|
+
linear-gradient(var(--tw-col-wash, transparent), var(--tw-col-wash, transparent)),
|
|
1678
|
+
var(--dt-paper, none),
|
|
1679
|
+
var(--dt-bg, #efebe9);
|
|
1680
|
+
}
|
|
1681
|
+
.tw-ev--on-now.tw-ev--current { --tw-ev-wash: var(--dt-accent-dim, rgba(29, 79, 215, 0.12)); }
|
|
1682
|
+
.tw-ev--on-now:hover { --tw-ev-wash: var(--dt-hover, rgba(15, 15, 15, 0.04)); }
|
|
1633
1683
|
.tw-ev--resizing {
|
|
1634
1684
|
z-index: 50;
|
|
1635
1685
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
|
|
@@ -1647,12 +1697,12 @@ function onWindowKeydown(e) {
|
|
|
1647
1697
|
grid; a tentative one is set in grey with a dashed bar. */
|
|
1648
1698
|
.tw-ev--cancelled .tw-ev-title {
|
|
1649
1699
|
text-decoration: line-through;
|
|
1650
|
-
color: var(--dt-text-2, rgba(
|
|
1700
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
|
|
1651
1701
|
}
|
|
1652
1702
|
.tw-ev--cancelled .tw-ev-stripe { opacity: 0.45; /* decorative bar only */ }
|
|
1653
1703
|
.tw-ev--tentative .tw-ev-title,
|
|
1654
1704
|
.tw-ev--full .tw-ev-title {
|
|
1655
|
-
color: var(--dt-text-2, rgba(
|
|
1705
|
+
color: var(--dt-text-2, rgba(15, 15, 15, 0.54));
|
|
1656
1706
|
}
|
|
1657
1707
|
.tw-ev--tentative .tw-ev-stripe,
|
|
1658
1708
|
.tw-ev--limited .tw-ev-stripe {
|
|
@@ -1681,25 +1731,30 @@ function onWindowKeydown(e) {
|
|
|
1681
1731
|
gap: 1px;
|
|
1682
1732
|
overflow: hidden;
|
|
1683
1733
|
}
|
|
1684
|
-
/* Compact (< ~35min at default zoom):
|
|
1734
|
+
/* Compact (< ~35min at default zoom): one line, "Title 9:00". The title
|
|
1735
|
+
wins the room: the time wraps onto a second line, which the block
|
|
1736
|
+
clips, before the title is cut; a title too long alone ellipsizes. */
|
|
1685
1737
|
.tw-ev--compact .tw-ev-body {
|
|
1686
1738
|
flex-direction: row;
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1739
|
+
flex-wrap: wrap;
|
|
1740
|
+
align-content: flex-start;
|
|
1741
|
+
align-items: baseline;
|
|
1742
|
+
gap: 24px 5px;
|
|
1743
|
+
padding-top: 2px;
|
|
1744
|
+
padding-bottom: 0;
|
|
1745
|
+
}
|
|
1746
|
+
.tw-ev--compact .tw-ev-title { flex: 0 1 auto; min-width: 0; }
|
|
1747
|
+
.tw-ev--compact .tw-ev-end { display: none; }
|
|
1692
1748
|
|
|
1693
1749
|
/* Title first, time under it; both one size, rank by weight and ink. */
|
|
1694
1750
|
.tw-ev-time {
|
|
1695
1751
|
order: 1;
|
|
1696
1752
|
font: 400 14px/1.2 var(--dt-sans, system-ui, sans-serif);
|
|
1697
1753
|
font-variant-numeric: tabular-nums;
|
|
1698
|
-
color: var(--dt-text, rgba(
|
|
1754
|
+
color: var(--dt-text, rgba(15, 15, 15, 0.87));
|
|
1699
1755
|
white-space: nowrap;
|
|
1700
1756
|
flex-shrink: 0;
|
|
1701
1757
|
}
|
|
1702
|
-
.tw-ev--compact .tw-ev-time { order: 0; }
|
|
1703
1758
|
/* A narrow overlap column keeps the start time whole and drops the end. */
|
|
1704
1759
|
@container tw-ev (max-width: 104px) {
|
|
1705
1760
|
.tw-ev-end { display: none; }
|
|
@@ -1708,7 +1763,7 @@ function onWindowKeydown(e) {
|
|
|
1708
1763
|
.tw-ev-title {
|
|
1709
1764
|
order: 0;
|
|
1710
1765
|
font: 500 15px/1.25 var(--dt-sans, system-ui, sans-serif);
|
|
1711
|
-
color: var(--dt-text, rgba(
|
|
1766
|
+
color: var(--dt-text, rgba(15, 15, 15, 0.87));
|
|
1712
1767
|
white-space: nowrap;
|
|
1713
1768
|
overflow: hidden;
|
|
1714
1769
|
text-overflow: ellipsis;
|
|
@@ -1717,7 +1772,7 @@ function onWindowKeydown(e) {
|
|
|
1717
1772
|
.tw-ev-loc {
|
|
1718
1773
|
order: 2;
|
|
1719
1774
|
font: 400 12.5px/1.2 var(--dt-sans, system-ui, sans-serif);
|
|
1720
|
-
color: var(--dt-text, rgba(
|
|
1775
|
+
color: var(--dt-text, rgba(15, 15, 15, 0.87));
|
|
1721
1776
|
white-space: nowrap;
|
|
1722
1777
|
overflow: hidden;
|
|
1723
1778
|
text-overflow: ellipsis;
|
|
@@ -1802,7 +1857,7 @@ function onWindowKeydown(e) {
|
|
|
1802
1857
|
right: 3px;
|
|
1803
1858
|
z-index: 40;
|
|
1804
1859
|
border-radius: 0;
|
|
1805
|
-
background: color-mix(in srgb, var(--ev-color) 12%, var(--dt-surface, var(--dt-bg, #
|
|
1860
|
+
background: color-mix(in srgb, var(--ev-color) 12%, var(--dt-surface, var(--dt-bg, #efebe9)));
|
|
1806
1861
|
outline: 1px solid color-mix(in srgb, var(--ev-color) 45%, transparent);
|
|
1807
1862
|
box-shadow: 0 6px 18px color-mix(in srgb, var(--ev-color) 24%, rgba(0, 0, 0, 0.22));
|
|
1808
1863
|
display: flex;
|
|
@@ -1820,14 +1875,14 @@ function onWindowKeydown(e) {
|
|
|
1820
1875
|
box-shadow: none;
|
|
1821
1876
|
}
|
|
1822
1877
|
.tw-ghost-time {
|
|
1823
|
-
font:
|
|
1878
|
+
font: 500 12.5px/1.15 var(--dt-sans, system-ui, sans-serif);
|
|
1824
1879
|
font-variant-numeric: tabular-nums;
|
|
1825
|
-
color: var(--ev-color, var(--dt-accent, #
|
|
1880
|
+
color: var(--ev-color, var(--dt-accent, #1d4fd7));
|
|
1826
1881
|
white-space: nowrap;
|
|
1827
1882
|
}
|
|
1828
1883
|
.tw-ghost-title {
|
|
1829
|
-
font:
|
|
1830
|
-
color: var(--dt-text, rgba(
|
|
1884
|
+
font: 500 12.5px/1.2 var(--dt-sans, system-ui, sans-serif);
|
|
1885
|
+
color: var(--dt-text, rgba(15, 15, 15, 0.87));
|
|
1831
1886
|
white-space: nowrap;
|
|
1832
1887
|
overflow: hidden;
|
|
1833
1888
|
text-overflow: ellipsis;
|
|
@@ -1849,7 +1904,7 @@ function onWindowKeydown(e) {
|
|
|
1849
1904
|
overflow: hidden scroll container. */
|
|
1850
1905
|
.tw-ev:focus-visible {
|
|
1851
1906
|
outline: none;
|
|
1852
|
-
box-shadow: 0 0 0 2px var(--dt-accent, #
|
|
1907
|
+
box-shadow: 0 0 0 2px var(--dt-accent, #1d4fd7);
|
|
1853
1908
|
z-index: 9;
|
|
1854
1909
|
}
|
|
1855
1910
|
|
|
@@ -48,6 +48,8 @@ export interface CalendarContext {
|
|
|
48
48
|
readonly emptySnippet: Snippet | undefined;
|
|
49
49
|
/** Per-instance labels (Calendar's `labels` prop merged over globals); global labels when headless. */
|
|
50
50
|
readonly labels: CalendarLabels;
|
|
51
|
+
/** Say something through the calendar's polite status line (no-op when headless). */
|
|
52
|
+
announce(text: string): void;
|
|
51
53
|
}
|
|
52
54
|
/**
|
|
53
55
|
* Read the calendar context.
|
|
@@ -18,3 +18,6 @@ export interface TimeSlot {
|
|
|
18
18
|
events: TimelineEvent[];
|
|
19
19
|
}
|
|
20
20
|
export declare function groupIntoSlots(evts: TimelineEvent[]): TimeSlot[];
|
|
21
|
+
/** A day in full, in the locale's own order: "Monday, October 19" (en-US),
|
|
22
|
+
* "poniedziałek, 19 października" (pl-PL). For screen-reader names. */
|
|
23
|
+
export declare function dateLong(ms: number, locale?: string): string;
|