@nomideusz/svelte-calendar 0.3.1 → 0.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.
@@ -72,6 +72,7 @@
72
72
  oneventclick?: (event: TimelineEvent) => void;
73
73
  oneventcreate?: (range: { start: Date; end: Date }) => void;
74
74
  oneventmove?: (event: TimelineEvent, newStart: Date, newEnd: Date) => void;
75
+ onviewchange?: (viewId: CalendarViewId) => void;
75
76
  }
76
77
 
77
78
  let {
@@ -90,6 +91,7 @@
90
91
  oneventclick,
91
92
  oneventcreate,
92
93
  oneventmove,
94
+ onviewchange,
93
95
  }: Props = $props();
94
96
 
95
97
  // In readOnly mode, suppress mutation callbacks
@@ -153,6 +155,23 @@
153
155
  store.load({ start, end });
154
156
  });
155
157
 
158
+ // Keep active view in sync when external defaultView changes after mount.
159
+ $effect(() => {
160
+ viewState.setView(defaultView);
161
+ });
162
+
163
+ // Keep view state's week-start rule in sync with incoming prop changes.
164
+ $effect(() => {
165
+ if (viewState.mondayStart !== mondayStart) {
166
+ viewState.setMondayStart(mondayStart);
167
+ }
168
+ });
169
+
170
+ // Notify host when active view changes (e.g. via toolbar concept/granularity toggles).
171
+ $effect(() => {
172
+ onviewchange?.(viewState.view);
173
+ });
174
+
156
175
  // ── Resolve active view ──
157
176
  const activeView = $derived(views.find((v) => v.id === viewState.view) ?? views[0]);
158
177
 
@@ -170,7 +189,7 @@
170
189
  lang={locale}
171
190
  >
172
191
  {#if showToolbar}
173
- <Toolbar {viewState} views={toolbarViews} {links} />
192
+ <Toolbar {viewState} views={toolbarViews} {links} {locale} />
174
193
  {/if}
175
194
 
176
195
  <div class="cal-body">
@@ -181,6 +200,7 @@
181
200
  style={theme}
182
201
  height={height - (showToolbar ? 48 : 0)}
183
202
  mondayStart={viewState.mondayStart}
203
+ {locale}
184
204
  focusDate={viewState.focusDate}
185
205
  oneventclick={oneventclick}
186
206
  oneventcreate={effectiveCreate}
@@ -47,6 +47,7 @@ interface Props {
47
47
  end: Date;
48
48
  }) => void;
49
49
  oneventmove?: (event: TimelineEvent, newStart: Date, newEnd: Date) => void;
50
+ onviewchange?: (viewId: CalendarViewId) => void;
50
51
  }
51
52
  declare const Calendar: Component<Props, {}, "">;
52
53
  type Calendar = ReturnType<typeof Calendar>;
@@ -19,20 +19,23 @@
19
19
  views?: ViewOption[];
20
20
  /** Links to show in the toolbar */
21
21
  links?: { href: string; label: string }[];
22
+ /** Locale used for labels */
23
+ locale?: string;
22
24
  }
23
25
 
24
26
  let {
25
27
  viewState,
26
28
  views = [],
27
29
  links = [],
30
+ locale,
28
31
  }: Props = $props();
29
32
 
30
33
  const dateLabel = $derived(() => {
31
34
  if (viewState.granularity === 'day') {
32
- return `${weekdayLong(viewState.focusDate.getTime())}, ${fmtDay(viewState.focusDate.getTime(), Date.now())}`;
35
+ return `${weekdayLong(viewState.focusDate.getTime(), locale)}, ${fmtDay(viewState.focusDate.getTime(), Date.now(), undefined, locale)}`;
33
36
  }
34
37
  const ws = viewState.range.start.getTime();
35
- return fmtWeekRange(ws);
38
+ return fmtWeekRange(ws, locale);
36
39
  });
37
40
 
38
41
  // Which granularities are available?
@@ -13,6 +13,8 @@ interface Props {
13
13
  href: string;
14
14
  label: string;
15
15
  }[];
16
+ /** Locale used for labels */
17
+ locale?: string;
16
18
  }
17
19
  declare const Toolbar: import("svelte").Component<Props, {}, "">;
18
20
  type Toolbar = ReturnType<typeof Toolbar>;
