@nomideusz/svelte-calendar 1.2.0 → 1.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.
- package/README.md +143 -93
- package/dist/adapters/mapped.d.ts +7 -7
- package/dist/adapters/mapped.js +5 -2
- package/dist/adapters/memory.d.ts +7 -6
- package/dist/adapters/memory.js +3 -4
- package/dist/adapters/recurring.d.ts +6 -6
- package/dist/adapters/recurring.js +12 -14
- package/dist/calendar/Calendar.svelte +226 -304
- package/dist/calendar/Calendar.svelte.d.ts +1 -1
- package/dist/primitives/DayHeader.svelte +7 -7
- package/dist/primitives/EmptySlot.svelte +6 -6
- package/dist/primitives/EventBlock.svelte +19 -19
- package/dist/primitives/FloatingPanel.svelte +4 -4
- package/dist/primitives/NowIndicator.svelte +5 -5
- package/dist/primitives/TimeGutter.svelte +4 -4
- package/dist/theme/auto.d.ts +5 -0
- package/dist/theme/auto.js +16 -3
- package/dist/theme/presets.d.ts +2 -2
- package/dist/theme/presets.js +2 -2
- package/dist/views/agenda/AgendaDay.svelte +207 -323
- package/dist/views/agenda/AgendaWeek.svelte +145 -222
- package/dist/views/mobile/MobileDay.svelte +79 -60
- package/dist/views/mobile/MobileWeek.svelte +48 -38
- package/dist/views/month/MonthGrid.svelte +92 -36
- package/dist/views/planner/PlannerScroll.svelte +78 -72
- package/dist/views/planner/PlannerWeek.svelte +145 -90
- package/dist/views/shared/context.svelte.d.ts +2 -0
- package/dist/views/shared/context.svelte.js +1 -0
- package/dist/views/shared/format.d.ts +3 -0
- package/dist/views/shared/format.js +10 -1
- package/package.json +1 -1
- package/widget/widget.js +816 -725
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@nomideusz/svelte-calendar) [](https://github.com/nomideusz/svelte-calendar/blob/main/LICENSE)
|
|
4
4
|
|
|
5
|
-
A themeable **Svelte 5** calendar: day and week **Planner** time grids, a multi-week **Scroll** view, **Agenda** lists, a **Month** grid and touch-first **Mobile** layouts
|
|
5
|
+
A themeable **Svelte 5** calendar: day and week **Planner** time grids, a multi-week **Scroll** view, **Agenda** lists, a **Month** grid and touch-first **Mobile** layouts, with drag-and-drop, timezones, a headless API, an embeddable web component, and a smart auto-theme that adapts to any page.
|
|
6
6
|
|
|
7
7
|
**[Live demo → svelte-calendar.xyz](https://svelte-calendar.xyz/)**
|
|
8
8
|
|
|
@@ -14,7 +14,7 @@ pnpm add @nomideusz/svelte-calendar
|
|
|
14
14
|
|
|
15
15
|
Requirements:
|
|
16
16
|
|
|
17
|
-
- **Svelte `^5.29.0`** (peer dependency
|
|
17
|
+
- **Svelte `^5.29.0`** (peer dependency: the package uses attachments, `{@attach}`).
|
|
18
18
|
- Runtime dependencies (installed for you): `date-fns`, `date-fns-tz`, `@chenglou/pretext`.
|
|
19
19
|
- Node ≥ 22 is only needed to develop the package itself, not to use it.
|
|
20
20
|
|
|
@@ -34,24 +34,24 @@ Requirements:
|
|
|
34
34
|
]);
|
|
35
35
|
</script>
|
|
36
36
|
|
|
37
|
-
<Calendar {adapter} />
|
|
37
|
+
<Calendar {adapter} view="week-planner" />
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
That's it
|
|
40
|
+
That's it: eight built-in views and drag-and-drop with live previews, out of the box. The default `auto` theme probes your page's background, accent color and fonts, so the calendar adapts to any design. Events without a `color` draw in ink; to color them automatically, give the adapter a [`palette`](#event-colors).
|
|
41
41
|
|
|
42
42
|
## Views
|
|
43
43
|
|
|
44
|
-
The default registry (`defaultViews`) holds eight views
|
|
44
|
+
The default registry (`defaultViews`) holds eight views. Six are the ones you choose with `view`; the two `*-mobile` views are what the others swap to in a narrow container (see [Mobile](#mobile)), so the demo's view list shows six.
|
|
45
45
|
|
|
46
46
|
| View ID | Mode | What it is |
|
|
47
47
|
|---------|------|------------|
|
|
48
|
-
| `day-planner` | day | Vertical time grid, one column.
|
|
48
|
+
| `day-planner` | day | Vertical time grid, one column. Opens when `view` is unset (the first registered view). The examples here, the demo, the widget and `createCalendar` open on `week-planner`. |
|
|
49
49
|
| `week-planner` | week | The same time grid, one column per day (`days`, default 7). |
|
|
50
50
|
| `week-scroll` | week | Weeks stacked in one infinite vertical scroller (Hey-Calendar style): each chip sits at the height of its start time, month names run down the side. Drag to move, drop onto a day; it scrolls under a drag. |
|
|
51
51
|
| `day-agenda` | day | Live list for one day: now / up next / done. |
|
|
52
52
|
| `week-agenda` | week | List of the week's days (`columns` turns it into a timetable grid). |
|
|
53
|
-
| `day-mobile` | day | Touch-first time grid with swipe navigation. |
|
|
54
|
-
| `week-mobile` | week | Touch-first list of the week's days. |
|
|
53
|
+
| `day-mobile` | day | Touch-first time grid with swipe navigation. Used automatically in a narrow container. |
|
|
54
|
+
| `week-mobile` | week | Touch-first list of the week's days. Used automatically in a narrow container. |
|
|
55
55
|
| `month-grid` | month | Week-aligned month grid, chips per day with a "+N more" overflow. |
|
|
56
56
|
|
|
57
57
|
```svelte
|
|
@@ -68,10 +68,10 @@ Users switch with the built-in pills: **Day / Week / Month** for the mode, plus
|
|
|
68
68
|
|
|
69
69
|
Planner views are designed for direct manipulation:
|
|
70
70
|
|
|
71
|
-
- **Move
|
|
72
|
-
- **Resize
|
|
73
|
-
- **Create
|
|
74
|
-
- **External drop
|
|
71
|
+
- **Move**: drag an event to another day or time; a ghost previews the target before the move commits.
|
|
72
|
+
- **Resize**: drag an event's top/bottom grip to change its duration; `minDuration`/`maxDuration` clamp the result.
|
|
73
|
+
- **Create**: press on empty canvas and sweep to draw a range, or click for a default-length slot. Both go through the same validation (blocked slots, disabled dates, `minDuration`/`maxDuration`) and then fire `oneventcreate`.
|
|
74
|
+
- **External drop**: an HTML5 drag from outside the calendar (a class chip, a template) dropped on the planner or `week-scroll` fires `onexternaldrop({ start, dataTransfer })`.
|
|
75
75
|
|
|
76
76
|
`week-scroll` supports move, click-to-create and external drops. In `week-agenda` with `columns` and an `oneventmove` handler, a card can be dragged to another day (it keeps its time of day); that move goes straight to `oneventmove` without writing the adapter.
|
|
77
77
|
|
|
@@ -81,8 +81,8 @@ The month grid shows up to three chips per day. Clicking a day or its "+N more"
|
|
|
81
81
|
|
|
82
82
|
When focus is inside the calendar:
|
|
83
83
|
|
|
84
|
-
- `t
|
|
85
|
-
- `←` /
|
|
84
|
+
- `t`: go to today.
|
|
85
|
+
- `←` / `→`: previous / next period (mirrored in RTL). Ignored while typing in a field or inside a pill group, where arrows move between pills.
|
|
86
86
|
- In `month-grid`: arrow keys move between days, `Enter` / `Space` opens the focused day (`ondayclick`).
|
|
87
87
|
- In `week-planner` / `day-planner`: the day columns are one tab stop; `←` / `→` move between days, `Enter` / `Space` creates an event (`oneventcreate`) at the next slot today, or 09:00. On a focused event, `Alt+↑` / `Alt+↓` move it one `snapInterval`, `Alt+←` / `Alt+→` move it a day, and `Alt+Shift+↑` / `Alt+Shift+↓` move its end; each goes through the same validation as a drag and fires `oneventmove`.
|
|
88
88
|
|
|
@@ -106,13 +106,13 @@ The `views` prop replaces the registry. Spread `defaultViews` to add your own vi
|
|
|
106
106
|
|
|
107
107
|
A `CalendarView` is `{ id, label, mode: 'day' | 'week' | 'month', component, props? }`. `label` names the view-type pill; views sharing a label across modes are what the Day/Week/Month pills switch between.
|
|
108
108
|
|
|
109
|
-
The component receives `CalendarViewProps` (plus your `props`)
|
|
109
|
+
The component receives `CalendarViewProps` (plus your `props`); declare only the ones it uses:
|
|
110
110
|
|
|
111
111
|
| Prop | Type | Notes |
|
|
112
112
|
|------|------|-------|
|
|
113
113
|
| `events` | `TimelineEvent[]` | Everything loaded for the current range |
|
|
114
114
|
| `style` | `string` | The active `--dt-*` theme string |
|
|
115
|
-
| `height` | `number \| null` | Currently always `null
|
|
115
|
+
| `height` | `number \| null` | Currently always `null`: size to the container |
|
|
116
116
|
| `mode` | `'day' \| 'week' \| 'month'` | |
|
|
117
117
|
| `mondayStart` | `boolean` | |
|
|
118
118
|
| `locale` | `string \| undefined` | |
|
|
@@ -143,15 +143,15 @@ The component receives `CalendarViewProps` (plus your `props`) — declare only
|
|
|
143
143
|
|
|
144
144
|
`useCalendarContext()` (type `CalendarContext`) gives a view the running Calendar's engines and config: `viewState`, `drag`, `commitDrag`, `labels`, `readOnly`, `snapInterval`, `minColumnWidth`, `blockedSlots`, `disabledDates` / `disabledSet`, `minDuration` / `maxDuration`, `hideDays`, `equalDays`, `showDates`, `compact`, `columns`, `isMobile`, `autoHeight`, `timezone`, `oneventmove`, `oneventhover`, `ondayclick`, `eventSnippet`, `emptySnippet`, `dayHeaderSnippet` and `loadRange` (a view can widen the range the store loads). Call it at component init, inside a `<Calendar>`.
|
|
145
145
|
|
|
146
|
-
The raw view components
|
|
146
|
+
The raw view components (`Planner`, `PlannerScroll`, `Agenda`, `Mobile`, `MonthGrid`) are exported so you can register them under your own ids. Building blocks for custom views are exported as primitives: `EventBlock` (an event card), `TimeGutter` (hour labels), `DayHeader`, `NowIndicator`, `EmptySlot` (click-to-create target) and `FloatingPanel` (see [Event details panel](#event-details-panel)).
|
|
147
147
|
|
|
148
148
|
## Mobile
|
|
149
149
|
|
|
150
150
|
When the calendar's **container** is narrower than 768px, it swaps to touch-first Mobile views with swipe navigation and a compact header:
|
|
151
151
|
|
|
152
152
|
```svelte
|
|
153
|
-
<!-- Auto-detect (default)
|
|
154
|
-
<Calendar {adapter} />
|
|
153
|
+
<!-- Auto-detect (default): switches at a 768px container width -->
|
|
154
|
+
<Calendar {adapter} view="week-planner" />
|
|
155
155
|
|
|
156
156
|
<!-- Force mobile layout -->
|
|
157
157
|
<Calendar {adapter} mobile={true} />
|
|
@@ -160,10 +160,10 @@ When the calendar's **container** is narrower than 768px, it swaps to touch-firs
|
|
|
160
160
|
<Calendar {adapter} mobile={false} />
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
-
- **MobileDay
|
|
164
|
-
- **MobileWeek
|
|
163
|
+
- **MobileDay**: vertical time grid with hour labels, swipe left/right to change days, all-day chips at the top, tap-to-create, stable columns for overlapping events.
|
|
164
|
+
- **MobileWeek**: vertical day list with relative labels (Today, Tomorrow, …) and accessible event buttons in each row.
|
|
165
165
|
|
|
166
|
-
In mobile mode every view except `*-agenda` and `*-mobile` is swapped for the `{mode}-mobile` entry of the same mode when one is registered
|
|
166
|
+
In mobile mode every view except `*-agenda` and `*-mobile` is swapped for the `{mode}-mobile` entry of the same mode when one is registered, custom views included. Agenda views keep their list layout; `month-grid` has no mobile entry and stays. The mobile header shows only the Day/Week/Month pills.
|
|
167
167
|
|
|
168
168
|
With `'auto'`, the first render (and the server render) is the desktop layout; the container is measured on mount, so SSR hydrates cleanly.
|
|
169
169
|
|
|
@@ -185,9 +185,9 @@ With `'auto'`, the first render (and the server render) is the desktop layout; t
|
|
|
185
185
|
|
|
186
186
|
| Callback | When it fires |
|
|
187
187
|
|----------|---------------|
|
|
188
|
-
| `oneventclick(event, anchor?)` | An event is clicked. The event is also selected (highlighted across views). `anchor` is the clicked block's viewport rect where the view has one (planner, `week-scroll`, `month-grid`)
|
|
188
|
+
| `oneventclick(event, anchor?)` | An event is clicked. The event is also selected (highlighted across views). `anchor` is the clicked block's viewport rect where the view has one (planner, `week-scroll`, `month-grid`), for positioning a `FloatingPanel`. |
|
|
189
189
|
| `oneventcreate({ start, end })` | A drag-create or click-to-create passed validation. The calendar does **not** store anything: add the event to your data and hand the Calendar the updated adapter. |
|
|
190
|
-
| `oneventmove(event, start, end)` | A drag or resize committed
|
|
190
|
+
| `oneventmove(event, start, end)` | A drag or resize committed: **after** the adapter stored it, or when the adapter refused with a read-only error (the host owns persistence then; the block stays where it was dropped). Other adapter failures revert the block and go to `onerror`. (The `week-agenda` columns day-drag is the exception: it only calls `oneventmove`.) |
|
|
191
191
|
| `onexternaldrop({ start, dataTransfer })` | An outside HTML5 drag was dropped on the grid; `start` is the pointer's time, snapped. |
|
|
192
192
|
| `onviewchange(viewId)` | Once on mount, then on every view change. |
|
|
193
193
|
| `ondatechange(date)` | Once on mount, then whenever the focused date changes (navigation, scrolling, a tapped day). |
|
|
@@ -197,7 +197,7 @@ With `'auto'`, the first render (and the server render) is the desktop layout; t
|
|
|
197
197
|
|
|
198
198
|
`oneventcreate`, `oneventmove` and `onexternaldrop` receive real instants, also with [`timezone`](#timezone-support). None of the write callbacks fire when `readOnly` is set.
|
|
199
199
|
|
|
200
|
-
To show a newly created or moved event, update your data and give the Calendar a new adapter
|
|
200
|
+
To show a newly created or moved event, update your data and give the Calendar a new adapter. The store reloads on a new adapter identity without blanking the grid:
|
|
201
201
|
|
|
202
202
|
```svelte
|
|
203
203
|
<script lang="ts">
|
|
@@ -246,7 +246,7 @@ To lock single events, set `data.readOnly: true` on them: views refuse to move o
|
|
|
246
246
|
| Prop | Type | Default | Description |
|
|
247
247
|
|------|------|---------|-------------|
|
|
248
248
|
| `title` | `string` | `''` | Header text and dialog label |
|
|
249
|
-
| `anchor` | `FloatingPanelAnchor` | `{ x: 24, y: 24 }` | `{ x, y, width?, height? }
|
|
249
|
+
| `anchor` | `FloatingPanelAnchor` | `{ x: 24, y: 24 }` | `{ x, y, width?, height? }`; a `DOMRect` works as is |
|
|
250
250
|
| `width` | `number` | `440` | Panel width in px |
|
|
251
251
|
| `theme` | `string` | `''` | A `--dt-*` theme string, as the Calendar takes |
|
|
252
252
|
| `closeLabel` | `string` | `'Close'` | Close button label |
|
|
@@ -320,7 +320,7 @@ Disable specific dates:
|
|
|
320
320
|
/>
|
|
321
321
|
```
|
|
322
322
|
|
|
323
|
-
Disabled dates refuse creating or moving events into those days. Existing events stay visible and clickable
|
|
323
|
+
Disabled dates refuse creating or moving events into those days. Existing events stay visible and clickable, which suits holidays or fully booked days.
|
|
324
324
|
|
|
325
325
|
Custom day headers and hover previews:
|
|
326
326
|
|
|
@@ -358,7 +358,7 @@ Replace the built-in navigation or the entire header chrome with your own contro
|
|
|
358
358
|
</Calendar>
|
|
359
359
|
```
|
|
360
360
|
|
|
361
|
-
Let agenda content determine height instead of forcing a fixed box
|
|
361
|
+
Let agenda content determine height instead of forcing a fixed box, for a calendar inside a scrolling page:
|
|
362
362
|
|
|
363
363
|
```svelte
|
|
364
364
|
<Calendar {adapter} view="week-agenda" height="auto" compact />
|
|
@@ -370,7 +370,7 @@ Three built-in presets:
|
|
|
370
370
|
|
|
371
371
|
| Preset | Description |
|
|
372
372
|
|--------|-------------|
|
|
373
|
-
| `auto` | **Default.** Probes the host page at mount
|
|
373
|
+
| `auto` | **Default.** Probes the host page at mount (background, accent color, fonts, light/dark mode) and writes matching `--dt-*` tokens. Re-probes when the host theme changes. |
|
|
374
374
|
| `neutral` | Explicit light theme. White bg, blue accent. Use when embedding standalone. |
|
|
375
375
|
| `midnight` | Explicit dark theme. Charcoal bg, red accent. |
|
|
376
376
|
|
|
@@ -390,11 +390,11 @@ Three built-in presets:
|
|
|
390
390
|
|
|
391
391
|
The default `auto` preset probes the page around the calendar and generates a theme that blends in. It detects:
|
|
392
392
|
|
|
393
|
-
- **Background color
|
|
394
|
-
- **Light/dark mode
|
|
395
|
-
- **Accent/brand color
|
|
396
|
-
- **Text color
|
|
397
|
-
- **Fonts
|
|
393
|
+
- **Background color**: from common CSS variables on `:root` (`--bg`, `--background`, `--color-bg`, `--bs-body-bg`, …), inline styles, or computed styles
|
|
394
|
+
- **Light/dark mode**: from background luminance
|
|
395
|
+
- **Accent/brand color**: from common CSS variables (`--accent`, `--primary`, `--brand`, `--bs-primary`, …), link colors, or button colors
|
|
396
|
+
- **Text color**: validated for contrast against the background
|
|
397
|
+
- **Fonts**: the host's computed font stack; the mono stack from `--font-mono` and similar variables
|
|
398
398
|
|
|
399
399
|
It watches for changes (a dark-mode toggle on `<html>`/`<body>`, the system color scheme) and updates automatically.
|
|
400
400
|
|
|
@@ -420,7 +420,7 @@ Fine-tune auto-detection with the `autoTheme` prop (`AutoThemeOptions`):
|
|
|
420
420
|
|
|
421
421
|
The calendar writes its theme inline on its own root element, so it **wins over** `--dt-*` values set on an ancestor or `:root`. With the default `auto` theme it writes a full probed set. To use your own values:
|
|
422
422
|
|
|
423
|
-
- **Change a few tokens
|
|
423
|
+
- **Change a few tokens**: append them to a preset (later declarations win):
|
|
424
424
|
|
|
425
425
|
```ts
|
|
426
426
|
import { neutral } from '@nomideusz/svelte-calendar';
|
|
@@ -432,8 +432,8 @@ The calendar writes its theme inline on its own root element, so it **wins over*
|
|
|
432
432
|
<Calendar {adapter} theme={custom} />
|
|
433
433
|
```
|
|
434
434
|
|
|
435
|
-
- **Write your own theme string
|
|
436
|
-
- **Inherit from the page
|
|
435
|
+
- **Write your own theme string**: any `--dt-*` declarations; tokens you leave out are inherited from ancestors or fall back to neutral defaults.
|
|
436
|
+
- **Inherit from the page**: pass `autoTheme={false}` (keeping the default `auto` theme). The calendar then writes no tokens and reads whatever `--dt-*` its ancestors define:
|
|
437
437
|
|
|
438
438
|
```svelte
|
|
439
439
|
<div style="--dt-accent: #e11d48; --dt-bg: #1a1a2e; --dt-text: rgba(255,255,255,0.87);">
|
|
@@ -457,6 +457,7 @@ Component fallbacks use system fonts and a neutral blue accent, so the package s
|
|
|
457
457
|
| `--dt-text-3` | Tertiary text |
|
|
458
458
|
| `--dt-accent` | Accent color |
|
|
459
459
|
| `--dt-accent-dim` | Accent at ~12% opacity (selection, highlights) |
|
|
460
|
+
| `--dt-event` | Bar color of an event without its own `color` (the presets set it to the text color, so such events draw in ink) |
|
|
460
461
|
| `--dt-accent-fg` | Text on the planner's today-number badge (default `#fff`; not set by the presets) |
|
|
461
462
|
| `--dt-btn-text` | Text on accent-filled buttons and badges |
|
|
462
463
|
| `--dt-glow` | Accent glow / focus ring |
|
|
@@ -481,8 +482,8 @@ Component fallbacks use system fonts and a neutral blue accent, so the package s
|
|
|
481
482
|
| `id` | `string` | Unique identifier |
|
|
482
483
|
| `title` | `string` | Event title |
|
|
483
484
|
| `start` / `end` | `Date` | Time range |
|
|
484
|
-
| `color` | `string?` |
|
|
485
|
-
| `category` | `string?` | Grouping key
|
|
485
|
+
| `color` | `string?` | The event's bar color. Without it the event draws in `--dt-event` (ink), or takes a color from the adapter's `palette` |
|
|
486
|
+
| `category` | `string?` | Grouping key: with a `palette`, events of the same category share a color |
|
|
486
487
|
| `subtitle` | `string?` | Secondary text below the title |
|
|
487
488
|
| `tags` | `string[]?` | Small accent-colored pills |
|
|
488
489
|
| `allDay` | `boolean?` | Render as an all-day event |
|
|
@@ -494,19 +495,25 @@ Component fallbacks use system fonts and a neutral blue accent, so the package s
|
|
|
494
495
|
|
|
495
496
|
Cancelled events render with a strikethrough but stay visible, so the slot isn't mistaken for free time.
|
|
496
497
|
|
|
497
|
-
###
|
|
498
|
+
### Event colors
|
|
499
|
+
|
|
500
|
+
An event with a `color` draws its bar in that color. An event without one draws in ink: `--dt-event`, which the presets set to the text color. Nothing is colored for you unless you ask.
|
|
498
501
|
|
|
499
|
-
|
|
502
|
+
To color events automatically, pass a `palette` to the memory, recurring or mapped adapter. Events without a `color` then take a palette color, grouped by `category` (or `title`):
|
|
500
503
|
|
|
501
504
|
```ts
|
|
505
|
+
import { createMemoryAdapter, VIVID_PALETTE } from '@nomideusz/svelte-calendar';
|
|
506
|
+
|
|
502
507
|
const events = [
|
|
503
508
|
{ id: '1', title: 'Yoga', category: 'wellness', start, end },
|
|
504
509
|
{ id: '2', title: 'Pilates', category: 'wellness', start, end }, // same color
|
|
505
510
|
{ id: '3', title: 'Standup', start, end }, // different color
|
|
506
511
|
];
|
|
512
|
+
|
|
513
|
+
const adapter = createMemoryAdapter(events, { palette: VIVID_PALETTE });
|
|
507
514
|
```
|
|
508
515
|
|
|
509
|
-
|
|
516
|
+
Or generate a theme-harmonious palette from any accent color:
|
|
510
517
|
|
|
511
518
|
```ts
|
|
512
519
|
import { createMemoryAdapter, generatePalette } from '@nomideusz/svelte-calendar';
|
|
@@ -515,7 +522,7 @@ const palette = generatePalette('#e11d48'); // (accent?, count = 15)
|
|
|
515
522
|
const adapter = createMemoryAdapter(events, { palette });
|
|
516
523
|
```
|
|
517
524
|
|
|
518
|
-
Related exports: `VIVID_PALETTE` (the default
|
|
525
|
+
Related exports: `VIVID_PALETTE` (the vivid palette, the default before 1.4) and `extractAccent(themeString)` (the accent color of a `--dt-*` theme string).
|
|
519
526
|
|
|
520
527
|
### Multi-day & All-day
|
|
521
528
|
|
|
@@ -530,7 +537,7 @@ const events = [
|
|
|
530
537
|
|
|
531
538
|
### Custom Event Rendering
|
|
532
539
|
|
|
533
|
-
The `event` snippet replaces the event *content* in every view (the interactive shell
|
|
540
|
+
The `event` snippet replaces the event *content* in every view (the interactive shell for click, keyboard, drag and selection stays intact). The `empty` snippet replaces the empty state of the day agenda, the day on mobile, and an empty planner week:
|
|
534
541
|
|
|
535
542
|
```svelte
|
|
536
543
|
<Calendar {adapter}>
|
|
@@ -541,11 +548,25 @@ The `event` snippet replaces the event *content* in every view (the interactive
|
|
|
541
548
|
</div>
|
|
542
549
|
{/snippet}
|
|
543
550
|
{#snippet empty()}
|
|
544
|
-
<p>Nothing booked
|
|
551
|
+
<p>Nothing booked. Drag on the grid to add a class.</p>
|
|
545
552
|
{/snippet}
|
|
546
553
|
</Calendar>
|
|
547
554
|
```
|
|
548
555
|
|
|
556
|
+
## Adapters
|
|
557
|
+
|
|
558
|
+
The calendar reads its events through an adapter. Which one:
|
|
559
|
+
|
|
560
|
+
| Adapter | Use it when |
|
|
561
|
+
|---------|-------------|
|
|
562
|
+
| `createMemoryAdapter(events)` | The events are already in the page (a fixed list, your own state). Writes stay in memory. See [Quick Start](#quick-start). |
|
|
563
|
+
| [`createRecurringAdapter(rules)`](#recurring-schedules) | The schedule repeats by rule: class timetables, office hours. Read-only. |
|
|
564
|
+
| [`createRestAdapter(options)`](#rest-adapter) | The events live behind your own HTTP API, which also stores creates and moves. |
|
|
565
|
+
| [`createJmapAdapter(client, options)`](#jmap-adapter) | The events are in a JMAP Calendars server (Fastmail, Stalwart, Cyrus). Read-only. |
|
|
566
|
+
| [`createMappedAdapter(records, options)`](#mapped-adapter) | You have records from another system with their own field names: map the fields instead of writing an adapter. |
|
|
567
|
+
| [`createCompositeAdapter(adapters)`](#composite-adapter) | One calendar shows several sources, e.g. a recurring timetable plus one-off events. |
|
|
568
|
+
| [Custom `CalendarAdapter`](#custom-adapter) | None of the above fits: implement `fetchEvents`, plus the writes you need. |
|
|
569
|
+
|
|
549
570
|
## Recurring Schedules
|
|
550
571
|
|
|
551
572
|
For fixed repeating events (class timetables, office hours):
|
|
@@ -564,7 +585,7 @@ For fixed repeating events (class timetables, office hours):
|
|
|
564
585
|
]);
|
|
565
586
|
</script>
|
|
566
587
|
|
|
567
|
-
<Calendar {adapter} />
|
|
588
|
+
<Calendar {adapter} view="week-planner" />
|
|
568
589
|
```
|
|
569
590
|
|
|
570
591
|
<details>
|
|
@@ -584,13 +605,13 @@ For fixed repeating events (class timetables, office hours):
|
|
|
584
605
|
| `until` | `string` | — | Last possible occurrence `"YYYY-MM-DD"` |
|
|
585
606
|
| `count` | `number` | — | Max occurrences from `startDate` (requires it). With `until`, the stricter wins. |
|
|
586
607
|
| `excludeDates` | `string[]` | — | `"YYYY-MM-DD"` dates this rule skips |
|
|
587
|
-
| `color` | `string` |
|
|
608
|
+
| `color` | `string` | — | Bar color; else from `palette`, else ink (`--dt-event`) |
|
|
588
609
|
| `subtitle` / `tags` / `category` / `location` / `resourceId` | | — | Copied to every occurrence |
|
|
589
610
|
| `data` | `Record<string, unknown>` | — | Copied to every occurrence, plus `recurringId` |
|
|
590
611
|
|
|
591
612
|
</details>
|
|
592
613
|
|
|
593
|
-
Options (`RecurringAdapterOptions`): `mondayStart` (default `true`), `palette
|
|
614
|
+
Options (`RecurringAdapterOptions`): `mondayStart` (default `true`), `palette` (colors rules without a `color`; off by default), `movable` (default `false`).
|
|
594
615
|
|
|
595
616
|
Occurrences get the id `` `${rule.id}--YYYYMMDD` `` and `data.recurringId`. The adapter projects and stores nothing, so by default every occurrence carries `data.readOnly` and can't be dragged (it can still be clicked). With `movable: true` the views allow the drag and the adapter refuses the write with a read-only error, so `oneventmove` fires and the host stores the move: add the date to the rule's `excludeDates` and keep the moved occurrence with your one-off events (for example the memory side of a [composite adapter](#composite-adapter)).
|
|
596
617
|
|
|
@@ -646,7 +667,7 @@ Read-only. Expands recurrences server-side and handles all-day events, ISO-durat
|
|
|
646
667
|
|
|
647
668
|
## Mapped Adapter
|
|
648
669
|
|
|
649
|
-
Wrap any static array of external records (class schedules, appointments, timetables) without writing a custom adapter. Supply a declarative field mapping
|
|
670
|
+
Wrap any static array of external records (class schedules, appointments, timetables) without writing a custom adapter. Supply a declarative field mapping (or a `mapEvent` function for full control) and the adapter handles parsing, colors, tags and status:
|
|
650
671
|
|
|
651
672
|
```ts
|
|
652
673
|
import { createMappedAdapter } from '@nomideusz/svelte-calendar';
|
|
@@ -667,7 +688,7 @@ const adapter = createMappedAdapter(rawClasses, {
|
|
|
667
688
|
|
|
668
689
|
- Works without options too: it looks for common keys (`id`, `title`/`name`, `start`/`end`, `starts_at_iso`/`ends_at_iso`, `date` + `start_time`/`end_time`, `room`/`location`, `is_cancelled`). A missing end defaults to one hour after the start.
|
|
669
690
|
- `start`/`end` accept ISO strings, `Date`s or millisecond timestamps. When records split date and time (`date: "2026-03-03"`, `startTime: "07:00"`), map `date` + `startTime` / `endTime`; times may be `7:00`, `07:00` or `07:00:00`.
|
|
670
|
-
-
|
|
691
|
+
- Source colors are kept. Records without one draw in ink, unless you pass a `palette` to fill them by category/title. `autoColor: true` ignores the source colors and colors every event from `palette` (default `VIVID_PALETTE`).
|
|
671
692
|
- `includeData` (default `'*'`) copies unmapped source fields into `event.data`; pass a list of keys to limit it.
|
|
672
693
|
|
|
673
694
|
For full control, pass `mapEvent(raw, index)` and skip `fields`:
|
|
@@ -689,7 +710,7 @@ Mapped adapters are read-only by default (writes throw a read-only error, so dra
|
|
|
689
710
|
|
|
690
711
|
## Composite Adapter
|
|
691
712
|
|
|
692
|
-
Merge several adapters into one
|
|
713
|
+
Merge several adapters into one, e.g. a recurring weekly schedule plus one-off events:
|
|
693
714
|
|
|
694
715
|
```ts
|
|
695
716
|
import { createMemoryAdapter, createRecurringAdapter, createCompositeAdapter } from '@nomideusz/svelte-calendar';
|
|
@@ -701,9 +722,9 @@ const adapter = createCompositeAdapter([memory, recurring]);
|
|
|
701
722
|
```
|
|
702
723
|
|
|
703
724
|
- **Reads** query every child in parallel and merge the results (the first event with a given id wins).
|
|
704
|
-
- **Creates** go to the primary child
|
|
725
|
+
- **Creates** go to the primary child: the first by default, or `primaryIndex`.
|
|
705
726
|
- **Updates and deletes** go to the child that returned the event. If that child can't write, the composite refuses with a read-only error (so `oneventmove` reaches the host). An id no fetch returned is offered to each writable child in turn.
|
|
706
|
-
- **`onFetchError(error, adapterIndex)
|
|
727
|
+
- **`onFetchError(error, adapterIndex)`**: with it, a failing child is reported to you and the others still load; without it, one failing child fails the whole load (surfacing through `onerror`).
|
|
707
728
|
|
|
708
729
|
```ts
|
|
709
730
|
const adapter = createCompositeAdapter([recurring, memory], {
|
|
@@ -724,7 +745,7 @@ const adapter: CalendarAdapter = {
|
|
|
724
745
|
fetchEvents: async (range: DateRange) => { /* return TimelineEvent[] */ },
|
|
725
746
|
// Optional: the same answer synchronously, when the data is already in memory
|
|
726
747
|
fetchEventsSync: (range) => { /* return TimelineEvent[], or undefined to go async */ },
|
|
727
|
-
// Optional writes
|
|
748
|
+
// Optional writes; omit them for a read-only source
|
|
728
749
|
createEvent: async (event) => { /* return the created TimelineEvent with its id */ },
|
|
729
750
|
updateEvent: async (id, patch) => { /* return the updated TimelineEvent */ },
|
|
730
751
|
deleteEvent: async (id) => { /* void */ },
|
|
@@ -733,7 +754,7 @@ const adapter: CalendarAdapter = {
|
|
|
733
754
|
|
|
734
755
|
`WritableCalendarAdapter` is the same interface with all three write methods required.
|
|
735
756
|
|
|
736
|
-
**`fetchEventsSync`** lets the first render
|
|
757
|
+
**`fetchEventsSync`** lets the first render (the server render too) hold the events instead of a loading state. The memory, recurring and seeded adapters implement it. To seed an async adapter with events you already loaded on the server, wrap it:
|
|
737
758
|
|
|
738
759
|
```ts
|
|
739
760
|
import { createRestAdapter, withInitialEvents } from '@nomideusz/svelte-calendar';
|
|
@@ -750,7 +771,7 @@ The Calendar tells two refusals apart when `updateEvent` throws:
|
|
|
750
771
|
|
|
751
772
|
| Throw | Meaning | What happens |
|
|
752
773
|
|-------|---------|--------------|
|
|
753
|
-
| `new CalendarReadOnlyError(message?)` | "I hold this event but can't store the change." | The block stays where it was dropped and `oneventmove` fires
|
|
774
|
+
| `new CalendarReadOnlyError(message?)` | "I hold this event but can't store the change." | The block stays where it was dropped and `oneventmove` fires; the host stores the move and refreshes. |
|
|
754
775
|
| `new EventNotFoundError(id)` | "Not my event." | A composite asks its next child; a drag ends quietly. |
|
|
755
776
|
| any other error | A real failure | The block reverts and the error goes to `onerror` (or `console.warn`). |
|
|
756
777
|
|
|
@@ -758,7 +779,7 @@ An adapter without `updateEvent` counts as read-only. Plain `Error`s whose messa
|
|
|
758
779
|
|
|
759
780
|
## Headless API
|
|
760
781
|
|
|
761
|
-
For full control over rendering, skip `<Calendar>` and drive everything from reactive state. `createCalendar()` returns computed layouts, navigation actions, drag helpers and the raw engines
|
|
782
|
+
For full control over rendering, skip `<Calendar>` and drive everything from reactive state. `createCalendar()` returns computed layouts, navigation actions, drag helpers and the raw engines. Zero DOM: bring your own UI. Call it during component initialisation.
|
|
762
783
|
|
|
763
784
|
```svelte
|
|
764
785
|
<script lang="ts">
|
|
@@ -793,7 +814,7 @@ Options (`HeadlessCalendarOptions`) mirror the Calendar props: `adapter`, `view`
|
|
|
793
814
|
|
|
794
815
|
`cal.days` gives flat `HeadlessDay[]` with events attached; `cal.weeks` groups them into periods (`HeadlessWeek`). `cal.todayQueue` returns `{ past, current, upcoming }` for today (`TodayQueue`), updated every second. `cal.hours` yields the visible hour numbers. Drag is fully wired: `beginDragMove`, `beginDragCreate`, `updateDrag`, `commitDrag` (validates like the Calendar), `cancelDrag`, plus `isDragging` / `dragPayload` / `dragMode`. `headerContext` / `navigationContext` match the Calendar's `header` / `navigation` snippet contexts. Raw engines (`store`, `viewState`, `selection`, `dragState`, `clock`) are exposed for advanced cases.
|
|
795
816
|
|
|
796
|
-
The engine factories are exported individually
|
|
817
|
+
The engine factories are exported individually (`createEventStore(adapter)`, `createViewState(options)`, `createSelection()`, `createDragState()`, `createClock(timezone?)`) if you want to compose your own calendar loop (types: `EventStore`, `ViewState`, `ViewStateOptions`, `CalendarSelection`, `DragState`, `DragMode`, `DragPayload`, `CalendarViewId`, `BuiltInViewId`, `ViewMode`).
|
|
797
818
|
|
|
798
819
|
### createAgenda
|
|
799
820
|
|
|
@@ -821,7 +842,7 @@ It returns `dayEvents`, `allDay`, `past`, `current`, `upcoming`, `upcomingSlots`
|
|
|
821
842
|
|
|
822
843
|
### createRangeAgenda
|
|
823
844
|
|
|
824
|
-
A window of days with events grouped per day
|
|
845
|
+
A window of days with events grouped per day; no clock, drag or selection. Built for read-only schedule surfaces (public timetables, embeds):
|
|
825
846
|
|
|
826
847
|
```svelte
|
|
827
848
|
<script lang="ts">
|
|
@@ -845,7 +866,7 @@ Options (`RangeAgendaOptions`): `adapter` (or a getter), `days` (default 7), `in
|
|
|
845
866
|
|
|
846
867
|
## Localization (i18n)
|
|
847
868
|
|
|
848
|
-
The `locale` prop controls date/time formatting (BCP 47). Without it, the global default locale is used
|
|
869
|
+
The `locale` prop controls date/time formatting (BCP 47). Without it, the global default locale is used: `'en-US'` unless you call `setDefaultLocale()`:
|
|
849
870
|
|
|
850
871
|
```svelte
|
|
851
872
|
<Calendar {adapter} locale="de-DE" />
|
|
@@ -853,7 +874,7 @@ The `locale` prop controls date/time formatting (BCP 47). Without it, the global
|
|
|
853
874
|
|
|
854
875
|
`setDefaultLocale('de-DE')` sets it for every calendar and formatter; `getDefaultLocale()` reads it back; `is24HourLocale(tag?)` tells you how times will format. An RTL locale (`ar-SA`, `he-IL`, …) sets `dir="rtl"` where the browser reports the locale's text direction (`Intl.Locale` text info); pass `dir` to be explicit.
|
|
855
876
|
|
|
856
|
-
Override UI labels per calendar with the `labels` prop
|
|
877
|
+
Override UI labels per calendar with the `labels` prop. It's reactive (swap it to switch language live) and instance-scoped (two calendars on one page can carry different languages):
|
|
857
878
|
|
|
858
879
|
```svelte
|
|
859
880
|
<Calendar {adapter} locale="de-DE" labels={{
|
|
@@ -871,7 +892,7 @@ import { setLabels } from '@nomideusz/svelte-calendar';
|
|
|
871
892
|
setLabels({ today: 'Heute', day: 'Tag', week: 'Woche' });
|
|
872
893
|
```
|
|
873
894
|
|
|
874
|
-
Both take a `Partial<CalendarLabels
|
|
895
|
+
Both take a `Partial<CalendarLabels>`, and that is the supported input: pass the keys you translate, and keys added in later minor releases fall back to English. The `labels` prop merges over the global set. `resetLabels()` restores English (`defaultLabels` exports it; `getLabels()` reads the active set). Global `setLabels()` calls after mount don't re-render mounted calendars; use the `labels` prop to switch language live. Standalone primitives (`DayHeader`, `EventBlock`, …) and the format helpers read the global set.
|
|
875
896
|
|
|
876
897
|
<details>
|
|
877
898
|
<summary>All label keys</summary>
|
|
@@ -911,7 +932,7 @@ Both take a `Partial<CalendarLabels>` — that is the supported input: pass the
|
|
|
911
932
|
|
|
912
933
|
## Timezone Support
|
|
913
934
|
|
|
914
|
-
Render the whole calendar in any IANA timezone
|
|
935
|
+
Render the whole calendar in any IANA timezone: events, the now-indicator and day boundaries all shift:
|
|
915
936
|
|
|
916
937
|
```svelte
|
|
917
938
|
<Calendar {adapter} timezone="Europe/Warsaw" />
|
|
@@ -919,7 +940,7 @@ Render the whole calendar in any IANA timezone — events, the now-indicator and
|
|
|
919
940
|
|
|
920
941
|
- `initialDate` and `currentDate` are instants, read in that zone.
|
|
921
942
|
- `oneventcreate`, `oneventmove` and `onexternaldrop` receive real instants.
|
|
922
|
-
- `ondatechange` and `ondayclick` receive instants too
|
|
943
|
+
- `ondatechange` and `ondayclick` receive instants too (the start of that day in the zone), so feeding one back is stable: `currentDate={date} ondatechange={(d) => (date = d)}`. To read the date, format it in the zone:
|
|
923
944
|
|
|
924
945
|
```ts
|
|
925
946
|
import { formatInTimeZone } from '@nomideusz/svelte-calendar';
|
|
@@ -970,20 +991,20 @@ Small helpers used by the built-in views, exported for custom rendering. Formatt
|
|
|
970
991
|
| `weekdayShort` / `weekdayLong` / `monthShort` / `monthLong` | Name parts of a timestamp |
|
|
971
992
|
| `sod(ms)` | Start of that day (local midnight) |
|
|
972
993
|
| `startOfWeek(ms, mondayStart = true)` | Start-of-week timestamp |
|
|
973
|
-
| `addDaysMs(ms, n)` / `diffDays(a, b)` | Add / count **calendar** days
|
|
994
|
+
| `addDaysMs(ms, n)` / `diffDays(a, b)` | Add / count **calendar** days, DST-safe (a DST day is 23 or 25 hours, so don't add `n * 86_400_000`) |
|
|
974
995
|
| `isAllDay(ev)` / `isMultiDay(ev)` | Event classification |
|
|
975
996
|
| `segmentForDay(ev, dayMs)` | The slice of a multi-day event on one day (`DaySegment`), or `null` |
|
|
976
997
|
| `createClock(timezone?)` | Reactive clock: `tick` (ms, every second), `today`, `hm`, `s`, `fractionalHour`, `destroy()` |
|
|
977
|
-
| `textWidth(text, font)` / `textHeight(text, font, width, lineHeight)` / `lineCount(text, font, width, options?)` / `fits(text, font, width, lines = 1)` | Text measurement via [pretext](https://github.com/chenglou/pretext)
|
|
998
|
+
| `textWidth(text, font)` / `textHeight(text, font, width, lineHeight)` / `lineCount(text, font, width, options?)` / `fits(text, font, width, lines = 1)` | Text measurement via [pretext](https://github.com/chenglou/pretext), before render, no layout thrash. `options` is `TextLayoutOptions` (`whiteSpace`, `wordBreak`, `letterSpacing`). Browser-only. |
|
|
978
999
|
| `pickFit(candidates, font, width, lines = 1)` | The longest candidate that fits |
|
|
979
1000
|
| `fitLabel(candidates, lines = 1)` | Attachment: `<span {@attach fitLabel([ev.title, ev.short])}>` keeps the longest label that fits its box, re-fitting on resize |
|
|
980
1001
|
| `fontOf(el)` | An element's computed font as a canvas font string |
|
|
981
1002
|
| `fitParts(parts, budget, measure?)` | Which parts of a dense chip fit, along either axis → `Record<key, boolean>`. Each `ChipPart` is `{ key, text, font }` to measure or `{ key, size }` to state its cost, plus `priority` (`0` is an anchor and never drops; higher numbers drop first) and `extra` (a gap or icon). The first optional part that doesn't fit ends the list, so a chip never keeps a later detail after dropping an earlier one. A budget of `0` (server-rendered, not yet measured) leaves only the anchors. |
|
|
982
|
-
| `typeset(text)` / `breakLines(text, font, width)` | Knuth-Plass paragraph breaking over the text's own spaces and soft hyphens. `<p {@attach typeset(text)}>` sets justified lines, re-done on resize; if the browser disagrees with the measure, the plain text goes back. Progressive
|
|
1003
|
+
| `typeset(text)` / `breakLines(text, font, width)` | Knuth-Plass paragraph breaking over the text's own spaces and soft hyphens. `<p {@attach typeset(text)}>` sets justified lines, re-done on resize; if the browser disagrees with the measure, the plain text goes back. Progressive: SSR text stays. |
|
|
983
1004
|
|
|
984
1005
|
## Embeddable Widget
|
|
985
1006
|
|
|
986
|
-
Drop into any HTML page
|
|
1007
|
+
Drop into any HTML page, no build tools needed. Registers a `<day-calendar>` custom element:
|
|
987
1008
|
|
|
988
1009
|
```html
|
|
989
1010
|
<script src="https://cdn.jsdelivr.net/npm/@nomideusz/svelte-calendar/widget/widget.js"></script>
|
|
@@ -1024,47 +1045,78 @@ Each event in `api` responses and `events` needs `start` and `end` as date strin
|
|
|
1024
1045
|
|
|
1025
1046
|
## All Props
|
|
1026
1047
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1048
|
+
Every `<Calendar>` prop (`CalendarProps`), grouped by what it controls.
|
|
1049
|
+
|
|
1050
|
+
### Data and editing
|
|
1029
1051
|
|
|
1030
1052
|
| Prop | Type | Default | Description |
|
|
1031
1053
|
|------|------|---------|-------------|
|
|
1032
1054
|
| `adapter` | `CalendarAdapter` | *required* | Data source (memory, recurring, mapped, composite, REST, JMAP, or custom) |
|
|
1033
|
-
| `views` | `readonly CalendarView[]` | `defaultViews` | View registry (the 8 built-ins). Spread `defaultViews` to add your own. |
|
|
1034
|
-
| `view` | `CalendarViewId` | first registered (`'day-planner'`) | Active view ID. Reactive. |
|
|
1035
|
-
| `theme` | `string` | `auto` | CSS theme string of `--dt-*` properties. `auto` probes the host page. |
|
|
1036
|
-
| `autoTheme` | `AutoThemeOptions \| false` | `undefined` (probe) | Fine-tune auto-detection: `{ mode, accent, font }`. `false` disables probing. |
|
|
1037
|
-
| `mobile` | `'auto' \| boolean` | `'auto'` | `'auto'` switches to mobile views below a 768px container width |
|
|
1038
|
-
| `height` | `number \| 'auto'` | `600` | Height in px, or `'auto'` to grow with content (ideal for Agenda views) |
|
|
1039
|
-
| `borderRadius` | `number` | `12` | Border radius in px. `0` for none. |
|
|
1040
|
-
| `locale` | `string` | global default (`'en-US'`) | BCP 47 locale tag; see `setDefaultLocale` |
|
|
1041
|
-
| `labels` | `Partial<CalendarLabels>` | — | Per-instance UI labels, merged over the global set. Reactive. |
|
|
1042
|
-
| `dir` | `'ltr' \| 'rtl' \| 'auto'` | from `locale` | Text direction |
|
|
1043
|
-
| `mondayStart` | `boolean` | `true` | Start weeks on Monday |
|
|
1044
1055
|
| `readOnly` | `boolean` | `false` | Disable drag, resize, click-to-create and external drops |
|
|
1045
|
-
| `
|
|
1056
|
+
| `snapInterval` | `number` | `15` | Drag snap in minutes |
|
|
1057
|
+
| `minDuration` | `number` | — | Minimum duration in minutes; clamps creates and resizes |
|
|
1058
|
+
| `maxDuration` | `number` | — | Maximum duration in minutes; clamps creates and resizes |
|
|
1059
|
+
| `blockedSlots` | `BlockedSlot[]` | — | `{ day?, start, end, label? }` hour ranges that can't be booked (hatched in planner views) |
|
|
1060
|
+
| `disabledDates` | `Date[]` | — | Dates that refuse creates/moves; existing events stay visible and clickable |
|
|
1061
|
+
|
|
1062
|
+
### View and navigation
|
|
1063
|
+
|
|
1064
|
+
| Prop | Type | Default | Description |
|
|
1065
|
+
|------|------|---------|-------------|
|
|
1066
|
+
| `view` | `CalendarViewId` | first registered (`'day-planner'`) | Active view ID. Reactive. |
|
|
1067
|
+
| `views` | `readonly CalendarView[]` | `defaultViews` | View registry (the eight built-ins). Spread `defaultViews` to add your own. |
|
|
1046
1068
|
| `initialDate` | `Date` | today | Date to focus at mount (an instant; read in `timezone`) |
|
|
1047
1069
|
| `currentDate` | `Date` | — | Controlled focus date (an instant; read in `timezone`) |
|
|
1048
|
-
| `timezone` | `string` | viewer's zone | IANA zone to render in. Read at mount. |
|
|
1049
|
-
| `snapInterval` | `number` | `15` | Drag snap in minutes |
|
|
1050
|
-
| `minColumnWidth` | `number` | `110` | Minimum day-column width (px) in planner views; below the total the grid scrolls horizontally |
|
|
1051
1070
|
| `days` | `number` | `7` | Days shown in week mode (e.g. `3` for a rolling 3-day view) |
|
|
1052
|
-
| `
|
|
1071
|
+
| `mobile` | `'auto' \| boolean` | `'auto'` | `'auto'` switches to mobile views below a 768px container width |
|
|
1053
1072
|
| `showModePills` | `boolean` | `true` | Show the Day/Week/Month pills and the view-type pills |
|
|
1054
1073
|
| `showNavigation` | `boolean` | `true` | Show prev/next/today |
|
|
1074
|
+
|
|
1075
|
+
### Display
|
|
1076
|
+
|
|
1077
|
+
| Prop | Type | Default | Description |
|
|
1078
|
+
|------|------|---------|-------------|
|
|
1079
|
+
| `height` | `number \| 'auto'` | `600` | Height in px, or `'auto'` to grow with content (ideal for Agenda views) |
|
|
1080
|
+
| `visibleHours` | `[number, number]` | — | Crop the grid to `[startHour, endHour)` |
|
|
1081
|
+
| `hideDays` | `number[]` | — | ISO weekdays to hide (1=Mon … 7=Sun), e.g. `[6, 7]` |
|
|
1082
|
+
| `mondayStart` | `boolean` | `true` | Start weeks on Monday |
|
|
1055
1083
|
| `showDates` | `boolean` | `true` | Show date numbers and the date label. `false` = day names only (templates, recurring schedules) |
|
|
1056
1084
|
| `equalDays` | `boolean` | `false` | Treat all days equally (no past-day dimming/collapsing) |
|
|
1057
|
-
| `blockedSlots` | `BlockedSlot[]` | — | `{ day?, start, end, label? }` hour ranges that can't be booked (hatched in planner views) |
|
|
1058
|
-
| `disabledDates` | `Date[]` | — | Dates that refuse creates/moves; existing events stay visible and clickable |
|
|
1059
|
-
| `minDuration` | `number` | — | Minimum duration in minutes; clamps creates and resizes |
|
|
1060
|
-
| `maxDuration` | `number` | — | Maximum duration in minutes; clamps creates and resizes |
|
|
1061
1085
|
| `compact` | `boolean` | `false` | Minimal text rows in Agenda views (dot + time + title) |
|
|
1062
1086
|
| `columns` | `boolean` | `false` | Timetable layout: `week-agenda` days side by side on desktop. Pairs with `equalDays`; overrides `compact` |
|
|
1087
|
+
| `minColumnWidth` | `number` | `110` | Minimum day-column width (px) in planner views; below the total the grid scrolls horizontally |
|
|
1088
|
+
|
|
1089
|
+
### Theming
|
|
1090
|
+
|
|
1091
|
+
| Prop | Type | Default | Description |
|
|
1092
|
+
|------|------|---------|-------------|
|
|
1093
|
+
| `theme` | `string` | `auto` | CSS theme string of `--dt-*` properties. `auto` probes the host page. |
|
|
1094
|
+
| `autoTheme` | `AutoThemeOptions \| false` | `undefined` (probe) | Fine-tune auto-detection: `{ mode, accent, font }`. `false` disables probing. |
|
|
1095
|
+
| `borderRadius` | `number` | `0` | Corner radius in px (square by default) |
|
|
1096
|
+
|
|
1097
|
+
### Locale and timezone
|
|
1098
|
+
|
|
1099
|
+
| Prop | Type | Default | Description |
|
|
1100
|
+
|------|------|---------|-------------|
|
|
1101
|
+
| `locale` | `string` | global default (`'en-US'`) | BCP 47 locale tag; see `setDefaultLocale` |
|
|
1102
|
+
| `labels` | `Partial<CalendarLabels>` | — | Per-instance UI labels, merged over the global set. Reactive. |
|
|
1103
|
+
| `dir` | `'ltr' \| 'rtl' \| 'auto'` | from `locale` | Text direction |
|
|
1104
|
+
| `timezone` | `string` | viewer's zone | IANA zone to render in. Read at mount. |
|
|
1105
|
+
|
|
1106
|
+
### Snippets
|
|
1107
|
+
|
|
1108
|
+
| Prop | Type | Default | Description |
|
|
1109
|
+
|------|------|---------|-------------|
|
|
1063
1110
|
| `event` | `Snippet<[TimelineEvent]>` | — | Custom event content |
|
|
1064
1111
|
| `empty` | `Snippet` | — | Empty state for the day agenda, mobile day and an empty planner week |
|
|
1065
1112
|
| `dayHeader` | `Snippet<[{ date, isToday, dayName }]>` | — | Custom day header |
|
|
1066
1113
|
| `header` | `Snippet<[HeaderContext]>` | — | Replace the whole header (`dateLabel`, `mode`, `modes`, `switchMode`, `prev`, `next`, `goToday`, `isViewOnToday`, `focusDate`) |
|
|
1067
1114
|
| `navigation` | `Snippet<[NavigationContext]>` | — | Replace prev/next/today (`prev`, `next`, `goToday`, `isViewOnToday`, `focusDate`, `mode`) |
|
|
1115
|
+
|
|
1116
|
+
### Callbacks
|
|
1117
|
+
|
|
1118
|
+
| Prop | Type | Default | Description |
|
|
1119
|
+
|------|------|---------|-------------|
|
|
1068
1120
|
| `oneventclick` | `(event, anchor?: DOMRect) => void` | — | Event clicked (and selected) |
|
|
1069
1121
|
| `oneventcreate` | `(range: { start, end }) => void` | — | A validated new range (real instants) |
|
|
1070
1122
|
| `oneventmove` | `(event, start, end) => void` | — | Drag/resize stored, or refused read-only (real instants) |
|
|
@@ -1075,8 +1127,6 @@ Each event in `api` responses and `events` needs `start` and `end` as date strin
|
|
|
1075
1127
|
| `oneventhover` | `(event) => void` | — | Pointer enters an event |
|
|
1076
1128
|
| `onerror` | `(error: Error) => void` | — | Load and commit failures |
|
|
1077
1129
|
|
|
1078
|
-
</details>
|
|
1079
|
-
|
|
1080
1130
|
## Versioning
|
|
1081
1131
|
|
|
1082
1132
|
The package follows [semver](https://semver.org/) from 1.0:
|
|
@@ -1084,7 +1134,7 @@ The package follows [semver](https://semver.org/) from 1.0:
|
|
|
1084
1134
|
- The public API is exactly what the `.` and `./widget` entry points export. Deep imports into `dist/` are not supported.
|
|
1085
1135
|
- `TimelineEvent`, `CalendarAdapter` and `DateRange` are stable shapes: fields may be added in minor releases, never renamed, removed or given new meaning outside a major.
|
|
1086
1136
|
- The `--dt-*` theme tokens are part of the contract, as are the `<day-calendar>` attributes.
|
|
1087
|
-
- `CalendarLabels` gains keys in minor releases
|
|
1137
|
+
- `CalendarLabels` gains keys in minor releases, so pass a `Partial` (see [Localization](#localization-i18n)).
|
|
1088
1138
|
|
|
1089
1139
|
## Development
|
|
1090
1140
|
|