@nomideusz/svelte-calendar 0.7.5 → 0.8.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.
Files changed (36) hide show
  1. package/README.md +19 -4
  2. package/dist/calendar/Calendar.svelte +364 -497
  3. package/dist/calendar/Calendar.svelte.d.ts +6 -2
  4. package/dist/core/clock.svelte.js +12 -5
  5. package/dist/core/locale.d.ts +4 -0
  6. package/dist/core/locale.js +4 -0
  7. package/dist/engine/view-state.svelte.d.ts +2 -2
  8. package/dist/engine/view-state.svelte.js +20 -0
  9. package/dist/headless/create-calendar.svelte.js +18 -2
  10. package/dist/headless/types.d.ts +6 -6
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +3 -0
  13. package/dist/primitives/DayHeader.svelte +9 -25
  14. package/dist/primitives/EmptySlot.svelte +15 -31
  15. package/dist/primitives/EventBlock.svelte +33 -61
  16. package/dist/primitives/NowIndicator.svelte +16 -42
  17. package/dist/primitives/TimeGutter.svelte +9 -23
  18. package/dist/views/agenda/Agenda.svelte +3 -10
  19. package/dist/views/agenda/AgendaDay.svelte +195 -167
  20. package/dist/views/agenda/AgendaWeek.svelte +141 -195
  21. package/dist/views/mobile/Mobile.svelte +3 -10
  22. package/dist/views/mobile/MobileDay.svelte +422 -266
  23. package/dist/views/mobile/MobileWeek.svelte +131 -186
  24. package/dist/views/month/MonthGrid.svelte +334 -0
  25. package/dist/views/month/MonthGrid.svelte.d.ts +15 -0
  26. package/dist/views/planner/Planner.svelte +3 -10
  27. package/dist/views/planner/PlannerDay.svelte +636 -546
  28. package/dist/views/planner/PlannerWeek.svelte +299 -412
  29. package/dist/views/shared/EventContent.svelte +16 -0
  30. package/dist/views/shared/EventContent.svelte.d.ts +9 -0
  31. package/dist/views/shared/context.svelte.d.ts +1 -0
  32. package/dist/views/shared/context.svelte.js +1 -0
  33. package/dist/widget/CalendarWidget.svelte +79 -116
  34. package/package.json +3 -2
  35. package/widget/svelte-calendar.css +321 -10
  36. package/widget/widget.js +1944 -1031
@@ -5,192 +5,135 @@
5
5
  list of events. Tap a day to drill into MobileDay. Swipe
6
6
  left/right to navigate weeks.
7
7
  -->
