kalendly 0.2.0 → 0.2.1
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 +133 -54
- package/dist/index.d.mts +14 -1
- package/dist/index.d.ts +14 -1
- package/dist/index.js +227 -33
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +227 -33
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +226 -32
- package/dist/index.umd.js.map +1 -1
- package/dist/styles/calendar.css +96 -0
- package/package.json +20 -34
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ A universal calendar web component — works in React, Vue, Svelte, Angular, Sol
|
|
|
9
9
|
- **Themeable**: CSS variables + JS property API
|
|
10
10
|
- **Type Safe**: Full TypeScript support
|
|
11
11
|
- **Event-rich**: Categories, priorities, time ranges, attendees, and more
|
|
12
|
+
- **Availability mode**: Day and time views for booking flows — hides event details, shows booked/free cells
|
|
13
|
+
- **Lazy loading**: Per-month on-demand fetch with skeleton shimmer state
|
|
12
14
|
- **Accessible**: Built with accessibility in mind
|
|
13
15
|
- **Tree-shakeable**: Import only what you need
|
|
14
16
|
|
|
@@ -60,11 +62,7 @@ npm install kalendly
|
|
|
60
62
|
/>
|
|
61
63
|
<script src="https://unpkg.com/kalendly/dist/index.umd.js"></script>
|
|
62
64
|
|
|
63
|
-
<kal-calendar
|
|
64
|
-
id="cal"
|
|
65
|
-
title="My Calendar"
|
|
66
|
-
initial-date="2025-01-15"
|
|
67
|
-
></kal-calendar>
|
|
65
|
+
<kal-calendar id="cal" title="My Calendar"></kal-calendar>
|
|
68
66
|
|
|
69
67
|
<script>
|
|
70
68
|
const cal = document.getElementById('cal');
|
|
@@ -242,20 +240,6 @@ function App() {
|
|
|
242
240
|
}
|
|
243
241
|
```
|
|
244
242
|
|
|
245
|
-
## Migration from v0.1.x
|
|
246
|
-
|
|
247
|
-
v0.2.0 replaces the four separate framework packages with a single web component.
|
|
248
|
-
|
|
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} />` |
|
|
256
|
-
|
|
257
|
-
React Native is out of scope and not replaced.
|
|
258
|
-
|
|
259
243
|
## Styling
|
|
260
244
|
|
|
261
245
|
### Loading styles
|
|
@@ -301,46 +285,148 @@ document.querySelector('kal-calendar').theme = {
|
|
|
301
285
|
|
|
302
286
|
Primitives are set as HTML attributes:
|
|
303
287
|
|
|
304
|
-
| Attribute | Type
|
|
305
|
-
| ----------------------- |
|
|
306
|
-
| `title` | `string`
|
|
307
|
-
| `initial-date` | `string`
|
|
308
|
-
| `min-year` | `string`
|
|
309
|
-
| `max-year` | `string`
|
|
310
|
-
| `week-starts-on` | `"0"\|"1"`
|
|
311
|
-
| `use-short-month-names` | `string`
|
|
288
|
+
| Attribute | Type | Default | Description |
|
|
289
|
+
| ----------------------- | ---------------- | ---------------- | ------------------------------------------------ |
|
|
290
|
+
| `title` | `string` | — | Calendar title |
|
|
291
|
+
| `initial-date` | `string` | today | ISO date string for initial view |
|
|
292
|
+
| `min-year` | `string` | currentYear - 30 | Minimum year in picker |
|
|
293
|
+
| `max-year` | `string` | currentYear + 10 | Maximum year in picker |
|
|
294
|
+
| `week-starts-on` | `"0"\|"1"` | `"0"` | Week start: 0 = Sunday, 1 = Monday |
|
|
295
|
+
| `use-short-month-names` | `string` | — | Present = use abbreviated month names |
|
|
296
|
+
| `availability-mode` | `"day"\|"time"` | — | Hides event details; shows booked/free cells |
|
|
297
|
+
| `selectable` | `"range"` | — | Enables day/slot selection (requires avail mode) |
|
|
298
|
+
| `loading` | `boolean` (flag) | — | Present = render skeleton shimmer cells |
|
|
312
299
|
|
|
313
300
|
## Properties
|
|
314
301
|
|
|
315
302
|
Rich objects are set as JS properties (not attributes):
|
|
316
303
|
|
|
317
|
-
| Property | Type | Description
|
|
318
|
-
| ---------------- | ---------------------------------- |
|
|
319
|
-
| `events` | `CalendarEvent[]` | Events to display
|
|
320
|
-
| `
|
|
321
|
-
| `
|
|
322
|
-
| `
|
|
323
|
-
| `
|
|
304
|
+
| Property | Type | Description |
|
|
305
|
+
| ---------------- | ---------------------------------- | ------------------------------------------------- |
|
|
306
|
+
| `events` | `CalendarEvent[]` | Events to display |
|
|
307
|
+
| `loading` | `boolean` | `true` = render skeleton cells; `false` = restore |
|
|
308
|
+
| `theme` | `CalendarTheme` | Custom theme colors |
|
|
309
|
+
| `categoryColors` | `CategoryColorMap` | Per-category color overrides |
|
|
310
|
+
| `renderEvent` | `(event: CalendarEvent) => string` | Custom event HTML renderer |
|
|
311
|
+
| `renderNoEvents` | `() => string` | Custom empty-state HTML renderer |
|
|
312
|
+
|
|
313
|
+
> `renderEvent` and `renderNoEvents` are ignored when `availability-mode` is set.
|
|
324
314
|
|
|
325
315
|
## Custom Events
|
|
326
316
|
|
|
327
|
-
| Event
|
|
328
|
-
|
|
|
329
|
-
| `cal-date-select`
|
|
330
|
-
| `cal-month-change`
|
|
317
|
+
| Event | `detail` shape | Description |
|
|
318
|
+
| ------------------------- | ---------------------------------------------------------------------- | -------------------------------------- |
|
|
319
|
+
| `cal-date-select` | `{ date: Date, events: CalendarEvent[] }` | User clicked a date (normal mode) |
|
|
320
|
+
| `cal-month-change` | `{ year: number, month: number }` | Fires **before** the new month renders |
|
|
321
|
+
| `cal-availability-select` | `{ startDate: Date, endDate: Date }` or `{ date, startTime, endTime }` | Day/slot selected in availability mode |
|
|
322
|
+
|
|
323
|
+
All events bubble and are composed (cross Shadow DOM boundaries).
|
|
324
|
+
|
|
325
|
+
`cal-availability-select` detail shape depends on mode:
|
|
326
|
+
|
|
327
|
+
- **Day mode** (`availability-mode="day"`): `{ startDate: Date, endDate: Date }` — first click gives `startDate === endDate`; second click extends the range; third click resets
|
|
328
|
+
- **Time mode** (`availability-mode="time"`): `{ date: Date, startTime: string, endTime: string }` — first click selects a single slot; second click extends; third click resets
|
|
329
|
+
|
|
330
|
+
## Availability Mode
|
|
331
|
+
|
|
332
|
+
Hides all event details from the end user — only booked/free state is shown. Designed for scheduling and booking flows where the server's event data must not be exposed to the viewer.
|
|
333
|
+
|
|
334
|
+
### Day view
|
|
335
|
+
|
|
336
|
+
```html
|
|
337
|
+
<kal-calendar availability-mode="day"></kal-calendar>
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Days with events get a red tint (booked); days without get a green tint (free). Clicking a day opens no popup.
|
|
341
|
+
|
|
342
|
+
Pass the minimal event shape — no names, no descriptions:
|
|
343
|
+
|
|
344
|
+
```js
|
|
345
|
+
cal.events = [
|
|
346
|
+
{ id: 1, date: new Date(2025, 4, 8) },
|
|
347
|
+
{ id: 2, date: new Date(2025, 4, 8), startTime: '14:00', endTime: '16:00' },
|
|
348
|
+
{ id: 3, date: new Date(2025, 4, 20), startTime: '10:00', endTime: '12:00' },
|
|
349
|
+
];
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Time view
|
|
353
|
+
|
|
354
|
+
```html
|
|
355
|
+
<kal-calendar availability-mode="time"></kal-calendar>
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Clicking a day opens a time-grid popup showing which hours are booked (red) and free (green). No event name or organiser is ever rendered.
|
|
359
|
+
|
|
360
|
+
### Selectable range
|
|
331
361
|
|
|
332
|
-
|
|
362
|
+
Add `selectable="range"` to let the user pick a free day or time slot:
|
|
333
363
|
|
|
334
|
-
|
|
364
|
+
```html
|
|
365
|
+
<kal-calendar availability-mode="day" selectable="range"></kal-calendar>
|
|
366
|
+
<kal-calendar availability-mode="time" selectable="range"></kal-calendar>
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
```js
|
|
370
|
+
// Day mode — fires on every click
|
|
371
|
+
cal.addEventListener('cal-availability-select', e => {
|
|
372
|
+
const { startDate, endDate } = e.detail;
|
|
373
|
+
console.log('Selected:', startDate, '→', endDate);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
// Time mode — fires on every slot click
|
|
377
|
+
cal.addEventListener('cal-availability-select', e => {
|
|
378
|
+
const { date, startTime, endTime } = e.detail;
|
|
379
|
+
console.log('Slot:', date, startTime, '–', endTime);
|
|
380
|
+
});
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
Booked days/slots cannot be selected. The 3-click state machine: first click selects, second extends, third resets.
|
|
384
|
+
|
|
385
|
+
## Lazy Event Fetching
|
|
386
|
+
|
|
387
|
+
`cal-month-change` fires **before** the new month renders, so you can set `loading = true` synchronously — the calendar shows skeleton shimmer cells from the first frame with no empty-calendar flash.
|
|
388
|
+
|
|
389
|
+
```js
|
|
390
|
+
cal.addEventListener('cal-month-change', async ({ detail }) => {
|
|
391
|
+
const { year, month } = detail;
|
|
392
|
+
cal.loading = true;
|
|
393
|
+
cal.events = await fetchEvents(year, month); // your API call
|
|
394
|
+
cal.loading = false;
|
|
395
|
+
});
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
The "dump all events upfront" pattern still works unchanged — `cal-month-change` is optional:
|
|
399
|
+
|
|
400
|
+
```js
|
|
401
|
+
// Load once, component handles all months
|
|
402
|
+
cal.events = allEvents;
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Core API
|
|
406
|
+
|
|
407
|
+
`querySelector('kal-calendar')` returns `CalendarElement | null` automatically — no cast needed:
|
|
408
|
+
|
|
409
|
+
```ts
|
|
410
|
+
import type { CalendarElement } from 'kalendly';
|
|
411
|
+
|
|
412
|
+
const cal = document.querySelector('kal-calendar'); // CalendarElement | null
|
|
413
|
+
cal?.goToDate(new Date());
|
|
414
|
+
cal?.updateEvents(events);
|
|
415
|
+
cal?.updateTheme(theme);
|
|
416
|
+
cal?.getCurrentDate(); // Date | null
|
|
417
|
+
cal?.getEngine(); // CalendarEngine
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**JavaScript** works the same way without the import:
|
|
335
421
|
|
|
336
422
|
```js
|
|
337
423
|
const cal = document.querySelector('kal-calendar');
|
|
338
424
|
|
|
339
|
-
cal.updateEvents(newEvents);
|
|
340
|
-
cal.updateTheme(newTheme);
|
|
341
|
-
cal.goToDate(new Date(
|
|
342
|
-
cal.getCurrentDate();
|
|
343
|
-
cal.getEngine();
|
|
425
|
+
cal.updateEvents(newEvents);
|
|
426
|
+
cal.updateTheme(newTheme);
|
|
427
|
+
cal.goToDate(new Date());
|
|
428
|
+
cal.getCurrentDate();
|
|
429
|
+
cal.getEngine();
|
|
344
430
|
```
|
|
345
431
|
|
|
346
432
|
## CalendarEvent Interface
|
|
@@ -470,14 +556,6 @@ Custom Elements v1 — Chrome 67+, Firefox 63+, Safari 12.1+, Edge 79+.
|
|
|
470
556
|
|
|
471
557
|
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
472
558
|
|
|
473
|
-
```bash
|
|
474
|
-
git clone https://github.com/callezenwaka/kalendly.git
|
|
475
|
-
cd kalendly
|
|
476
|
-
npm install
|
|
477
|
-
npm test
|
|
478
|
-
npm run dev:examples
|
|
479
|
-
```
|
|
480
|
-
|
|
481
559
|
## License
|
|
482
560
|
|
|
483
561
|
MIT © Callis Ezenwaka
|
|
@@ -488,7 +566,8 @@ See [CHANGELOG.md](CHANGELOG.md).
|
|
|
488
566
|
|
|
489
567
|
### Recent Updates
|
|
490
568
|
|
|
491
|
-
- **v0.2.
|
|
569
|
+
- **v0.2.1**: Add availability mode (day/time views), selectable range, lazy event fetching with skeleton loading
|
|
570
|
+
- **v0.2.0**: Migrated to a single `<kal-calendar>` web component — works natively in React, Vue, Angular, Svelte, Solid.js, and plain HTML with no framework dependency
|
|
492
571
|
- **v0.1.7**: Vanilla calendar performance optimization with event delegation
|
|
493
572
|
- **v0.1.6**: Navigation enhancements — Today button, month/year picker, optional `title` prop
|
|
494
573
|
- **v0.1.5**: Universal theming system, TypeScript improvements
|
package/dist/index.d.mts
CHANGED
|
@@ -239,15 +239,23 @@ declare class CalendarElement extends HTMLElement {
|
|
|
239
239
|
private _categoryColors;
|
|
240
240
|
private _renderEvent;
|
|
241
241
|
private _renderNoEvents;
|
|
242
|
+
private _rangeStart;
|
|
243
|
+
private _rangeEnd;
|
|
244
|
+
private _timeRangeDate;
|
|
245
|
+
private _timeRangeStart;
|
|
246
|
+
private _timeRangeEnd;
|
|
247
|
+
private _timeRangeComplete;
|
|
242
248
|
get events(): CalendarEvent[];
|
|
243
249
|
set events(val: CalendarEvent[]);
|
|
244
250
|
set theme(val: CalendarTheme);
|
|
245
251
|
set categoryColors(val: CategoryColorMap);
|
|
246
252
|
set renderEvent(val: (e: CalendarEvent) => string);
|
|
247
253
|
set renderNoEvents(val: () => string);
|
|
254
|
+
get loading(): boolean;
|
|
255
|
+
set loading(val: boolean);
|
|
248
256
|
connectedCallback(): void;
|
|
249
257
|
disconnectedCallback(): void;
|
|
250
|
-
attributeChangedCallback(
|
|
258
|
+
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
251
259
|
private get minYear();
|
|
252
260
|
private get maxYear();
|
|
253
261
|
private initEngine;
|
|
@@ -265,6 +273,11 @@ declare class CalendarElement extends HTMLElement {
|
|
|
265
273
|
getEngine(): CalendarEngine;
|
|
266
274
|
}
|
|
267
275
|
declare function defineCalendarElement(tagName?: string): void;
|
|
276
|
+
declare global {
|
|
277
|
+
interface HTMLElementTagNameMap {
|
|
278
|
+
'kal-calendar': CalendarElement;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
268
281
|
|
|
269
282
|
interface CalendarElementProps {
|
|
270
283
|
events?: CalendarEvent[];
|
package/dist/index.d.ts
CHANGED
|
@@ -239,15 +239,23 @@ declare class CalendarElement extends HTMLElement {
|
|
|
239
239
|
private _categoryColors;
|
|
240
240
|
private _renderEvent;
|
|
241
241
|
private _renderNoEvents;
|
|
242
|
+
private _rangeStart;
|
|
243
|
+
private _rangeEnd;
|
|
244
|
+
private _timeRangeDate;
|
|
245
|
+
private _timeRangeStart;
|
|
246
|
+
private _timeRangeEnd;
|
|
247
|
+
private _timeRangeComplete;
|
|
242
248
|
get events(): CalendarEvent[];
|
|
243
249
|
set events(val: CalendarEvent[]);
|
|
244
250
|
set theme(val: CalendarTheme);
|
|
245
251
|
set categoryColors(val: CategoryColorMap);
|
|
246
252
|
set renderEvent(val: (e: CalendarEvent) => string);
|
|
247
253
|
set renderNoEvents(val: () => string);
|
|
254
|
+
get loading(): boolean;
|
|
255
|
+
set loading(val: boolean);
|
|
248
256
|
connectedCallback(): void;
|
|
249
257
|
disconnectedCallback(): void;
|
|
250
|
-
attributeChangedCallback(
|
|
258
|
+
attributeChangedCallback(name: string, oldVal: string | null, newVal: string | null): void;
|
|
251
259
|
private get minYear();
|
|
252
260
|
private get maxYear();
|
|
253
261
|
private initEngine;
|
|
@@ -265,6 +273,11 @@ declare class CalendarElement extends HTMLElement {
|
|
|
265
273
|
getEngine(): CalendarEngine;
|
|
266
274
|
}
|
|
267
275
|
declare function defineCalendarElement(tagName?: string): void;
|
|
276
|
+
declare global {
|
|
277
|
+
interface HTMLElementTagNameMap {
|
|
278
|
+
'kal-calendar': CalendarElement;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
268
281
|
|
|
269
282
|
interface CalendarElementProps {
|
|
270
283
|
events?: CalendarEvent[];
|