@nomideusz/svelte-calendar 1.4.0 → 1.4.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 +85 -62
- package/dist/calendar/Calendar.svelte +33 -2
- package/dist/core/locale.d.ts +5 -0
- package/dist/core/locale.js +68 -17
- package/dist/primitives/DayHeader.svelte +2 -2
- package/dist/primitives/EmptySlot.svelte +1 -1
- package/dist/theme/auto.js +16 -1
- package/dist/views/agenda/AgendaDay.svelte +13 -4
- package/dist/views/agenda/AgendaWeek.svelte +12 -9
- package/dist/views/mobile/MobileDay.svelte +4 -2
- package/dist/views/mobile/MobileWeek.svelte +11 -14
- package/dist/views/month/MonthGrid.svelte +12 -6
- package/dist/views/planner/PlannerScroll.svelte +9 -4
- package/dist/views/planner/PlannerWeek.svelte +77 -13
- package/package.json +1 -1
- package/widget/widget.js +291 -194
|
@@ -10,7 +10,7 @@ import EventContent from "../shared/EventContent.svelte";
|
|
|
10
10
|
import { createClock } from "../../core/clock.svelte.js";
|
|
11
11
|
import { sod, addDaysMs, isAllDay } from "../../core/time.js";
|
|
12
12
|
import { startOfWeek as sowFn } from "../../core/time.js";
|
|
13
|
-
import { fmtTime as _fmtTime, fmtWeekRange, weekdayShort } from "../../core/locale.js";
|
|
13
|
+
import { fmtTime as _fmtTime, fmtDayNum, fmtWeekRange, weekdayShort } from "../../core/locale.js";
|
|
14
14
|
import { dateLong } from "../shared/format.js";
|
|
15
15
|
import { createSwipe } from "./swipe.js";
|
|
16
16
|
let { mondayStart = true, locale, height = null, events = [], style = "", focusDate, oneventclick, selectedEventId = null } = $props();
|
|
@@ -207,7 +207,7 @@ function handleDayKeydown(e, dayMs) {
|
|
|
207
207
|
<div class="mw-date">
|
|
208
208
|
<span class="mw-day-name" class:mw-day-name--today={cell.isToday}>{cell.dayName}</span>
|
|
209
209
|
{#if showDates}
|
|
210
|
-
<span class="mw-day-num" class:mw-day-num--today={cell.isToday}>{cell.
|
|
210
|
+
<span class="mw-day-num" class:mw-day-num--today={cell.isToday}>{fmtDayNum(cell.ms, locale)}</span>
|
|
211
211
|
{/if}
|
|
212
212
|
</div>
|
|
213
213
|
|
|
@@ -231,7 +231,7 @@ function handleDayKeydown(e, dayMs) {
|
|
|
231
231
|
onclick={(e) => { e.stopPropagation(); oneventclick?.(ev); }}
|
|
232
232
|
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); oneventclick?.(ev); } }}
|
|
233
233
|
onpointerenter={() => oneventhover?.(ev)}
|
|
234
|
-
aria-label="{ev.title}{statusText(ev)}, {evTimeLabel(ev)}"
|
|
234
|
+
aria-label="{ev.title}{statusText(ev)}, {dateLong(cell.ms, locale)}, {evTimeLabel(ev)}"
|
|
235
235
|
>
|
|
236
236
|
<span class="mw-ev-stripe"></span>
|
|
237
237
|
<div class="mw-ev-body">
|
|
@@ -247,6 +247,7 @@ function handleDayKeydown(e, dayMs) {
|
|
|
247
247
|
type="button"
|
|
248
248
|
class="mw-ev-more"
|
|
249
249
|
aria-expanded={expandedDays.has(cell.ms)}
|
|
250
|
+
aria-label="{expandedDays.has(cell.ms) ? L.showLess : L.nMore(cell.totalCount - MAX_EVENTS)}, {dateLong(cell.ms, locale)}"
|
|
250
251
|
onclick={() => toggleExpand(cell.ms)}
|
|
251
252
|
>
|
|
252
253
|
{expandedDays.has(cell.ms) ? L.showLess : L.nMore(cell.totalCount - MAX_EVENTS)}
|
|
@@ -356,7 +357,7 @@ function handleDayKeydown(e, dayMs) {
|
|
|
356
357
|
}
|
|
357
358
|
.mw-row-target:focus-visible {
|
|
358
359
|
outline: none;
|
|
359
|
-
box-shadow: inset 0 0 0 2px var(--dt-
|
|
360
|
+
box-shadow: inset 0 0 0 2px var(--dt-text, #0f0f0f);
|
|
360
361
|
}
|
|
361
362
|
|
|
362
363
|
/* ─── Date column ────────────────────────────────── */
|
|
@@ -533,19 +534,15 @@ function handleDayKeydown(e, dayMs) {
|
|
|
533
534
|
pointer-events: auto;
|
|
534
535
|
-webkit-tap-highlight-color: transparent;
|
|
535
536
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
right: 0;
|
|
542
|
-
top: 50%;
|
|
543
|
-
transform: translateY(-50%);
|
|
544
|
-
height: 44px;
|
|
537
|
+
@media (pointer: coarse) {
|
|
538
|
+
.mw-ev-more {
|
|
539
|
+
min-height: 44px;
|
|
540
|
+
min-width: 44px;
|
|
541
|
+
}
|
|
545
542
|
}
|
|
546
543
|
.mw-ev-more:focus-visible {
|
|
547
544
|
outline: none;
|
|
548
|
-
box-shadow: 0 0 0 2px var(--dt-
|
|
545
|
+
box-shadow: 0 0 0 2px var(--dt-text, #0f0f0f);
|
|
549
546
|
}
|
|
550
547
|
|
|
551
548
|
/* ─── Chevron ────────────────────────────────────── */
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
<script lang="ts">import { useCalendarContext } from "../shared/context.svelte.js";
|
|
10
10
|
import { createClock } from "../../core/clock.svelte.js";
|
|
11
11
|
import { DAY_MS, sod, addDaysMs, isAllDay } from "../../core/time.js";
|
|
12
|
-
import { fmtTime, weekdayShort } from "../../core/locale.js";
|
|
12
|
+
import { fmtTime, fmtDayNum, weekdayShort } from "../../core/locale.js";
|
|
13
|
+
import { dateLong } from "../shared/format.js";
|
|
13
14
|
let { events = [], style = "", height = null, locale, focusDate, oneventclick, selectedEventId = null } = $props();
|
|
14
15
|
const ctx = useCalendarContext();
|
|
15
16
|
const L = $derived(ctx.labels);
|
|
@@ -248,7 +249,7 @@ function chipTime(e) {
|
|
|
248
249
|
onkeydown={(e) => cellKeydown(e, cell)}
|
|
249
250
|
>
|
|
250
251
|
<span class="mg-daynum" class:mg-daynum--today={cell.isToday}>
|
|
251
|
-
{cell.
|
|
252
|
+
{fmtDayNum(cell.ms, locale)}
|
|
252
253
|
</span>
|
|
253
254
|
<!-- Phones: dots are a picture of the day; the cell (its label counts
|
|
254
255
|
the events) is the one tap and tab target. -->
|
|
@@ -282,7 +283,7 @@ function chipTime(e) {
|
|
|
282
283
|
class:mg-chip--cancelled={ev.status === 'cancelled'}
|
|
283
284
|
style:--mg-chip-color={ev.color ?? (isAllDay(ev) ? 'var(--dt-accent)' : 'var(--dt-event, var(--dt-accent))')}
|
|
284
285
|
title={ev.title}
|
|
285
|
-
aria-label="{ev.title}{chipTime(ev) ? `, ${chipTime(ev)}` : ''}"
|
|
286
|
+
aria-label="{ev.title}, {dateLong(cell.ms, locale)}{chipTime(ev) ? `, ${chipTime(ev)}` : ''}"
|
|
286
287
|
onclick={(e) => {
|
|
287
288
|
e.stopPropagation();
|
|
288
289
|
oneventclick?.(ev, e.currentTarget.getBoundingClientRect());
|
|
@@ -304,7 +305,7 @@ function chipTime(e) {
|
|
|
304
305
|
type="button"
|
|
305
306
|
class="mg-more"
|
|
306
307
|
aria-expanded={ondayclick ? undefined : false}
|
|
307
|
-
aria-label={L.nMore(cell.overflow)}
|
|
308
|
+
aria-label="{L.nMore(cell.overflow)}, {dateLong(cell.ms, locale)}"
|
|
308
309
|
onclick={(e) => overflowClick(e, cell)}
|
|
309
310
|
>
|
|
310
311
|
{L.nMore(cell.overflow)}
|
|
@@ -417,7 +418,7 @@ function chipTime(e) {
|
|
|
417
418
|
background: var(--dt-hover, rgba(15, 15, 15, 0.04));
|
|
418
419
|
}
|
|
419
420
|
.mg-cell:focus-visible {
|
|
420
|
-
outline: 2px solid var(--dt-
|
|
421
|
+
outline: 2px solid var(--dt-text, #0f0f0f);
|
|
421
422
|
outline-offset: -2px;
|
|
422
423
|
}
|
|
423
424
|
|
|
@@ -498,7 +499,12 @@ function chipTime(e) {
|
|
|
498
499
|
overflow: hidden;
|
|
499
500
|
text-overflow: ellipsis;
|
|
500
501
|
white-space: nowrap;
|
|
502
|
+
/* A Latin title in RTL keeps its own direction: the ellipsis cuts its end */
|
|
503
|
+
unicode-bidi: plaintext;
|
|
504
|
+
text-align: left;
|
|
501
505
|
}
|
|
506
|
+
/* …but it sits on the calendar's side, by the bar */
|
|
507
|
+
.mg-chip-title:dir(rtl) { text-align: right; }
|
|
502
508
|
.mg-more {
|
|
503
509
|
align-self: flex-start;
|
|
504
510
|
border: none;
|
|
@@ -515,7 +521,7 @@ function chipTime(e) {
|
|
|
515
521
|
color: var(--dt-text);
|
|
516
522
|
}
|
|
517
523
|
.mg-more:focus-visible {
|
|
518
|
-
box-shadow: 0 0 0 2px var(--dt-
|
|
524
|
+
box-shadow: 0 0 0 2px var(--dt-text, #0f0f0f);
|
|
519
525
|
outline: none;
|
|
520
526
|
}
|
|
521
527
|
|
|
@@ -22,7 +22,7 @@ import EventContent from "../shared/EventContent.svelte";
|
|
|
22
22
|
import { createClock } from "../../core/clock.svelte.js";
|
|
23
23
|
import { HOUR_MS, sod, addDaysMs, diffDays } from "../../core/time.js";
|
|
24
24
|
import { startOfWeek as sowFn, isAllDay, segmentForDay } from "../../core/time.js";
|
|
25
|
-
import { weekdayShort, monthLong, fmtTime as _fmtTime } from "../../core/locale.js";
|
|
25
|
+
import { weekdayShort, monthLong, fmtDayNum, fmtTime as _fmtTime } from "../../core/locale.js";
|
|
26
26
|
import { createChipFit } from "../shared/chip-fit.svelte.js";
|
|
27
27
|
let { mondayStart = true, locale, height = 520, events = [], style = "", focusDate, oneventclick, oneventcreate, onexternaldrop, selectedEventId = null, readOnly = false, visibleHours } = $props();
|
|
28
28
|
const ctx = useCalendarContext();
|
|
@@ -873,7 +873,7 @@ function onCellKeydown(e, ms) {
|
|
|
873
873
|
<div class="wg-cell-hd" class:wg-cell-hd--today={day.isToday}>
|
|
874
874
|
<span class="wg-day-wd">{weekdayShort(day.ms, locale)}</span>
|
|
875
875
|
{#if showDates}
|
|
876
|
-
<span class="wg-day-num">{day.
|
|
876
|
+
<span class="wg-day-num">{fmtDayNum(day.ms, locale)}</span>
|
|
877
877
|
{/if}
|
|
878
878
|
</div>
|
|
879
879
|
|
|
@@ -1446,7 +1446,12 @@ function onCellKeydown(e, ms) {
|
|
|
1446
1446
|
text-overflow: ellipsis;
|
|
1447
1447
|
min-width: 0;
|
|
1448
1448
|
flex: 1 1 auto;
|
|
1449
|
+
/* A Latin title in RTL keeps its own direction: the ellipsis cuts its end */
|
|
1450
|
+
unicode-bidi: plaintext;
|
|
1451
|
+
text-align: left;
|
|
1449
1452
|
}
|
|
1453
|
+
/* …but it sits on the calendar's side, by the bar */
|
|
1454
|
+
.wg-ev-title:dir(rtl) { text-align: right; }
|
|
1450
1455
|
|
|
1451
1456
|
.wg-ev-loc {
|
|
1452
1457
|
font: 400 12.5px / 1 var(--dt-sans, system-ui, sans-serif);
|
|
@@ -1476,12 +1481,12 @@ function onCellKeydown(e, ms) {
|
|
|
1476
1481
|
|
|
1477
1482
|
.wg-ev-more:focus-visible {
|
|
1478
1483
|
outline: none;
|
|
1479
|
-
box-shadow: 0 0 0 2px var(--dt-
|
|
1484
|
+
box-shadow: 0 0 0 2px var(--dt-text, #0f0f0f);
|
|
1480
1485
|
}
|
|
1481
1486
|
|
|
1482
1487
|
/* ─── Focus-visible ──────────────────────────────── */
|
|
1483
1488
|
.wg-cell:focus-visible {
|
|
1484
|
-
outline: 2px solid var(--dt-
|
|
1489
|
+
outline: 2px solid var(--dt-text, #0f0f0f);
|
|
1485
1490
|
outline-offset: -2px;
|
|
1486
1491
|
}
|
|
1487
1492
|
|
|
@@ -21,7 +21,7 @@ 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, fmtWeekRange, weekdayShort, weekdayLong } from "../../core/locale.js";
|
|
24
|
+
import { fmtHParts, fmtTime, fmtDayNum, fmtDuration, fmtWeekRange, weekdayShort, weekdayLong } from "../../core/locale.js";
|
|
25
25
|
import { dateLong } from "../shared/format.js";
|
|
26
26
|
let { mode = "week", mondayStart = true, locale, height = 520, events = [], style = "", focusDate, oneventclick, oneventcreate, onexternaldrop, selectedEventId = null, readOnly = false, visibleHours } = $props();
|
|
27
27
|
// ── Context ────────────────────────────────────────
|
|
@@ -305,6 +305,9 @@ const weekIsEmpty = $derived(!events.some((ev) => ev.start.getTime() < weekEndMs
|
|
|
305
305
|
// with room for its label (centred on the line) below the sticky top.
|
|
306
306
|
// An event running across that hour line would be sliced under the sticky
|
|
307
307
|
// top, so the scroll starts at that event's hour instead.
|
|
308
|
+
// A server-rendered grid sits at midnight until this runs: it stays
|
|
309
|
+
// hidden until placed (.tw-body--unplaced), and shows anyway after 1.5s.
|
|
310
|
+
let placed = $state(false);
|
|
308
311
|
$effect(() => {
|
|
309
312
|
void weekStartMs;
|
|
310
313
|
void startHour;
|
|
@@ -339,6 +342,7 @@ $effect(() => {
|
|
|
339
342
|
}
|
|
340
343
|
}
|
|
341
344
|
el.scrollTop = Math.max(0, (hour - startHour) * HOUR_H - LABEL_ROOM);
|
|
345
|
+
placed = true;
|
|
342
346
|
});
|
|
343
347
|
});
|
|
344
348
|
// ── Pointer coalescing ─────────────────────────────
|
|
@@ -442,6 +446,9 @@ const TIME_LINE = 11 * 1.1;
|
|
|
442
446
|
const TITLE_LINE = 12 * 1.2;
|
|
443
447
|
const ROOM_LINE = 10 * 1.2;
|
|
444
448
|
const ROOM_AIR = 9;
|
|
449
|
+
/** Tall enough for two title lines over the time (.tw-ev--tall), in the
|
|
450
|
+
* CSS's own line boxes: title 15px/1.25, time 14px/1.2. */
|
|
451
|
+
const TWO_LINE_H = BODY_PAD_Y + 2 * 15 * 1.25 + LINE_GAP + 14 * 1.2;
|
|
445
452
|
function blockParts(ev, height) {
|
|
446
453
|
return fitParts([
|
|
447
454
|
{
|
|
@@ -661,6 +668,20 @@ function handleColsClick(e) {
|
|
|
661
668
|
let focusedColMs = $state(null);
|
|
662
669
|
const tabbableColMs = $derived((dayCols.find((d) => d.ms === focusedColMs) ?? dayCols.find((d) => d.isToday) ?? dayCols[0])?.ms);
|
|
663
670
|
const colsCreate = $derived(!!oneventcreate && !readOnly);
|
|
671
|
+
// After Enter creates, the keyboard follows the new block once the host
|
|
672
|
+
// adds it: the first unseen event at that start, within two updates.
|
|
673
|
+
let createFocus = null;
|
|
674
|
+
$effect(() => {
|
|
675
|
+
const list = events;
|
|
676
|
+
untrack(() => {
|
|
677
|
+
if (!createFocus) return;
|
|
678
|
+
const { startMs, known } = createFocus;
|
|
679
|
+
const ev = list.find((e) => !known.has(e.id) && e.start.getTime() === startMs);
|
|
680
|
+
const block = ev && colsEl?.querySelector(`.tw-ev[data-event-id="${CSS.escape(ev.id)}"]`);
|
|
681
|
+
if (block) block.focus();
|
|
682
|
+
if (block || --createFocus.tries <= 0) createFocus = null;
|
|
683
|
+
});
|
|
684
|
+
});
|
|
664
685
|
function onColKeydown(e, i) {
|
|
665
686
|
if (e.target !== e.currentTarget) return;
|
|
666
687
|
const day = dayCols[i];
|
|
@@ -675,6 +696,11 @@ function onColKeydown(e, i) {
|
|
|
675
696
|
const slot = isBlockedAt(day.ms, hour);
|
|
676
697
|
if (slot) return ctx.announce(`${slot.label || L.unavailable}, ${blockedRangeLabel(day.ms, slot.start, slot.end)}`);
|
|
677
698
|
const startMs = atHour(day.ms, hour);
|
|
699
|
+
createFocus = {
|
|
700
|
+
startMs,
|
|
701
|
+
known: new Set(events.map((ev) => ev.id)),
|
|
702
|
+
tries: 2
|
|
703
|
+
};
|
|
678
704
|
oneventcreate({
|
|
679
705
|
start: new Date(startMs),
|
|
680
706
|
end: new Date(startMs + Math.max(60, minDuration ?? 0) * 6e4)
|
|
@@ -948,7 +974,7 @@ function onWindowKeydown(e) {
|
|
|
948
974
|
>
|
|
949
975
|
<span class="tw-hd-wd">{singleDay ? weekdayLong(day.ms, locale) : weekdayShort(day.ms, locale)}</span>
|
|
950
976
|
{#if showDates}
|
|
951
|
-
<span class="tw-hd-num" class:tw-hd-num--today={day.markToday}>{day.
|
|
977
|
+
<span class="tw-hd-num" class:tw-hd-num--today={day.markToday}>{fmtDayNum(day.ms, locale)}</span>
|
|
952
978
|
{/if}
|
|
953
979
|
{#if dayHeaderSnippet}
|
|
954
980
|
<div class="tw-hd-custom">
|
|
@@ -989,18 +1015,16 @@ function onWindowKeydown(e) {
|
|
|
989
1015
|
{/if}
|
|
990
1016
|
|
|
991
1017
|
<!-- Grid body -->
|
|
992
|
-
<div class="tw-body" style:height="{gridHeight}px">
|
|
1018
|
+
<div class="tw-body" class:tw-body--unplaced={!placed} style:height="{gridHeight}px">
|
|
993
1019
|
<!-- Time gutter -->
|
|
994
1020
|
<div class="tw-gutter" style:width="{GUTTER_W}px" aria-hidden="true">
|
|
995
1021
|
{#each { length: hourCount } as _, i}
|
|
996
|
-
{
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
style:top="{i * HOUR_H}px">{hNum}<small>{hSuf}</small></span>
|
|
1003
|
-
{/if}
|
|
1022
|
+
{@const [hNum, hSuf] = fmtHParts(startHour + i, locale)}
|
|
1023
|
+
<!-- an hour the now plate would half-cover gives way to it -->
|
|
1024
|
+
<span
|
|
1025
|
+
class="tw-gutter-lb"
|
|
1026
|
+
class:tw-gutter-lb--under={nowY !== null && weekHasToday && Math.abs(i * HOUR_H - nowY) < 18}
|
|
1027
|
+
style:top="{i * HOUR_H}px">{hNum}<small>{hSuf}</small></span>
|
|
1004
1028
|
{/each}
|
|
1005
1029
|
{#if axisGhost}
|
|
1006
1030
|
<!-- The axis reads the drag to the minute, at both edges. -->
|
|
@@ -1095,6 +1119,7 @@ function onWindowKeydown(e) {
|
|
|
1095
1119
|
class:tw-ev--past={p.ev.end.getTime() < clock.tick}
|
|
1096
1120
|
class:tw-ev--short={p.height < 44}
|
|
1097
1121
|
class:tw-ev--compact={p.height < 34}
|
|
1122
|
+
class:tw-ev--tall={p.height >= TWO_LINE_H}
|
|
1098
1123
|
class:tw-ev--on-now={weekHasToday && nowY !== null && p.top < nowY && p.top + p.height > nowY}
|
|
1099
1124
|
style:top="{p.top}px"
|
|
1100
1125
|
style:height="{p.height}px"
|
|
@@ -1378,9 +1403,13 @@ function onWindowKeydown(e) {
|
|
|
1378
1403
|
white-space: nowrap;
|
|
1379
1404
|
overflow: hidden;
|
|
1380
1405
|
text-overflow: ellipsis;
|
|
1406
|
+
unicode-bidi: plaintext;
|
|
1407
|
+
text-align: left;
|
|
1381
1408
|
flex: 1;
|
|
1382
1409
|
min-width: 0;
|
|
1383
1410
|
}
|
|
1411
|
+
/* …but it sits on the calendar's side, by the bar */
|
|
1412
|
+
.tw-ad-title:dir(rtl) { text-align: right; }
|
|
1384
1413
|
.tw-ad-span {
|
|
1385
1414
|
font: 400 12.5px/1 var(--dt-sans, system-ui, sans-serif);
|
|
1386
1415
|
font-variant-numeric: tabular-nums;
|
|
@@ -1424,7 +1453,7 @@ function onWindowKeydown(e) {
|
|
|
1424
1453
|
.tw-ad-more:hover { color: var(--dt-text, rgba(15, 15, 15, 0.87)); }
|
|
1425
1454
|
.tw-ad-more:focus-visible {
|
|
1426
1455
|
outline: none;
|
|
1427
|
-
box-shadow: 0 0 0 2px var(--dt-
|
|
1456
|
+
box-shadow: 0 0 0 2px var(--dt-text, #0f0f0f);
|
|
1428
1457
|
}
|
|
1429
1458
|
|
|
1430
1459
|
/* ─── Grid body ──────────────────────────────────── */
|
|
@@ -1432,6 +1461,11 @@ function onWindowKeydown(e) {
|
|
|
1432
1461
|
display: flex;
|
|
1433
1462
|
position: relative;
|
|
1434
1463
|
}
|
|
1464
|
+
.tw-body--unplaced {
|
|
1465
|
+
visibility: hidden;
|
|
1466
|
+
animation: tw-reveal 0s 1.5s forwards;
|
|
1467
|
+
}
|
|
1468
|
+
@keyframes tw-reveal { to { visibility: visible; } }
|
|
1435
1469
|
|
|
1436
1470
|
/* ─── Time gutter ────────────────────────────────── */
|
|
1437
1471
|
.tw-gutter {
|
|
@@ -1469,6 +1503,10 @@ function onWindowKeydown(e) {
|
|
|
1469
1503
|
align-self: center;
|
|
1470
1504
|
background: var(--dt-border-day, rgba(15, 15, 15, 0.3));
|
|
1471
1505
|
}
|
|
1506
|
+
/* The first hour has no room above its line: it hangs below it, the
|
|
1507
|
+
tick still on the line. */
|
|
1508
|
+
.tw-gutter-lb:first-child { transform: none; }
|
|
1509
|
+
.tw-gutter-lb:first-child::after { align-self: flex-start; }
|
|
1472
1510
|
.tw-gutter-lb--under {
|
|
1473
1511
|
visibility: hidden;
|
|
1474
1512
|
}
|
|
@@ -1545,7 +1583,7 @@ function onWindowKeydown(e) {
|
|
|
1545
1583
|
box-sizing: border-box;
|
|
1546
1584
|
}
|
|
1547
1585
|
.tw-col:focus-visible {
|
|
1548
|
-
outline: 2px solid var(--dt-
|
|
1586
|
+
outline: 2px solid var(--dt-text, #0f0f0f);
|
|
1549
1587
|
outline-offset: -2px;
|
|
1550
1588
|
}
|
|
1551
1589
|
/* The gutter's right border already bounds the first column */
|
|
@@ -1767,6 +1805,30 @@ function onWindowKeydown(e) {
|
|
|
1767
1805
|
white-space: nowrap;
|
|
1768
1806
|
overflow: hidden;
|
|
1769
1807
|
text-overflow: ellipsis;
|
|
1808
|
+
/* A Latin title in an RTL calendar keeps its own direction, so the
|
|
1809
|
+
ellipsis cuts its end, not its start. */
|
|
1810
|
+
unicode-bidi: plaintext;
|
|
1811
|
+
text-align: left;
|
|
1812
|
+
}
|
|
1813
|
+
/* …but it sits on the calendar's side, by the bar */
|
|
1814
|
+
:is(.tw-ev-title, .tw-ev-loc):dir(rtl) { text-align: right; }
|
|
1815
|
+
/* A block tall enough for two title lines over the time wraps the title
|
|
1816
|
+
to two. The parts flow in a wrapping column, so a room that no longer
|
|
1817
|
+
fits under them moves into a second column the block clips: it gives
|
|
1818
|
+
way whole, before the title is cut, instead of being sliced. */
|
|
1819
|
+
.tw-ev--tall .tw-ev-body {
|
|
1820
|
+
flex-wrap: wrap;
|
|
1821
|
+
column-gap: 16px;
|
|
1822
|
+
}
|
|
1823
|
+
.tw-ev--tall :is(.tw-ev-title, .tw-ev-time, .tw-ev-loc) { width: 100%; }
|
|
1824
|
+
.tw-ev--tall .tw-ev-title {
|
|
1825
|
+
display: -webkit-box;
|
|
1826
|
+
-webkit-box-orient: vertical;
|
|
1827
|
+
-webkit-line-clamp: 2;
|
|
1828
|
+
line-clamp: 2;
|
|
1829
|
+
white-space: normal;
|
|
1830
|
+
overflow-wrap: break-word; /* a word wider than an overlap lane breaks, not clips */
|
|
1831
|
+
hyphens: auto; /* …and hyphenates where the host page declares a lang */
|
|
1770
1832
|
}
|
|
1771
1833
|
|
|
1772
1834
|
.tw-ev-loc {
|
|
@@ -1776,6 +1838,8 @@ function onWindowKeydown(e) {
|
|
|
1776
1838
|
white-space: nowrap;
|
|
1777
1839
|
overflow: hidden;
|
|
1778
1840
|
text-overflow: ellipsis;
|
|
1841
|
+
unicode-bidi: plaintext;
|
|
1842
|
+
text-align: left;
|
|
1779
1843
|
}
|
|
1780
1844
|
|
|
1781
1845
|
.tw-ev-live {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nomideusz/svelte-calendar",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.2",
|
|
4
4
|
"description": "A themeable Svelte 5 calendar: day, week, scrolling-week and month views, agenda lists, touch-first mobile layouts, drag-and-drop, timezones, a headless API and an embeddable web component.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": [
|