kalendly 0.1.7 → 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/README.md +317 -681
- package/dist/core/index.js +3 -3
- package/dist/index.d.mts +48 -602
- package/dist/index.d.ts +48 -602
- package/dist/index.js +753 -2359
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +727 -2348
- package/dist/index.mjs.map +1 -1
- package/dist/{vanilla/index.umd.js → index.umd.js} +218 -218
- package/dist/index.umd.js.map +1 -0
- package/package.json +41 -91
- package/dist/react/index.d.mts +0 -251
- package/dist/react/index.d.ts +0 -251
- package/dist/react/index.js +0 -969
- package/dist/react/index.js.map +0 -1
- package/dist/react/index.mjs +0 -924
- package/dist/react/index.mjs.map +0 -1
- package/dist/react-native/index.d.mts +0 -642
- package/dist/react-native/index.d.ts +0 -642
- package/dist/react-native/index.js +0 -1649
- package/dist/react-native/index.js.map +0 -1
- package/dist/react-native/index.mjs +0 -1615
- package/dist/react-native/index.mjs.map +0 -1
- package/dist/vanilla/index.d.mts +0 -271
- package/dist/vanilla/index.d.ts +0 -271
- package/dist/vanilla/index.js +0 -1064
- package/dist/vanilla/index.js.map +0 -1
- package/dist/vanilla/index.mjs +0 -1013
- package/dist/vanilla/index.mjs.map +0 -1
- package/dist/vanilla/index.umd.js.map +0 -1
- package/dist/vue/components/Calendar.vue.d.ts +0 -43
- package/dist/vue/components/Calendar.vue.d.ts.map +0 -1
- package/dist/vue/index.d.ts +0 -134
- package/dist/vue/index.d.ts.map +0 -1
- package/dist/vue/index.js +0 -1
- package/dist/vue/index.mjs +0 -717
- package/dist/vue/types.d.ts +0 -21
- package/dist/vue/types.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
# kalendly
|
|
1
|
+
# kalendly
|
|
2
2
|
|
|
3
|
-
A universal calendar component
|
|
3
|
+
A universal calendar web component — works in React, Vue, Svelte, Angular, Solid.js, and plain HTML with no framework dependency.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
- 📦 **Tree Shakeable**: Import only what you need
|
|
7
|
+
- **Framework-agnostic**: Single `<kal-calendar>` custom element, no framework required
|
|
8
|
+
- **Responsive**: Mobile-friendly, matches your existing UI
|
|
9
|
+
- **Themeable**: CSS variables + JS property API
|
|
10
|
+
- **Type Safe**: Full TypeScript support
|
|
11
|
+
- **Event-rich**: Categories, priorities, time ranges, attendees, and more
|
|
12
|
+
- **Accessible**: Built with accessibility in mind
|
|
13
|
+
- **Tree-shakeable**: Import only what you need
|
|
15
14
|
|
|
16
|
-
##
|
|
15
|
+
## Live Demo
|
|
17
16
|
|
|
18
17
|
<div align="center">
|
|
19
18
|
|
|
20
19
|
[](https://kalendly-example.netlify.app/)
|
|
21
20
|
|
|
22
|
-
**[
|
|
21
|
+
**[Try the Interactive Demo →](https://kalendly-example.netlify.app/)**
|
|
23
22
|
|
|
24
23
|
</div>
|
|
25
24
|
|
|
@@ -33,809 +32,449 @@ A universal calendar component that works seamlessly across React, Vue, and Reac
|
|
|
33
32
|
<a href="https://kalendly-example.netlify.app/vue">
|
|
34
33
|
<img src="https://img.shields.io/badge/Vue-4FC08D?style=for-the-badge&logo=vue.js&logoColor=white" alt="Vue Demo"/>
|
|
35
34
|
</a>
|
|
35
|
+
<a href="https://kalendly-example.netlify.app/angular">
|
|
36
|
+
<img src="https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white" alt="Angular Demo"/>
|
|
37
|
+
</a>
|
|
38
|
+
<a href="https://kalendly-example.netlify.app/svelte">
|
|
39
|
+
<img src="https://img.shields.io/badge/Svelte-FF3E00?style=for-the-badge&logo=svelte&logoColor=white" alt="Svelte Demo"/>
|
|
40
|
+
</a>
|
|
41
|
+
<a href="https://kalendly-example.netlify.app/solid">
|
|
42
|
+
<img src="https://img.shields.io/badge/Solid.js-2C4F7C?style=for-the-badge&logo=solid&logoColor=white" alt="Solid.js Demo"/>
|
|
43
|
+
</a>
|
|
36
44
|
</p>
|
|
37
45
|
|
|
38
46
|
## Installation
|
|
39
47
|
|
|
40
48
|
```bash
|
|
41
49
|
npm install kalendly
|
|
42
|
-
# or
|
|
43
|
-
yarn add kalendly
|
|
44
|
-
# or
|
|
45
|
-
pnpm add kalendly
|
|
46
50
|
```
|
|
47
51
|
|
|
48
52
|
## Usage
|
|
49
53
|
|
|
50
|
-
###
|
|
51
|
-
|
|
52
|
-
```jsx
|
|
53
|
-
import React from 'react';
|
|
54
|
-
import { Calendar } from 'kalendly/react';
|
|
55
|
-
import 'kalendly/styles';
|
|
54
|
+
### Vanilla HTML / CDN
|
|
56
55
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
56
|
+
```html
|
|
57
|
+
<link
|
|
58
|
+
rel="stylesheet"
|
|
59
|
+
href="https://unpkg.com/kalendly/dist/styles/calendar.css"
|
|
60
|
+
/>
|
|
61
|
+
<script src="https://unpkg.com/kalendly/dist/index.umd.js"></script>
|
|
62
|
+
|
|
63
|
+
<kal-calendar
|
|
64
|
+
id="cal"
|
|
65
|
+
title="My Calendar"
|
|
66
|
+
initial-date="2025-01-15"
|
|
67
|
+
></kal-calendar>
|
|
68
|
+
|
|
69
|
+
<script>
|
|
70
|
+
const cal = document.getElementById('cal');
|
|
71
|
+
|
|
72
|
+
// Set events (JS property — not an attribute)
|
|
73
|
+
cal.events = [
|
|
74
|
+
{ id: 1, name: 'Team Meeting', date: new Date(2025, 0, 15) },
|
|
75
|
+
{ id: 2, name: 'Project Deadline', date: new Date(2025, 0, 20) },
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
// Listen to custom events
|
|
79
|
+
cal.addEventListener('cal-date-select', e => {
|
|
80
|
+
console.log('Selected:', e.detail.date, e.detail.events);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
cal.addEventListener('cal-month-change', e => {
|
|
84
|
+
console.log('Month:', e.detail.year, e.detail.month);
|
|
85
|
+
});
|
|
86
|
+
</script>
|
|
87
87
|
```
|
|
88
88
|
|
|
89
|
-
###
|
|
90
|
-
|
|
91
|
-
```vue
|
|
92
|
-
<template>
|
|
93
|
-
<div>
|
|
94
|
-
<Calendar
|
|
95
|
-
:events="events"
|
|
96
|
-
@date-select="handleDateSelect"
|
|
97
|
-
title="My Calendar"
|
|
98
|
-
>
|
|
99
|
-
<template #event="{ event }">
|
|
100
|
-
<div class="custom-event">{{ event.name }}</div>
|
|
101
|
-
</template>
|
|
102
|
-
</Calendar>
|
|
103
|
-
</div>
|
|
104
|
-
</template>
|
|
89
|
+
### ES Modules
|
|
105
90
|
|
|
106
|
-
|
|
107
|
-
import
|
|
91
|
+
```js
|
|
92
|
+
import 'kalendly';
|
|
108
93
|
import 'kalendly/styles';
|
|
109
94
|
|
|
110
|
-
|
|
111
|
-
{
|
|
112
|
-
id: 1,
|
|
113
|
-
name: 'Team Meeting',
|
|
114
|
-
date: '2025-01-15',
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
id: 2,
|
|
118
|
-
name: 'Project Deadline',
|
|
119
|
-
date: '2025-01-20',
|
|
120
|
-
},
|
|
121
|
-
];
|
|
122
|
-
|
|
123
|
-
const handleDateSelect = date => {
|
|
124
|
-
console.log('Selected date:', date);
|
|
125
|
-
};
|
|
126
|
-
</script>
|
|
95
|
+
// <kal-calendar> is now registered and ready
|
|
127
96
|
```
|
|
128
97
|
|
|
129
|
-
### React
|
|
98
|
+
### React 19
|
|
99
|
+
|
|
100
|
+
React 19 has full custom element support — pass objects/arrays as props and listen to custom events directly.
|
|
130
101
|
|
|
131
102
|
```jsx
|
|
132
|
-
import
|
|
133
|
-
import
|
|
134
|
-
import { Calendar } from 'kalendly/react-native';
|
|
135
|
-
|
|
136
|
-
const events = [
|
|
137
|
-
{
|
|
138
|
-
id: 1,
|
|
139
|
-
name: 'Team Meeting',
|
|
140
|
-
date: '2025-01-15',
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
id: 2,
|
|
144
|
-
name: 'Project Deadline',
|
|
145
|
-
date: '2025-01-20',
|
|
146
|
-
},
|
|
147
|
-
];
|
|
103
|
+
import 'kalendly';
|
|
104
|
+
import 'kalendly/styles';
|
|
148
105
|
|
|
149
106
|
function App() {
|
|
150
|
-
const handleDateSelect = date => {
|
|
151
|
-
console.log('Selected date:', date);
|
|
152
|
-
};
|
|
153
|
-
|
|
154
107
|
return (
|
|
155
|
-
<
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
</View>
|
|
108
|
+
<kal-calendar
|
|
109
|
+
title="My Calendar"
|
|
110
|
+
events={events}
|
|
111
|
+
oncal-date-select={e => console.log(e.detail.date)}
|
|
112
|
+
oncal-month-change={e => console.log(e.detail.year, e.detail.month)}
|
|
113
|
+
/>
|
|
162
114
|
);
|
|
163
115
|
}
|
|
164
|
-
|
|
165
|
-
export default App;
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Vanilla JavaScript
|
|
169
|
-
|
|
170
|
-
#### Modern ES Modules (Recommended)
|
|
171
|
-
|
|
172
|
-
```html
|
|
173
|
-
<!DOCTYPE html>
|
|
174
|
-
<html>
|
|
175
|
-
<head>
|
|
176
|
-
<link
|
|
177
|
-
rel="stylesheet"
|
|
178
|
-
href="node_modules/kalendly/dist/styles/calendar.css"
|
|
179
|
-
/>
|
|
180
|
-
<title>Vanilla JS Calendar</title>
|
|
181
|
-
</head>
|
|
182
|
-
<body>
|
|
183
|
-
<div id="calendar"></div>
|
|
184
|
-
|
|
185
|
-
<script type="module">
|
|
186
|
-
import { createCalendar } from 'kalendly/vanilla';
|
|
187
|
-
|
|
188
|
-
const events = [
|
|
189
|
-
{ id: 1, name: 'Team Meeting', date: '2025-01-15' },
|
|
190
|
-
{ id: 2, name: 'Project Deadline', date: '2025-01-20' },
|
|
191
|
-
];
|
|
192
|
-
|
|
193
|
-
const calendar = createCalendar({
|
|
194
|
-
container: '#calendar',
|
|
195
|
-
events: events,
|
|
196
|
-
title: 'My Calendar',
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
// Listen to events (note: use addEventListener, not onclick)
|
|
200
|
-
document.getElementById('calendar').addEventListener('dateSelect', e => {
|
|
201
|
-
console.log('Selected date:', e.detail.date);
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
document.getElementById('calendar').addEventListener('monthChange', e => {
|
|
205
|
-
console.log('Month changed:', e.detail.year, e.detail.month);
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
// Update events dynamically
|
|
209
|
-
// calendar.updateEvents(newEvents);
|
|
210
|
-
|
|
211
|
-
// Navigate to specific date
|
|
212
|
-
// calendar.goToDate(new Date(2025, 5, 15));
|
|
213
|
-
|
|
214
|
-
// Cleanup when done
|
|
215
|
-
// calendar.destroy();
|
|
216
|
-
</script>
|
|
217
|
-
</body>
|
|
218
|
-
</html>
|
|
219
116
|
```
|
|
220
117
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
<link
|
|
255
|
-
rel="stylesheet"
|
|
256
|
-
href="https://unpkg.com/kalendly/dist/styles/calendar.css"
|
|
257
|
-
/>
|
|
258
|
-
</head>
|
|
259
|
-
<body>
|
|
260
|
-
<div id="calendar"></div>
|
|
261
|
-
|
|
262
|
-
<script src="https://unpkg.com/kalendly/dist/vanilla/index.umd.js"></script>
|
|
263
|
-
<script>
|
|
264
|
-
const { createCalendar } = Kalendly;
|
|
265
|
-
|
|
266
|
-
const calendar = createCalendar({
|
|
267
|
-
container: '#calendar',
|
|
268
|
-
events: [{ id: 1, name: 'Meeting', date: '2025-01-15' }],
|
|
269
|
-
title: 'My Calendar',
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
// Now you can use global functions with onclick
|
|
273
|
-
function handleDateSelect() {
|
|
274
|
-
console.log('Date selected!');
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
document
|
|
278
|
-
.getElementById('calendar')
|
|
279
|
-
.addEventListener('dateSelect', handleDateSelect);
|
|
280
|
-
</script>
|
|
281
|
-
</body>
|
|
282
|
-
</html>
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
## API Reference
|
|
286
|
-
|
|
287
|
-
### Props
|
|
288
|
-
|
|
289
|
-
| Prop | Type | Default | Description |
|
|
290
|
-
| -------------------- | --------------------------------------- | ------------------ | --------------------------------------- |
|
|
291
|
-
| `events` | `CalendarEvent[]` | `[]` | Array of events to display |
|
|
292
|
-
| `initialDate` | `Date` | `new Date()` | Initial date to display |
|
|
293
|
-
| `minYear` | `number` | `currentYear - 30` | Minimum selectable year |
|
|
294
|
-
| `maxYear` | `number` | `currentYear + 10` | Maximum selectable year |
|
|
295
|
-
| `weekStartsOn` | `0 \| 1` | `0` | Week start day (0 = Sunday, 1 = Monday) |
|
|
296
|
-
| `useShortMonthNames` | `boolean` | `false` | Use abbreviated month names (Jan, Feb) |
|
|
297
|
-
| `categoryColors` | `CategoryColorMap` | `{}` | Custom colors for event categories |
|
|
298
|
-
| `theme` | `CalendarTheme` | `undefined` | Custom theme colors for the calendar |
|
|
299
|
-
| `title` | `string` | `undefined` | Optional calendar title displayed above |
|
|
300
|
-
| `onDateSelect` | `(date: Date) => void` | - | Callback when date is selected |
|
|
301
|
-
| `onEventClick` | `(event: CalendarEvent) => void` | - | Callback when event is clicked |
|
|
302
|
-
| `onMonthChange` | `(year: number, month: number) => void` | - | Callback when month changes |
|
|
303
|
-
|
|
304
|
-
### CalendarEvent Interface
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
interface CalendarEvent {
|
|
308
|
-
// Required fields
|
|
309
|
-
id: string | number;
|
|
310
|
-
name: string;
|
|
311
|
-
date: string | Date;
|
|
312
|
-
|
|
313
|
-
// Time fields
|
|
314
|
-
startTime?: string; // e.g., "09:00", "14:30"
|
|
315
|
-
endTime?: string; // e.g., "10:00", "16:00"
|
|
316
|
-
allDay?: boolean; // True for all-day events
|
|
317
|
-
|
|
318
|
-
// Display & categorization
|
|
319
|
-
description?: string;
|
|
320
|
-
color?: string; // Custom event color
|
|
321
|
-
category?:
|
|
322
|
-
| 'work'
|
|
323
|
-
| 'personal'
|
|
324
|
-
| 'meeting'
|
|
325
|
-
| 'deadline'
|
|
326
|
-
| 'appointment'
|
|
327
|
-
| 'other';
|
|
328
|
-
location?: string; // Event location
|
|
329
|
-
url?: string; // Related URL or meeting link
|
|
118
|
+
> **React 18 users:** React 18 does not forward object/array props or custom events to custom elements. You need to wire these up via a `ref`:
|
|
119
|
+
>
|
|
120
|
+
> ```jsx
|
|
121
|
+
> import { useRef, useEffect } from 'react';
|
|
122
|
+
> import 'kalendly';
|
|
123
|
+
>
|
|
124
|
+
> function Calendar({ events, onDateSelect, onMonthChange, ...attrs }) {
|
|
125
|
+
> const ref = useRef(null);
|
|
126
|
+
>
|
|
127
|
+
> useEffect(() => {
|
|
128
|
+
> if (ref.current) ref.current.events = events;
|
|
129
|
+
> }, [events]);
|
|
130
|
+
>
|
|
131
|
+
> useEffect(() => {
|
|
132
|
+
> const el = ref.current;
|
|
133
|
+
> if (!el) return;
|
|
134
|
+
> const onSelect = e => onDateSelect?.(e.detail.date, e.detail.events);
|
|
135
|
+
> const onChange = e => onMonthChange?.(e.detail.year, e.detail.month);
|
|
136
|
+
> el.addEventListener('cal-date-select', onSelect);
|
|
137
|
+
> el.addEventListener('cal-month-change', onChange);
|
|
138
|
+
> return () => {
|
|
139
|
+
> el.removeEventListener('cal-date-select', onSelect);
|
|
140
|
+
> el.removeEventListener('cal-month-change', onChange);
|
|
141
|
+
> };
|
|
142
|
+
> }, [onDateSelect, onMonthChange]);
|
|
143
|
+
>
|
|
144
|
+
> return <kal-calendar ref={ref} {...attrs} />;
|
|
145
|
+
> }
|
|
146
|
+
> ```
|
|
147
|
+
|
|
148
|
+
### Vue 3
|
|
149
|
+
|
|
150
|
+
Vue 3 supports custom elements natively — bind props with `:` and listen to events with `@`:
|
|
330
151
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
152
|
+
```vue
|
|
153
|
+
<template>
|
|
154
|
+
<kal-calendar
|
|
155
|
+
title="My Calendar"
|
|
156
|
+
:events="events"
|
|
157
|
+
@cal-date-select="onDateSelect"
|
|
158
|
+
@cal-month-change="onMonthChange"
|
|
159
|
+
/>
|
|
160
|
+
</template>
|
|
338
161
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
frequency: 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
343
|
-
interval?: number; // Every X days/weeks/months/years
|
|
344
|
-
endDate?: string | Date; // When recurrence ends
|
|
345
|
-
daysOfWeek?: number[]; // For weekly recurrence (0 = Sunday)
|
|
346
|
-
};
|
|
162
|
+
<script setup>
|
|
163
|
+
import 'kalendly';
|
|
164
|
+
import 'kalendly/styles';
|
|
347
165
|
|
|
348
|
-
|
|
349
|
-
notes?: string; // Additional notes
|
|
350
|
-
tags?: string[]; // Event tags
|
|
351
|
-
createdAt?: string | Date; // Creation timestamp
|
|
352
|
-
updatedAt?: string | Date; // Last update timestamp
|
|
166
|
+
const events = [{ id: 1, name: 'Team Meeting', date: new Date(2025, 0, 15) }];
|
|
353
167
|
|
|
354
|
-
|
|
355
|
-
|
|
168
|
+
function onDateSelect(e) {
|
|
169
|
+
console.log('Selected:', e.detail.date);
|
|
356
170
|
}
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
#### Example with Enhanced Fields
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
const events = [
|
|
363
|
-
{
|
|
364
|
-
id: 1,
|
|
365
|
-
name: 'Team Standup',
|
|
366
|
-
date: '2025-01-15',
|
|
367
|
-
startTime: '09:00',
|
|
368
|
-
endTime: '09:30',
|
|
369
|
-
category: 'meeting',
|
|
370
|
-
location: 'Conference Room A',
|
|
371
|
-
url: 'https://meet.google.com/abc-defg-hij',
|
|
372
|
-
attendees: ['john@example.com', 'jane@example.com'],
|
|
373
|
-
organizer: 'team-lead@example.com',
|
|
374
|
-
priority: 'high',
|
|
375
|
-
status: 'scheduled',
|
|
376
|
-
reminders: [15, 60],
|
|
377
|
-
recurring: {
|
|
378
|
-
frequency: 'daily',
|
|
379
|
-
interval: 1,
|
|
380
|
-
daysOfWeek: [1, 2, 3, 4, 5], // Mon-Fri
|
|
381
|
-
endDate: '2025-12-31',
|
|
382
|
-
},
|
|
383
|
-
tags: ['team', 'sync'],
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
id: 2,
|
|
387
|
-
name: 'Project Deadline',
|
|
388
|
-
date: '2025-01-20',
|
|
389
|
-
allDay: true,
|
|
390
|
-
category: 'deadline',
|
|
391
|
-
priority: 'high',
|
|
392
|
-
status: 'scheduled',
|
|
393
|
-
description: 'Final submission for Q1 project',
|
|
394
|
-
notes: 'Make sure all tests pass before submission',
|
|
395
|
-
},
|
|
396
|
-
];
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
#### Category Colors
|
|
400
|
-
|
|
401
|
-
You can customize colors for different event categories:
|
|
402
|
-
|
|
403
|
-
```typescript
|
|
404
|
-
const categoryColors = {
|
|
405
|
-
work: '#4CAF50',
|
|
406
|
-
personal: '#2196F3',
|
|
407
|
-
meeting: '#FF9800',
|
|
408
|
-
deadline: '#F44336',
|
|
409
|
-
appointment: '#9C27B0',
|
|
410
|
-
other: '#607D8B'
|
|
411
|
-
};
|
|
412
171
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
## Theming
|
|
417
|
-
|
|
418
|
-
Kalendly supports custom theming across all frameworks with a **consistent API**. Customize calendar colors to match your brand or create light/dark themes.
|
|
419
|
-
|
|
420
|
-
### CalendarTheme Interface
|
|
421
|
-
|
|
422
|
-
```typescript
|
|
423
|
-
interface CalendarTheme {
|
|
424
|
-
primary?: string; // Primary brand color
|
|
425
|
-
secondary?: string; // Secondary brand color
|
|
426
|
-
tertiary?: string; // Tertiary/accent color
|
|
427
|
-
textColor?: string; // Main text color
|
|
428
|
-
textLight?: string; // Light/secondary text color
|
|
429
|
-
background?: string; // Background color
|
|
430
|
-
cellHover?: string; // Cell hover state color
|
|
431
|
-
borderColor?: string; // Border color
|
|
432
|
-
todayOutline?: string; // Today indicator color
|
|
433
|
-
selectedBg?: string; // Selected date background
|
|
434
|
-
eventIndicator?: string; // Event indicator dot color
|
|
172
|
+
function onMonthChange(e) {
|
|
173
|
+
console.log('Month:', e.detail.year, e.detail.month);
|
|
435
174
|
}
|
|
175
|
+
</script>
|
|
436
176
|
```
|
|
437
177
|
|
|
438
|
-
###
|
|
178
|
+
### Angular
|
|
439
179
|
|
|
440
|
-
|
|
180
|
+
```ts
|
|
181
|
+
// app.config.ts
|
|
182
|
+
import { ApplicationConfig } from '@angular/core';
|
|
183
|
+
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
441
184
|
|
|
442
|
-
|
|
443
|
-
import
|
|
185
|
+
// app.component.ts
|
|
186
|
+
import 'kalendly';
|
|
444
187
|
import 'kalendly/styles';
|
|
445
|
-
|
|
446
|
-
function App() {
|
|
447
|
-
return (
|
|
448
|
-
<Calendar
|
|
449
|
-
events={events}
|
|
450
|
-
theme={{
|
|
451
|
-
primary: '#3b82f6',
|
|
452
|
-
secondary: '#60a5fa',
|
|
453
|
-
tertiary: '#93c5fd',
|
|
454
|
-
borderColor: '#e5e7eb',
|
|
455
|
-
todayOutline: '#fbbf24',
|
|
456
|
-
eventIndicator: '#10b981',
|
|
457
|
-
}}
|
|
458
|
-
/>
|
|
459
|
-
);
|
|
460
|
-
}
|
|
461
188
|
```
|
|
462
189
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
190
|
+
```html
|
|
191
|
+
<!-- app.component.html -->
|
|
192
|
+
<kal-calendar
|
|
193
|
+
title="My Calendar"
|
|
194
|
+
[events]="events"
|
|
195
|
+
(cal-date-select)="onDateSelect($event)"
|
|
196
|
+
(cal-month-change)="onMonthChange($event)"
|
|
197
|
+
></kal-calendar>
|
|
198
|
+
```
|
|
469
199
|
|
|
470
|
-
|
|
471
|
-
import { Calendar } from 'kalendly/vue';
|
|
472
|
-
import 'kalendly/styles';
|
|
200
|
+
### Svelte 5
|
|
473
201
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
todayOutline: '#fbbf24',
|
|
480
|
-
eventIndicator: '#10b981',
|
|
481
|
-
};
|
|
202
|
+
```svelte
|
|
203
|
+
<script>
|
|
204
|
+
import 'kalendly';
|
|
205
|
+
import 'kalendly/styles';
|
|
206
|
+
let { events = [] } = $props();
|
|
482
207
|
</script>
|
|
483
|
-
```
|
|
484
208
|
|
|
485
|
-
|
|
209
|
+
<kal-calendar {events} oncal-date-select={e => console.log(e.detail.date)} />
|
|
210
|
+
```
|
|
486
211
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
212
|
+
### Svelte 4
|
|
213
|
+
|
|
214
|
+
```svelte
|
|
215
|
+
<script>
|
|
216
|
+
import { onMount } from 'svelte';
|
|
217
|
+
import 'kalendly';
|
|
218
|
+
import 'kalendly/styles';
|
|
219
|
+
export let events = [];
|
|
220
|
+
let calEl;
|
|
221
|
+
onMount(() => { calEl.events = events; });
|
|
222
|
+
$: if (calEl) calEl.events = events;
|
|
223
|
+
</script>
|
|
490
224
|
|
|
491
|
-
|
|
492
|
-
container: '#calendar',
|
|
493
|
-
events: events,
|
|
494
|
-
theme: {
|
|
495
|
-
primary: '#3b82f6',
|
|
496
|
-
secondary: '#60a5fa',
|
|
497
|
-
tertiary: '#93c5fd',
|
|
498
|
-
borderColor: '#e5e7eb',
|
|
499
|
-
todayOutline: '#fbbf24',
|
|
500
|
-
eventIndicator: '#10b981',
|
|
501
|
-
},
|
|
502
|
-
});
|
|
225
|
+
<kal-calendar bind:this={calEl} on:cal-date-select on:cal-month-change />
|
|
503
226
|
```
|
|
504
227
|
|
|
505
|
-
|
|
228
|
+
### Solid.js
|
|
506
229
|
|
|
507
|
-
```
|
|
508
|
-
import
|
|
230
|
+
```jsx
|
|
231
|
+
import 'kalendly';
|
|
232
|
+
import 'kalendly/styles';
|
|
509
233
|
|
|
510
234
|
function App() {
|
|
511
235
|
return (
|
|
512
|
-
<
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
secondary: '#60a5fa',
|
|
517
|
-
tertiary: '#93c5fd',
|
|
518
|
-
borderColor: '#e5e7eb',
|
|
519
|
-
todayOutline: '#fbbf24',
|
|
520
|
-
eventIndicator: '#10b981',
|
|
521
|
-
}}
|
|
236
|
+
<kal-calendar
|
|
237
|
+
title="My Calendar"
|
|
238
|
+
prop:events={events}
|
|
239
|
+
on:cal-date-select={e => console.log(e.detail.date)}
|
|
522
240
|
/>
|
|
523
241
|
);
|
|
524
242
|
}
|
|
525
243
|
```
|
|
526
244
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
```typescript
|
|
530
|
-
const darkTheme = {
|
|
531
|
-
primary: '#6366f1',
|
|
532
|
-
secondary: '#818cf8',
|
|
533
|
-
tertiary: '#a5b4fc',
|
|
534
|
-
textColor: '#f9fafb',
|
|
535
|
-
textLight: '#d1d5db',
|
|
536
|
-
background: '#1f2937',
|
|
537
|
-
cellHover: '#374151',
|
|
538
|
-
borderColor: '#4b5563',
|
|
539
|
-
todayOutline: '#fbbf24',
|
|
540
|
-
selectedBg: '#312e81',
|
|
541
|
-
eventIndicator: '#34d399'
|
|
542
|
-
};
|
|
245
|
+
## Migration from v0.1.x
|
|
543
246
|
|
|
544
|
-
|
|
545
|
-
```
|
|
247
|
+
v0.2.0 replaces the four separate framework packages with a single web component.
|
|
546
248
|
|
|
547
|
-
|
|
249
|
+
| Before (v0.1.x) | After (v0.2.0+) |
|
|
250
|
+
| --------------------------------------------------- | ---------------------------------- |
|
|
251
|
+
| `import { Calendar } from 'kalendly/react'` | `import 'kalendly'` |
|
|
252
|
+
| `import { Calendar } from 'kalendly/vue'` | `import 'kalendly'` |
|
|
253
|
+
| `import { Calendar } from 'kalendly/react-native'` | Not supported |
|
|
254
|
+
| `import { createCalendar } from 'kalendly/vanilla'` | `import 'kalendly'` |
|
|
255
|
+
| `<Calendar events={events} />` | `<kal-calendar events={events} />` |
|
|
548
256
|
|
|
549
|
-
|
|
257
|
+
React Native is out of scope and not replaced.
|
|
550
258
|
|
|
551
|
-
|
|
552
|
-
import { useState } from 'react';
|
|
553
|
-
import { Calendar } from 'kalendly/react';
|
|
259
|
+
## Styling
|
|
554
260
|
|
|
555
|
-
|
|
556
|
-
blue: { primary: '#3b82f6', secondary: '#60a5fa' },
|
|
557
|
-
purple: { primary: '#8b5cf6', secondary: '#a78bfa' },
|
|
558
|
-
green: { primary: '#10b981', secondary: '#34d399' },
|
|
559
|
-
};
|
|
261
|
+
### Loading styles
|
|
560
262
|
|
|
561
|
-
|
|
562
|
-
|
|
263
|
+
```js
|
|
264
|
+
// Bundler (Vite, webpack) — add once in your app entry (e.g. main.tsx)
|
|
265
|
+
import 'kalendly/styles';
|
|
563
266
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
<button onClick={() => setCurrentTheme('blue')}>Blue</button>
|
|
567
|
-
<button onClick={() => setCurrentTheme('purple')}>Purple</button>
|
|
568
|
-
<button onClick={() => setCurrentTheme('green')}>Green</button>
|
|
267
|
+
// Plain HTML
|
|
268
|
+
// <link rel="stylesheet" href="/node_modules/kalendly/dist/styles/calendar.css">
|
|
569
269
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
);
|
|
573
|
-
}
|
|
270
|
+
// Angular — add to angular.json → projects → architect → build → styles
|
|
271
|
+
// "node_modules/kalendly/dist/styles/calendar.css"
|
|
574
272
|
```
|
|
575
273
|
|
|
576
|
-
|
|
274
|
+
### Overriding styles
|
|
577
275
|
|
|
578
|
-
|
|
579
|
-
<template>
|
|
580
|
-
<div>
|
|
581
|
-
<button @click="currentTheme = 'blue'">Blue</button>
|
|
582
|
-
<button @click="currentTheme = 'purple'">Purple</button>
|
|
583
|
-
<button @click="currentTheme = 'green'">Green</button>
|
|
276
|
+
kalendly uses Light DOM — all standard CSS techniques work:
|
|
584
277
|
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
const themes = {
|
|
594
|
-
blue: { primary: '#3b82f6', secondary: '#60a5fa' },
|
|
595
|
-
purple: { primary: '#8b5cf6', secondary: '#a78bfa' },
|
|
596
|
-
green: { primary: '#10b981', secondary: '#34d399' },
|
|
597
|
-
};
|
|
278
|
+
```css
|
|
279
|
+
/* 1. CSS custom properties (recommended) */
|
|
280
|
+
:root {
|
|
281
|
+
--calendar-primary-color: #6366f1;
|
|
282
|
+
--calendar-background: #1e1e2e;
|
|
283
|
+
--calendar-border-color: #334155;
|
|
284
|
+
}
|
|
598
285
|
|
|
599
|
-
|
|
600
|
-
|
|
286
|
+
/* 2. Direct class overrides */
|
|
287
|
+
.kalendly-calendar .calendar--card {
|
|
288
|
+
border-radius: 12px;
|
|
289
|
+
}
|
|
601
290
|
```
|
|
602
291
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
const themes = {
|
|
609
|
-
blue: { primary: '#3b82f6', secondary: '#60a5fa' },
|
|
610
|
-
purple: { primary: '#8b5cf6', secondary: '#a78bfa' },
|
|
611
|
-
green: { primary: '#10b981', secondary: '#34d399' },
|
|
292
|
+
```js
|
|
293
|
+
// 3. JS theme property
|
|
294
|
+
document.querySelector('kal-calendar').theme = {
|
|
295
|
+
primary: '#6366f1',
|
|
296
|
+
background: '#1e1e2e',
|
|
612
297
|
};
|
|
613
|
-
|
|
614
|
-
const calendar = createCalendar({
|
|
615
|
-
container: '#calendar',
|
|
616
|
-
events: events,
|
|
617
|
-
theme: themes.blue,
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
// Update theme dynamically without recreation
|
|
621
|
-
document.getElementById('purple-btn').addEventListener('click', () => {
|
|
622
|
-
calendar.updateTheme(themes.purple);
|
|
623
|
-
});
|
|
624
298
|
```
|
|
625
299
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
## Framework-Specific Features
|
|
629
|
-
|
|
630
|
-
### React Props
|
|
631
|
-
|
|
632
|
-
| Prop | Type | Description |
|
|
633
|
-
| ---------------- | ------------------------------------- | ------------------------ |
|
|
634
|
-
| `className` | `string` | CSS class name |
|
|
635
|
-
| `style` | `React.CSSProperties` | Inline styles |
|
|
636
|
-
| `renderEvent` | `(event: CalendarEvent) => ReactNode` | Custom event renderer |
|
|
637
|
-
| `renderNoEvents` | `() => ReactNode` | Custom no events message |
|
|
300
|
+
## Attributes
|
|
638
301
|
|
|
639
|
-
|
|
302
|
+
Primitives are set as HTML attributes:
|
|
640
303
|
|
|
641
|
-
|
|
|
642
|
-
|
|
|
643
|
-
| `title`
|
|
644
|
-
| `
|
|
645
|
-
| `
|
|
304
|
+
| Attribute | Type | Default | Description |
|
|
305
|
+
| ----------------------- | ---------- | ---------------- | ------------------------------------- |
|
|
306
|
+
| `title` | `string` | — | Calendar title |
|
|
307
|
+
| `initial-date` | `string` | today | ISO date string for initial view |
|
|
308
|
+
| `min-year` | `string` | currentYear - 30 | Minimum year in picker |
|
|
309
|
+
| `max-year` | `string` | currentYear + 10 | Maximum year in picker |
|
|
310
|
+
| `week-starts-on` | `"0"\|"1"` | `"0"` | Week start: 0 = Sunday, 1 = Monday |
|
|
311
|
+
| `use-short-month-names` | `string` | — | Present = use abbreviated month names |
|
|
646
312
|
|
|
647
|
-
|
|
313
|
+
## Properties
|
|
648
314
|
|
|
649
|
-
|
|
650
|
-
| ----------------- | ----------- | -------------------------- |
|
|
651
|
-
| `style` | `ViewStyle` | Container style |
|
|
652
|
-
| `headerStyle` | `ViewStyle` | Header style |
|
|
653
|
-
| `cellStyle` | `ViewStyle` | Calendar cell style |
|
|
654
|
-
| `showCloseButton` | `boolean` | Show close button in popup |
|
|
315
|
+
Rich objects are set as JS properties (not attributes):
|
|
655
316
|
|
|
656
|
-
|
|
317
|
+
| Property | Type | Description |
|
|
318
|
+
| ---------------- | ---------------------------------- | -------------------------------- |
|
|
319
|
+
| `events` | `CalendarEvent[]` | Events to display |
|
|
320
|
+
| `theme` | `CalendarTheme` | Custom theme colors |
|
|
321
|
+
| `categoryColors` | `CategoryColorMap` | Per-category color overrides |
|
|
322
|
+
| `renderEvent` | `(event: CalendarEvent) => string` | Custom event HTML renderer |
|
|
323
|
+
| `renderNoEvents` | `() => string` | Custom empty-state HTML renderer |
|
|
657
324
|
|
|
658
|
-
|
|
659
|
-
| ---------------- | ---------------------------------- | ----------------------------- |
|
|
660
|
-
| `container` | `HTMLElement \| string` | Container element or selector |
|
|
661
|
-
| `className` | `string` | Additional CSS class |
|
|
662
|
-
| `renderEvent` | `(event: CalendarEvent) => string` | Custom event HTML renderer |
|
|
663
|
-
| `renderNoEvents` | `() => string` | Custom no events HTML |
|
|
325
|
+
## Custom Events
|
|
664
326
|
|
|
665
|
-
|
|
327
|
+
| Event | `detail` shape | Description |
|
|
328
|
+
| ------------------ | ----------------------------------------- | ------------------------- |
|
|
329
|
+
| `cal-date-select` | `{ date: Date, events: CalendarEvent[] }` | User clicked a date |
|
|
330
|
+
| `cal-month-change` | `{ year: number, month: number }` | Month navigation occurred |
|
|
666
331
|
|
|
667
|
-
|
|
668
|
-
// Listen to calendar events
|
|
669
|
-
calendar.container.addEventListener('dateSelect', e => {
|
|
670
|
-
console.log('Date selected:', e.detail.date);
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
calendar.container.addEventListener('monthChange', e => {
|
|
674
|
-
console.log('Month changed:', e.detail.year, e.detail.month);
|
|
675
|
-
});
|
|
676
|
-
```
|
|
332
|
+
Both events bubble and are composed (cross Shadow DOM boundaries).
|
|
677
333
|
|
|
678
|
-
|
|
334
|
+
## JavaScript API
|
|
679
335
|
|
|
680
|
-
```
|
|
681
|
-
const
|
|
336
|
+
```js
|
|
337
|
+
const cal = document.querySelector('kal-calendar');
|
|
682
338
|
|
|
683
|
-
//
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
calendar.destroy(); // Cleanup
|
|
339
|
+
cal.updateEvents(newEvents); // Re-render with new events
|
|
340
|
+
cal.updateTheme(newTheme); // Apply new theme
|
|
341
|
+
cal.goToDate(new Date(2025, 5, 1)); // Navigate to date
|
|
342
|
+
cal.getCurrentDate(); // Returns currently selected Date
|
|
343
|
+
cal.getEngine(); // Access CalendarEngine directly
|
|
689
344
|
```
|
|
690
345
|
|
|
691
|
-
##
|
|
692
|
-
|
|
693
|
-
### Vanilla JavaScript
|
|
694
|
-
|
|
695
|
-
**Issue: "Function is not defined" errors with onclick handlers**
|
|
696
|
-
|
|
697
|
-
❌ **Wrong:**
|
|
346
|
+
## CalendarEvent Interface
|
|
698
347
|
|
|
699
|
-
```
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
✅ **Correct:**
|
|
707
|
-
|
|
708
|
-
```html
|
|
709
|
-
<button id="myButton">Click me</button>
|
|
710
|
-
<script type="module">
|
|
711
|
-
function myFunction() {}
|
|
712
|
-
document.getElementById('myButton').addEventListener('click', myFunction);
|
|
713
|
-
</script>
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
**Issue: Module imports not working**
|
|
348
|
+
```typescript
|
|
349
|
+
interface CalendarEvent {
|
|
350
|
+
id: string | number;
|
|
351
|
+
name: string;
|
|
352
|
+
date: string | Date;
|
|
717
353
|
|
|
718
|
-
|
|
354
|
+
startTime?: string; // e.g. "09:00"
|
|
355
|
+
endTime?: string; // e.g. "10:00"
|
|
356
|
+
allDay?: boolean;
|
|
719
357
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
358
|
+
description?: string;
|
|
359
|
+
color?: string;
|
|
360
|
+
category?:
|
|
361
|
+
| 'work'
|
|
362
|
+
| 'personal'
|
|
363
|
+
| 'meeting'
|
|
364
|
+
| 'deadline'
|
|
365
|
+
| 'appointment'
|
|
366
|
+
| 'other';
|
|
367
|
+
location?: string;
|
|
368
|
+
url?: string;
|
|
723
369
|
|
|
724
|
-
|
|
370
|
+
status?: 'scheduled' | 'completed' | 'cancelled' | 'tentative';
|
|
371
|
+
priority?: 'low' | 'medium' | 'high';
|
|
725
372
|
|
|
726
|
-
|
|
373
|
+
attendees?: string[];
|
|
374
|
+
organizer?: string;
|
|
375
|
+
reminders?: number[]; // minutes before event
|
|
376
|
+
recurring?: {
|
|
377
|
+
frequency: 'daily' | 'weekly' | 'monthly' | 'yearly';
|
|
378
|
+
interval?: number;
|
|
379
|
+
endDate?: string | Date;
|
|
380
|
+
daysOfWeek?: number[];
|
|
381
|
+
};
|
|
727
382
|
|
|
728
|
-
|
|
729
|
-
|
|
383
|
+
notes?: string;
|
|
384
|
+
tags?: string[];
|
|
385
|
+
[key: string]: unknown;
|
|
386
|
+
}
|
|
730
387
|
```
|
|
731
388
|
|
|
732
|
-
##
|
|
389
|
+
## Theming
|
|
733
390
|
|
|
734
|
-
### CSS
|
|
391
|
+
### All CSS variables
|
|
735
392
|
|
|
736
393
|
```css
|
|
737
394
|
:root {
|
|
738
395
|
--calendar-primary-color: #fc8917;
|
|
739
|
-
--calendar-primary-color-rgb: 252, 137, 23;
|
|
740
396
|
--calendar-secondary-color: #fca045;
|
|
741
|
-
--calendar-secondary-color-rgb: 252, 160, 69;
|
|
742
397
|
--calendar-tertiary-color: #fdb873;
|
|
743
398
|
--calendar-text-color: #2c3e50;
|
|
399
|
+
--calendar-text-light: #6b7280;
|
|
744
400
|
--calendar-border-color: #dee2e6;
|
|
745
401
|
--calendar-today-outline: #f7db04;
|
|
746
402
|
--calendar-event-indicator: #1890ff;
|
|
747
403
|
--calendar-background: #fff;
|
|
404
|
+
--calendar-cell-hover: #f3f4f6;
|
|
405
|
+
--calendar-selected-bg: #eff6ff;
|
|
748
406
|
}
|
|
749
407
|
```
|
|
750
408
|
|
|
751
|
-
|
|
409
|
+
### JS theme property (full reference)
|
|
752
410
|
|
|
753
|
-
|
|
411
|
+
```js
|
|
412
|
+
cal.theme = {
|
|
413
|
+
primary: '#3b82f6',
|
|
414
|
+
secondary: '#60a5fa',
|
|
415
|
+
tertiary: '#93c5fd',
|
|
416
|
+
textColor: '#111827',
|
|
417
|
+
textLight: '#6b7280',
|
|
418
|
+
background: '#ffffff',
|
|
419
|
+
cellHover: '#f3f4f6',
|
|
420
|
+
borderColor: '#e5e7eb',
|
|
421
|
+
todayOutline: '#fbbf24',
|
|
422
|
+
selectedBg: '#eff6ff',
|
|
423
|
+
eventIndicator: '#10b981',
|
|
424
|
+
};
|
|
425
|
+
```
|
|
754
426
|
|
|
755
|
-
|
|
756
|
-
import { calendarStyles } from 'kalendly/react-native';
|
|
427
|
+
### Dark theme example
|
|
757
428
|
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
429
|
+
```js
|
|
430
|
+
cal.theme = {
|
|
431
|
+
primary: '#6366f1',
|
|
432
|
+
secondary: '#818cf8',
|
|
433
|
+
textColor: '#f9fafb',
|
|
434
|
+
textLight: '#d1d5db',
|
|
435
|
+
background: '#1f2937',
|
|
436
|
+
cellHover: '#374151',
|
|
437
|
+
borderColor: '#4b5563',
|
|
438
|
+
todayOutline: '#fbbf24',
|
|
439
|
+
selectedBg: '#312e81',
|
|
440
|
+
eventIndicator: '#34d399',
|
|
765
441
|
};
|
|
766
442
|
```
|
|
767
443
|
|
|
768
|
-
## Core
|
|
769
|
-
|
|
770
|
-
You can also use the core calendar engine directly:
|
|
444
|
+
## Core Engine (advanced)
|
|
771
445
|
|
|
772
446
|
```typescript
|
|
773
447
|
import { CalendarEngine } from 'kalendly/core';
|
|
774
448
|
|
|
775
|
-
const engine = new CalendarEngine({
|
|
776
|
-
events: myEvents,
|
|
777
|
-
initialDate: new Date(),
|
|
778
|
-
});
|
|
449
|
+
const engine = new CalendarEngine({ events, initialDate: new Date() });
|
|
779
450
|
|
|
780
|
-
// Subscribe to changes
|
|
781
451
|
const unsubscribe = engine.subscribe(() => {
|
|
782
|
-
|
|
452
|
+
const viewModel = engine.getViewModel();
|
|
453
|
+
// re-render
|
|
783
454
|
});
|
|
784
455
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
// Navigate months
|
|
790
|
-
actions.next();
|
|
791
|
-
actions.previous();
|
|
792
|
-
actions.jump(2025, 5); // June 2025
|
|
793
|
-
actions.goToToday(); // Navigate to current month
|
|
456
|
+
engine.getActions().next();
|
|
457
|
+
engine.getActions().previous();
|
|
458
|
+
engine.getActions().jump(2025, 5);
|
|
459
|
+
engine.getActions().goToToday();
|
|
794
460
|
|
|
795
|
-
// Check current view
|
|
796
|
-
const isCurrentMonth = actions.isCurrentMonth(); // true if viewing today's month
|
|
797
|
-
|
|
798
|
-
// Clean up
|
|
799
461
|
unsubscribe();
|
|
800
462
|
engine.destroy();
|
|
801
463
|
```
|
|
802
464
|
|
|
803
|
-
## TypeScript Support
|
|
804
|
-
|
|
805
|
-
The package is written in TypeScript and provides full type definitions:
|
|
806
|
-
|
|
807
|
-
```typescript
|
|
808
|
-
import type { CalendarEvent, CalendarProps, CalendarState } from 'kalendly';
|
|
809
|
-
```
|
|
810
|
-
|
|
811
465
|
## Browser Support
|
|
812
466
|
|
|
813
|
-
|
|
814
|
-
- **React Native**: iOS 12+, Android API 21+
|
|
467
|
+
Custom Elements v1 — Chrome 67+, Firefox 63+, Safari 12.1+, Edge 79+.
|
|
815
468
|
|
|
816
469
|
## Contributing
|
|
817
470
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
- Development setup
|
|
821
|
-
- Project structure
|
|
822
|
-
- Building and testing
|
|
823
|
-
- Running examples
|
|
824
|
-
- Submitting pull requests
|
|
825
|
-
- Release process
|
|
826
|
-
|
|
827
|
-
Quick start:
|
|
471
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
828
472
|
|
|
829
473
|
```bash
|
|
830
|
-
# Clone and install
|
|
831
474
|
git clone https://github.com/callezenwaka/kalendly.git
|
|
832
475
|
cd kalendly
|
|
833
476
|
npm install
|
|
834
|
-
|
|
835
|
-
# Run tests
|
|
836
477
|
npm test
|
|
837
|
-
|
|
838
|
-
# Run examples locally
|
|
839
478
|
npm run dev:examples
|
|
840
479
|
```
|
|
841
480
|
|
|
@@ -845,15 +484,12 @@ MIT © Callis Ezenwaka
|
|
|
845
484
|
|
|
846
485
|
## Changelog
|
|
847
486
|
|
|
848
|
-
See [CHANGELOG.md](CHANGELOG.md)
|
|
487
|
+
See [CHANGELOG.md](CHANGELOG.md).
|
|
849
488
|
|
|
850
489
|
### Recent Updates
|
|
851
490
|
|
|
852
|
-
- **v0.
|
|
853
|
-
- **v0.1.
|
|
854
|
-
- **v0.1.
|
|
855
|
-
- **v0.1.
|
|
856
|
-
- **v0.1.3**: Vue types generation improvements
|
|
857
|
-
- **v0.1.2**: Enhanced event parameters with structured metadata, categories, recurrence, collaboration features
|
|
858
|
-
- **v0.1.1**: Pre-commit hooks and trusted publishing with OIDC
|
|
491
|
+
- **v0.2.0**: Migrated to a single `<kal-calendar>` web component — works natively in React, Vue, Angular, and plain HTML with no framework dependency
|
|
492
|
+
- **v0.1.7**: Vanilla calendar performance optimization with event delegation
|
|
493
|
+
- **v0.1.6**: Navigation enhancements — Today button, month/year picker, optional `title` prop
|
|
494
|
+
- **v0.1.5**: Universal theming system, TypeScript improvements
|
|
859
495
|
- **v0.1.0**: Initial release with React, Vue, React Native, and Vanilla JavaScript support
|