@@ -28,6 +28,7 @@ export interface ViewState {
28
28
  /** IANA timezone, or undefined for local */
29
29
  readonly timezone: string | undefined;
30
30
  setView(id: CalendarViewId): void;
31
+ setMondayStart(value: boolean): void;
31
32
  setFocusDate(date: Date): void;
32
33
  next(): void;
33
34
  prev(): void;
@@ -60,6 +60,9 @@ export function createViewState(options = {}) {
60
60
  setView(id) {
61
61
  view = id;
62
62
  },
63
+ setMondayStart(value) {
64
+ mondayStart = value;
65
+ },
63
66
  setFocusDate(date) {
64
67
  focusDate = date;
65
68
  },
@@ -25,6 +25,7 @@
25
25
  /** 'day' = single-day timeline rail, 'week' = rolling 7-day view */
26
26
  mode?: 'day' | 'week';
27
27
  mondayStart?: boolean;
28
+ locale?: string;
28
29
  height?: number;
29
30
  events?: TimelineEvent[];
30
31
  style?: string;
@@ -38,6 +39,7 @@
38
39
  let {
39
40
  mode = 'day',
40
41
  mondayStart = true,
42
+ locale,
41
43
  height = 520,
42
44
  events = [],
43
45
  style = '',
@@ -51,7 +53,7 @@
51
53
  // ── Format helpers ──────────────────────────────────
52
54
  function fmtTime(d: Date): string {
53
55
  return d
54
- .toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true })
56
+ .toLocaleTimeString(locale ?? 'en-US', { hour: 'numeric', minute: '2-digit', hour12: true })
55
57
  .toLowerCase();
56
58
  }
57
59
 
@@ -220,7 +222,7 @@
220
222
  ? startOfWeek(sod(focusDate.getTime()), mondayStart)
221
223
  : startOfWeek(clock.today, mondayStart),
222
224
  );
223
- const weekLabel = $derived(fmtWeekRange(weekStartMs));
225
+ const weekLabel = $derived(fmtWeekRange(weekStartMs, locale));
224
226
 
