@nomideusz/svelte-calendar 0.1.1 → 0.2.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/dist/calendar/Calendar.svelte +21 -1
- package/dist/calendar/Calendar.svelte.d.ts +4 -0
- package/dist/calendar/Toolbar.svelte +1 -1
- package/dist/core/index.d.ts +2 -1
- package/dist/core/index.js +3 -1
- package/dist/core/locale.d.ts +3 -2
- package/dist/core/locale.js +19 -2
- package/dist/core/timezone.d.ts +22 -0
- package/dist/core/timezone.js +53 -0
- package/dist/engine/index.d.ts +1 -1
- package/dist/engine/view-state.svelte.d.ts +14 -2
- package/dist/engine/view-state.svelte.js +4 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/primitives/EmptySlot.svelte +17 -3
- package/dist/primitives/EventBlock.svelte +25 -2
- package/dist/primitives/NowIndicator.svelte +3 -3
- package/package.json +3 -2
|
@@ -59,6 +59,10 @@
|
|
|
59
59
|
showToolbar?: boolean;
|
|
60
60
|
/** Links to display in toolbar */
|
|
61
61
|
links?: { href: string; label: string }[];
|
|
62
|
+
/** Text direction: 'ltr' (default), 'rtl', or 'auto' */
|
|
63
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
64
|
+
/** BCP 47 locale tag (e.g. 'en-US', 'ar-SA') — sets lang and locale for formatting */
|
|
65
|
+
locale?: string;
|
|
62
66
|
|
|
63
67
|
// ── Callbacks ──
|
|
64
68
|
oneventclick?: (event: TimelineEvent) => void;
|
|
@@ -75,11 +79,20 @@
|
|
|
75
79
|
height = 600,
|
|
76
80
|
showToolbar = true,
|
|
77
81
|
links = [],
|
|
82
|
+
dir,
|
|
83
|
+
locale,
|
|
78
84
|
oneventclick,
|
|
79
85
|
oneventcreate,
|
|
80
86
|
oneventmove,
|
|
81
87
|
}: Props = $props();
|
|
82
88
|
|
|
89
|
+
import { setDefaultLocale } from '../core/locale.js';
|
|
90
|
+
|
|
91
|
+
// ── Set locale when provided ──
|
|
92
|
+
$effect(() => {
|
|
93
|
+
if (locale) setDefaultLocale(locale);
|
|
94
|
+
});
|
|
95
|
+
|
|
83
96
|
// ── Create reactive state ──
|
|
84
97
|
const store: EventStore = $derived(createEventStore(adapter));
|
|
85
98
|
const viewState: ViewState = createViewState(untrack(() => ({
|
|
@@ -135,7 +148,14 @@
|
|
|
135
148
|
);
|
|
136
149
|
</script>
|
|
137
150
|
|
|
138
|
-
<div
|
|
151
|
+
<div
|
|
152
|
+
class="cal"
|
|
153
|
+
style="{theme}; --cal-h: {height}px"
|
|
154
|
+
role="region"
|
|
155
|
+
aria-label="Calendar"
|
|
156
|
+
dir={dir}
|
|
157
|
+
lang={locale}
|
|
158
|
+
>
|
|
139
159
|
{#if showToolbar}
|
|
140
160
|
<Toolbar {viewState} views={toolbarViews} {links} />
|
|
141
161
|
{/if}
|
|
@@ -33,6 +33,10 @@ interface Props {
|
|
|
33
33
|
href: string;
|
|
34
34
|
label: string;
|
|
35
35
|
}[];
|
|
36
|
+
/** Text direction: 'ltr' (default), 'rtl', or 'auto' */
|
|
37
|
+
dir?: 'ltr' | 'rtl' | 'auto';
|
|
38
|
+
/** BCP 47 locale tag (e.g. 'en-US', 'ar-SA') — sets lang and locale for formatting */
|
|
39
|
+
locale?: string;
|
|
36
40
|
oneventclick?: (event: TimelineEvent) => void;
|
|
37
41
|
oneventcreate?: (range: {
|
|
38
42
|
start: Date;
|
package/dist/core/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { createClock } from './clock.svelte.js';
|
|
2
2
|
export type { Clock } from './clock.svelte.js';
|
|
3
3
|
export { DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, } from './time.js';
|
|
4
|
-
export { setDefaultLocale, getDefaultLocale, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, } from './locale.js';
|
|
4
|
+
export { setDefaultLocale, getDefaultLocale, is24HourLocale, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, } from './locale.js';
|
|
5
|
+
export { toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './timezone.js';
|
|
5
6
|
export type { TimelineEvent, WeekTimelineProps, DayTimelineProps, } from './types.js';
|
|
6
7
|
export { timeToX } from './types.js';
|
package/dist/core/index.js
CHANGED
|
@@ -4,5 +4,7 @@ export { createClock } from './clock.svelte.js';
|
|
|
4
4
|
// Time constants & math
|
|
5
5
|
export { DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, } from './time.js';
|
|
6
6
|
// Locale-aware formatting
|
|
7
|
-
export { setDefaultLocale, getDefaultLocale, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, } from './locale.js';
|
|
7
|
+
export { setDefaultLocale, getDefaultLocale, is24HourLocale, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, } from './locale.js';
|
|
8
|
+
// Timezone utilities
|
|
9
|
+
export { toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './timezone.js';
|
|
8
10
|
export { timeToX } from './types.js';
|
package/dist/core/locale.d.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
export declare function setDefaultLocale(tag: string): void;
|
|
12
12
|
/** Get the current default locale */
|
|
13
13
|
export declare function getDefaultLocale(): string;
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
export declare function is24HourLocale(locale?: string): boolean;
|
|
15
|
+
/** Format hour index (0-23) as compact label: 12h ("12a", "1p") or 24h ("0", "13") */
|
|
16
|
+
export declare function fmtH(h: number, locale?: string): string;
|
|
16
17
|
/** Short weekday name for a timestamp: "Mon", "Tue", etc. */
|
|
17
18
|
export declare function weekdayShort(ms: number, locale?: string): string;
|
|
18
19
|
/** Long weekday name for a timestamp: "Monday", "Tuesday", etc. */
|
package/dist/core/locale.js
CHANGED
|
@@ -17,8 +17,25 @@ export function setDefaultLocale(tag) {
|
|
|
17
17
|
export function getDefaultLocale() {
|
|
18
18
|
return defaultLocale;
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Detect whether the current locale uses 12-hour or 24-hour time.
|
|
22
|
+
* Caches per locale tag for performance.
|
|
23
|
+
*/
|
|
24
|
+
const hourCycleCache = new Map();
|
|
25
|
+
export function is24HourLocale(locale) {
|
|
26
|
+
const loc = locale ?? defaultLocale;
|
|
27
|
+
if (hourCycleCache.has(loc))
|
|
28
|
+
return hourCycleCache.get(loc);
|
|
29
|
+
const sample = new Intl.DateTimeFormat(loc, { hour: 'numeric' }).resolvedOptions();
|
|
30
|
+
const is24 = sample.hourCycle === 'h23' || sample.hourCycle === 'h24';
|
|
31
|
+
hourCycleCache.set(loc, is24);
|
|
32
|
+
return is24;
|
|
33
|
+
}
|
|
34
|
+
/** Format hour index (0-23) as compact label: 12h ("12a", "1p") or 24h ("0", "13") */
|
|
35
|
+
export function fmtH(h, locale) {
|
|
36
|
+
if (is24HourLocale(locale)) {
|
|
37
|
+
return String(h);
|
|
38
|
+
}
|
|
22
39
|
if (h === 0)
|
|
23
40
|
return '12a';
|
|
24
41
|
if (h === 12)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert a Date (assumed UTC or local) to a Date representing
|
|
3
|
+
* the same instant in the target timezone.
|
|
4
|
+
*
|
|
5
|
+
* The returned Date's local getters (getHours, getMinutes, etc.)
|
|
6
|
+
* will return the values as they appear in the target timezone.
|
|
7
|
+
*/
|
|
8
|
+
export declare function toZonedTime(date: Date | number, timezone: string): Date;
|
|
9
|
+
/**
|
|
10
|
+
* Convert a "zoned" Date (whose local getters represent a specific timezone)
|
|
11
|
+
* back to a true UTC Date. Use this before persisting to a backend.
|
|
12
|
+
*/
|
|
13
|
+
export declare function fromZonedTime(date: Date | number, timezone: string): Date;
|
|
14
|
+
/**
|
|
15
|
+
* Get the current time as it appears in the given timezone.
|
|
16
|
+
*/
|
|
17
|
+
export declare function nowInZone(timezone: string): Date;
|
|
18
|
+
/**
|
|
19
|
+
* Format a Date in a specific timezone using Intl.DateTimeFormat.
|
|
20
|
+
* Returns a locale-aware string.
|
|
21
|
+
*/
|
|
22
|
+
export declare function formatInTimeZone(date: Date | number, timezone: string, options?: Intl.DateTimeFormatOptions, locale?: string): string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timezone utilities — convert between IANA timezones and local time.
|
|
3
|
+
*
|
|
4
|
+
* Uses date-fns-tz under the hood. All functions accept an IANA timezone
|
|
5
|
+
* string (e.g. 'America/New_York', 'Europe/Warsaw', 'Asia/Tokyo').
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { toZonedTime, fromZonedTime, nowInZone } from '@nomideusz/svelte-calendar';
|
|
9
|
+
*
|
|
10
|
+
* // Convert a UTC date to display in a specific timezone
|
|
11
|
+
* const localDate = toZonedTime(utcDate, 'America/New_York');
|
|
12
|
+
*
|
|
13
|
+
* // Convert a "display" date back to UTC for storage
|
|
14
|
+
* const utcDate = fromZonedTime(localDate, 'America/New_York');
|
|
15
|
+
*
|
|
16
|
+
* // Get current time in a timezone
|
|
17
|
+
* const now = nowInZone('Asia/Tokyo');
|
|
18
|
+
*/
|
|
19
|
+
import { toZonedTime as dfnsToZoned, fromZonedTime as dfnsFromZoned } from 'date-fns-tz';
|
|
20
|
+
/**
|
|
21
|
+
* Convert a Date (assumed UTC or local) to a Date representing
|
|
22
|
+
* the same instant in the target timezone.
|
|
23
|
+
*
|
|
24
|
+
* The returned Date's local getters (getHours, getMinutes, etc.)
|
|
25
|
+
* will return the values as they appear in the target timezone.
|
|
26
|
+
*/
|
|
27
|
+
export function toZonedTime(date, timezone) {
|
|
28
|
+
return dfnsToZoned(date, timezone);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Convert a "zoned" Date (whose local getters represent a specific timezone)
|
|
32
|
+
* back to a true UTC Date. Use this before persisting to a backend.
|
|
33
|
+
*/
|
|
34
|
+
export function fromZonedTime(date, timezone) {
|
|
35
|
+
return dfnsFromZoned(date, timezone);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get the current time as it appears in the given timezone.
|
|
39
|
+
*/
|
|
40
|
+
export function nowInZone(timezone) {
|
|
41
|
+
return dfnsToZoned(new Date(), timezone);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Format a Date in a specific timezone using Intl.DateTimeFormat.
|
|
45
|
+
* Returns a locale-aware string.
|
|
46
|
+
*/
|
|
47
|
+
export function formatInTimeZone(date, timezone, options = {}, locale) {
|
|
48
|
+
const d = typeof date === 'number' ? new Date(date) : date;
|
|
49
|
+
return new Intl.DateTimeFormat(locale ?? 'en-US', {
|
|
50
|
+
...options,
|
|
51
|
+
timeZone: timezone,
|
|
52
|
+
}).format(d);
|
|
53
|
+
}
|
package/dist/engine/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { createEventStore } from './event-store.svelte.js';
|
|
2
2
|
export type { EventStore } from './event-store.svelte.js';
|
|
3
3
|
export { createViewState } from './view-state.svelte.js';
|
|
4
|
-
export type { ViewState, ViewStateOptions, CalendarViewId, ViewGranularity, DateRange as ViewDateRange, } from './view-state.svelte.js';
|
|
4
|
+
export type { ViewState, ViewStateOptions, CalendarViewId, BuiltInViewId, ViewGranularity, DateRange as ViewDateRange, } from './view-state.svelte.js';
|
|
5
5
|
export { createSelection } from './selection.svelte.js';
|
|
6
6
|
export type { Selection } from './selection.svelte.js';
|
|
7
7
|
export { createDragState } from './drag.svelte.js';
|
|
@@ -1,9 +1,19 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Built-in view IDs. Custom view IDs are also supported — CalendarViewId
|
|
3
|
+
* is typed as `string` so consumers can register any ID.
|
|
4
|
+
*/
|
|
5
|
+
export type BuiltInViewId = 'day-grid' | 'day-agenda' | 'week-grid' | 'week-agenda' | 'week-heatmap';
|
|
6
|
+
/**
|
|
7
|
+
* Any view identifier. Use built-in strings like 'day-grid' or your own
|
|
8
|
+
* custom IDs like 'day-kanban', 'week-resource', etc.
|
|
9
|
+
*/
|
|
10
|
+
export type CalendarViewId = string;
|
|
3
11
|
export type ViewGranularity = 'day' | 'week';
|
|
4
12
|
export interface ViewStateOptions {
|
|
5
13
|
defaultView?: CalendarViewId;
|
|
6
14
|
mondayStart?: boolean;
|
|
15
|
+
/** IANA timezone string (e.g. 'America/New_York'). Defaults to local timezone. */
|
|
16
|
+
timezone?: string;
|
|
7
17
|
}
|
|
8
18
|
export interface DateRange {
|
|
9
19
|
start: Date;
|
|
@@ -15,6 +25,8 @@ export interface ViewState {
|
|
|
15
25
|
readonly range: DateRange;
|
|
16
26
|
readonly granularity: ViewGranularity;
|
|
17
27
|
readonly mondayStart: boolean;
|
|
28
|
+
/** IANA timezone, or undefined for local */
|
|
29
|
+
readonly timezone: string | undefined;
|
|
18
30
|
setView(id: CalendarViewId): void;
|
|
19
31
|
setFocusDate(date: Date): void;
|
|
20
32
|
next(): void;
|
|
@@ -35,6 +35,7 @@ export function createViewState(options = {}) {
|
|
|
35
35
|
let view = $state(options.defaultView ?? 'week-grid');
|
|
36
36
|
let focusDate = $state(new Date());
|
|
37
37
|
let mondayStart = $state(options.mondayStart ?? true);
|
|
38
|
+
const timezone = options.timezone;
|
|
38
39
|
const granularity = $derived(granularityFor(view));
|
|
39
40
|
const range = $derived(computeRange(focusDate, granularity, mondayStart));
|
|
40
41
|
return {
|
|
@@ -53,6 +54,9 @@ export function createViewState(options = {}) {
|
|
|
53
54
|
get mondayStart() {
|
|
54
55
|
return mondayStart;
|
|
55
56
|
},
|
|
57
|
+
get timezone() {
|
|
58
|
+
return timezone;
|
|
59
|
+
},
|
|
56
60
|
setView(id) {
|
|
57
61
|
view = id;
|
|
58
62
|
},
|
package/dist/index.d.ts
CHANGED
|
@@ -4,10 +4,10 @@ export { NowIndicator, EventBlock, TimeGutter, DayHeader, EmptySlot, } from './p
|
|
|
4
4
|
export { Calendar, Toolbar } from './calendar/index.js';
|
|
5
5
|
export type { CalendarView } from './calendar/index.js';
|
|
6
6
|
export { createEventStore, createViewState, createSelection, createDragState, } from './engine/index.js';
|
|
7
|
-
export type { EventStore, ViewState, ViewStateOptions, CalendarViewId, ViewGranularity, ViewDateRange, Selection, DragState, DragMode, DragPayload, } from './engine/index.js';
|
|
7
|
+
export type { EventStore, ViewState, ViewStateOptions, CalendarViewId, BuiltInViewId, ViewGranularity, ViewDateRange, Selection, DragState, DragMode, DragPayload, } from './engine/index.js';
|
|
8
8
|
export { createMemoryAdapter, createRestAdapter } from './adapters/index.js';
|
|
9
9
|
export type { CalendarAdapter, DateRange, RestAdapterOptions } from './adapters/index.js';
|
|
10
|
-
export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, timeToX, } from './core/index.js';
|
|
10
|
+
export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, timeToX, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './core/index.js';
|
|
11
11
|
export type { Clock, TimelineEvent, WeekTimelineProps, DayTimelineProps, } from './core/index.js';
|
|
12
12
|
export { midnight, parchment, indigo, presets, stageBg } from './theme/index.js';
|
|
13
13
|
export type { PresetName } from './theme/index.js';
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,6 @@ export { createEventStore, createViewState, createSelection, createDragState, }
|
|
|
9
9
|
// ─── Adapters ───────────────────────────────────────────
|
|
10
10
|
export { createMemoryAdapter, createRestAdapter } from './adapters/index.js';
|
|
11
11
|
// ─── Core: clock, time, locale, types ───────────────────
|
|
12
|
-
export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, timeToX, } from './core/index.js';
|
|
12
|
+
export { createClock, DAY_MS, HOUR_MS, HOURS, sod, startOfWeek, addDaysMs, diffDays, pad, fractionalHour, fmtHM, fmtS, dayNum, dayOfWeek, fmtH, weekdayShort, weekdayLong, monthShort, monthLong, dateShort, dateWithWeekday, fmtDay, fmtWeekRange, setDefaultLocale, getDefaultLocale, is24HourLocale, timeToX, toZonedTime, fromZonedTime, nowInZone, formatInTimeZone, } from './core/index.js';
|
|
13
13
|
// ─── Themes ─────────────────────────────────────────────
|
|
14
14
|
export { midnight, parchment, indigo, presets, stageBg } from './theme/index.js';
|
|
@@ -39,17 +39,26 @@
|
|
|
39
39
|
const m = mins % 60;
|
|
40
40
|
return m > 0 ? `${h}h ${m}m free` : `${h}h free`;
|
|
41
41
|
});
|
|
42
|
+
|
|
43
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
44
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
onclick?.({ start, end });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
42
49
|
</script>
|
|
43
50
|
|
|
44
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
45
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
46
51
|
<div
|
|
47
52
|
class="es"
|
|
48
53
|
class:es-v={orientation === 'vertical'}
|
|
49
54
|
class:es-h={orientation === 'horizontal'}
|
|
55
|
+
role="button"
|
|
56
|
+
tabindex="0"
|
|
57
|
+
aria-label="Create event, {fmtTime(start)} to {fmtTime(end)}, {dur()}"
|
|
50
58
|
onclick={() => onclick?.({ start, end })}
|
|
59
|
+
onkeydown={handleKeydown}
|
|
51
60
|
>
|
|
52
|
-
<div class="es-hint">
|
|
61
|
+
<div class="es-hint" aria-hidden="true">
|
|
53
62
|
<span class="es-plus">+</span>
|
|
54
63
|
<span class="es-range">{fmtTime(start)} – {fmtTime(end)}</span>
|
|
55
64
|
</div>
|
|
@@ -68,6 +77,11 @@
|
|
|
68
77
|
border-color: var(--dt-accent-dim, rgba(239, 68, 68, 0.18));
|
|
69
78
|
background: var(--dt-accent-dim, rgba(239, 68, 68, 0.05));
|
|
70
79
|
}
|
|
80
|
+
.es:focus-visible {
|
|
81
|
+
outline: 2px solid var(--dt-accent, #ef4444);
|
|
82
|
+
outline-offset: 2px;
|
|
83
|
+
border-color: var(--dt-accent-dim, rgba(239, 68, 68, 0.18));
|
|
84
|
+
}
|
|
71
85
|
|
|
72
86
|
.es-hint {
|
|
73
87
|
position: absolute;
|
|
@@ -61,17 +61,35 @@
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
const accentColor = $derived(event.color || 'var(--dt-accent, #ef4444)');
|
|
64
|
+
|
|
65
|
+
const ariaLabel = $derived(() => {
|
|
66
|
+
const t = event.title;
|
|
67
|
+
const time = `${fmtTime(event.start)} to ${fmtTime(event.end)}`;
|
|
68
|
+
const dur = fmtDuration(event.start, event.end);
|
|
69
|
+
const status = active ? ', happening now' : past ? ', past' : '';
|
|
70
|
+
return `${t}, ${time}, ${dur}${status}`;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
function handleKeydown(e: KeyboardEvent) {
|
|
74
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
75
|
+
e.preventDefault();
|
|
76
|
+
onclick?.(event);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
64
79
|
</script>
|
|
65
80
|
|
|
66
|
-
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
|
67
|
-
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
68
81
|
<div
|
|
69
82
|
class="eb eb-{variant}"
|
|
70
83
|
class:eb-active={active}
|
|
71
84
|
class:eb-past={past}
|
|
72
85
|
class:eb-editable={editable}
|
|
73
86
|
style="--eb-color: {accentColor}"
|
|
87
|
+
role={onclick ? 'button' : 'article'}
|
|
88
|
+
tabindex={onclick ? 0 : -1}
|
|
89
|
+
aria-label={ariaLabel()}
|
|
90
|
+
aria-current={active ? 'true' : undefined}
|
|
74
91
|
onclick={() => onclick?.(event)}
|
|
92
|
+
onkeydown={handleKeydown}
|
|
75
93
|
>
|
|
76
94
|
{#if children}
|
|
77
95
|
{@render children(event)}
|
|
@@ -115,6 +133,11 @@
|
|
|
115
133
|
.eb-editable:hover {
|
|
116
134
|
transform: translateY(-1px);
|
|
117
135
|
}
|
|
136
|
+
.eb:focus-visible {
|
|
137
|
+
outline: 2px solid var(--dt-accent, #ef4444);
|
|
138
|
+
outline-offset: 2px;
|
|
139
|
+
border-radius: 4px;
|
|
140
|
+
}
|
|
118
141
|
.eb-past {
|
|
119
142
|
opacity: 0.5;
|
|
120
143
|
}
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
</script>
|
|
54
54
|
|
|
55
55
|
{#if mode === 'badge'}
|
|
56
|
-
<span class="ni-badge" style={colorVar}>
|
|
56
|
+
<span class="ni-badge" style={colorVar} role="status" aria-live="polite" aria-label="Current time: {time}">
|
|
57
57
|
{#if children}
|
|
58
58
|
{@render children()}
|
|
59
59
|
{:else}
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
{/if}
|
|
62
62
|
</span>
|
|
63
63
|
{:else if mode === 'dot'}
|
|
64
|
-
<div class="ni ni-dot {orientation}" style="{posStyle}; {colorVar}">
|
|
64
|
+
<div class="ni ni-dot {orientation}" style="{posStyle}; {colorVar}" role="status" aria-label="Current time: {time}">
|
|
65
65
|
<div class="ni-dot-circle"></div>
|
|
66
66
|
{#if showLabel && time}
|
|
67
67
|
<div class="ni-label">
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
{/if}
|
|
72
72
|
</div>
|
|
73
73
|
{:else}
|
|
74
|
-
<div class="ni ni-line {orientation}" style="{posStyle}; {colorVar}">
|
|
74
|
+
<div class="ni ni-line {orientation}" style="{posStyle}; {colorVar}" role="status" aria-label="Current time: {time}">
|
|
75
75
|
<div class="ni-line-bar"></div>
|
|
76
76
|
{#if showLabel && time}
|
|
77
77
|
<div class="ni-label">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nomideusz/svelte-calendar",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "A themeable, pluggable Svelte 5 calendar with Day and Week views — Grid, Timeline, Agenda, Heatmap.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"vitest": "^4.0.18"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"date-fns": "^4.1.0"
|
|
36
|
+
"date-fns": "^4.1.0",
|
|
37
|
+
"date-fns-tz": "^3.2.0"
|
|
37
38
|
},
|
|
38
39
|
"keywords": [
|
|
39
40
|
"svelte",
|