8
- <script lang="ts">
9
- import { useCalendarContext } from '../shared/context.svelte.js';
10
- import { createClock } from '../../core/clock.svelte.js';
11
- import type { TimelineEvent } from '../../core/types.js';
12
- import { DAY_MS, sod, isAllDay, isMultiDay } from '../../core/time.js';
13
- import { startOfWeek as sowFn } from '../../core/time.js';
14
- import { fmtTime as _fmtTime, weekdayShort, getLabels } from '../../core/locale.js';
15
-
16
- const L = $derived(getLabels());
17
-
18
- interface Props {
19
- mondayStart?: boolean;
20
- locale?: string;
21
- height?: number | null;
22
- events?: TimelineEvent[];
23
- style?: string;
24
- focusDate?: Date;
25
- oneventclick?: (event: TimelineEvent) => void;
26
- oneventcreate?: (range: { start: Date; end: Date }) => void;
27
- selectedEventId?: string | null;
28
- readOnly?: boolean;
29
- [key: string]: unknown;
30
- }
31
-
32
- let {
33
- mondayStart = true,
34
- locale,
35
- height = null,
36
- events = [],
37
- style = '',
38
- focusDate,
39
- oneventclick,
40
- oneventcreate,
41
- selectedEventId = null,
42
- readOnly = false,
43
- }: Props = $props();
44
-
45
- // ── Context ────────────────────────────────────────
46
- const ctx = useCalendarContext();
47
- const viewState = $derived(ctx.viewState);
48
- const equalDays = $derived(ctx.equalDays);
49
- const showDates = $derived(ctx.showDates);
50
- const hideDays = $derived(ctx.hideDays);
51
- const autoHeight = $derived(ctx.autoHeight);
52
- const oneventhover = $derived(ctx.oneventhover);
53
- const disabledSet = $derived(ctx.disabledSet);
54
- const loadRangeCtx = $derived(ctx.loadRange);
55
- const minDuration = $derived(ctx.minDuration);
56
-
57
- const clock = createClock();
58
-
59
- // ── Config ─────────────────────────────────────────
60
- const MAX_EVENTS = 3;
61
- const customDays = $derived(viewState?.dayCount ?? 7);
62
-
63
- // ── Derived week data ──────────────────────────────
64
- const todayMs = $derived(clock.today);
65
- const focusMs = $derived(focusDate ? sod(focusDate.getTime()) : todayMs);
66
-
67
- const weekStart = $derived(
68
- customDays === 7
69
- ? sowFn(focusMs, mondayStart)
70
- : sod(focusMs)
71
- );
72
-
73
- // ── Load range ─────────────────────────────────────
74
- $effect(() => {
75
- if (!loadRangeCtx) return;
76
- const rangeStart = new Date(weekStart - 7 * DAY_MS);
77
- const rangeEnd = new Date(weekStart + (customDays + 7) * DAY_MS);
78
- loadRangeCtx.set({ start: rangeStart, end: rangeEnd });
79
- return () => loadRangeCtx.set(null);
80
- });
81
-
82
- // ── Day cells ──────────────────────────────────────
83
- interface DayCell {
84
- ms: number;
85
- dayNum: number;
86
- dayName: string;
87
- isToday: boolean;
88
- isPast: boolean;
89
- isDisabled: boolean;
90
- isWeekend: boolean;
91
- events: TimelineEvent[];
92
- allDayCount: number;
93
- totalCount: number;
94
- }
95
-
96
- const dayCells = $derived.by(() => {
97
- const result: DayCell[] = [];
98
- const hideSet = new Set(hideDays ?? []);
99
-
100
- for (let i = 0; i < customDays; i++) {
101
- const ms = weekStart + i * DAY_MS;
102
- const d = new Date(ms);
103
- const jsDay = d.getDay();
104
- const isoDay = jsDay === 0 ? 7 : jsDay;
105
-
106
- if (hideSet.has(isoDay)) continue;
107
-
108
- const isToday = ms === todayMs;
109
- const isPast = equalDays ? false : ms < todayMs;
110
- const isWeekend = jsDay === 0 || jsDay === 6;
111
- const isDisabled = disabledSet.has(ms);
112
- const dayEnd = ms + DAY_MS;
113
-
114
- const dayEvents = events
115
- .filter(ev => ev.start.getTime() < dayEnd && ev.end.getTime() > ms)
116
- .sort((a, b) => a.start.getTime() - b.start.getTime());
117
-
118
- const allDayCount = dayEvents.filter(ev => isAllDay(ev) || isMultiDay(ev)).length;
119
-
120
- result.push({
121
- ms,
122
- dayNum: d.getDate(),
123
- dayName: weekdayShort(ms, locale),
124
- isToday,
125
- isPast,
126
- isDisabled,
127
- isWeekend,
128
- events: dayEvents,
129
- allDayCount,
130
- totalCount: dayEvents.length,
131
- });
132
- }
133
- return result;
134
- });
135
-
136
- // ── Format helpers ─────────────────────────────────
137
- function fmtTime(d: Date): string {
138
- return _fmtTime(d, locale);
139
- }
140
-
141
- // ── Touch swipe ────────────────────────────────────
142
- let touchStartX = 0;
143
- let touchStartY = 0;
144
- let swiping = false;
145
- let swipeOffset = $state(0);
146
- const SWIPE_THRESHOLD = 60;
147
-
148
- function onTouchStart(e: TouchEvent) {
149
- const t = e.touches[0];
150
- touchStartX = t.clientX;
151
- touchStartY = t.clientY;
152
- swiping = true;
153
- swipeOffset = 0;
154
- }
155
-
156
- function onTouchMove(e: TouchEvent) {
157
- if (!swiping) return;
158
- const t = e.touches[0];
159
- const dx = t.clientX - touchStartX;
160
- const dy = t.clientY - touchStartY;
161
- if (Math.abs(dy) > Math.abs(dx) * 0.8) { swiping = false; return; }
162
- swipeOffset = dx;
163
- }
164
-
165
- function onTouchEnd() {
166
- if (!swiping) { swipeOffset = 0; return; }
167
- if (Math.abs(swipeOffset) > SWIPE_THRESHOLD) {
168
- if (swipeOffset > 0) {
169
- viewState?.prev();
170
- } else {
171
- viewState?.next();
172
- }
173
- }
174
- swipeOffset = 0;
175
- swiping = false;
176
- }
177
-
178
- // ── Day tap → switch to day mode ───────────────────
179
- function handleDayTap(dayMs: number) {
180
- if (viewState) {
181
- viewState.setFocusDate(new Date(dayMs));
182
- // Switch to day-mobile view if available
183
- const currentView = viewState.view;
184
- const dayView = currentView.replace('week', 'day');
185
- viewState.setView(dayView);
186
- }
187
- }
188
-
189
- function handleDayKeydown(e: KeyboardEvent, dayMs: number) {
190
- if (e.key !== 'Enter' && e.key !== ' ') return;
191
- e.preventDefault();
192
- handleDayTap(dayMs);
193
- }
8
+ <script lang="ts">import { useCalendarContext } from "../shared/context.svelte.js";
9
+ import EventContent from "../shared/EventContent.svelte";
10
+ import { createClock } from "../../core/clock.svelte.js";
11
+ import { DAY_MS, sod, isAllDay, isMultiDay } from "../../core/time.js";
12
+ import { startOfWeek as sowFn } from "../../core/time.js";
13
+ import { fmtTime as _fmtTime, weekdayShort, getLabels } from "../../core/locale.js";
14
+ const L = $derived(getLabels());
15
+ let {
16
+ mondayStart = true,
17
+ locale,
18
+ height = null,
19
+ events = [],
20
+ style = "",
21
+ focusDate,
22
+ oneventclick,
23
+ oneventcreate,
24
+ selectedEventId = null,
25
+ readOnly = false
26
+ } = $props();
27
+ const ctx = useCalendarContext();
28
+ const viewState = $derived(ctx.viewState);
29
+ const equalDays = $derived(ctx.equalDays);
30
+ const showDates = $derived(ctx.showDates);
31
+ const hideDays = $derived(ctx.hideDays);
32
+ const autoHeight = $derived(ctx.autoHeight);
33
+ const oneventhover = $derived(ctx.oneventhover);
34
+ const disabledSet = $derived(ctx.disabledSet);
35
+ const loadRangeCtx = $derived(ctx.loadRange);
36
+ const minDuration = $derived(ctx.minDuration);
37
+ const clock = createClock();
38
+ const MAX_EVENTS = 3;
39
+ const customDays = $derived(viewState?.dayCount ?? 7);
40
+ const todayMs = $derived(clock.today);
41
+ const focusMs = $derived(focusDate ? sod(focusDate.getTime()) : todayMs);
42
+ const weekStart = $derived(
43
+ customDays === 7 ? sowFn(focusMs, mondayStart) : sod(focusMs)
44
+ );
45
+ $effect(() => {
46
+ if (!loadRangeCtx) return;
47
+ const rangeStart = new Date(weekStart - 7 * DAY_MS);
48
+ const rangeEnd = new Date(weekStart + (customDays + 7) * DAY_MS);
49
+ loadRangeCtx.set({ start: rangeStart, end: rangeEnd });
50
+ return () => loadRangeCtx.set(null);
51
+ });
52
+ const dayCells = $derived.by(() => {
53
+ const result = [];
54
+ const hideSet = new Set(hideDays ?? []);
55
+ for (let i = 0; i < customDays; i++) {
56
+ const ms = weekStart + i * DAY_MS;
57
+ const d = new Date(ms);
58
+ const jsDay = d.getDay();
59
+ const isoDay = jsDay === 0 ? 7 : jsDay;
60
+ if (hideSet.has(isoDay)) continue;
61
+ const isToday = ms === todayMs;
62
+ const isPast = equalDays ? false : ms < todayMs;
63
+ const isWeekend = jsDay === 0 || jsDay === 6;
64
+ const isDisabled = disabledSet.has(ms);
65
+ const dayEnd = ms + DAY_MS;
66
+ const dayEvents = events.filter((ev) => ev.start.getTime() < dayEnd && ev.end.getTime() > ms).sort((a, b) => a.start.getTime() - b.start.getTime());
67
+ const allDayCount = dayEvents.filter((ev) => isAllDay(ev) || isMultiDay(ev)).length;
68
+ result.push({
69
+ ms,
70
+ dayNum: d.getDate(),
71
+ dayName: weekdayShort(ms, locale),
72
+ isToday,
73
+ isPast,
74
+ isDisabled,
75
+ isWeekend,
76
+ events: dayEvents,
77
+ allDayCount,
78
+ totalCount: dayEvents.length
79
+ });
80
+ }
81
+ return result;
82
+ });
83
+ function fmtTime(d) {
84
+ return _fmtTime(d, locale);
85
+ }
86
+ let touchStartX = 0;
87
+ let touchStartY = 0;
88
+ let swiping = false;
89
+ let swipeOffset = $state(0);
90
+ const SWIPE_THRESHOLD = 60;
91
+ function onTouchStart(e) {
92
+ const t = e.touches[0];
93
+ touchStartX = t.clientX;
94
+ touchStartY = t.clientY;
95
+ swiping = true;
96
+ swipeOffset = 0;
97
+ }
98
+ function onTouchMove(e) {
99
+ if (!swiping) return;
100
+ const t = e.touches[0];
101
+ const dx = t.clientX - touchStartX;
102
+ const dy = t.clientY - touchStartY;
103
+ if (Math.abs(dy) > Math.abs(dx) * 0.8) {
104
+ swiping = false;
105
+ return;
106
+ }
107
+ swipeOffset = dx;
108
+ }
109
+ function onTouchEnd() {
110
+ if (!swiping) {
111
+ swipeOffset = 0;
112
+ return;
113
+ }
114
+ if (Math.abs(swipeOffset) > SWIPE_THRESHOLD) {
115
+ if (swipeOffset > 0) {
116
+ viewState?.prev();
117
+ } else {
118
+ viewState?.next();
119
+ }
120
+ }
121
+ swipeOffset = 0;
122
+ swiping = false;
123
+ }
124
+ function handleDayTap(dayMs) {
125
+ if (viewState) {
126
+ viewState.setFocusDate(new Date(dayMs));
127
+ const currentView = viewState.view;
128
+ const dayView = currentView.replace("week", "day");
129
+ viewState.setView(dayView);
130
+ }
131
+ }
132
+ function handleDayKeydown(e, dayMs) {
133
+ if (e.key !== "Enter" && e.key !== " ") return;
134
+ e.preventDefault();
135
+ handleDayTap(dayMs);
136
+ }
194
137
  </script>