225
227
  const weekDays = $derived.by((): DayGroup[] => {
226
228
  if (mode !== 'week') return [];
@@ -255,8 +257,8 @@
255
257
 
256
258
  out.push({
257
259
  ms,
258
- dayName: tier === 'today' || tier === 'tomorrow' ? weekdayLong(ms) : weekdayShort(ms),
259
- dateLabel: `${monthShort(ms)} ${dayNum(ms)}`,
260
+ dayName: tier === 'today' || tier === 'tomorrow' ? weekdayLong(ms, locale) : weekdayShort(ms, locale),
261
+ dateLabel: `${monthShort(ms, locale)} ${dayNum(ms)}`,
260
262
  tier,
261
263
  events: dayEvts,
262
264
  pastEvents,
@@ -325,7 +327,7 @@
325
327
  <header class="ag-header">
326
328
  {#if mode === 'day'}
327
329
  <div class="ag-header-left">
328
- <span class="ag-title">{fmtDay(dayMs, clock.today, { short: false })}</span>
330
+ <span class="ag-title">{fmtDay(dayMs, clock.today, { short: false }, locale)}</span>
329
331
  {#if isToday}
330
332
  <span class="ag-clock">{clock.hm}</span>
331
333
  {:else if isPastDay}
@@ -3,6 +3,7 @@ interface Props {
3
3
  /** 'day' = single-day timeline rail, 'week' = rolling 7-day view */
4
4
  mode?: 'day' | 'week';
5
5
  mondayStart?: boolean;
6
+ locale?: string;
6
7
  height?: number;
7
8
  events?: TimelineEvent[];
8
9
  style?: string;
@@ -35,6 +35,8 @@
35
35
  style?: string;
36
36
  /** The date to centre this view on */
37
37
  focusDate?: Date;
38
+ /** Locale for labels */
39
+ locale?: string;
38
40
  /** Called when the user clicks an event */
39
41
  oneventclick?: (event: TimelineEvent) => void;
40
42
  /** Called when the user clicks an empty time slot */
@@ -58,6 +60,7 @@
58
60
  height = 520,
59
61
  events = [],
60
62
  style = '',
63
+ locale,
61
64
  focusDate,
62
65
  oneventclick,
63
66
  oneventcreate,
@@ -130,7 +133,7 @@
130
133
 
131
134
  layouts.push({
132
135
  ms,
133
- name: fmtDay(ms, clock.today, { short: true }),
136
+ name: fmtDay(ms, clock.today, { short: true }, locale),
134
137
  today: isToday,
135
138
  past: isPast,
136
139
  dayX: x,
@@ -579,7 +582,7 @@
579
582
  {@const hour = NIGHT_END + h}
580
583
  {@const x = h * hourWidth}
581
584
  <div class="fs-tick" style:left="{x}px">
582
- <span class="fs-tick-lb">{fmtH(hour)}</span>
585
+ <span class="fs-tick-lb">{fmtH(hour, locale)}</span>
583
586
  </div>
584
587
  <div class="fs-tick fs-tick--half" style:left="{x + hourWidth * 0.5}px"></div>
585
588
  {/each}
@@ -605,7 +608,7 @@
605
608
  {@const hour = (NIGHT_START + h) % 24}
606
609
  {@const x = h * hourWidth}
607
610
  <div class="fs-tick fs-tick--night" style:left="{x}px">
608
- <span class="fs-tick-lb">{fmtH(hour)}</span>
611
+ <span class="fs-tick-lb">{fmtH(hour, locale)}</span>
609
612
  </div>
610
613
  {/each}
611
614
  <button class="fs-night-toggle" onclick={(e) => { e.stopPropagation(); toggleNight(i); }}>
@@ -16,6 +16,8 @@ interface Props {
16
16
  style?: string;
17
17
  /** The date to centre this view on */
18
18
  focusDate?: Date;
19
+ /** Locale for labels */
20
+ locale?: string;
19
21
  /** Called when the user clicks an event */
20
22
  oneventclick?: (event: TimelineEvent) => void;
21
23
  /** Called when the user clicks an empty time slot */
@@ -14,10 +14,11 @@
14
14
  nowPosition = 0.25,
15
15
  events = [],
16
16
  style = '',
17
+ locale,
17
18
  focusDate,
18
19
  oneventclick,
19
20
  selectedEventId = null,
20
- }: DayTimelineProps = $props();
21
+ }: DayTimelineProps & { locale?: string; [key: string]: unknown } = $props();
21
22
 
22
23
  // ── Drag support (available when inside Calendar) ──
23
24
  const drag = getContext<DragState>('calendar:drag') as DragState | undefined;
@@ -48,7 +49,7 @@
48
49
  out.push({
49
50
  ms,
50
51
  x: i * dayW,
51
- name: fmtDay(ms, clock.today),
52
+ name: fmtDay(ms, clock.today, undefined, locale),
52
53
  today: ms === clock.today
53
54
  });
54
55
  }
@@ -242,7 +243,7 @@
242
243
  {#each HOURS as h}
243
244
  {@const x = d.x + h * hourWidth}
244
245
  <div class="dt-tick" style:left="{x}px">
245
- <span class="dt-tick-lb">{fmtH(h)}</span>
246
+ <span class="dt-tick-lb">{fmtH(h, locale)}</span>
246
247
  </div>
247
248
  <div class="dt-tick dt-tick--h" style:left="{x + hourWidth * 0.5}px"></div>
248
249
  {/each}
@@ -1,4 +1,8 @@
1
1
  import type { DayTimelineProps } from '../../core/types.js';
2
- declare const DayTimeline: import("svelte").Component<DayTimelineProps, {}, "">;
2
+ type $$ComponentProps = DayTimelineProps & {
3
+ locale?: string;
4
+ [key: string]: unknown;
5
+ };
6
+ declare const DayTimeline: import("svelte").Component<$$ComponentProps, {}, "">;
3
7
  type DayTimeline = ReturnType<typeof DayTimeline>;
4
8
  export default DayTimeline;
@@ -40,6 +40,8 @@
40
40
  theme?: string;
41
41
  /** BCP 47 locale */
42
42
  locale?: string;
43
+ /** Text direction */
44
+ dir?: 'ltr' | 'rtl' | 'auto';
43
45
  /** Total height */
44
46
  height?: number;
45
47
  /** Start week on Monday */
@@ -67,6 +69,7 @@
67
69
  schedule,
68
70
  theme = '',
69
71
  locale,
72
+ dir,
70
73
  height = 560,
71
74
  mondayStart = true,
72
75
  readOnly = true,
@@ -123,6 +126,7 @@
123
126
  defaultView="week-grid"
124
127
  {theme}
125
128
  {locale}
129
+ {dir}
126
130
  {height}
127
131
  {mondayStart}
128
132
  {readOnly}
@@ -9,6 +9,8 @@ interface Props {
9
9
  theme?: string;
10
10
  /** BCP 47 locale */
11
11
  locale?: string;
12
+ /** Text direction */
13
+ dir?: 'ltr' | 'rtl' | 'auto';
12
14
  /** Total height */
13
15
  height?: number;
14
16
  /** Start week on Monday */