@nomideusz/svelte-calendar 0.7.4 → 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 +645 -549
  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 +329 -13
  36. package/widget/widget.js +1945 -1031
@@ -0,0 +1,16 @@
1
+ <!--
2
+ EventContent — renders the host's `event` snippet when provided, else the
3
+ view's default markup (passed as children). Views keep their interactive
4
+ shell (click/keyboard/selection/drag); only the content is swappable.
5
+ -->
6
+ <script lang="ts">import { useCalendarContext } from "./context.svelte.js";
7
+ let { event, children } = $props();
8
+ const ctx = useCalendarContext();
9
+ const eventSnippet = $derived(ctx.eventSnippet);
10
+ </script>
11
+
12
+ {#if eventSnippet}
13
+ {@render eventSnippet(event)}
14
+ {:else}
15
+ {@render children()}
16
+ {/if}
@@ -0,0 +1,9 @@
1
+ import type { Snippet } from 'svelte';
2
+ import type { TimelineEvent } from '../../core/types.js';
3
+ type $$ComponentProps = {
4
+ event: TimelineEvent;
5
+ children: Snippet;
6
+ };
7
+ declare const EventContent: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type EventContent = ReturnType<typeof EventContent>;
9
+ export default EventContent;
@@ -23,6 +23,7 @@ export interface CalendarContext {
23
23
  readonly minDuration: number | undefined;
24
24
  readonly maxDuration: number | undefined;
25
25
  readonly oneventhover: ((event: TimelineEvent) => void) | undefined;
26
+ readonly ondayclick: ((date: Date) => void) | undefined;
26
27
  readonly disabledDates: Date[] | undefined;
27
28
  readonly disabledSet: Set<number>;
28
29
  readonly loadRange: {
@@ -30,6 +30,7 @@ export function useCalendarContext() {
30
30
  get minDuration() { return raw?.minDuration; },
31
31
  get maxDuration() { return raw?.maxDuration; },
32
32
  get oneventhover() { return raw?.oneventhover; },
33
+ get ondayclick() { return raw?.ondayclick; },
33
34
  get disabledDates() { return raw?.disabledDates; },
34
35
  get disabledSet() { return new Set(raw?.disabledDates?.map(d => sod(d.getTime())) ?? []); },
35
36
  get loadRange() {
@@ -13,122 +13,85 @@
13
13
  locale="en-US"
14
14
  ></day-calendar>
15
15
  -->
16
- <script lang="ts">
17
- import Calendar from '../calendar/Calendar.svelte';
18
- import { createRestAdapter } from '../adapters/rest.js';
19
- import { createMemoryAdapter } from '../adapters/memory.js';
20
- import { presets } from '../theme/presets.js';
21
- import type { PresetName } from '../theme/presets.js';
22
- import type { TimelineEvent } from '../core/types.js';
23
-
24
- interface Props {
25
- /** REST API base URL — if provided, fetches events from this endpoint */
26
- api?: string;
27
- /** JSON string of events for static/inline data (alternative to api) */
28
- events?: string;
29
- /** Theme preset name: midnight, neutral */
30
- theme?: string;
31
- /** Default view ID */
32
- view?: string;
33
- /** Calendar height in pixels */
34
- height?: string;
35
- /** BCP 47 locale tag (e.g. 'en-US', 'pl-PL') */
36
- locale?: string;
37
- /** Text direction: ltr, rtl, auto */
38
- dir?: string;
39
- /** Start week on Monday (default: true) */
40
- mondaystart?: string;
41
- /** Custom HTTP headers as JSON string for REST adapter */
42
- headers?: string;
43
- }
44
-
45
- let {
46
- api,
47
- events,
48
- theme = 'neutral',
49
- view = 'week-planner',
50
- height = '600',
51
- locale,
52
- dir,
53
- mondaystart = 'true',
54
- headers,
55
- }: Props = $props();
56
-
57
- // ── Parse attributes ──
58
- const heightPx = $derived(parseInt(height, 10) || 600);
59
- const isMondayStart = $derived(mondaystart !== 'false');
60
- const themeStyle = $derived(
61
- (presets as Record<string, string>)[theme] || presets.neutral
62
- );
63
- const dirValue = $derived(
64
- (dir === 'rtl' || dir === 'ltr' || dir === 'auto') ? dir as 'ltr' | 'rtl' | 'auto' : undefined
65
- );
66
-
67
- // ── Parse static events from JSON attribute ──
68
- function parseHeaders(json?: string): Record<string, string> | undefined {
69
- if (!json) return undefined;
70
- try {
71
- const parsed = JSON.parse(json) as Record<string, unknown>;
72
- const out: Record<string, string> = {};
73
- for (const [k, v] of Object.entries(parsed)) {
74
- out[k] = String(v);
75
- }
76
- return out;
77
- } catch {
78
- console.warn('[day-calendar] Failed to parse headers JSON:', json);
79
- return undefined;
80
- }
81
- }
82
-
83
- function toEvent(raw: Record<string, unknown>, fallbackId: string): TimelineEvent | null {
84
- const start = new Date(String(raw.start ?? ''));
85
- const end = new Date(String(raw.end ?? ''));
86
- if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end <= start) {
87
- return null;
88
- }
89
- return {
90
- id: String(raw.id ?? fallbackId),
91
- title: String(raw.title ?? 'Untitled'),
92
- start,
93
- end,
94
- color: raw.color ? String(raw.color) : undefined,
95
- };
96
- }
97
-
98
- function parseEvents(json?: string): TimelineEvent[] {
99
- if (!json) return [];
100
- try {
101
- const raw = JSON.parse(json) as Array<Record<string, unknown>>;
102
- const parsed = raw
103
- .map((e, idx) => toEvent(e, `inline-${idx}`))
104
- .filter((ev): ev is TimelineEvent => ev !== null);
105
- if (parsed.length !== raw.length) {
106
- console.warn(`[day-calendar] Ignored ${raw.length - parsed.length} invalid event(s) from events JSON.`);
107
- }
108
- return parsed;
109
- } catch {
110
- console.warn('[day-calendar] Failed to parse events JSON:', json);
111
- return [];
112
- }
113
- }
114
-
115
- // ── Create adapter ──
116
- const adapter = $derived.by(() => {
117
- if (api) {
118
- const parsedHeaders = parseHeaders(headers);
119
- return createRestAdapter({
120
- baseUrl: api,
121
- headers: parsedHeaders,
122
- mapEvents: (data: unknown) => {
123
- const arr = Array.isArray(data) ? data : (data as Record<string, unknown>).events as unknown[] ?? [];
124
- return arr
125
- .map((e: unknown, idx) => toEvent(e as Record<string, unknown>, `api-${idx}`))
126
- .filter((ev): ev is TimelineEvent => ev !== null);
127
- },
128
- });
129
- }
130
- return createMemoryAdapter(parseEvents(events));
131
- });
16
+ <script lang="ts">import Calendar from "../calendar/Calendar.svelte";
17
+ import { createRestAdapter } from "../adapters/rest.js";
18
+ import { createMemoryAdapter } from "../adapters/memory.js";
19
+ import { presets } from "../theme/presets.js";
20
+ let {
21
+ api,
22
+ events,
23
+ theme = "neutral",
24
+ view = "week-planner",
25
+ height = "600",
26
+ locale,
27
+ dir,
28
+ mondaystart = "true",
29
+ headers
30
+ } = $props();
31
+ const heightPx = $derived(parseInt(height, 10) || 600);
32
+ const isMondayStart = $derived(mondaystart !== "false");
33
+ const themeStyle = $derived(
34
+ presets[theme] || presets.neutral
35
+ );
36
+ const dirValue = $derived(
37
+ dir === "rtl" || dir === "ltr" || dir === "auto" ? dir : void 0
38
+ );
39
+ function parseHeaders(json) {
40
+ if (!json) return void 0;
41
+ try {
42
+ const parsed = JSON.parse(json);
43
+ const out = {};
44
+ for (const [k, v] of Object.entries(parsed)) {
45
+ out[k] = String(v);
46
+ }
47
+ return out;
48
+ } catch {
49
+ console.warn("[day-calendar] Failed to parse headers JSON:", json);
50
+ return void 0;
51
+ }
52
+ }
53
+ function toEvent(raw, fallbackId) {
54
+ const start = new Date(String(raw.start ?? ""));
55
+ const end = new Date(String(raw.end ?? ""));
56
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end <= start) {
57
+ return null;
58
+ }
59
+ return {
60
+ id: String(raw.id ?? fallbackId),
61
+ title: String(raw.title ?? "Untitled"),
62
+ start,
63
+ end,
64
+ color: raw.color ? String(raw.color) : void 0
65
+ };
66
+ }
67
+ function parseEvents(json) {
68
+ if (!json) return [];
69
+ try {
70
+ const raw = JSON.parse(json);
71
+ const parsed = raw.map((e, idx) => toEvent(e, `inline-${idx}`)).filter((ev) => ev !== null);
72
+ if (parsed.length !== raw.length) {
73
+ console.warn(`[day-calendar] Ignored ${raw.length - parsed.length} invalid event(s) from events JSON.`);
74
+ }
75
+ return parsed;
76
+ } catch {
77
+ console.warn("[day-calendar] Failed to parse events JSON:", json);
78
+ return [];
79
+ }
80
+ }
81
+ const adapter = $derived.by(() => {
82
+ if (api) {
83
+ const parsedHeaders = parseHeaders(headers);
84
+ return createRestAdapter({
85
+ baseUrl: api,
86
+ headers: parsedHeaders,
87
+ mapEvents: (data) => {
88
+ const arr = Array.isArray(data) ? data : data.events ?? [];
89
+ return arr.map((e, idx) => toEvent(e, `api-${idx}`)).filter((ev) => ev !== null);
90
+ }
91
+ });
92
+ }
93
+ return createMemoryAdapter(parseEvents(events));
94
+ });
132
95
  </script>
133
96
 
134
97
  <Calendar
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nomideusz/svelte-calendar",
3
- "version": "0.7.4",
3
+ "version": "0.8.0",
4
4
  "description": "A themeable Svelte 5 calendar with Day and Week views — Planner and Agenda.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,10 +24,11 @@
24
24
  "dev": "vite dev",
25
25
  "build": "vite build",
26
26
  "package": "svelte-kit sync && svelte-package",
27
+ "package:watch": "svelte-kit sync && svelte-package --watch",
27
28
  "build:widget": "vite build --config vite.config.widget.ts",
28
29
  "prepublishOnly": "npm run package",
29
30
  "preview": "vite preview",
30
- "prepare": "svelte-kit sync || echo ''",
31
+ "prepare": "svelte-kit sync && svelte-package",
31
32
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
32
33
  "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
33
34
  "test": "vitest run",