195
138
 
196
139
  <div
@@ -253,12 +196,14 @@
253
196
  >
254
197
  <span class="mw-ev-stripe"></span>
255
198
  <div class="mw-ev-body">
199
+ <EventContent event={ev}>
256
200
  <span class="mw-ev-title">{ev.title}</span>
257
201
  {#if isAllDay(ev) || isMultiDay(ev)}
258
202
  <span class="mw-ev-time">{L.allDay}</span>
259
203
  {:else}
260
204
  <span class="mw-ev-time">{fmtTime(ev.start)}</span>
261
205
  {/if}
206
+ </EventContent>
262
207
  </div>
263
208
  </button>
264
209
  {/each}
@@ -0,0 +1,334 @@
1
+ <!--
2
+ MonthGrid — classic month overview.
3
+
4
+ Week-aligned grid (4–6 rows, driven by the view-state 'month' range).
5
+ Each cell lists up to MAX_CHIPS events plus a "+N more" overflow; clicking
6
+ an event fires oneventclick, clicking a day (or the overflow) fires
7
+ ondayclick — the natural month → day drill-down.
8
+ -->
9
+ <script lang="ts">import { useCalendarContext } from "../shared/context.svelte.js";
10
+ import { createClock } from "../../core/clock.svelte.js";
11
+ import { DAY_MS, sod, isAllDay } from "../../core/time.js";
12
+ import { fmtTime, weekdayShort, getLabels } from "../../core/locale.js";
13
+ const L = $derived(getLabels());
14
+ let {
15
+ events = [],
16
+ style = "",
17
+ height = null,
18
+ locale,
19
+ focusDate,
20
+ oneventclick,
21
+ selectedEventId = null
22
+ } = $props();
23
+ const ctx = useCalendarContext();
24
+ const viewState = $derived(ctx.viewState);
25
+ const autoHeight = $derived(ctx.autoHeight);
26
+ const isMobile = $derived(ctx.isMobile);
27
+ const disabledSet = $derived(ctx.disabledSet);
28
+ const oneventhover = $derived(ctx.oneventhover);
29
+ const ondayclick = $derived(ctx.ondayclick);
30
+ const eventSnippet = $derived(ctx.eventSnippet);
31
+ const loadRangeCtx = $derived(ctx.loadRange);
32
+ const clock = createClock();
33
+ const todayMs = $derived(clock.today);
34
+ const MAX_CHIPS = $derived(isMobile ? 2 : 3);
35
+ const range = $derived(viewState?.range);
36
+ const focusMonth = $derived((focusDate ?? /* @__PURE__ */ new Date()).getMonth());
37
+ $effect(() => {
38
+ if (!loadRangeCtx || !range) return;
39
+ loadRangeCtx.set({
40
+ start: new Date(range.start.getTime() - 7 * DAY_MS),
41
+ end: new Date(range.end.getTime() + 7 * DAY_MS)
42
+ });
43
+ return () => loadRangeCtx.set(null);
44
+ });
45
+ function eventsForDay(ms) {
46
+ const dayStart = ms;
47
+ const dayEnd = ms + DAY_MS;
48
+ return events.filter((e) => e.start.getTime() < dayEnd && e.end.getTime() > dayStart).sort((a, b) => {
49
+ const aAll = isAllDay(a) ? 0 : 1;
50
+ const bAll = isAllDay(b) ? 0 : 1;
51
+ return aAll - bAll || a.start.getTime() - b.start.getTime();
52
+ });
53
+ }
54
+ const weeks = $derived.by(() => {
55
+ if (!range) return [];
56
+ const rows = [];
57
+ for (let ms = sod(range.start.getTime()); ms < range.end.getTime(); ms += 7 * DAY_MS) {
58
+ const row = [];
59
+ for (let i = 0; i < 7; i++) {
60
+ const cellMs = ms + i * DAY_MS;
61
+ const date = new Date(cellMs);
62
+ const jsDay = date.getDay();
63
+ const dayEvents = eventsForDay(cellMs);
64
+ row.push({
65
+ ms: cellMs,
66
+ date,
67
+ dayNum: date.getDate(),
68
+ inMonth: date.getMonth() === focusMonth,
69
+ isToday: cellMs === todayMs,
70
+ isWeekend: jsDay === 0 || jsDay === 6,
71
+ isDisabled: disabledSet.has(cellMs),
72
+ chips: dayEvents.slice(0, MAX_CHIPS),
73
+ overflow: Math.max(0, dayEvents.length - MAX_CHIPS)
74
+ });
75
+ }
76
+ rows.push(row);
77
+ }
78
+ return rows;
79
+ });
80
+ const weekdayLabels = $derived.by(() => {
81
+ const first = weeks[0];
82
+ if (!first) return [];
83
+ return first.map((c) => weekdayShort(c.ms, locale));
84
+ });
85
+ function chipTime(e) {
86
+ return isAllDay(e) ? "" : fmtTime(e.start, locale);
87
+ }
88
+ </script>
89
+
90
+ <div
91
+ class="mg"
92
+ class:mg--auto={autoHeight}
93
+ style={style || undefined}
94
+ style:height={autoHeight ? undefined : height ? `${height}px` : '100%'}
95
+ role="grid"
96
+ aria-label={L.month}
97
+ >
98
+ <div class="mg-head" role="row">
99
+ {#each weekdayLabels as name (name)}
100
+ <div class="mg-head-cell" role="columnheader">{name}</div>
101
+ {/each}
102
+ </div>
103
+
104
+ <div class="mg-body" style:--mg-rows={weeks.length}>
105
+ {#each weeks as row, ri (ri)}
106
+ {#each row as cell (cell.ms)}
107
+ <div
108
+ class="mg-cell"
109
+ class:mg-cell--out={!cell.inMonth}
110
+ class:mg-cell--today={cell.isToday}
111
+ class:mg-cell--weekend={cell.isWeekend}
112
+ class:mg-cell--disabled={cell.isDisabled}
113
+ class:mg-cell--clickable={!!ondayclick && !cell.isDisabled}
114
+ role="gridcell"
115
+ tabindex={ondayclick && !cell.isDisabled ? 0 : undefined}
116
+ onclick={() => {
117
+ if (!cell.isDisabled) ondayclick?.(cell.date);
118
+ }}
119
+ onkeydown={(e) => {
120
+ if ((e.key === 'Enter' || e.key === ' ') && !cell.isDisabled) {
121
+ e.preventDefault();
122
+ ondayclick?.(cell.date);
123
+ }
124
+ }}
125
+ >
126
+ <span class="mg-daynum" class:mg-daynum--today={cell.isToday}>
127
+ {cell.dayNum}
128
+ </span>
129
+ <div class="mg-chips">
130
+ {#each cell.chips as ev (ev.id + cell.ms)}
131
+ {#if eventSnippet}
132
+ <button
133
+ class="mg-chip mg-chip--custom"
134
+ class:mg-chip--selected={ev.id === selectedEventId}
135
+ onclick={(e) => {
136
+ e.stopPropagation();
137
+ oneventclick?.(ev);
138
+ }}
139
+ onmouseenter={() => oneventhover?.(ev)}
140
+ >
141
+ {@render eventSnippet(ev)}
142
+ </button>
143
+ {:else}
144
+ <button
145
+ class="mg-chip"
146
+ class:mg-chip--selected={ev.id === selectedEventId}
147
+ class:mg-chip--cancelled={ev.status === 'cancelled'}
148
+ style:--mg-chip-color={ev.color ?? 'var(--dt-accent)'}
149
+ title={ev.title}
150
+ onclick={(e) => {
151
+ e.stopPropagation();
152
+ oneventclick?.(ev);
153
+ }}
154
+ onmouseenter={() => oneventhover?.(ev)}
155
+ >
156
+ <span class="mg-chip-dot" aria-hidden="true"></span>
157
+ {#if chipTime(ev)}<span class="mg-chip-time">{chipTime(ev)}</span>{/if}
158
+ <span class="mg-chip-title">{ev.title}</span>
159
+ </button>
160
+ {/if}
161
+ {/each}
162
+ {#if cell.overflow > 0}
163
+ <span class="mg-more">{L.nMore(cell.overflow)}</span>
164
+ {/if}
165
+ </div>
166
+ </div>
167
+ {/each}
168
+ {/each}
169
+ </div>
170
+ </div>
171
+
172
+ <style>
173
+ .mg {
174
+ display: flex;
175
+ flex-direction: column;
176
+ background: var(--dt-bg);
177
+ color: var(--dt-text);
178
+ font-family: var(--dt-sans);
179
+ overflow: hidden;
180
+ }
181
+ .mg--auto {
182
+ height: auto;
183
+ }
184
+
185
+ .mg-head {
186
+ display: grid;
187
+ grid-template-columns: repeat(7, 1fr);
188
+ border-bottom: 1px solid var(--dt-border);
189
+ flex: none;
190
+ }
191
+ .mg-head-cell {
192
+ padding: 6px 8px;
193
+ font-family: var(--dt-mono);
194
+ font-size: 11px;
195
+ font-weight: 600;
196
+ text-transform: uppercase;
197
+ letter-spacing: 0.06em;
198
+ color: var(--dt-text-3);
199
+ }
200
+
201
+ .mg-body {
202
+ flex: 1;
203
+ display: grid;
204
+ grid-template-columns: repeat(7, 1fr);
205
+ grid-template-rows: repeat(var(--mg-rows, 5), minmax(88px, 1fr));
206
+ min-height: 0;
207
+ }
208
+ .mg--auto .mg-body {
209
+ grid-template-rows: repeat(var(--mg-rows, 5), minmax(88px, auto));
210
+ }
211
+
212
+ .mg-cell {
213
+ display: flex;
214
+ flex-direction: column;
215
+ gap: 3px;
216
+ padding: 6px;
217
+ border-right: 1px solid var(--dt-border-day);
218
+ border-bottom: 1px solid var(--dt-border-day);
219
+ min-width: 0;
220
+ overflow: hidden;
221
+ text-align: left;
222
+ }
223
+ .mg-cell:nth-child(7n) {
224
+ border-right: none;
225
+ }
226
+ .mg-cell--weekend {
227
+ background: var(--dt-weekend-bg);
228
+ }
229
+ .mg-cell--out {
230
+ opacity: 0.45;
231
+ }
232
+ .mg-cell--today {
233
+ background: var(--dt-today-bg);
234
+ }
235
+ .mg-cell--disabled {
236
+ opacity: 0.35;
237
+ pointer-events: none;
238
+ }
239
+ .mg-cell--clickable {
240
+ cursor: pointer;
241
+ }
242
+ .mg-cell--clickable:hover {
243
+ background: var(--dt-hover);
244
+ }
245
+ .mg-cell--clickable:focus-visible {
246
+ outline: 2px solid var(--dt-accent);
247
+ outline-offset: -2px;
248
+ }
249
+
250
+ .mg-daynum {
251
+ flex: none;
252
+ font-family: var(--dt-mono);
253
+ font-size: 12px;
254
+ font-weight: 600;
255
+ color: var(--dt-text-2);
256
+ width: 22px;
257
+ height: 22px;
258
+ display: inline-flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ border-radius: 999px;
262
+ }
263
+ .mg-daynum--today {
264
+ background: var(--dt-accent);
265
+ color: var(--dt-btn-text);
266
+ }
267
+
268
+ .mg-chips {
269
+ display: flex;
270
+ flex-direction: column;
271
+ gap: 2px;
272
+ min-height: 0;
273
+ overflow: hidden;
274
+ }
275
+ .mg-chip {
276
+ display: flex;
277
+ align-items: center;
278
+ gap: 5px;
279
+ border: none;
280
+ background: none;
281
+ padding: 2px 4px;
282
+ border-radius: 5px;
283
+ font-family: var(--dt-sans);
284
+ font-size: 12px;
285
+ line-height: 1.3;
286
+ color: var(--dt-text);
287
+ cursor: pointer;
288
+ min-width: 0;
289
+ text-align: left;
290
+ }
291
+ .mg-chip:hover {
292
+ background: var(--dt-hover);
293
+ }
294
+ .mg-chip--selected {
295
+ background: var(--dt-accent-dim);
296
+ }
297
+ .mg-chip--cancelled {
298
+ text-decoration: line-through;
299
+ opacity: 0.55;
300
+ }
301
+ .mg-chip-dot {
302
+ flex: none;
303
+ width: 7px;
304
+ height: 7px;
305
+ border-radius: 999px;
306
+ background: var(--mg-chip-color);
307
+ }
308
+ .mg-chip-time {
309
+ flex: none;
310
+ font-family: var(--dt-mono);
311
+ font-size: 11px;
312
+ color: var(--dt-text-2);
313
+ }
314
+ .mg-chip-title {
315
+ overflow: hidden;
316
+ text-overflow: ellipsis;
317
+ white-space: nowrap;
318
+ }
319
+ .mg-more {
320
+ padding: 1px 4px;
321
+ font-family: var(--dt-mono);
322
+ font-size: 11px;
323
+ color: var(--dt-text-3);
324
+ }
325
+
326
+ @media (max-width: 640px) {
327
+ .mg-body {
328
+ grid-template-rows: repeat(var(--mg-rows, 5), minmax(64px, 1fr));
329
+ }
330
+ .mg-chip-time {
331
+ display: none;
332
+ }
333
+ }
334
+ </style>
@@ -0,0 +1,15 @@
1
+ import type { TimelineEvent } from '../../core/types.js';
2
+ interface Props {
3
+ events?: TimelineEvent[];
4
+ style?: string;
5
+ height?: number | null;
6
+ locale?: string;
7
+ focusDate?: Date;
8
+ oneventclick?: (event: TimelineEvent) => void;
9
+ selectedEventId?: string | null;
10
+ readOnly?: boolean;
11
+ [key: string]: unknown;
12
+ }
13
+ declare const MonthGrid: import("svelte").Component<Props, {}, "">;
14
+ type MonthGrid = ReturnType<typeof MonthGrid>;
15
+ export default MonthGrid;